From 2d6217eb57c9f25112837c0962bfb8955ff1d3d3 Mon Sep 17 00:00:00 2001
From: Nalin Dahyabhai <nalin@dahyabhai.net>
Date: Wed, 29 Jun 2011 18:25:05 -0400
Subject: [PATCH 127/150] - try to handle signed-data inside data inside
 enveloped-data

---
 src/plugins/preauth/pkinit/pkinit_crypto_nss.c |   80 ++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
index debc1e7..291ac29 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
@@ -4563,37 +4563,87 @@ crypto_signeddata_common_verify(krb5_context context,
 				CERTCertDBHandle *certdb,
 				SECCertUsage usage,
 				SECOidTag expected_type,
+				PLArenaPool *pool,
 				SECItem **plain,
 				int cms_msg_type,
 				int *is_signed)
 {
 	NSSCMSSignedData *sdata;
 	NSSCMSSignerInfo *signer;
+	NSSCMSMessage *ecmsg;
 	NSSCMSContentInfo *ecinfo;
 	CERTCertificate *cert;
 	SECOidTag encapsulated_tag;
 	SECStatus status;
+	SECItem *edata;
 	int n_signers;
 
 	*is_signed = 0;
 
+	/* Handle cases where we're passed data containing signed-data. */
+	if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA) {
+		/* Look at the payload data. */
+		edata = NSS_CMSContentInfo_GetContent(cinfo);
+		if (edata == NULL) {
+			pkiDebug("%s: no plain-data content\n", __FUNCTION__);
+			return ENOMEM;
+		}
+		/* See if it's content-info. */
+		ecmsg = NSS_CMSMessage_CreateFromDER(edata,
+						     NULL, NULL,
+						     crypto_pwcb,
+						     crypto_pwcb_prep(id_cryptoctx,
+								      context),
+						     NULL, NULL);
+		if (ecmsg == NULL) {
+			pkiDebug("%s: plain-data not parsable\n", __FUNCTION__);
+			return ENOMEM;
+		}
+		/* Check if it actually contains signed-data. */
+		ecinfo = NSS_CMSMessage_GetContentInfo(ecmsg);
+		if (ecinfo == NULL) {
+			pkiDebug("%s: plain-data has no cinfo\n", __FUNCTION__);
+			NSS_CMSMessage_Destroy(ecmsg);
+			return ENOMEM;
+		}
+		if (NSS_CMSContentInfo_GetContentTypeTag(ecinfo) !=
+		    SEC_OID_PKCS7_SIGNED_DATA) {
+			pkiDebug("%s: plain-data is not sdata\n", __FUNCTION__);
+			NSS_CMSMessage_Destroy(ecmsg);
+			return EINVAL;
+		}
+		cinfo = ecinfo;
+	} else {
+		/* Okay, it's a normal signed-data blob. */
+		ecmsg = NULL;
+	}
+
 	/* Check that we have signed data, that it has exactly one signature,
 	 * and fish out the signer information. */
 	if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) !=
 	    SEC_OID_PKCS7_SIGNED_DATA) {
 		pkiDebug("%s: content type mismatch\n", __FUNCTION__);
+		if (ecmsg != NULL) {
+			NSS_CMSMessage_Destroy(ecmsg);
+		}
 		return EINVAL;
 	}
 	sdata = NSS_CMSContentInfo_GetContent(cinfo);
 	if (sdata == NULL) {
 		pkiDebug("%s: decoding error? content-info was NULL\n",
 			 __FUNCTION__);
+		if (ecmsg != NULL) {
+			NSS_CMSMessage_Destroy(ecmsg);
+		}
 		return ENOENT;
 	}
 	n_signers = NSS_CMSSignedData_SignerInfoCount(sdata);
 	if (n_signers > 1) {
 		pkiDebug("%s: wrong number of signers (%d, not 0 or 1)\n",
 			 __FUNCTION__, n_signers);
+		if (ecmsg != NULL) {
+			NSS_CMSMessage_Destroy(ecmsg);
+		}
 		return ENOENT;
 	}
 	if (n_signers < 1) {
@@ -4604,16 +4654,25 @@ crypto_signeddata_common_verify(krb5_context context,
 						  PR_FALSE) != SECSuccess) {
 			pkiDebug("%s: error importing signer certs\n",
 				 __FUNCTION__);
+			if (ecmsg != NULL) {
+				NSS_CMSMessage_Destroy(ecmsg);
+			}
 			return ENOENT;
 		}
 		signer = NSS_CMSSignedData_GetSignerInfo(sdata, 0);
 		if (signer == NULL) {
 			pkiDebug("%s: no signers?\n", __FUNCTION__);
+			if (ecmsg != NULL) {
+				NSS_CMSMessage_Destroy(ecmsg);
+			}
 			return ENOENT;
 		}
 		/* Verify the signer's certificate. */
 		if (!NSS_CMSSignedData_HasDigests(sdata)) {
 			pkiDebug("%s: no digests?\n", __FUNCTION__);
+			if (ecmsg != NULL) {
+				NSS_CMSMessage_Destroy(ecmsg);
+			}
 			return ENOENT;
 		}
 		status = CERT_EnableOCSPChecking(certdb);
@@ -4622,6 +4681,9 @@ crypto_signeddata_common_verify(krb5_context context,
 				 PR_ErrorToString(status == SECFailure ?
 						  PORT_GetError() : status,
 						  PR_LANGUAGE_I_DEFAULT));
+			if (ecmsg != NULL) {
+				NSS_CMSMessage_Destroy(ecmsg);
+			}
 			return ENOMEM;
 		}
 		/* NSS will use OCSP if there's no applicable CRL cached, and
@@ -4637,6 +4699,9 @@ crypto_signeddata_common_verify(krb5_context context,
 				 PR_ErrorToString(status == SECFailure ?
 						  PORT_GetError() : status,
 						  PR_LANGUAGE_I_DEFAULT));
+			if (ecmsg != NULL) {
+				NSS_CMSMessage_Destroy(ecmsg);
+			}
 			return ENOMEM;
 		}
 		status = NSS_CMSSignedData_VerifySignerInfo(sdata, 0, certdb,
@@ -4646,6 +4711,9 @@ crypto_signeddata_common_verify(krb5_context context,
 				 PR_ErrorToString(status == SECFailure ?
 						  PORT_GetError() : status,
 						  PR_LANGUAGE_I_DEFAULT));
+			if (ecmsg != NULL) {
+				NSS_CMSMessage_Destroy(ecmsg);
+			}
 			switch (cms_msg_type) {
 			case CMS_SIGN_DRAFT9:
 			case CMS_SIGN_CLIENT:
@@ -4667,12 +4735,18 @@ crypto_signeddata_common_verify(krb5_context context,
 	if (ecinfo == NULL) {
 		pkiDebug("%s: error getting encapsulated content\n",
 			 __FUNCTION__);
+		if (ecmsg != NULL) {
+			NSS_CMSMessage_Destroy(ecmsg);
+		}
 		return ENOMEM;
 	}
 	encapsulated_tag = NSS_CMSContentInfo_GetContentTypeTag(ecinfo);
 	if (encapsulated_tag != expected_type) {
 		pkiDebug("%s: wrong encapsulated content type\n",
 			 __FUNCTION__);
+		if (ecmsg != NULL) {
+			NSS_CMSMessage_Destroy(ecmsg);
+		}
 		return EINVAL;
 	}
 	*plain = NSS_CMSContentInfo_GetContent(ecinfo);
@@ -4689,6 +4763,10 @@ crypto_signeddata_common_verify(krb5_context context,
 		cert = NSS_CMSSignerInfo_GetSigningCertificate(signer, certdb);
 		req_cryptoctx->peer_cert = CERT_DupCertificate(cert);
 	}
+	if (ecmsg != NULL) {
+		*plain = SECITEM_ArenaDupItem(pool, *plain);
+		NSS_CMSMessage_Destroy(ecmsg);
+	}
 	return 0;
 }
 
@@ -4775,6 +4853,7 @@ cms_envelopeddata_verify(krb5_context context,
 					      certdb,
 					      usage,
 					      expected_tag,
+					      pool,
 					      &plain,
 					      CMS_ENVEL_SERVER,
 					      &is_signed);
@@ -5055,6 +5134,7 @@ cms_signeddata_verify(krb5_context context,
 						      certdb,
 						      usage,
 						      expected_tag,
+						      pool,
 						      &plain,
 						      cms_msg_type,
 						      &was_signed);
-- 
1.7.6.4

