Bug 342461: verify signature on an OCSP response without intermediate decoding and encoding. r=nelson, sr=wtc NSS_3_11_BRANCH
authoralexei.volkov.bugs%sun.com
Thu, 25 Jan 2007 00:36:29 +0000
branchNSS_3_11_BRANCH
changeset 7648 06f96c82a0880e57c41a065ccb088656969d0cdc
parent 7635 c391f2239374d7333ca70124e663bc5362257980
child 7651 2f5215d3d87e6f290e10f12d75599455895e8ccc
push idunknown
push userunknown
push dateunknown
reviewersnelson, wtc
bugs342461
Bug 342461: verify signature on an OCSP response without intermediate decoding and encoding. r=nelson, sr=wtc
security/nss/lib/certhigh/ocsp.c
security/nss/lib/certhigh/ocspti.h
--- a/security/nss/lib/certhigh/ocsp.c
+++ b/security/nss/lib/certhigh/ocsp.c
@@ -348,16 +348,18 @@ const SEC_ASN1Template ocsp_PointerToRes
  *	tbsResponseData		ResponseData,
  *	signatureAlgorithm	AlgorithmIdentifier,
  *	signature		BIT STRING,
  *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
  */
 static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = {
     { SEC_ASN1_SEQUENCE,
 	0, NULL, sizeof(ocspBasicOCSPResponse) },
+    { SEC_ASN1_ANY | SEC_ASN1_SAVE,
+	offsetof(ocspBasicOCSPResponse, tbsResponseDataDER) },
     { SEC_ASN1_POINTER,
 	offsetof(ocspBasicOCSPResponse, tbsResponseData),
 	ocsp_ResponseDataTemplate },
     { SEC_ASN1_INLINE,
 	offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
 	SECOID_AlgorithmIDTemplate },
     { SEC_ASN1_BIT_STRING,
 	offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
@@ -1566,19 +1568,29 @@ loser:
  *
  * XXX This routine only works when a valid response structure is passed
  * into it; this is checked with many assertions.  Assuming the response
  * was creating by decoding, it wouldn't make it this far without being
  * okay.  That is a sufficient assumption since the entire OCSP interface
  * is only used internally.  When this interface is officially exported,
  * each assertion below will need to be followed-up with setting an error
  * and returning (null).
+ *
+ * FUNCTION: ocsp_GetResponseData
+ *   Returns ocspResponseData structure and a pointer to tbs response
+ *   data DER from a valid ocsp response. 
+ * INPUTS:
+ *   CERTOCSPResponse *response
+ *     structure of a valid ocsp response
+ * RETURN:
+ *   decoded OCSP response data and a pointer(tbsResponseDataDER) to its
+ *   undecoded data DER.
  */
 static ocspResponseData *
-ocsp_GetResponseData(CERTOCSPResponse *response)
+ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER)
 {
     ocspBasicOCSPResponse *basic;
     ocspResponseData *responseData;
 
     PORT_Assert(response != NULL);
 
     PORT_Assert(response->responseBytes != NULL);
 
@@ -1586,16 +1598,23 @@ ocsp_GetResponseData(CERTOCSPResponse *r
 		== SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
 
     basic = response->responseBytes->decodedResponse.basic;
     PORT_Assert(basic != NULL);
 
     responseData = basic->tbsResponseData;
     PORT_Assert(responseData != NULL);
 
+    if (tbsResponseDataDER) {
+        *tbsResponseDataDER = &basic->tbsResponseDataDER;
+
+        PORT_Assert((*tbsResponseDataDER)->data != NULL);
+        PORT_Assert((*tbsResponseDataDER)->len != 0);
+    }
+
     return responseData;
 }
 
 /*
  * Much like the routine above, except it returns the response signature.
  * Again, no copy is done.
  */
 static ocspSignature *
@@ -2536,25 +2555,23 @@ ocsp_CertGetDefaultResponder(CERTCertDBH
  * an error will be set with the reason.  Most likely are:
  *	SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found
  *	SEC_ERROR_BAD_SIGNATURE - the signature did not verify
  * Other errors are any of the many possible failures in cert verification
  * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
  * verifying the signer's cert, or low-level problems (no memory, etc.)
  */
 static SECStatus
-ocsp_CheckSignature(ocspSignature *signature, void *tbs,
-		    const SEC_ASN1Template *encodeTemplate,
+ocsp_CheckSignature(ocspSignature *signature, SECItem *encodedTBS,
 		    CERTCertDBHandle *handle, SECCertUsage certUsage,
 		    int64 checkTime, PRBool lookupByName, void *certIndex,
 		    void *pwArg, CERTCertificate **pSignerCert,
 		    CERTCertificate *issuer)
 {
     SECItem rawSignature;
-    SECItem *encodedTBS = NULL;
     CERTCertificate *responder = NULL;
     CERTCertificate *signerCert = NULL;
     SECKEYPublicKey *signerKey = NULL;
     CERTCertificate **certs = NULL;
     SECStatus rv = SECFailure;
     int certCount;
     int i;
 
@@ -2657,23 +2674,16 @@ ocsp_CheckSignature(ocspSignature *signa
      * Now get the public key from the signer's certificate; we need
      * it to perform the verification.
      */
     signerKey = CERT_ExtractPublicKey(signerCert);
     if (signerKey == NULL)
 	goto finish;
 
     /*
-     * Prepare the data to be verified; it needs to be DER encoded first.
-     */
-    encodedTBS = SEC_ASN1EncodeItem(NULL, NULL, tbs, encodeTemplate);
-    if (encodedTBS == NULL)
-	goto finish;
-
-    /*
      * We copy the signature data *pointer* and length, so that we can
      * modify the length without damaging the original copy.  This is a
      * simple copy, not a dup, so no destroy/free is necessary.
      */
     rawSignature = signature->signature;
     /*
      * The raw signature is a bit string, but we need to represent its
      * length in bytes, because that is what the verify function expects.
@@ -2701,19 +2711,16 @@ finish:
 	    /*
 	     * Pass pointer to signer's certificate back to our caller,
 	     * who is also now responsible for destroying it.
 	     */
 	    *pSignerCert = CERT_DupCertificate(signerCert);
 	}
     }
 
-    if (encodedTBS != NULL)
-	SECITEM_FreeItem(encodedTBS, PR_TRUE);
-
     if (signerKey != NULL)
 	SECKEY_DestroyPublicKey(signerKey);
 
     if (certs != NULL)
 	CERT_DestroyCertArray(certs, certCount);
 	/* Free CERTS from SPKDigest Table */
 
     return rv;
@@ -2751,22 +2758,23 @@ finish:
  */
 SECStatus
 CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,	
 				 CERTCertDBHandle *handle, void *pwArg,
 				 CERTCertificate **pSignerCert,
 				 CERTCertificate *issuer)
 {
     ocspResponseData *tbsData;		/* this is what is signed */
+    SECItem *tbsResponseDataDER;
     PRBool byName;
     void *certIndex;
     int64 producedAt;
     SECStatus rv;
 
-    tbsData = ocsp_GetResponseData(response);
+    tbsData = ocsp_GetResponseData(response, &tbsResponseDataDER);
 
     PORT_Assert(tbsData->responderID != NULL);
     switch (tbsData->responderID->responderIDType) {
       case ocspResponderID_byName:
 	byName = PR_TRUE;
 	certIndex = &tbsData->responderID->responderIDValue.name;
 	break;
       case ocspResponderID_byKey:
@@ -2786,17 +2794,17 @@ CERT_VerifyOCSPResponseSignature(CERTOCS
      * purposes we expect it to be valid when the response was signed.
      * The value of "producedAt" is the signing time.
      */
     rv = DER_GeneralizedTimeToTime(&producedAt, &tbsData->producedAt);
     if (rv != SECSuccess)
 	return rv;
 
     return ocsp_CheckSignature(ocsp_GetResponseSignature(response),
-			       tbsData, ocsp_ResponseDataTemplate,
+			       tbsResponseDataDER,
 			       handle, certUsageStatusResponder, producedAt,
 			       byName, certIndex, pwArg, pSignerCert, issuer);
 }
 
 /*
  * See if the request's certID and the single response's certID match.
  * This can be easy or difficult, depending on whether the same hash
  * algorithm was used.
@@ -3616,17 +3624,17 @@ CERT_GetOCSPStatusForCertID(CERTCertDBHa
     SECStatus rv;
     ocspResponseData *responseData;
     int64 producedAt;
     CERTOCSPSingleResponse *single;
 
     /*
      * The ResponseData part is the real guts of the response.
      */
-    responseData = ocsp_GetResponseData(response);
+    responseData = ocsp_GetResponseData(response, NULL);
     if (responseData == NULL) {
 	rv = SECFailure;
 	goto loser;
     }
 
     /*
      * There is one producedAt time for the entire response (and a separate
      * thisUpdate time for each individual single response).  We need to
--- a/security/nss/lib/certhigh/ocspti.h
+++ b/security/nss/lib/certhigh/ocspti.h
@@ -274,16 +274,17 @@ struct ocspResponseBytesStr {
  * encoding of one of these.
  *
  * Note that in the OCSP specification, the signature fields are not
  * part of a separate sub-structure.  But since they are the same fields
  * as we define for the signature in a request, it made sense to share
  * the C data structure here and in some shared code to operate on them.
  */
 struct ocspBasicOCSPResponseStr {
+    SECItem tbsResponseDataDER;
     ocspResponseData *tbsResponseData;	/* "tbs" == To Be Signed */
     ocspSignature responseSignature;
 };
 
 /*
  * A ResponseData is the part of a BasicOCSPResponse that is signed
  * (after it is DER encoded).  It contains the real details of the response
  * (a per-certificate status).