Bug 842856 - Add SEC_PKCS7VerifyDetachedSignatureAtTime for verifying the certificate chain at the current time instead of the signing time, r=rrelyea NSS_3_15_BETA1
authorBrian Smith <bsmith@mozilla.com>
Thu, 04 Apr 2013 21:59:57 +0200
changeset 10725 8b2a6b06539153448d895d3d83a32546ad94bc7b
parent 10724 0198afefa09ab41f82f4b9d8c61879830a5f1ec9
child 10726 4b43c609072d21ddec6738f698ab51fa7e31bff2
push id35
push userkaie@kuix.de
push dateThu, 04 Apr 2013 20:00:07 +0000
reviewersrrelyea
bugs842856
Bug 842856 - Add SEC_PKCS7VerifyDetachedSignatureAtTime for verifying the certificate chain at the current time instead of the signing time, r=rrelyea
lib/pkcs7/p7decode.c
lib/pkcs7/secpkcs7.h
lib/smime/smime.def
--- a/lib/pkcs7/p7decode.c
+++ b/lib/pkcs7/p7decode.c
@@ -1241,23 +1241,27 @@ SEC_PKCS7ContentIsSigned(SEC_PKCS7Conten
     if (signerinfos != NULL && signerinfos[0] != NULL)
 	return PR_TRUE;
     else
 	return PR_FALSE;
 }
 
 
 /*
- * SEC_PKCS7ContentVerifySignature
+ * sec_pkcs7_verify_signature
+ *
  *	Look at a PKCS7 contentInfo and check if the signature is good.
  *	The digest was either calculated earlier (and is stored in the
  *	contentInfo itself) or is passed in via "detached_digest".
  *
  *	The verification checks that the signing cert is valid and trusted
- *	for the purpose specified by "certusage".
+ *	for the purpose specified by "certusage" at
+ * 	- "*atTime" if "atTime" is not null, or
+ * 	- the signing time if the signing time is available in "cinfo", or
+ *	- the current time (as returned by PR_Now).
  *
  *	In addition, if "keepcerts" is true, add any new certificates found
  *	into our local database.
  *
  * XXX Each place which returns PR_FALSE should be sure to have a good
  * error set for inspection by the caller.  Alternatively, we could create
  * an enumeration of success and each type of failure and return that
  * instead of a boolean.  For now, the default in a bad situation is to
@@ -1276,17 +1280,18 @@ SEC_PKCS7ContentIsSigned(SEC_PKCS7Conten
  * there should be NO authenticatedAttributes (signerinfo->authAttr should
  * be NULL).
  */
 static PRBool
 sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
 			   SECCertUsage certusage,
 			   const SECItem *detached_digest,
 			   HASH_HashType digest_type,
-			   PRBool keepcerts)
+			   PRBool keepcerts,
+			   const PRTime *atTime)
 {
     SECAlgorithmID **digestalgs, *bulkid;
     const SECItem *digest;
     SECItem **digests;
     SECItem **rawcerts;
     CERTSignedCrl **crls;
     SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
     CERTCertificate *cert, **certs;
@@ -1294,17 +1299,18 @@ sec_pkcs7_verify_signature(SEC_PKCS7Cont
     CERTCertDBHandle *certdb, *defaultdb; 
     SECOidTag encTag,digestTag;
     HASH_HashType found_type;
     int i, certcount;
     SECKEYPublicKey *publickey;
     SECItem *content_type;
     PK11SymKey *sigkey;
     SECItem *encoded_stime;
-    int64 stime;
+    PRTime stime;
+    PRTime verificationTime;
     SECStatus rv;
 
     /*
      * Everything needed in order to "goto done" safely.
      */
     goodsig = PR_FALSE;
     certcount = 0;
     cert = NULL;
@@ -1431,18 +1437,24 @@ sec_pkcs7_verify_signature(SEC_PKCS7Cont
     /*
      * XXX  This uses the signing time, if available.  Additionally, we
      * might want to, if there is no signing time, get the message time
      * from the mail header itself, and use that.  That would require
      * a change to our interface though, and for S/MIME callers to pass
      * in a time (and for non-S/MIME callers to pass in nothing, or
      * maybe make them pass in the current time, always?).
      */
-    if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage,
-			 encoded_stime != NULL ? stime : PR_Now(),
+    if (atTime) {
+	verificationTime = *atTime;
+    } else if (encoded_stime != NULL) {
+	verificationTime = stime;
+    } else {
+	verificationTime = PR_Now();
+    }
+    if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, verificationTime,
 			 cinfo->pwfn_arg, NULL) != SECSuccess)
 	{
 	/*
 	 * XXX Give the user an option to check the signature anyway?
 	 * If we want to do this, need to give a way to leave and display
 	 * some dialog and get the answer and come back through (or do
 	 * the rest of what we do below elsewhere, maybe by putting it
 	 * in a function that we call below and could call from a dialog
@@ -1743,17 +1755,17 @@ done:
  *	into our local database.
  */
 PRBool
 SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
 			 SECCertUsage certusage,
 			 PRBool keepcerts)
 {
     return sec_pkcs7_verify_signature (cinfo, certusage,
-				       NULL, HASH_AlgNULL, keepcerts);
+				       NULL, HASH_AlgNULL, keepcerts, 0);
 }
 
 /*
  * SEC_PKCS7VerifyDetachedSignature
  *	Look at a PKCS7 contentInfo and check if the signature matches
  *	a passed-in digest (calculated, supposedly, from detached contents).
  *	The verification checks that the signing cert is valid and trusted
  *	for the purpose specified by "certusage".
@@ -1765,19 +1777,41 @@ PRBool
 SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
 				 SECCertUsage certusage,
 				 const SECItem *detached_digest,
 				 HASH_HashType digest_type,
 				 PRBool keepcerts)
 {
     return sec_pkcs7_verify_signature (cinfo, certusage,
 				       detached_digest, digest_type,
-				       keepcerts);
+				       keepcerts, NULL);
 }
 
+/*
+ * SEC_PKCS7VerifyDetachedSignatureAtTime
+ *      Look at a PKCS7 contentInfo and check if the signature matches
+ *      a passed-in digest (calculated, supposedly, from detached contents).
+ *      The verification checks that the signing cert is valid and trusted
+ *      for the purpose specified by "certusage" at time "atTime".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ */
+PRBool
+SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
+				       SECCertUsage certusage,
+				       const SECItem *detached_digest,
+				       HASH_HashType digest_type,
+				       PRBool keepcerts,
+				       PRTime atTime)
+{
+    return sec_pkcs7_verify_signature (cinfo, certusage,
+				       detached_digest, digest_type,
+				       keepcerts, &atTime);
+}
 
 /*
  * Return the asked-for portion of the name of the signer of a PKCS7
  * signed object.
  *
  * Returns a pointer to allocated memory, which must be freed.
  * A NULL return value is an error.
  */
@@ -1830,17 +1864,17 @@ sec_pkcs7_get_signer_cert_info(SEC_PKCS7
      */
     if (signercert == NULL) {
 	/*
 	 * The cert usage does not matter in this case, because we do not
 	 * actually care about the verification itself, but we have to pick
 	 * some valid usage to pass in.
 	 */
 	(void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner,
-					   NULL, HASH_AlgNULL, PR_FALSE);
+					   NULL, HASH_AlgNULL, PR_FALSE, 0);
 	signercert = signerinfos[0]->cert;
 	if (signercert == NULL)
 	    return NULL;
     }
 
     switch (selector) {
       case sec_common_name:
 	container = CERT_GetCommonName (&signercert->subject);
--- a/lib/pkcs7/secpkcs7.h
+++ b/lib/pkcs7/secpkcs7.h
@@ -129,16 +129,34 @@ extern PRBool SEC_PKCS7VerifySignature(S
  */
 extern PRBool SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
 					       SECCertUsage certusage,
 					       const SECItem *detached_digest,
 					       HASH_HashType digest_type,
 					       PRBool keepcerts);
 
 /*
+ * SEC_PKCS7VerifyDetachedSignatureAtTime
+ *      Look at a PKCS7 contentInfo and check if the signature matches
+ *      a passed-in digest (calculated, supposedly, from detached contents).
+ *      The verification checks that the signing cert is valid and trusted
+ *      for the purpose specified by "certusage" at time "atTime".
+ *
+ *	In addition, if "keepcerts" is true, add any new certificates found
+ *	into our local database.
+ */
+extern PRBool
+SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
+				       SECCertUsage certusage,
+				       const SECItem *detached_digest,
+				       HASH_HashType digest_type,
+				       PRBool keepcerts,
+				       PRTime atTime);
+
+/*
  * SEC_PKCS7GetSignerCommonName, SEC_PKCS7GetSignerEmailAddress
  *      The passed-in contentInfo is espected to be Signed, and these
  *      functions return the specified portion of the full signer name.
  *
  *      Returns a pointer to allocated memory, which must be freed.
  *      A NULL return value is an error.
  */
 extern char *SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo);
--- a/lib/smime/smime.def
+++ b/lib/smime/smime.def
@@ -262,8 +262,14 @@ NSS_Get_NSS_PointerToCMSGenericWrapperDa
 ;+       *;
 ;+};
 ;+NSS_3.13 {    # NSS 3.13 release
 ;+    global:
 NSSSMIME_GetVersion;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.15 {    # NSS 3.15 release
+;+    global:
+SEC_PKCS7VerifyDetachedSignatureAtTime;
+;+    local:
+;+       *;
+;+};