Blame SOURCES/0036-Re-order-the-way-the-SCEP-signing-and-CA-certs-are-c.patch

f0b236
From b3dad1c94f2fca289fdf22ded38a1f1463bab95f Mon Sep 17 00:00:00 2001
f0b236
From: Rob Crittenden <rcritten@redhat.com>
f0b236
Date: Wed, 15 Apr 2020 17:16:42 -0400
f0b236
Subject: [PATCH 36/39] Re-order the way the SCEP signing and CA certs are
f0b236
 collected
f0b236
f0b236
Put cacert into the ca store, the racert at the top of the
f0b236
othercerts list. Then we parse certs, placing all ca certs
f0b236
we find into the ca store, and all other certs we find after
f0b236
the racert.
f0b236
f0b236
Variables are renamed to match the cm_pkcs7_parse() and
f0b236
cm_pkcs7_verify_signed() calls.
f0b236
f0b236
A special case for IPA (dogtag) was added because dogtag
f0b236
uses its CA cert to sign the PKCS7 so it is both an RA cert
f0b236
and a CA cert. If a self-signed CA is detected and no other
f0b236
certs are provided then the CA is treated as the RA.
f0b236
f0b236
https://bugzilla.redhat.com/show_bug.cgi?id=1808052
f0b236
f0b236
Graham Leggett did the majority of the work on this patch.
f0b236
---
f0b236
 src/pkcs7.c |  18 +++++++++
f0b236
 src/pkcs7.h |   1 +
f0b236
 src/scep.c  | 104 +++++++++++++++++++++++++++++++++++-----------------
f0b236
 3 files changed, 89 insertions(+), 34 deletions(-)
f0b236
f0b236
diff --git a/src/pkcs7.c b/src/pkcs7.c
f0b236
index 29420b9..f81174f 100644
f0b236
--- a/src/pkcs7.c
f0b236
+++ b/src/pkcs7.c
f0b236
@@ -1189,3 +1189,21 @@ done:
f0b236
 	}
f0b236
 	return ret;
f0b236
 }
f0b236
+
f0b236
+/* Return 0 if we think "issuer" could have issued "issued", which includes
f0b236
+ * self-signing. */
f0b236
+int
f0b236
+cm_selfsigned(char *cert) 
f0b236
+{
f0b236
+	BIO *in;
f0b236
+	X509 *c;
f0b236
+
f0b236
+	in = BIO_new_mem_buf(cert, -1);
f0b236
+	if (in == NULL) {
f0b236
+		cm_log(0, "Out of memory.\n");
f0b236
+		return 1;
f0b236
+	}
f0b236
+	c = PEM_read_bio_X509(in, NULL, NULL, NULL);
f0b236
+	BIO_free(in);
f0b236
+	return(issuerissued(c, c));
f0b236
+}
f0b236
diff --git a/src/pkcs7.h b/src/pkcs7.h
f0b236
index fae52f8..cbde1bc 100644
f0b236
--- a/src/pkcs7.h
f0b236
+++ b/src/pkcs7.h
f0b236
@@ -62,6 +62,7 @@ int cm_pkcs7_verify_signed(unsigned char *data, size_t length,
f0b236
 			   unsigned char **recipient_nonce,
f0b236
 			   size_t *recipient_nonce_length,
f0b236
 			   unsigned char **payload, size_t *payload_length);
f0b236
+int cm_selfsigned(char *cert);
f0b236
 
f0b236
 void log_pkcs7_errors(int level, char *msg);
f0b236
 
f0b236
diff --git a/src/scep.c b/src/scep.c
f0b236
index 4d00692..b80278e 100644
f0b236
--- a/src/scep.c
f0b236
+++ b/src/scep.c
f0b236
@@ -211,12 +211,12 @@ main(int argc, const char **argv)
f0b236
 	const char *mode = NULL, *content_type = NULL, *content_type2 = NULL;
f0b236
 	void *ctx;
f0b236
 	char *params = "", *params2 = NULL, *racert = NULL, *cacert = NULL;
f0b236
-	char **othercerts = NULL, *cert1 = NULL, *cert2 = NULL, *certs = NULL;
f0b236
+	char **certothers = NULL, *certleaf = NULL, *certtop = NULL, *certs = NULL;
f0b236
 	char **racertp, **cacertp, *dracert = NULL, *dcacert = NULL;
f0b236
 	char buf[LINE_MAX] = "";
f0b236
 	const unsigned char **buffers = NULL;
f0b236
 	size_t n_buffers = 0, *lengths = NULL, j;
f0b236
-	const char *cacerts[3], **racerts;
f0b236
+	const char *root[3], **othercerts;
f0b236
 	dbus_bool_t missing_args = FALSE;
f0b236
 	char *sent_tx, *tx, *msgtype, *pkistatus, *failinfo, *s, *tmp1, *tmp2;
f0b236
 	unsigned char *sent_nonce, *sender_nonce, *recipient_nonce, *payload;
f0b236
@@ -871,27 +871,27 @@ main(int argc, const char **argv)
f0b236
 			n_buffers++;
f0b236
 		}
f0b236
 		if (cm_pkcs7_parsev(CM_PKCS7_LEAF_PREFER_ENCRYPT, ctx,
f0b236
-				    racertp, cacertp, &othercerts,
f0b236
+				    racertp, cacertp, &certothers,
f0b236
 				    NULL, NULL,
f0b236
 				    n_buffers, buffers, lengths) == 0) {
f0b236
 			if (racert != NULL) {
f0b236
 				printf("%s", racert);
f0b236
 				if (cacert != NULL) {
f0b236
 					printf("%s", cacert);
f0b236
-					if (othercerts != NULL) {
f0b236
+					if (certothers != NULL) {
f0b236
 						for (c = 0;
f0b236
-						     othercerts[c] != NULL;
f0b236
+						     certothers[c] != NULL;
f0b236
 						     c++) {
f0b236
 							printf("%s",
f0b236
-							       othercerts[c]);
f0b236
+							       certothers[c]);
f0b236
 						}
f0b236
 					}
f0b236
 					if ((dracert != NULL) &&
f0b236
-					    (cert_among(dracert, racert, cacert, othercerts) != 0)) {
f0b236
+					    (cert_among(dracert, racert, cacert, certothers) != 0)) {
f0b236
 						printf("%s", dracert);
f0b236
 					}
f0b236
 					if ((dcacert != NULL) &&
f0b236
-					    (cert_among(dcacert, racert, cacert, othercerts) != 0)) {
f0b236
+					    (cert_among(dcacert, racert, cacert, certothers) != 0)) {
f0b236
 						printf("%s", dcacert);
f0b236
 					}
f0b236
 				}
f0b236
@@ -907,47 +907,83 @@ main(int argc, const char **argv)
f0b236
 	case op_pkcsreq:
f0b236
 		if ((content_type2 != NULL) && (strcasecmp(content_type2,
f0b236
 			       "application/x-pki-message") == 0)) {
f0b236
-			memset(&cacerts, 0, sizeof(cacerts));
f0b236
-			cacerts[0] = cacert ? cacert : racert;
f0b236
-			cacerts[1] = cacert ? racert : NULL;
f0b236
-			cacerts[2] = NULL;
f0b236
-			racerts = NULL;
f0b236
+			/*
f0b236
+			 * At this point, we have:
f0b236
+			 * - zero or more ra certs; and
f0b236
+			 * - zero or more ca certificates; and
f0b236
+			 * - zero or more other certificates; that
f0b236
+			 * need to be reordered so that the leaf
f0b236
+			 * certificates go first, the ca certificates
f0b236
+			 * are separated into a seperate certificate
f0b236
+			 * store, and the other certificates go after
f0b236
+			 * the leaf certificates.
f0b236
+			 *
f0b236
+			 * To do this we put cacert into the ca store,
f0b236
+			 * the racert at the top of the othercerts list.
f0b236
+			 * Then we parse certs, placing all ca certs
f0b236
+			 * we find into the ca store, and all other
f0b236
+			 * certs we find after the racert.
f0b236
+			 *
f0b236
+			 * As a limitation of cm_pkcs7_parse(), we
f0b236
+			 * can only isolate one ca certificate in the
f0b236
+			 * list of other certificates.
f0b236
+			 */
f0b236
+			/* handle the other certs */
f0b236
 			if ((certs != NULL) &&
f0b236
 			    (cm_pkcs7_parse(0, ctx,
f0b236
-					    &cert1, &cert2, &othercerts,
f0b236
+					    &certleaf, &certtop, &certothers,
f0b236
 					    NULL, NULL,
f0b236
 					    (const unsigned char *) certs,
f0b236
 					    strlen(certs), NULL) == 0)) {
f0b236
-				for (c = 0;
f0b236
-				     (othercerts != NULL) &&
f0b236
-				     (othercerts[c] != NULL);
f0b236
-				     c++) {
f0b236
-					continue;
f0b236
+				/* Special case for IPA which uses dogtag which signs SCEP
f0b236
+				 * certs using the CA cert and the typical way to get
f0b236
+				 * verification to work is to use -I /etc/ipa/ca.crt.
f0b236
+				 * Because cm_pkcs7_parse explicitly doesn't allow
f0b236
+				 * certleaf to equal certtop we end up with no CAs so verification
f0b236
+				 * fails.
f0b236
+				 * 
f0b236
+				 * So if cacert and certleaf are both NULL and certtop is
f0b236
+				 * self-signed then assume the IPA case and set certtop equal
f0b236
+				 * to certleaf.
f0b236
+				 */
f0b236
+				if ((cacert == NULL) && (certtop == NULL) && (certleaf != NULL)) {
f0b236
+					if (cm_selfsigned(certleaf) == 0) {
f0b236
+						certtop = certleaf;
f0b236
+					}
f0b236
 				}
f0b236
-				racerts = talloc_array_ptrtype(ctx, racerts, c + 5);
f0b236
+				memset(&root, 0, sizeof(root));
f0b236
+				root[0] = cacert ? cacert : certtop ? certtop : NULL;
f0b236
+				root[1] = cacert ? certtop : NULL;
f0b236
+				root[2] = NULL;
f0b236
 				for (c = 0;
f0b236
-				     (othercerts != NULL) &&
f0b236
-				     (othercerts[c] != NULL);
f0b236
+				     (certothers != NULL) &&
f0b236
+				     (certothers[c] != NULL);
f0b236
 				     c++) {
f0b236
-					racerts[c] = othercerts[c];
f0b236
-				}
f0b236
-				if (cacert != NULL) {
f0b236
-					racerts[c++] = cacert;
f0b236
+					continue;
f0b236
 				}
f0b236
-				if (cert1 != NULL) {
f0b236
-					racerts[c++] = cert1;
f0b236
+				othercerts = talloc_array_ptrtype(ctx, othercerts, c + 3);
f0b236
+				c = 0;
f0b236
+				if (racert != NULL) {
f0b236
+					othercerts[c++] = racert;
f0b236
 				}
f0b236
-				if (cert2 != NULL) {
f0b236
-					racerts[c++] = cert2;
f0b236
+				if (certleaf != NULL) {
f0b236
+					othercerts[c++] = certleaf;
f0b236
 				}
f0b236
-				if (racert != NULL) {
f0b236
-					racerts[c++] = racert;
f0b236
+				while (certothers != NULL && *certothers != NULL) {
f0b236
+					othercerts[c++] = *certothers++;
f0b236
 				}
f0b236
-				racerts[c++] = NULL;
f0b236
+				othercerts[c++] = NULL;
f0b236
+			}
f0b236
+			else {
f0b236
+				root[0] = cacert;
f0b236
+				root[1] = NULL;
f0b236
+				othercerts = talloc_array_ptrtype(ctx, othercerts, 2);
f0b236
+				othercerts[0] = racert ? racert : NULL;
f0b236
+				othercerts[1] = NULL;
f0b236
 			}
f0b236
 			ERR_clear_error();
f0b236
 			i = cm_pkcs7_verify_signed((unsigned char *) results2, results_length2,
f0b236
-						   cacerts, racerts,
f0b236
+						   root, othercerts,
f0b236
 						   NID_pkcs7_data, ctx, NULL,
f0b236
 						   &tx, &msgtype, &pkistatus, &failinfo,
f0b236
 						   &sender_nonce, &sender_nonce_length,
f0b236
-- 
f0b236
2.21.1
f0b236