Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@agl
Created January 26, 2010 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agl/286886 to your computer and use it in GitHub Desktop.
Save agl/286886 to your computer and use it in GitHub Desktop.
diff --git a/mozilla/security/nss/lib/certhigh/ocsp.c b/mozilla/security/nss/lib/certhigh/ocsp.c
index 0ffdb34..4a225df 100644
--- a/mozilla/security/nss/lib/certhigh/ocsp.c
+++ b/mozilla/security/nss/lib/certhigh/ocsp.c
@@ -4797,6 +4797,112 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
}
/*
+ * FUNCTION: CERT_CacheOCSPResponseFromSideChannel
+ * First, this function caches the OCSP cache to see if a positive response
+ * for the given certificate already exists. If it does, then the function
+ * returns successfully.
+ *
+ * If not, then it validates that the given OCSP response is a valid,
+ * positive, response for the given certificate and inserts it into the
+ * cache.
+ *
+ * This function is intended for use when OCSP responses are provided via a
+ * side-channel, i.e. TLS OCSP stapling (a.k.a. the status_request extension).
+ *
+ * INPUTS:
+ * CERTCertDBHandle *handle
+ * certificate DB of the cert that is being checked
+ * CERTCertificate *cert
+ * the certificate being checked
+ * int64 time
+ * time for which status is to be determined
+ * SECItem encodedResponse
+ * the DER encoded bytes of the OCSP response
+ * RETURN:
+ * SECSuccess if the cert was found in the cache, or if the OCSP response was
+ * found to be valid and inserted into the cache. SECFailure otherwise.
+ */
+SECStatus
+CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle,
+ CERTCertificate *cert,
+ int64 time,
+ SECItem *encodedResponse)
+{
+ CERTOCSPCertID *certID = NULL;
+ PRBool certIDWasConsumed = PR_FALSE;
+ SECStatus rv = SECFailure;
+ SECStatus rvOcsp;
+ SECErrorCodes dummy_error_code; /* we ignore this */
+ CERTOCSPResponse *response = NULL;
+ CERTCertificate *signerCert = NULL;
+ CERTCertificate *issuerCert = NULL;
+ CERTOCSPSingleResponse *single = NULL;
+
+ certID = CERT_CreateOCSPCertID(cert, time);
+ if (certID == NULL)
+ goto out;
+ rv = ocsp_GetCachedOCSPResponseStatusIfFresh(
+ certID, time, PR_FALSE /* ignoreGlobalOcspFailureSetting */,
+ &rvOcsp, &dummy_error_code);
+ if (rv == SECSuccess && rvOcsp == SECSuccess) {
+ /* The cached value is positive. We don't want to waste time validating
+ * this OCSP response. */
+ rv = SECSuccess;
+ goto out;
+ }
+
+ response = CERT_DecodeOCSPResponse(encodedResponse);
+ if (response == NULL)
+ goto out;
+
+ /* We aren't interested unless the response is positive. */
+ if (CERT_GetOCSPResponseStatus(response) != SECSuccess)
+ goto out;
+
+ issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
+ rv = CERT_VerifyOCSPResponseSignature(
+ response, handle, NULL /* pwArg not given */, &signerCert,
+ issuerCert);
+ if (rv != SECSuccess)
+ goto out;
+
+ PORT_Assert(signerCert != NULL); /* internal consistency check */
+
+ rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID,
+ signerCert, time, &single);
+ if (rv != SECSuccess)
+ goto out;
+
+ rv = ocsp_SingleResponseCertHasGoodStatus(single, time);
+ if (rv != SECSuccess)
+ goto out;
+
+ PR_EnterMonitor(OCSP_Global.monitor);
+ if (OCSP_Global.maxCacheEntries >= 0) {
+ ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single,
+ &certIDWasConsumed);
+ /* ignore cache update failures */
+ if (certIDWasConsumed)
+ certID = NULL;
+ }
+ PR_ExitMonitor(OCSP_Global.monitor);
+ rv = SECSuccess;
+
+out:
+ /* single points within the response so there's no need to free it. */
+
+ if (issuerCert != NULL)
+ CERT_DestroyCertificate(issuerCert);
+ if (signerCert != NULL)
+ CERT_DestroyCertificate(signerCert);
+ if (response != NULL)
+ CERT_DestroyOCSPResponse(response);
+ if (certID != NULL)
+ CERT_DestroyOCSPCertID(certID);
+ return rv;
+}
+
+/*
* Status in *certIDWasConsumed will always be correct, regardless of
* return value.
*/
diff --git a/mozilla/security/nss/lib/certhigh/ocsp.h b/mozilla/security/nss/lib/certhigh/ocsp.h
index 04a406a..da4e16e 100644
--- a/mozilla/security/nss/lib/certhigh/ocsp.h
+++ b/mozilla/security/nss/lib/certhigh/ocsp.h
@@ -550,6 +550,39 @@ CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath);
extern SECStatus
CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
PRTime time, void *pwArg);
+
+/*
+ * FUNCTION: CERT_CacheOCSPResponseFromSideChannel
+ * First, this function caches the OCSP cache to see if a positive response
+ * for the given certificate already exists. If it does, then the function
+ * returns successfully.
+ *
+ * If not, then it validates that the given OCSP response is a valid,
+ * positive, response for the given certificate and inserts it into the
+ * cache.
+ *
+ * This function is intended for use when OCSP responses are provided via a
+ * side-channel, i.e. TLS OCSP stapling (a.k.a. the status_request extension).
+ *
+ * INPUTS:
+ * CERTCertDBHandle *handle
+ * certificate DB of the cert that is being checked
+ * CERTCertificate *cert
+ * the certificate being checked
+ * int64 time
+ * time for which status is to be determined
+ * SECItem encodedResponse
+ * the DER encoded bytes of the OCSP response
+ * RETURN:
+ * SECSuccess if the cert was found in the cache, or if the OCSP response was
+ * found to be valid and inserted into the cache. SECFailure otherwise.
+ */
+extern SECStatus
+CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle,
+ CERTCertificate *cert,
+ int64 time,
+ SECItem *encodedResponse);
+
/*
* FUNCTION: CERT_GetOCSPStatusForCertID
* Returns the OCSP status contained in the passed in paramter response
diff --git a/mozilla/security/nss/lib/nss/nss.def b/mozilla/security/nss/lib/nss/nss.def
index 3447150..a2081b2 100644
--- a/mozilla/security/nss/lib/nss/nss.def
+++ b/mozilla/security/nss/lib/nss/nss.def
@@ -993,6 +993,7 @@ SECMOD_GetSkipFirstFlag;
;+ global:
CERT_DistNamesFromCertList;
CERT_DupDistNames;
+CERT_CacheOCSPResponseFromSideChannel;
;+ local:
;+ *;
;+};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment