/security/nss/lib/certhigh/ocsp.c
http://github.com/zpao/v8monkey · C · 5734 lines · 3549 code · 656 blank · 1529 comment · 913 complexity · 0c459ade7a54e7874d3c23421dab4cb9 MD5 · raw file
Large files are truncated click here to view the full file
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1994-2000
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Kai Engert (kengert@redhat.com)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- /*
- * Implementation of OCSP services, for both client and server.
- * (XXX, really, mostly just for client right now, but intended to do both.)
- *
- * $Id: ocsp.c,v 1.67 2011/08/10 12:31:52 kaie%kuix.de Exp $
- */
- #include "prerror.h"
- #include "prprf.h"
- #include "plarena.h"
- #include "prnetdb.h"
- #include "seccomon.h"
- #include "secitem.h"
- #include "secoidt.h"
- #include "secasn1.h"
- #include "secder.h"
- #include "cert.h"
- #include "xconst.h"
- #include "secerr.h"
- #include "secoid.h"
- #include "hasht.h"
- #include "sechash.h"
- #include "secasn1.h"
- #include "keyhi.h"
- #include "cryptohi.h"
- #include "ocsp.h"
- #include "ocspti.h"
- #include "ocspi.h"
- #include "genname.h"
- #include "certxutl.h"
- #include "pk11func.h" /* for PK11_HashBuf */
- #include <stdarg.h>
- #include <plhash.h>
- #define DEFAULT_OCSP_CACHE_SIZE 1000
- #define DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 1*60*60L
- #define DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 24*60*60L
- #define DEFAULT_OSCP_TIMEOUT_SECONDS 60
- #define MICROSECONDS_PER_SECOND 1000000L
- typedef struct OCSPCacheItemStr OCSPCacheItem;
- typedef struct OCSPCacheDataStr OCSPCacheData;
- struct OCSPCacheItemStr {
- /* LRU linking */
- OCSPCacheItem *moreRecent;
- OCSPCacheItem *lessRecent;
- /* key */
- CERTOCSPCertID *certID;
- /* CertID's arena also used to allocate "this" cache item */
- /* cache control information */
- PRTime nextFetchAttemptTime;
- /* Cached contents. Use a separate arena, because lifetime is different */
- PRArenaPool *certStatusArena; /* NULL means: no cert status cached */
- ocspCertStatus certStatus;
- /* This may contain an error code when no OCSP response is available. */
- SECErrorCodes missingResponseError;
- PRPackedBool haveThisUpdate;
- PRPackedBool haveNextUpdate;
- PRTime thisUpdate;
- PRTime nextUpdate;
- };
- struct OCSPCacheDataStr {
- PLHashTable *entries;
- PRUint32 numberOfEntries;
- OCSPCacheItem *MRUitem; /* most recently used cache item */
- OCSPCacheItem *LRUitem; /* least recently used cache item */
- };
- static struct OCSPGlobalStruct {
- PRMonitor *monitor;
- const SEC_HttpClientFcn *defaultHttpClientFcn;
- PRInt32 maxCacheEntries;
- PRUint32 minimumSecondsToNextFetchAttempt;
- PRUint32 maximumSecondsToNextFetchAttempt;
- PRUint32 timeoutSeconds;
- OCSPCacheData cache;
- SEC_OcspFailureMode ocspFailureMode;
- CERT_StringFromCertFcn alternateOCSPAIAFcn;
- } OCSP_Global = { NULL,
- NULL,
- DEFAULT_OCSP_CACHE_SIZE,
- DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
- DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
- DEFAULT_OSCP_TIMEOUT_SECONDS,
- {NULL, 0, NULL, NULL},
- ocspMode_FailureIsVerificationFailure,
- NULL
- };
- /* Forward declarations */
- static SECItem *
- ocsp_GetEncodedOCSPResponseFromRequest(PRArenaPool *arena,
- CERTOCSPRequest *request,
- char *location, int64 time,
- PRBool addServiceLocator,
- void *pwArg,
- CERTOCSPRequest **pRequest);
- static SECStatus
- ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle,
- CERTOCSPCertID *certID,
- CERTCertificate *cert,
- int64 time,
- void *pwArg,
- PRBool *certIDWasConsumed,
- SECStatus *rv_ocsp);
- static SECStatus
- ocsp_CacheEncodedOCSPResponse(CERTCertDBHandle *handle,
- CERTOCSPCertID *certID,
- CERTCertificate *cert,
- int64 time,
- void *pwArg,
- SECItem *encodedResponse,
- PRBool *certIDWasConsumed,
- PRBool cacheNegative,
- SECStatus *rv_ocsp);
- static SECStatus
- ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle,
- CERTOCSPResponse *response,
- CERTOCSPCertID *certID,
- CERTCertificate *signerCert,
- int64 time,
- CERTOCSPSingleResponse **pSingleResponse);
- static SECStatus
- ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, int64 time);
- #ifndef DEBUG
- #define OCSP_TRACE(msg)
- #define OCSP_TRACE_TIME(msg, time)
- #define OCSP_TRACE_CERT(cert)
- #define OCSP_TRACE_CERTID(certid)
- #else
- #define OCSP_TRACE(msg) ocsp_Trace msg
- #define OCSP_TRACE_TIME(msg, time) ocsp_dumpStringWithTime(msg, time)
- #define OCSP_TRACE_CERT(cert) dumpCertificate(cert)
- #define OCSP_TRACE_CERTID(certid) dumpCertID(certid)
- #if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) \
- || defined(XP_MACOSX)) && !defined(_WIN32_WCE)
- #define NSS_HAVE_GETENV 1
- #endif
- static PRBool wantOcspTrace()
- {
- static PRBool firstTime = PR_TRUE;
- static PRBool wantTrace = PR_FALSE;
- #ifdef NSS_HAVE_GETENV
- if (firstTime) {
- char *ev = getenv("NSS_TRACE_OCSP");
- if (ev && ev[0]) {
- wantTrace = PR_TRUE;
- }
- firstTime = PR_FALSE;
- }
- #endif
- return wantTrace;
- }
- static void
- ocsp_Trace(const char *format, ...)
- {
- char buf[2000];
- va_list args;
-
- if (!wantOcspTrace())
- return;
- va_start(args, format);
- PR_vsnprintf(buf, sizeof(buf), format, args);
- va_end(args);
- PR_LogPrint("%s", buf);
- }
- static void
- ocsp_dumpStringWithTime(const char *str, int64 time)
- {
- PRExplodedTime timePrintable;
- char timestr[256];
- if (!wantOcspTrace())
- return;
- PR_ExplodeTime(time, PR_GMTParameters, &timePrintable);
- if (PR_FormatTime(timestr, 256, "%a %b %d %H:%M:%S %Y", &timePrintable)) {
- ocsp_Trace("OCSP %s %s\n", str, timestr);
- }
- }
- static void
- printHexString(const char *prefix, SECItem *hexval)
- {
- unsigned int i;
- char *hexbuf = NULL;
- for (i = 0; i < hexval->len; i++) {
- if (i != hexval->len - 1) {
- hexbuf = PR_sprintf_append(hexbuf, "%02x:", hexval->data[i]);
- } else {
- hexbuf = PR_sprintf_append(hexbuf, "%02x", hexval->data[i]);
- }
- }
- if (hexbuf) {
- ocsp_Trace("%s %s\n", prefix, hexbuf);
- PR_smprintf_free(hexbuf);
- }
- }
- static void
- dumpCertificate(CERTCertificate *cert)
- {
- if (!wantOcspTrace())
- return;
- ocsp_Trace("OCSP ----------------\n");
- ocsp_Trace("OCSP ## SUBJECT: %s\n", cert->subjectName);
- {
- int64 timeBefore, timeAfter;
- PRExplodedTime beforePrintable, afterPrintable;
- char beforestr[256], afterstr[256];
- PRStatus rv1, rv2;
- DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore);
- DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter);
- PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable);
- PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable);
- rv1 = PR_FormatTime(beforestr, 256, "%a %b %d %H:%M:%S %Y",
- &beforePrintable);
- rv2 = PR_FormatTime(afterstr, 256, "%a %b %d %H:%M:%S %Y",
- &afterPrintable);
- ocsp_Trace("OCSP ## VALIDITY: %s to %s\n", rv1 ? beforestr : "",
- rv2 ? afterstr : "");
- }
- ocsp_Trace("OCSP ## ISSUER: %s\n", cert->issuerName);
- printHexString("OCSP ## SERIAL NUMBER:", &cert->serialNumber);
- }
- static void
- dumpCertID(CERTOCSPCertID *certID)
- {
- if (!wantOcspTrace())
- return;
- printHexString("OCSP certID issuer", &certID->issuerNameHash);
- printHexString("OCSP certID serial", &certID->serialNumber);
- }
- #endif
- SECStatus
- SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
- {
- if (!OCSP_Global.monitor) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- PR_EnterMonitor(OCSP_Global.monitor);
- OCSP_Global.defaultHttpClientFcn = fcnTable;
- PR_ExitMonitor(OCSP_Global.monitor);
-
- return SECSuccess;
- }
- SECStatus
- CERT_RegisterAlternateOCSPAIAInfoCallBack(
- CERT_StringFromCertFcn newCallback,
- CERT_StringFromCertFcn * oldCallback)
- {
- CERT_StringFromCertFcn old;
- if (!OCSP_Global.monitor) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- PR_EnterMonitor(OCSP_Global.monitor);
- old = OCSP_Global.alternateOCSPAIAFcn;
- OCSP_Global.alternateOCSPAIAFcn = newCallback;
- PR_ExitMonitor(OCSP_Global.monitor);
- if (oldCallback)
- *oldCallback = old;
- return SECSuccess;
- }
- static PLHashNumber PR_CALLBACK
- ocsp_CacheKeyHashFunction(const void *key)
- {
- CERTOCSPCertID *cid = (CERTOCSPCertID *)key;
- PLHashNumber hash = 0;
- unsigned int i;
- unsigned char *walk;
-
- /* a very simple hash calculation for the initial coding phase */
- walk = (unsigned char*)cid->issuerNameHash.data;
- for (i=0; i < cid->issuerNameHash.len; ++i, ++walk) {
- hash += *walk;
- }
- walk = (unsigned char*)cid->issuerKeyHash.data;
- for (i=0; i < cid->issuerKeyHash.len; ++i, ++walk) {
- hash += *walk;
- }
- walk = (unsigned char*)cid->serialNumber.data;
- for (i=0; i < cid->serialNumber.len; ++i, ++walk) {
- hash += *walk;
- }
- return hash;
- }
- static PRIntn PR_CALLBACK
- ocsp_CacheKeyCompareFunction(const void *v1, const void *v2)
- {
- CERTOCSPCertID *cid1 = (CERTOCSPCertID *)v1;
- CERTOCSPCertID *cid2 = (CERTOCSPCertID *)v2;
-
- return (SECEqual == SECITEM_CompareItem(&cid1->issuerNameHash,
- &cid2->issuerNameHash)
- && SECEqual == SECITEM_CompareItem(&cid1->issuerKeyHash,
- &cid2->issuerKeyHash)
- && SECEqual == SECITEM_CompareItem(&cid1->serialNumber,
- &cid2->serialNumber));
- }
- static SECStatus
- ocsp_CopyRevokedInfo(PRArenaPool *arena, ocspCertStatus *dest,
- ocspRevokedInfo *src)
- {
- SECStatus rv = SECFailure;
- void *mark;
-
- mark = PORT_ArenaMark(arena);
-
- dest->certStatusInfo.revokedInfo =
- (ocspRevokedInfo *) PORT_ArenaZAlloc(arena, sizeof(ocspRevokedInfo));
- if (!dest->certStatusInfo.revokedInfo) {
- goto loser;
- }
-
- rv = SECITEM_CopyItem(arena,
- &dest->certStatusInfo.revokedInfo->revocationTime,
- &src->revocationTime);
- if (rv != SECSuccess) {
- goto loser;
- }
-
- if (src->revocationReason) {
- dest->certStatusInfo.revokedInfo->revocationReason =
- SECITEM_ArenaDupItem(arena, src->revocationReason);
- if (!dest->certStatusInfo.revokedInfo->revocationReason) {
- goto loser;
- }
- } else {
- dest->certStatusInfo.revokedInfo->revocationReason = NULL;
- }
-
- PORT_ArenaUnmark(arena, mark);
- return SECSuccess;
- loser:
- PORT_ArenaRelease(arena, mark);
- return SECFailure;
- }
- static SECStatus
- ocsp_CopyCertStatus(PRArenaPool *arena, ocspCertStatus *dest,
- ocspCertStatus*src)
- {
- SECStatus rv = SECFailure;
- dest->certStatusType = src->certStatusType;
-
- switch (src->certStatusType) {
- case ocspCertStatus_good:
- dest->certStatusInfo.goodInfo =
- SECITEM_ArenaDupItem(arena, src->certStatusInfo.goodInfo);
- if (dest->certStatusInfo.goodInfo != NULL) {
- rv = SECSuccess;
- }
- break;
- case ocspCertStatus_revoked:
- rv = ocsp_CopyRevokedInfo(arena, dest,
- src->certStatusInfo.revokedInfo);
- break;
- case ocspCertStatus_unknown:
- dest->certStatusInfo.unknownInfo =
- SECITEM_ArenaDupItem(arena, src->certStatusInfo.unknownInfo);
- if (dest->certStatusInfo.unknownInfo != NULL) {
- rv = SECSuccess;
- }
- break;
- case ocspCertStatus_other:
- default:
- PORT_Assert(src->certStatusType == ocspCertStatus_other);
- dest->certStatusInfo.otherInfo =
- SECITEM_ArenaDupItem(arena, src->certStatusInfo.otherInfo);
- if (dest->certStatusInfo.otherInfo != NULL) {
- rv = SECSuccess;
- }
- break;
- }
- return rv;
- }
- static void
- ocsp_AddCacheItemToLinkedList(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
- {
- PR_EnterMonitor(OCSP_Global.monitor);
- if (!cache->LRUitem) {
- cache->LRUitem = new_most_recent;
- }
- new_most_recent->lessRecent = cache->MRUitem;
- new_most_recent->moreRecent = NULL;
- if (cache->MRUitem) {
- cache->MRUitem->moreRecent = new_most_recent;
- }
- cache->MRUitem = new_most_recent;
- PR_ExitMonitor(OCSP_Global.monitor);
- }
- static void
- ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData *cache, OCSPCacheItem *item)
- {
- PR_EnterMonitor(OCSP_Global.monitor);
- if (!item->lessRecent && !item->moreRecent) {
- /*
- * Fail gracefully on attempts to remove an item from the list,
- * which is currently not part of the list.
- * But check for the edge case it is the single entry in the list.
- */
- if (item == cache->LRUitem &&
- item == cache->MRUitem) {
- /* remove the single entry */
- PORT_Assert(cache->numberOfEntries == 1);
- PORT_Assert(item->moreRecent == NULL);
- cache->MRUitem = NULL;
- cache->LRUitem = NULL;
- }
- PR_ExitMonitor(OCSP_Global.monitor);
- return;
- }
- PORT_Assert(cache->numberOfEntries > 1);
-
- if (item == cache->LRUitem) {
- PORT_Assert(item != cache->MRUitem);
- PORT_Assert(item->lessRecent == NULL);
- PORT_Assert(item->moreRecent != NULL);
- PORT_Assert(item->moreRecent->lessRecent == item);
- cache->LRUitem = item->moreRecent;
- cache->LRUitem->lessRecent = NULL;
- }
- else if (item == cache->MRUitem) {
- PORT_Assert(item->moreRecent == NULL);
- PORT_Assert(item->lessRecent != NULL);
- PORT_Assert(item->lessRecent->moreRecent == item);
- cache->MRUitem = item->lessRecent;
- cache->MRUitem->moreRecent = NULL;
- } else {
- /* remove an entry in the middle of the list */
- PORT_Assert(item->moreRecent != NULL);
- PORT_Assert(item->lessRecent != NULL);
- PORT_Assert(item->lessRecent->moreRecent == item);
- PORT_Assert(item->moreRecent->lessRecent == item);
- item->moreRecent->lessRecent = item->lessRecent;
- item->lessRecent->moreRecent = item->moreRecent;
- }
- item->lessRecent = NULL;
- item->moreRecent = NULL;
- PR_ExitMonitor(OCSP_Global.monitor);
- }
- static void
- ocsp_MakeCacheEntryMostRecent(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
- {
- OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent THREADID %p\n",
- PR_GetCurrentThread()));
- PR_EnterMonitor(OCSP_Global.monitor);
- if (cache->MRUitem == new_most_recent) {
- OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent ALREADY MOST\n"));
- PR_ExitMonitor(OCSP_Global.monitor);
- return;
- }
- OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent NEW entry\n"));
- ocsp_RemoveCacheItemFromLinkedList(cache, new_most_recent);
- ocsp_AddCacheItemToLinkedList(cache, new_most_recent);
- PR_ExitMonitor(OCSP_Global.monitor);
- }
- static PRBool
- ocsp_IsCacheDisabled()
- {
- /*
- * maxCacheEntries == 0 means unlimited cache entries
- * maxCacheEntries < 0 means cache is disabled
- */
- PRBool retval;
- PR_EnterMonitor(OCSP_Global.monitor);
- retval = (OCSP_Global.maxCacheEntries < 0);
- PR_ExitMonitor(OCSP_Global.monitor);
- return retval;
- }
- static OCSPCacheItem *
- ocsp_FindCacheEntry(OCSPCacheData *cache, CERTOCSPCertID *certID)
- {
- OCSPCacheItem *found_ocsp_item = NULL;
- OCSP_TRACE(("OCSP ocsp_FindCacheEntry\n"));
- OCSP_TRACE_CERTID(certID);
- PR_EnterMonitor(OCSP_Global.monitor);
- if (ocsp_IsCacheDisabled())
- goto loser;
-
- found_ocsp_item = (OCSPCacheItem *)PL_HashTableLookup(
- cache->entries, certID);
- if (!found_ocsp_item)
- goto loser;
-
- OCSP_TRACE(("OCSP ocsp_FindCacheEntry FOUND!\n"));
- ocsp_MakeCacheEntryMostRecent(cache, found_ocsp_item);
- loser:
- PR_ExitMonitor(OCSP_Global.monitor);
- return found_ocsp_item;
- }
- static void
- ocsp_FreeCacheItem(OCSPCacheItem *item)
- {
- OCSP_TRACE(("OCSP ocsp_FreeCacheItem\n"));
- if (item->certStatusArena) {
- PORT_FreeArena(item->certStatusArena, PR_FALSE);
- }
- if (item->certID->poolp) {
- /* freeing this poolp arena will also free item */
- PORT_FreeArena(item->certID->poolp, PR_FALSE);
- }
- }
- static void
- ocsp_RemoveCacheItem(OCSPCacheData *cache, OCSPCacheItem *item)
- {
- /* The item we're removing could be either the least recently used item,
- * or it could be an item that couldn't get updated with newer status info
- * because of an allocation failure, or it could get removed because we're
- * cleaning up.
- */
- PRBool couldRemoveFromHashTable;
- OCSP_TRACE(("OCSP ocsp_RemoveCacheItem, THREADID %p\n", PR_GetCurrentThread()));
- PR_EnterMonitor(OCSP_Global.monitor);
- ocsp_RemoveCacheItemFromLinkedList(cache, item);
- couldRemoveFromHashTable = PL_HashTableRemove(cache->entries,
- item->certID);
- PORT_Assert(couldRemoveFromHashTable);
- --cache->numberOfEntries;
- ocsp_FreeCacheItem(item);
- PR_ExitMonitor(OCSP_Global.monitor);
- }
- static void
- ocsp_CheckCacheSize(OCSPCacheData *cache)
- {
- OCSP_TRACE(("OCSP ocsp_CheckCacheSize\n"));
- PR_EnterMonitor(OCSP_Global.monitor);
- if (OCSP_Global.maxCacheEntries > 0) {
- /* Cache is not disabled. Number of cache entries is limited.
- * The monitor ensures that maxCacheEntries remains positive.
- */
- while (cache->numberOfEntries >
- (PRUint32)OCSP_Global.maxCacheEntries) {
- ocsp_RemoveCacheItem(cache, cache->LRUitem);
- }
- }
- PR_ExitMonitor(OCSP_Global.monitor);
- }
- SECStatus
- CERT_ClearOCSPCache()
- {
- OCSP_TRACE(("OCSP CERT_ClearOCSPCache\n"));
- PR_EnterMonitor(OCSP_Global.monitor);
- while (OCSP_Global.cache.numberOfEntries > 0) {
- ocsp_RemoveCacheItem(&OCSP_Global.cache,
- OCSP_Global.cache.LRUitem);
- }
- PR_ExitMonitor(OCSP_Global.monitor);
- return SECSuccess;
- }
- static SECStatus
- ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData *cache,
- CERTOCSPCertID *certID,
- OCSPCacheItem **pCacheItem)
- {
- PRArenaPool *arena;
- void *mark;
- PLHashEntry *new_hash_entry;
- OCSPCacheItem *item;
-
- PORT_Assert(pCacheItem != NULL);
- *pCacheItem = NULL;
- PR_EnterMonitor(OCSP_Global.monitor);
- arena = certID->poolp;
- mark = PORT_ArenaMark(arena);
-
- /* ZAlloc will init all Bools to False and all Pointers to NULL
- and all error codes to zero/good. */
- item = (OCSPCacheItem *)PORT_ArenaZAlloc(certID->poolp,
- sizeof(OCSPCacheItem));
- if (!item) {
- goto loser;
- }
- item->certID = certID;
- new_hash_entry = PL_HashTableAdd(cache->entries, item->certID,
- item);
- if (!new_hash_entry) {
- goto loser;
- }
- ++cache->numberOfEntries;
- PORT_ArenaUnmark(arena, mark);
- ocsp_AddCacheItemToLinkedList(cache, item);
- *pCacheItem = item;
- PR_ExitMonitor(OCSP_Global.monitor);
- return SECSuccess;
-
- loser:
- PORT_ArenaRelease(arena, mark);
- PR_ExitMonitor(OCSP_Global.monitor);
- return SECFailure;
- }
- static SECStatus
- ocsp_SetCacheItemResponse(OCSPCacheItem *item,
- const CERTOCSPSingleResponse *response)
- {
- if (item->certStatusArena) {
- PORT_FreeArena(item->certStatusArena, PR_FALSE);
- item->certStatusArena = NULL;
- }
- item->haveThisUpdate = item->haveNextUpdate = PR_FALSE;
- if (response) {
- SECStatus rv;
- item->certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (item->certStatusArena == NULL) {
- return SECFailure;
- }
- rv = ocsp_CopyCertStatus(item->certStatusArena, &item->certStatus,
- response->certStatus);
- if (rv != SECSuccess) {
- PORT_FreeArena(item->certStatusArena, PR_FALSE);
- item->certStatusArena = NULL;
- return rv;
- }
- item->missingResponseError = 0;
- rv = DER_GeneralizedTimeToTime(&item->thisUpdate,
- &response->thisUpdate);
- item->haveThisUpdate = (rv == SECSuccess);
- if (response->nextUpdate) {
- rv = DER_GeneralizedTimeToTime(&item->nextUpdate,
- response->nextUpdate);
- item->haveNextUpdate = (rv == SECSuccess);
- } else {
- item->haveNextUpdate = PR_FALSE;
- }
- }
- return SECSuccess;
- }
- static void
- ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem *cacheItem)
- {
- PRTime now;
- PRTime earliestAllowedNextFetchAttemptTime;
- PRTime latestTimeWhenResponseIsConsideredFresh;
-
- OCSP_TRACE(("OCSP ocsp_FreshenCacheItemNextFetchAttemptTime\n"));
- PR_EnterMonitor(OCSP_Global.monitor);
-
- now = PR_Now();
- OCSP_TRACE_TIME("now:", now);
-
- if (cacheItem->haveThisUpdate) {
- OCSP_TRACE_TIME("thisUpdate:", cacheItem->thisUpdate);
- latestTimeWhenResponseIsConsideredFresh = cacheItem->thisUpdate +
- OCSP_Global.maximumSecondsToNextFetchAttempt *
- MICROSECONDS_PER_SECOND;
- OCSP_TRACE_TIME("latestTimeWhenResponseIsConsideredFresh:",
- latestTimeWhenResponseIsConsideredFresh);
- } else {
- latestTimeWhenResponseIsConsideredFresh = now +
- OCSP_Global.minimumSecondsToNextFetchAttempt *
- MICROSECONDS_PER_SECOND;
- OCSP_TRACE_TIME("no thisUpdate, "
- "latestTimeWhenResponseIsConsideredFresh:",
- latestTimeWhenResponseIsConsideredFresh);
- }
-
- if (cacheItem->haveNextUpdate) {
- OCSP_TRACE_TIME("have nextUpdate:", cacheItem->nextUpdate);
- }
-
- if (cacheItem->haveNextUpdate &&
- cacheItem->nextUpdate < latestTimeWhenResponseIsConsideredFresh) {
- latestTimeWhenResponseIsConsideredFresh = cacheItem->nextUpdate;
- OCSP_TRACE_TIME("nextUpdate is smaller than latestFresh, setting "
- "latestTimeWhenResponseIsConsideredFresh:",
- latestTimeWhenResponseIsConsideredFresh);
- }
-
- earliestAllowedNextFetchAttemptTime = now +
- OCSP_Global.minimumSecondsToNextFetchAttempt *
- MICROSECONDS_PER_SECOND;
- OCSP_TRACE_TIME("earliestAllowedNextFetchAttemptTime:",
- earliestAllowedNextFetchAttemptTime);
-
- if (latestTimeWhenResponseIsConsideredFresh <
- earliestAllowedNextFetchAttemptTime) {
- latestTimeWhenResponseIsConsideredFresh =
- earliestAllowedNextFetchAttemptTime;
- OCSP_TRACE_TIME("latest < earliest, setting latest to:",
- latestTimeWhenResponseIsConsideredFresh);
- }
-
- cacheItem->nextFetchAttemptTime =
- latestTimeWhenResponseIsConsideredFresh;
- OCSP_TRACE_TIME("nextFetchAttemptTime",
- latestTimeWhenResponseIsConsideredFresh);
- PR_ExitMonitor(OCSP_Global.monitor);
- }
- static PRBool
- ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem)
- {
- PRTime now;
- PRBool retval;
- PR_EnterMonitor(OCSP_Global.monitor);
- now = PR_Now();
- retval = (cacheItem->nextFetchAttemptTime > now);
- OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", retval));
- PR_ExitMonitor(OCSP_Global.monitor);
- return retval;
- }
- /*
- * Status in *certIDWasConsumed will always be correct, regardless of
- * return value.
- */
- static SECStatus
- ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache,
- CERTOCSPCertID *certID,
- CERTOCSPSingleResponse *single,
- PRBool *certIDWasConsumed)
- {
- SECStatus rv;
- OCSPCacheItem *cacheItem;
- OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n"));
-
- if (!certIDWasConsumed) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- *certIDWasConsumed = PR_FALSE;
-
- PR_EnterMonitor(OCSP_Global.monitor);
- PORT_Assert(OCSP_Global.maxCacheEntries >= 0);
-
- cacheItem = ocsp_FindCacheEntry(cache, certID);
- if (!cacheItem) {
- rv = ocsp_CreateCacheItemAndConsumeCertID(cache, certID,
- &cacheItem);
- if (rv != SECSuccess) {
- PR_ExitMonitor(OCSP_Global.monitor);
- return rv;
- }
- *certIDWasConsumed = PR_TRUE;
- }
- if (single) {
- rv = ocsp_SetCacheItemResponse(cacheItem, single);
- if (rv != SECSuccess) {
- ocsp_RemoveCacheItem(cache, cacheItem);
- PR_ExitMonitor(OCSP_Global.monitor);
- return rv;
- }
- } else {
- cacheItem->missingResponseError = PORT_GetError();
- }
- ocsp_FreshenCacheItemNextFetchAttemptTime(cacheItem);
- ocsp_CheckCacheSize(cache);
- PR_ExitMonitor(OCSP_Global.monitor);
- return SECSuccess;
- }
- extern SECStatus
- CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode)
- {
- switch (ocspFailureMode) {
- case ocspMode_FailureIsVerificationFailure:
- case ocspMode_FailureIsNotAVerificationFailure:
- break;
- default:
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- PR_EnterMonitor(OCSP_Global.monitor);
- OCSP_Global.ocspFailureMode = ocspFailureMode;
- PR_ExitMonitor(OCSP_Global.monitor);
- return SECSuccess;
- }
- SECStatus
- CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
- PRUint32 minimumSecondsToNextFetchAttempt,
- PRUint32 maximumSecondsToNextFetchAttempt)
- {
- if (minimumSecondsToNextFetchAttempt > maximumSecondsToNextFetchAttempt
- || maxCacheEntries < -1) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- PR_EnterMonitor(OCSP_Global.monitor);
-
- if (maxCacheEntries < 0) {
- OCSP_Global.maxCacheEntries = -1; /* disable cache */
- } else if (maxCacheEntries == 0) {
- OCSP_Global.maxCacheEntries = 0; /* unlimited cache entries */
- } else {
- OCSP_Global.maxCacheEntries = maxCacheEntries;
- }
-
- if (minimumSecondsToNextFetchAttempt <
- OCSP_Global.minimumSecondsToNextFetchAttempt
- || maximumSecondsToNextFetchAttempt <
- OCSP_Global.maximumSecondsToNextFetchAttempt) {
- /*
- * Ensure our existing cache entries are not used longer than the
- * new settings allow, we're lazy and just clear the cache
- */
- CERT_ClearOCSPCache();
- }
-
- OCSP_Global.minimumSecondsToNextFetchAttempt =
- minimumSecondsToNextFetchAttempt;
- OCSP_Global.maximumSecondsToNextFetchAttempt =
- maximumSecondsToNextFetchAttempt;
- ocsp_CheckCacheSize(&OCSP_Global.cache);
-
- PR_ExitMonitor(OCSP_Global.monitor);
- return SECSuccess;
- }
- SECStatus
- CERT_SetOCSPTimeout(PRUint32 seconds)
- {
- /* no locking, see bug 406120 */
- OCSP_Global.timeoutSeconds = seconds;
- return SECSuccess;
- }
- /* this function is called at NSS initialization time */
- SECStatus OCSP_InitGlobal(void)
- {
- SECStatus rv = SECFailure;
- if (OCSP_Global.monitor == NULL) {
- OCSP_Global.monitor = PR_NewMonitor();
- }
- if (!OCSP_Global.monitor)
- return SECFailure;
- PR_EnterMonitor(OCSP_Global.monitor);
- if (!OCSP_Global.cache.entries) {
- OCSP_Global.cache.entries =
- PL_NewHashTable(0,
- ocsp_CacheKeyHashFunction,
- ocsp_CacheKeyCompareFunction,
- PL_CompareValues,
- NULL,
- NULL);
- OCSP_Global.ocspFailureMode = ocspMode_FailureIsVerificationFailure;
- OCSP_Global.cache.numberOfEntries = 0;
- OCSP_Global.cache.MRUitem = NULL;
- OCSP_Global.cache.LRUitem = NULL;
- } else {
- /*
- * NSS might call this function twice while attempting to init.
- * But it's not allowed to call this again after any activity.
- */
- PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- }
- if (OCSP_Global.cache.entries)
- rv = SECSuccess;
- PR_ExitMonitor(OCSP_Global.monitor);
- return rv;
- }
- SECStatus OCSP_ShutdownGlobal(void)
- {
- if (!OCSP_Global.monitor)
- return SECSuccess;
- PR_EnterMonitor(OCSP_Global.monitor);
- if (OCSP_Global.cache.entries) {
- CERT_ClearOCSPCache();
- PL_HashTableDestroy(OCSP_Global.cache.entries);
- OCSP_Global.cache.entries = NULL;
- }
- PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
- OCSP_Global.cache.MRUitem = NULL;
- OCSP_Global.cache.LRUitem = NULL;
- OCSP_Global.defaultHttpClientFcn = NULL;
- OCSP_Global.maxCacheEntries = DEFAULT_OCSP_CACHE_SIZE;
- OCSP_Global.minimumSecondsToNextFetchAttempt =
- DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
- OCSP_Global.maximumSecondsToNextFetchAttempt =
- DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
- OCSP_Global.ocspFailureMode =
- ocspMode_FailureIsVerificationFailure;
- PR_ExitMonitor(OCSP_Global.monitor);
- PR_DestroyMonitor(OCSP_Global.monitor);
- OCSP_Global.monitor = NULL;
- return SECSuccess;
- }
- /*
- * A return value of NULL means:
- * The application did not register it's own HTTP client.
- */
- const SEC_HttpClientFcn *SEC_GetRegisteredHttpClient()
- {
- const SEC_HttpClientFcn *retval;
- if (!OCSP_Global.monitor) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return NULL;
- }
- PR_EnterMonitor(OCSP_Global.monitor);
- retval = OCSP_Global.defaultHttpClientFcn;
- PR_ExitMonitor(OCSP_Global.monitor);
-
- return retval;
- }
- /*
- * The following structure is only used internally. It is allocated when
- * someone turns on OCSP checking, and hangs off of the status-configuration
- * structure in the certdb structure. We use it to keep configuration
- * information specific to OCSP checking.
- */
- typedef struct ocspCheckingContextStr {
- PRBool useDefaultResponder;
- char *defaultResponderURI;
- char *defaultResponderNickname;
- CERTCertificate *defaultResponderCert;
- } ocspCheckingContext;
- SEC_ASN1_MKSUB(SEC_AnyTemplate)
- SEC_ASN1_MKSUB(SEC_IntegerTemplate)
- SEC_ASN1_MKSUB(SEC_NullTemplate)
- SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
- SEC_ASN1_MKSUB(SEC_PointerToAnyTemplate)
- SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
- SEC_ASN1_MKSUB(SEC_SequenceOfAnyTemplate)
- SEC_ASN1_MKSUB(SEC_PointerToGeneralizedTimeTemplate)
- SEC_ASN1_MKSUB(SEC_PointerToEnumeratedTemplate)
- /*
- * Forward declarations of sub-types, so I can lay out the types in the
- * same order as the ASN.1 is laid out in the OCSP spec itself.
- *
- * These are in alphabetical order (case-insensitive); please keep it that way!
- */
- extern const SEC_ASN1Template ocsp_CertIDTemplate[];
- extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[];
- extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[];
- extern const SEC_ASN1Template ocsp_ResponseDataTemplate[];
- extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[];
- extern const SEC_ASN1Template ocsp_SingleRequestTemplate[];
- extern const SEC_ASN1Template ocsp_SingleResponseTemplate[];
- extern const SEC_ASN1Template ocsp_TBSRequestTemplate[];
- /*
- * Request-related templates...
- */
- /*
- * OCSPRequest ::= SEQUENCE {
- * tbsRequest TBSRequest,
- * optionalSignature [0] EXPLICIT Signature OPTIONAL }
- */
- static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTOCSPRequest) },
- { SEC_ASN1_POINTER,
- offsetof(CERTOCSPRequest, tbsRequest),
- ocsp_TBSRequestTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(CERTOCSPRequest, optionalSignature),
- ocsp_PointerToSignatureTemplate },
- { 0 }
- };
- /*
- * TBSRequest ::= SEQUENCE {
- * version [0] EXPLICIT Version DEFAULT v1,
- * requestorName [1] EXPLICIT GeneralName OPTIONAL,
- * requestList SEQUENCE OF Request,
- * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
- *
- * Version ::= INTEGER { v1(0) }
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_TBSRequestTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspTBSRequest) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- offsetof(ocspTBSRequest, version),
- SEC_ASN1_SUB(SEC_IntegerTemplate) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
- offsetof(ocspTBSRequest, derRequestorName),
- SEC_ASN1_SUB(SEC_PointerToAnyTemplate) },
- { SEC_ASN1_SEQUENCE_OF,
- offsetof(ocspTBSRequest, requestList),
- ocsp_SingleRequestTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
- offsetof(ocspTBSRequest, requestExtensions),
- CERT_SequenceOfCertExtensionTemplate },
- { 0 }
- };
- /*
- * Signature ::= SEQUENCE {
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING,
- * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
- */
- static const SEC_ASN1Template ocsp_SignatureTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspSignature) },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
- offsetof(ocspSignature, signatureAlgorithm),
- SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
- { SEC_ASN1_BIT_STRING,
- offsetof(ocspSignature, signature) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- offsetof(ocspSignature, derCerts),
- SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
- { 0 }
- };
- /*
- * This template is just an extra level to use in an explicitly-tagged
- * reference to a Signature.
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = {
- { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate }
- };
- /*
- * Request ::= SEQUENCE {
- * reqCert CertID,
- * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_SingleRequestTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspSingleRequest) },
- { SEC_ASN1_POINTER,
- offsetof(ocspSingleRequest, reqCert),
- ocsp_CertIDTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(ocspSingleRequest, singleRequestExtensions),
- CERT_SequenceOfCertExtensionTemplate },
- { 0 }
- };
- /*
- * This data structure and template (CertID) is used by both OCSP
- * requests and responses. It is the only one that is shared.
- *
- * CertID ::= SEQUENCE {
- * hashAlgorithm AlgorithmIdentifier,
- * issuerNameHash OCTET STRING, -- Hash of Issuer DN
- * issuerKeyHash OCTET STRING, -- Hash of Issuer public key
- * serialNumber CertificateSerialNumber }
- *
- * CertificateSerialNumber ::= INTEGER
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_CertIDTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTOCSPCertID) },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
- offsetof(CERTOCSPCertID, hashAlgorithm),
- SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(CERTOCSPCertID, issuerNameHash) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(CERTOCSPCertID, issuerKeyHash) },
- { SEC_ASN1_INTEGER,
- offsetof(CERTOCSPCertID, serialNumber) },
- { 0 }
- };
- /*
- * Response-related templates...
- */
- /*
- * OCSPResponse ::= SEQUENCE {
- * responseStatus OCSPResponseStatus,
- * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
- */
- static const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTOCSPResponse) },
- { SEC_ASN1_ENUMERATED,
- offsetof(CERTOCSPResponse, responseStatus) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(CERTOCSPResponse, responseBytes),
- ocsp_PointerToResponseBytesTemplate },
- { 0 }
- };
- /*
- * ResponseBytes ::= SEQUENCE {
- * responseType OBJECT IDENTIFIER,
- * response OCTET STRING }
- */
- static const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspResponseBytes) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(ocspResponseBytes, responseType) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(ocspResponseBytes, response) },
- { 0 }
- };
- /*
- * This template is just an extra level to use in an explicitly-tagged
- * reference to a ResponseBytes.
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = {
- { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate }
- };
- /*
- * BasicOCSPResponse ::= SEQUENCE {
- * 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 | SEC_ASN1_XTRN,
- offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
- SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
- { SEC_ASN1_BIT_STRING,
- offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
- SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
- { 0 }
- };
- /*
- * ResponseData ::= SEQUENCE {
- * version [0] EXPLICIT Version DEFAULT v1,
- * responderID ResponderID,
- * producedAt GeneralizedTime,
- * responses SEQUENCE OF SingleResponse,
- * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_ResponseDataTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspResponseData) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- offsetof(ocspResponseData, version),
- SEC_ASN1_SUB(SEC_IntegerTemplate) },
- { SEC_ASN1_ANY,
- offsetof(ocspResponseData, derResponderID) },
- { SEC_ASN1_GENERALIZED_TIME,
- offsetof(ocspResponseData, producedAt) },
- { SEC_ASN1_SEQUENCE_OF,
- offsetof(ocspResponseData, responses),
- ocsp_SingleResponseTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(ocspResponseData, responseExtensions),
- CERT_SequenceOfCertExtensionTemplate },
- { 0 }
- };
- /*
- * ResponderID ::= CHOICE {
- * byName [1] EXPLICIT Name,
- * byKey [2] EXPLICIT KeyHash }
- *
- * KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
- * (excluding the tag and length fields)
- *
- * XXX Because the ASN.1 encoder and decoder currently do not provide
- * a way to automatically handle a CHOICE, we need to do it in two
- * steps, looking at the type tag and feeding the exact choice back
- * to the ASN.1 code. Hopefully that will change someday and this
- * can all be simplified down into a single template. Anyway, for
- * now we list each choice as its own template:
- */
- static const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = {
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(ocspResponderID, responderIDValue.name),
- CERT_NameTemplate }
- };
- static const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = {
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
- SEC_ASN1_XTRN | 2,
- offsetof(ocspResponderID, responderIDValue.keyHash),
- SEC_ASN1_SUB(SEC_OctetStringTemplate) }
- };
- static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = {
- { SEC_ASN1_ANY,
- offsetof(ocspResponderID, responderIDValue.other) }
- };
- /* Decode choice container, but leave x509 name object encoded */
- static const SEC_ASN1Template ocsp_ResponderIDDerNameTemplate[] = {
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
- SEC_ASN1_XTRN | 1, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
- };
- /*
- * SingleResponse ::= SEQUENCE {
- * certID CertID,
- * certStatus CertStatus,
- * thisUpdate GeneralizedTime,
- * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
- * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_SingleResponseTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTOCSPSingleResponse) },
- { SEC_ASN1_POINTER,
- offsetof(CERTOCSPSingleResponse, certID),
- ocsp_CertIDTemplate },
- { SEC_ASN1_ANY,
- offsetof(CERTOCSPSingleResponse, derCertStatus) },
- { SEC_ASN1_GENERALIZED_TIME,
- offsetof(CERTOCSPSingleResponse, thisUpdate) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- offsetof(CERTOCSPSingleResponse, nextUpdate),
- SEC_ASN1_SUB(SEC_PointerToGeneralizedTimeTemplate) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(CERTOCSPSingleResponse, singleExtensions),
- CERT_SequenceOfCertExtensionTemplate },
- { 0 }
- };
- /*
- * CertStatus ::= CHOICE {
- * good [0] IMPLICIT NULL,
- * revoked [1] IMPLICIT RevokedInfo,
- * unknown [2] IMPLICIT UnknownInfo }
- *
- * Because the ASN.1 encoder and decoder currently do not provide
- * a way to automatically handle a CHOICE, we need to do it in two
- * steps, looking at the type tag and feeding the exact choice back
- * to the ASN.1 code. Hopefully that will change someday and this
- * can all be simplified down into a single template. Anyway, for
- * now we list each choice as its own template:
- */
- static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = {
- { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- offsetof(ocspCertStatus, certStatusInfo.goodInfo),
- SEC_ASN1_SUB(SEC_NullTemplate) }
- };
- static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = {
- { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
- ocsp_RevokedInfoTemplate }
- };
- static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = {
- { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
- offsetof(ocspCertStatus, certStatusInfo.unknownInfo),
- SEC_ASN1_SUB(SEC_NullTemplate) }
- };
- static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = {
- { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
- offsetof(ocspCertStatus, certStatusInfo.otherInfo),
- SEC_ASN1_SUB(SEC_AnyTemplate) }
- };
- /*
- * RevokedInfo ::= SEQUENCE {
- * revocationTime GeneralizedTime,
- * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
- *
- * Note: this should be static but the AIX compiler doesn't like it (because it
- * was forward-declared above); it is not meant to be exported, but this
- * is the only way it will compile.
- */
- const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspRevokedInfo) },
- { SEC_ASN1_GENERALIZED_TIME,
- offsetof(ocspRevokedInfo, revocationTime) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
- SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
- SEC_ASN1_XTRN | 0,
- offsetof(ocspRevokedInfo, revocationReason),
- SEC_ASN1_SUB(SEC_PointerToEnumeratedTemplate) },
- { 0 }
- };
- /*
- * OCSP-specific extension templates:
- */
- /*
- * ServiceLocator ::= SEQUENCE {
- * issuer Name,
- * locator AuthorityInfoAccessSyntax OPTIONAL }
- */
- static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(ocspServiceLocator) },
- { SEC_ASN1_POINTER,
- offsetof(ocspServiceLocator, issuer),
- CERT_NameTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
- offsetof(ocspServiceLocator, locator) },
- { 0 }
- };
- /*
- * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy):
- */
- /*
- * FUNCTION: CERT_EncodeOCSPRequest
- * DER encodes an OCSP Request, possibly adding a signature as well.
- * XXX Signing is not yet supported, however; see comments in code.
- * INPUTS:
- * PRArenaPool *arena
- * The return value is allocated from here.
- * If a NULL is passed in, allocation is done from the heap instead.
- * CERTOCSPRequest *request
- * The request to be encoded.
- * void *pwArg
- * Pointer to argument for password prompting, if needed. (Definitely
- * not needed if not signing.)
- * RETURN:
- * Returns a NULL on error and a pointer to the SECItem with the
- * encoded value otherwise. Any error is likely to be low-level
- * (e.g. no memory).
- */
- SECItem *
- CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request,
- void *pwArg)
- {
- ocspTBSRequest *tbsRequest;
- SECStatus rv;
- /* XXX All of these should generate errors if they fail. */
- PORT_Assert(request);
- PORT_Assert(request->tbsRequest);
- tbsRequest = request->tbsRequest;
- if (request->tbsRequest->extensionHandle != NULL) {
- rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle);
- request->tbsRequest->extensionHandle = NULL;
- if (rv != SECSuccess)
- return NULL;
- }
- /*
- * XXX When signed requests are supported and request->optionalSignature
- * is not NULL:
- * - need to encode tbsRequest->requestorName
- * - need to encode tbsRequest
- * - need to sign that encoded result (using cert in sig), filling in the
- * request->optionalSignature structure with the result, the signing
- * algorithm and (perhaps?) the cert (and its chain?) in derCerts
- */
- return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate);
- }
- /*
- * FUNCTION: CERT_DecodeOCSPRequest
- * Decode a DER encoded OCSP Request.
- * INPUTS:
- * SECItem *src
- * Pointer to a SECItem holding DER encoded OCSP Request.
- * RETURN:
- * Returns a pointer to a CERTOCSPRequest containing the decoded request.
- * On error, returns NULL. Most likely error is trouble decoding
- * (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
- */
- CERTOCSPRequest *
- CERT_DecodeOCSPRequest(SECItem *src)
- {
- PRArenaPool *arena = NULL;
- SECStatus rv = SECFailure;
- CERTOCSPRequest *dest = NULL;
- int i;
- SECItem newSrc;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) {
- goto loser;
- }
- dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena,
- siz…