1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/certhigh/ocsp.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,6190 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Implementation of OCSP services, for both client and server. 1.10 + * (XXX, really, mostly just for client right now, but intended to do both.) 1.11 + */ 1.12 + 1.13 +#include "prerror.h" 1.14 +#include "prprf.h" 1.15 +#include "plarena.h" 1.16 +#include "prnetdb.h" 1.17 + 1.18 +#include "seccomon.h" 1.19 +#include "secitem.h" 1.20 +#include "secoidt.h" 1.21 +#include "secasn1.h" 1.22 +#include "secder.h" 1.23 +#include "cert.h" 1.24 +#include "certi.h" 1.25 +#include "xconst.h" 1.26 +#include "secerr.h" 1.27 +#include "secoid.h" 1.28 +#include "hasht.h" 1.29 +#include "sechash.h" 1.30 +#include "secasn1.h" 1.31 +#include "plbase64.h" 1.32 +#include "keyhi.h" 1.33 +#include "cryptohi.h" 1.34 +#include "ocsp.h" 1.35 +#include "ocspti.h" 1.36 +#include "ocspi.h" 1.37 +#include "genname.h" 1.38 +#include "certxutl.h" 1.39 +#include "pk11func.h" /* for PK11_HashBuf */ 1.40 +#include <stdarg.h> 1.41 +#include <plhash.h> 1.42 + 1.43 +#define DEFAULT_OCSP_CACHE_SIZE 1000 1.44 +#define DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 1*60*60L 1.45 +#define DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 24*60*60L 1.46 +#define DEFAULT_OSCP_TIMEOUT_SECONDS 60 1.47 +#define MICROSECONDS_PER_SECOND 1000000L 1.48 + 1.49 +typedef struct OCSPCacheItemStr OCSPCacheItem; 1.50 +typedef struct OCSPCacheDataStr OCSPCacheData; 1.51 + 1.52 +struct OCSPCacheItemStr { 1.53 + /* LRU linking */ 1.54 + OCSPCacheItem *moreRecent; 1.55 + OCSPCacheItem *lessRecent; 1.56 + 1.57 + /* key */ 1.58 + CERTOCSPCertID *certID; 1.59 + /* CertID's arena also used to allocate "this" cache item */ 1.60 + 1.61 + /* cache control information */ 1.62 + PRTime nextFetchAttemptTime; 1.63 + 1.64 + /* Cached contents. Use a separate arena, because lifetime is different */ 1.65 + PLArenaPool *certStatusArena; /* NULL means: no cert status cached */ 1.66 + ocspCertStatus certStatus; 1.67 + 1.68 + /* This may contain an error code when no OCSP response is available. */ 1.69 + SECErrorCodes missingResponseError; 1.70 + 1.71 + PRPackedBool haveThisUpdate; 1.72 + PRPackedBool haveNextUpdate; 1.73 + PRTime thisUpdate; 1.74 + PRTime nextUpdate; 1.75 +}; 1.76 + 1.77 +struct OCSPCacheDataStr { 1.78 + PLHashTable *entries; 1.79 + PRUint32 numberOfEntries; 1.80 + OCSPCacheItem *MRUitem; /* most recently used cache item */ 1.81 + OCSPCacheItem *LRUitem; /* least recently used cache item */ 1.82 +}; 1.83 + 1.84 +static struct OCSPGlobalStruct { 1.85 + PRMonitor *monitor; 1.86 + const SEC_HttpClientFcn *defaultHttpClientFcn; 1.87 + PRInt32 maxCacheEntries; 1.88 + PRUint32 minimumSecondsToNextFetchAttempt; 1.89 + PRUint32 maximumSecondsToNextFetchAttempt; 1.90 + PRUint32 timeoutSeconds; 1.91 + OCSPCacheData cache; 1.92 + SEC_OcspFailureMode ocspFailureMode; 1.93 + CERT_StringFromCertFcn alternateOCSPAIAFcn; 1.94 + PRBool forcePost; 1.95 +} OCSP_Global = { NULL, 1.96 + NULL, 1.97 + DEFAULT_OCSP_CACHE_SIZE, 1.98 + DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT, 1.99 + DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT, 1.100 + DEFAULT_OSCP_TIMEOUT_SECONDS, 1.101 + {NULL, 0, NULL, NULL}, 1.102 + ocspMode_FailureIsVerificationFailure, 1.103 + NULL, 1.104 + PR_FALSE 1.105 + }; 1.106 + 1.107 + 1.108 + 1.109 +/* Forward declarations */ 1.110 +static SECItem * 1.111 +ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena, 1.112 + CERTOCSPRequest *request, 1.113 + const char *location, 1.114 + const char *method, 1.115 + PRTime time, 1.116 + PRBool addServiceLocator, 1.117 + void *pwArg, 1.118 + CERTOCSPRequest **pRequest); 1.119 +static SECStatus 1.120 +ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 1.121 + CERTOCSPCertID *certID, 1.122 + CERTCertificate *cert, 1.123 + PRTime time, 1.124 + void *pwArg, 1.125 + PRBool *certIDWasConsumed, 1.126 + SECStatus *rv_ocsp); 1.127 + 1.128 +static SECStatus 1.129 +ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle *handle, 1.130 + CERTOCSPCertID *certID, 1.131 + CERTCertificate *cert, 1.132 + PRTime time, 1.133 + void *pwArg, 1.134 + const SECItem *encodedResponse, 1.135 + CERTOCSPResponse **pDecodedResponse, 1.136 + CERTOCSPSingleResponse **pSingle); 1.137 + 1.138 +static SECStatus 1.139 +ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time); 1.140 + 1.141 +static CERTOCSPCertID * 1.142 +cert_DupOCSPCertID(const CERTOCSPCertID *src); 1.143 + 1.144 +#ifndef DEBUG 1.145 +#define OCSP_TRACE(msg) 1.146 +#define OCSP_TRACE_TIME(msg, time) 1.147 +#define OCSP_TRACE_CERT(cert) 1.148 +#define OCSP_TRACE_CERTID(certid) 1.149 +#else 1.150 +#define OCSP_TRACE(msg) ocsp_Trace msg 1.151 +#define OCSP_TRACE_TIME(msg, time) ocsp_dumpStringWithTime(msg, time) 1.152 +#define OCSP_TRACE_CERT(cert) dumpCertificate(cert) 1.153 +#define OCSP_TRACE_CERTID(certid) dumpCertID(certid) 1.154 + 1.155 +#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) \ 1.156 + || defined(XP_MACOSX) 1.157 +#define NSS_HAVE_GETENV 1 1.158 +#endif 1.159 + 1.160 +static PRBool wantOcspTrace(void) 1.161 +{ 1.162 + static PRBool firstTime = PR_TRUE; 1.163 + static PRBool wantTrace = PR_FALSE; 1.164 + 1.165 +#ifdef NSS_HAVE_GETENV 1.166 + if (firstTime) { 1.167 + char *ev = getenv("NSS_TRACE_OCSP"); 1.168 + if (ev && ev[0]) { 1.169 + wantTrace = PR_TRUE; 1.170 + } 1.171 + firstTime = PR_FALSE; 1.172 + } 1.173 +#endif 1.174 + return wantTrace; 1.175 +} 1.176 + 1.177 +static void 1.178 +ocsp_Trace(const char *format, ...) 1.179 +{ 1.180 + char buf[2000]; 1.181 + va_list args; 1.182 + 1.183 + if (!wantOcspTrace()) 1.184 + return; 1.185 + va_start(args, format); 1.186 + PR_vsnprintf(buf, sizeof(buf), format, args); 1.187 + va_end(args); 1.188 + PR_LogPrint("%s", buf); 1.189 +} 1.190 + 1.191 +static void 1.192 +ocsp_dumpStringWithTime(const char *str, PRTime time) 1.193 +{ 1.194 + PRExplodedTime timePrintable; 1.195 + char timestr[256]; 1.196 + 1.197 + if (!wantOcspTrace()) 1.198 + return; 1.199 + PR_ExplodeTime(time, PR_GMTParameters, &timePrintable); 1.200 + if (PR_FormatTime(timestr, 256, "%a %b %d %H:%M:%S %Y", &timePrintable)) { 1.201 + ocsp_Trace("OCSP %s %s\n", str, timestr); 1.202 + } 1.203 +} 1.204 + 1.205 +static void 1.206 +printHexString(const char *prefix, SECItem *hexval) 1.207 +{ 1.208 + unsigned int i; 1.209 + char *hexbuf = NULL; 1.210 + 1.211 + for (i = 0; i < hexval->len; i++) { 1.212 + if (i != hexval->len - 1) { 1.213 + hexbuf = PR_sprintf_append(hexbuf, "%02x:", hexval->data[i]); 1.214 + } else { 1.215 + hexbuf = PR_sprintf_append(hexbuf, "%02x", hexval->data[i]); 1.216 + } 1.217 + } 1.218 + if (hexbuf) { 1.219 + ocsp_Trace("%s %s\n", prefix, hexbuf); 1.220 + PR_smprintf_free(hexbuf); 1.221 + } 1.222 +} 1.223 + 1.224 +static void 1.225 +dumpCertificate(CERTCertificate *cert) 1.226 +{ 1.227 + if (!wantOcspTrace()) 1.228 + return; 1.229 + 1.230 + ocsp_Trace("OCSP ----------------\n"); 1.231 + ocsp_Trace("OCSP ## SUBJECT: %s\n", cert->subjectName); 1.232 + { 1.233 + PRTime timeBefore, timeAfter; 1.234 + PRExplodedTime beforePrintable, afterPrintable; 1.235 + char beforestr[256], afterstr[256]; 1.236 + PRStatus rv1, rv2; 1.237 + DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore); 1.238 + DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter); 1.239 + PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable); 1.240 + PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable); 1.241 + rv1 = PR_FormatTime(beforestr, 256, "%a %b %d %H:%M:%S %Y", 1.242 + &beforePrintable); 1.243 + rv2 = PR_FormatTime(afterstr, 256, "%a %b %d %H:%M:%S %Y", 1.244 + &afterPrintable); 1.245 + ocsp_Trace("OCSP ## VALIDITY: %s to %s\n", rv1 ? beforestr : "", 1.246 + rv2 ? afterstr : ""); 1.247 + } 1.248 + ocsp_Trace("OCSP ## ISSUER: %s\n", cert->issuerName); 1.249 + printHexString("OCSP ## SERIAL NUMBER:", &cert->serialNumber); 1.250 +} 1.251 + 1.252 +static void 1.253 +dumpCertID(CERTOCSPCertID *certID) 1.254 +{ 1.255 + if (!wantOcspTrace()) 1.256 + return; 1.257 + 1.258 + printHexString("OCSP certID issuer", &certID->issuerNameHash); 1.259 + printHexString("OCSP certID serial", &certID->serialNumber); 1.260 +} 1.261 +#endif 1.262 + 1.263 +SECStatus 1.264 +SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable) 1.265 +{ 1.266 + if (!OCSP_Global.monitor) { 1.267 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.268 + return SECFailure; 1.269 + } 1.270 + 1.271 + PR_EnterMonitor(OCSP_Global.monitor); 1.272 + OCSP_Global.defaultHttpClientFcn = fcnTable; 1.273 + PR_ExitMonitor(OCSP_Global.monitor); 1.274 + 1.275 + return SECSuccess; 1.276 +} 1.277 + 1.278 +SECStatus 1.279 +CERT_RegisterAlternateOCSPAIAInfoCallBack( 1.280 + CERT_StringFromCertFcn newCallback, 1.281 + CERT_StringFromCertFcn * oldCallback) 1.282 +{ 1.283 + CERT_StringFromCertFcn old; 1.284 + 1.285 + if (!OCSP_Global.monitor) { 1.286 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.287 + return SECFailure; 1.288 + } 1.289 + 1.290 + PR_EnterMonitor(OCSP_Global.monitor); 1.291 + old = OCSP_Global.alternateOCSPAIAFcn; 1.292 + OCSP_Global.alternateOCSPAIAFcn = newCallback; 1.293 + PR_ExitMonitor(OCSP_Global.monitor); 1.294 + if (oldCallback) 1.295 + *oldCallback = old; 1.296 + return SECSuccess; 1.297 +} 1.298 + 1.299 +static PLHashNumber PR_CALLBACK 1.300 +ocsp_CacheKeyHashFunction(const void *key) 1.301 +{ 1.302 + CERTOCSPCertID *cid = (CERTOCSPCertID *)key; 1.303 + PLHashNumber hash = 0; 1.304 + unsigned int i; 1.305 + unsigned char *walk; 1.306 + 1.307 + /* a very simple hash calculation for the initial coding phase */ 1.308 + walk = (unsigned char*)cid->issuerNameHash.data; 1.309 + for (i=0; i < cid->issuerNameHash.len; ++i, ++walk) { 1.310 + hash += *walk; 1.311 + } 1.312 + walk = (unsigned char*)cid->issuerKeyHash.data; 1.313 + for (i=0; i < cid->issuerKeyHash.len; ++i, ++walk) { 1.314 + hash += *walk; 1.315 + } 1.316 + walk = (unsigned char*)cid->serialNumber.data; 1.317 + for (i=0; i < cid->serialNumber.len; ++i, ++walk) { 1.318 + hash += *walk; 1.319 + } 1.320 + return hash; 1.321 +} 1.322 + 1.323 +static PRIntn PR_CALLBACK 1.324 +ocsp_CacheKeyCompareFunction(const void *v1, const void *v2) 1.325 +{ 1.326 + CERTOCSPCertID *cid1 = (CERTOCSPCertID *)v1; 1.327 + CERTOCSPCertID *cid2 = (CERTOCSPCertID *)v2; 1.328 + 1.329 + return (SECEqual == SECITEM_CompareItem(&cid1->issuerNameHash, 1.330 + &cid2->issuerNameHash) 1.331 + && SECEqual == SECITEM_CompareItem(&cid1->issuerKeyHash, 1.332 + &cid2->issuerKeyHash) 1.333 + && SECEqual == SECITEM_CompareItem(&cid1->serialNumber, 1.334 + &cid2->serialNumber)); 1.335 +} 1.336 + 1.337 +static SECStatus 1.338 +ocsp_CopyRevokedInfo(PLArenaPool *arena, ocspCertStatus *dest, 1.339 + ocspRevokedInfo *src) 1.340 +{ 1.341 + SECStatus rv = SECFailure; 1.342 + void *mark; 1.343 + 1.344 + mark = PORT_ArenaMark(arena); 1.345 + 1.346 + dest->certStatusInfo.revokedInfo = 1.347 + (ocspRevokedInfo *) PORT_ArenaZAlloc(arena, sizeof(ocspRevokedInfo)); 1.348 + if (!dest->certStatusInfo.revokedInfo) { 1.349 + goto loser; 1.350 + } 1.351 + 1.352 + rv = SECITEM_CopyItem(arena, 1.353 + &dest->certStatusInfo.revokedInfo->revocationTime, 1.354 + &src->revocationTime); 1.355 + if (rv != SECSuccess) { 1.356 + goto loser; 1.357 + } 1.358 + 1.359 + if (src->revocationReason) { 1.360 + dest->certStatusInfo.revokedInfo->revocationReason = 1.361 + SECITEM_ArenaDupItem(arena, src->revocationReason); 1.362 + if (!dest->certStatusInfo.revokedInfo->revocationReason) { 1.363 + goto loser; 1.364 + } 1.365 + } else { 1.366 + dest->certStatusInfo.revokedInfo->revocationReason = NULL; 1.367 + } 1.368 + 1.369 + PORT_ArenaUnmark(arena, mark); 1.370 + return SECSuccess; 1.371 + 1.372 +loser: 1.373 + PORT_ArenaRelease(arena, mark); 1.374 + return SECFailure; 1.375 +} 1.376 + 1.377 +static SECStatus 1.378 +ocsp_CopyCertStatus(PLArenaPool *arena, ocspCertStatus *dest, 1.379 + ocspCertStatus*src) 1.380 +{ 1.381 + SECStatus rv = SECFailure; 1.382 + dest->certStatusType = src->certStatusType; 1.383 + 1.384 + switch (src->certStatusType) { 1.385 + case ocspCertStatus_good: 1.386 + dest->certStatusInfo.goodInfo = 1.387 + SECITEM_ArenaDupItem(arena, src->certStatusInfo.goodInfo); 1.388 + if (dest->certStatusInfo.goodInfo != NULL) { 1.389 + rv = SECSuccess; 1.390 + } 1.391 + break; 1.392 + case ocspCertStatus_revoked: 1.393 + rv = ocsp_CopyRevokedInfo(arena, dest, 1.394 + src->certStatusInfo.revokedInfo); 1.395 + break; 1.396 + case ocspCertStatus_unknown: 1.397 + dest->certStatusInfo.unknownInfo = 1.398 + SECITEM_ArenaDupItem(arena, src->certStatusInfo.unknownInfo); 1.399 + if (dest->certStatusInfo.unknownInfo != NULL) { 1.400 + rv = SECSuccess; 1.401 + } 1.402 + break; 1.403 + case ocspCertStatus_other: 1.404 + default: 1.405 + PORT_Assert(src->certStatusType == ocspCertStatus_other); 1.406 + dest->certStatusInfo.otherInfo = 1.407 + SECITEM_ArenaDupItem(arena, src->certStatusInfo.otherInfo); 1.408 + if (dest->certStatusInfo.otherInfo != NULL) { 1.409 + rv = SECSuccess; 1.410 + } 1.411 + break; 1.412 + } 1.413 + return rv; 1.414 +} 1.415 + 1.416 +static void 1.417 +ocsp_AddCacheItemToLinkedList(OCSPCacheData *cache, OCSPCacheItem *new_most_recent) 1.418 +{ 1.419 + PR_EnterMonitor(OCSP_Global.monitor); 1.420 + 1.421 + if (!cache->LRUitem) { 1.422 + cache->LRUitem = new_most_recent; 1.423 + } 1.424 + new_most_recent->lessRecent = cache->MRUitem; 1.425 + new_most_recent->moreRecent = NULL; 1.426 + 1.427 + if (cache->MRUitem) { 1.428 + cache->MRUitem->moreRecent = new_most_recent; 1.429 + } 1.430 + cache->MRUitem = new_most_recent; 1.431 + 1.432 + PR_ExitMonitor(OCSP_Global.monitor); 1.433 +} 1.434 + 1.435 +static void 1.436 +ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData *cache, OCSPCacheItem *item) 1.437 +{ 1.438 + PR_EnterMonitor(OCSP_Global.monitor); 1.439 + 1.440 + if (!item->lessRecent && !item->moreRecent) { 1.441 + /* 1.442 + * Fail gracefully on attempts to remove an item from the list, 1.443 + * which is currently not part of the list. 1.444 + * But check for the edge case it is the single entry in the list. 1.445 + */ 1.446 + if (item == cache->LRUitem && 1.447 + item == cache->MRUitem) { 1.448 + /* remove the single entry */ 1.449 + PORT_Assert(cache->numberOfEntries == 1); 1.450 + PORT_Assert(item->moreRecent == NULL); 1.451 + cache->MRUitem = NULL; 1.452 + cache->LRUitem = NULL; 1.453 + } 1.454 + PR_ExitMonitor(OCSP_Global.monitor); 1.455 + return; 1.456 + } 1.457 + 1.458 + PORT_Assert(cache->numberOfEntries > 1); 1.459 + 1.460 + if (item == cache->LRUitem) { 1.461 + PORT_Assert(item != cache->MRUitem); 1.462 + PORT_Assert(item->lessRecent == NULL); 1.463 + PORT_Assert(item->moreRecent != NULL); 1.464 + PORT_Assert(item->moreRecent->lessRecent == item); 1.465 + cache->LRUitem = item->moreRecent; 1.466 + cache->LRUitem->lessRecent = NULL; 1.467 + } 1.468 + else if (item == cache->MRUitem) { 1.469 + PORT_Assert(item->moreRecent == NULL); 1.470 + PORT_Assert(item->lessRecent != NULL); 1.471 + PORT_Assert(item->lessRecent->moreRecent == item); 1.472 + cache->MRUitem = item->lessRecent; 1.473 + cache->MRUitem->moreRecent = NULL; 1.474 + } else { 1.475 + /* remove an entry in the middle of the list */ 1.476 + PORT_Assert(item->moreRecent != NULL); 1.477 + PORT_Assert(item->lessRecent != NULL); 1.478 + PORT_Assert(item->lessRecent->moreRecent == item); 1.479 + PORT_Assert(item->moreRecent->lessRecent == item); 1.480 + item->moreRecent->lessRecent = item->lessRecent; 1.481 + item->lessRecent->moreRecent = item->moreRecent; 1.482 + } 1.483 + 1.484 + item->lessRecent = NULL; 1.485 + item->moreRecent = NULL; 1.486 + 1.487 + PR_ExitMonitor(OCSP_Global.monitor); 1.488 +} 1.489 + 1.490 +static void 1.491 +ocsp_MakeCacheEntryMostRecent(OCSPCacheData *cache, OCSPCacheItem *new_most_recent) 1.492 +{ 1.493 + OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent THREADID %p\n", 1.494 + PR_GetCurrentThread())); 1.495 + PR_EnterMonitor(OCSP_Global.monitor); 1.496 + if (cache->MRUitem == new_most_recent) { 1.497 + OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent ALREADY MOST\n")); 1.498 + PR_ExitMonitor(OCSP_Global.monitor); 1.499 + return; 1.500 + } 1.501 + OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent NEW entry\n")); 1.502 + ocsp_RemoveCacheItemFromLinkedList(cache, new_most_recent); 1.503 + ocsp_AddCacheItemToLinkedList(cache, new_most_recent); 1.504 + PR_ExitMonitor(OCSP_Global.monitor); 1.505 +} 1.506 + 1.507 +static PRBool 1.508 +ocsp_IsCacheDisabled(void) 1.509 +{ 1.510 + /* 1.511 + * maxCacheEntries == 0 means unlimited cache entries 1.512 + * maxCacheEntries < 0 means cache is disabled 1.513 + */ 1.514 + PRBool retval; 1.515 + PR_EnterMonitor(OCSP_Global.monitor); 1.516 + retval = (OCSP_Global.maxCacheEntries < 0); 1.517 + PR_ExitMonitor(OCSP_Global.monitor); 1.518 + return retval; 1.519 +} 1.520 + 1.521 +static OCSPCacheItem * 1.522 +ocsp_FindCacheEntry(OCSPCacheData *cache, CERTOCSPCertID *certID) 1.523 +{ 1.524 + OCSPCacheItem *found_ocsp_item = NULL; 1.525 + OCSP_TRACE(("OCSP ocsp_FindCacheEntry\n")); 1.526 + OCSP_TRACE_CERTID(certID); 1.527 + PR_EnterMonitor(OCSP_Global.monitor); 1.528 + if (ocsp_IsCacheDisabled()) 1.529 + goto loser; 1.530 + 1.531 + found_ocsp_item = (OCSPCacheItem *)PL_HashTableLookup( 1.532 + cache->entries, certID); 1.533 + if (!found_ocsp_item) 1.534 + goto loser; 1.535 + 1.536 + OCSP_TRACE(("OCSP ocsp_FindCacheEntry FOUND!\n")); 1.537 + ocsp_MakeCacheEntryMostRecent(cache, found_ocsp_item); 1.538 + 1.539 +loser: 1.540 + PR_ExitMonitor(OCSP_Global.monitor); 1.541 + return found_ocsp_item; 1.542 +} 1.543 + 1.544 +static void 1.545 +ocsp_FreeCacheItem(OCSPCacheItem *item) 1.546 +{ 1.547 + OCSP_TRACE(("OCSP ocsp_FreeCacheItem\n")); 1.548 + if (item->certStatusArena) { 1.549 + PORT_FreeArena(item->certStatusArena, PR_FALSE); 1.550 + } 1.551 + if (item->certID->poolp) { 1.552 + /* freeing this poolp arena will also free item */ 1.553 + PORT_FreeArena(item->certID->poolp, PR_FALSE); 1.554 + } 1.555 +} 1.556 + 1.557 +static void 1.558 +ocsp_RemoveCacheItem(OCSPCacheData *cache, OCSPCacheItem *item) 1.559 +{ 1.560 + /* The item we're removing could be either the least recently used item, 1.561 + * or it could be an item that couldn't get updated with newer status info 1.562 + * because of an allocation failure, or it could get removed because we're 1.563 + * cleaning up. 1.564 + */ 1.565 + PRBool couldRemoveFromHashTable; 1.566 + OCSP_TRACE(("OCSP ocsp_RemoveCacheItem, THREADID %p\n", PR_GetCurrentThread())); 1.567 + PR_EnterMonitor(OCSP_Global.monitor); 1.568 + 1.569 + ocsp_RemoveCacheItemFromLinkedList(cache, item); 1.570 + couldRemoveFromHashTable = PL_HashTableRemove(cache->entries, 1.571 + item->certID); 1.572 + PORT_Assert(couldRemoveFromHashTable); 1.573 + --cache->numberOfEntries; 1.574 + ocsp_FreeCacheItem(item); 1.575 + PR_ExitMonitor(OCSP_Global.monitor); 1.576 +} 1.577 + 1.578 +static void 1.579 +ocsp_CheckCacheSize(OCSPCacheData *cache) 1.580 +{ 1.581 + OCSP_TRACE(("OCSP ocsp_CheckCacheSize\n")); 1.582 + PR_EnterMonitor(OCSP_Global.monitor); 1.583 + if (OCSP_Global.maxCacheEntries > 0) { 1.584 + /* Cache is not disabled. Number of cache entries is limited. 1.585 + * The monitor ensures that maxCacheEntries remains positive. 1.586 + */ 1.587 + while (cache->numberOfEntries > 1.588 + (PRUint32)OCSP_Global.maxCacheEntries) { 1.589 + ocsp_RemoveCacheItem(cache, cache->LRUitem); 1.590 + } 1.591 + } 1.592 + PR_ExitMonitor(OCSP_Global.monitor); 1.593 +} 1.594 + 1.595 +SECStatus 1.596 +CERT_ClearOCSPCache(void) 1.597 +{ 1.598 + OCSP_TRACE(("OCSP CERT_ClearOCSPCache\n")); 1.599 + PR_EnterMonitor(OCSP_Global.monitor); 1.600 + while (OCSP_Global.cache.numberOfEntries > 0) { 1.601 + ocsp_RemoveCacheItem(&OCSP_Global.cache, 1.602 + OCSP_Global.cache.LRUitem); 1.603 + } 1.604 + PR_ExitMonitor(OCSP_Global.monitor); 1.605 + return SECSuccess; 1.606 +} 1.607 + 1.608 +static SECStatus 1.609 +ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData *cache, 1.610 + CERTOCSPCertID *certID, 1.611 + OCSPCacheItem **pCacheItem) 1.612 +{ 1.613 + PLArenaPool *arena; 1.614 + void *mark; 1.615 + PLHashEntry *new_hash_entry; 1.616 + OCSPCacheItem *item; 1.617 + 1.618 + PORT_Assert(pCacheItem != NULL); 1.619 + *pCacheItem = NULL; 1.620 + 1.621 + PR_EnterMonitor(OCSP_Global.monitor); 1.622 + arena = certID->poolp; 1.623 + mark = PORT_ArenaMark(arena); 1.624 + 1.625 + /* ZAlloc will init all Bools to False and all Pointers to NULL 1.626 + and all error codes to zero/good. */ 1.627 + item = (OCSPCacheItem *)PORT_ArenaZAlloc(certID->poolp, 1.628 + sizeof(OCSPCacheItem)); 1.629 + if (!item) { 1.630 + goto loser; 1.631 + } 1.632 + item->certID = certID; 1.633 + new_hash_entry = PL_HashTableAdd(cache->entries, item->certID, 1.634 + item); 1.635 + if (!new_hash_entry) { 1.636 + goto loser; 1.637 + } 1.638 + ++cache->numberOfEntries; 1.639 + PORT_ArenaUnmark(arena, mark); 1.640 + ocsp_AddCacheItemToLinkedList(cache, item); 1.641 + *pCacheItem = item; 1.642 + 1.643 + PR_ExitMonitor(OCSP_Global.monitor); 1.644 + return SECSuccess; 1.645 + 1.646 +loser: 1.647 + PORT_ArenaRelease(arena, mark); 1.648 + PR_ExitMonitor(OCSP_Global.monitor); 1.649 + return SECFailure; 1.650 +} 1.651 + 1.652 +static SECStatus 1.653 +ocsp_SetCacheItemResponse(OCSPCacheItem *item, 1.654 + const CERTOCSPSingleResponse *response) 1.655 +{ 1.656 + if (item->certStatusArena) { 1.657 + PORT_FreeArena(item->certStatusArena, PR_FALSE); 1.658 + item->certStatusArena = NULL; 1.659 + } 1.660 + item->haveThisUpdate = item->haveNextUpdate = PR_FALSE; 1.661 + if (response) { 1.662 + SECStatus rv; 1.663 + item->certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.664 + if (item->certStatusArena == NULL) { 1.665 + return SECFailure; 1.666 + } 1.667 + rv = ocsp_CopyCertStatus(item->certStatusArena, &item->certStatus, 1.668 + response->certStatus); 1.669 + if (rv != SECSuccess) { 1.670 + PORT_FreeArena(item->certStatusArena, PR_FALSE); 1.671 + item->certStatusArena = NULL; 1.672 + return rv; 1.673 + } 1.674 + item->missingResponseError = 0; 1.675 + rv = DER_GeneralizedTimeToTime(&item->thisUpdate, 1.676 + &response->thisUpdate); 1.677 + item->haveThisUpdate = (rv == SECSuccess); 1.678 + if (response->nextUpdate) { 1.679 + rv = DER_GeneralizedTimeToTime(&item->nextUpdate, 1.680 + response->nextUpdate); 1.681 + item->haveNextUpdate = (rv == SECSuccess); 1.682 + } else { 1.683 + item->haveNextUpdate = PR_FALSE; 1.684 + } 1.685 + } 1.686 + return SECSuccess; 1.687 +} 1.688 + 1.689 +static void 1.690 +ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem *cacheItem) 1.691 +{ 1.692 + PRTime now; 1.693 + PRTime earliestAllowedNextFetchAttemptTime; 1.694 + PRTime latestTimeWhenResponseIsConsideredFresh; 1.695 + 1.696 + OCSP_TRACE(("OCSP ocsp_FreshenCacheItemNextFetchAttemptTime\n")); 1.697 + 1.698 + PR_EnterMonitor(OCSP_Global.monitor); 1.699 + 1.700 + now = PR_Now(); 1.701 + OCSP_TRACE_TIME("now:", now); 1.702 + 1.703 + if (cacheItem->haveThisUpdate) { 1.704 + OCSP_TRACE_TIME("thisUpdate:", cacheItem->thisUpdate); 1.705 + latestTimeWhenResponseIsConsideredFresh = cacheItem->thisUpdate + 1.706 + OCSP_Global.maximumSecondsToNextFetchAttempt * 1.707 + MICROSECONDS_PER_SECOND; 1.708 + OCSP_TRACE_TIME("latestTimeWhenResponseIsConsideredFresh:", 1.709 + latestTimeWhenResponseIsConsideredFresh); 1.710 + } else { 1.711 + latestTimeWhenResponseIsConsideredFresh = now + 1.712 + OCSP_Global.minimumSecondsToNextFetchAttempt * 1.713 + MICROSECONDS_PER_SECOND; 1.714 + OCSP_TRACE_TIME("no thisUpdate, " 1.715 + "latestTimeWhenResponseIsConsideredFresh:", 1.716 + latestTimeWhenResponseIsConsideredFresh); 1.717 + } 1.718 + 1.719 + if (cacheItem->haveNextUpdate) { 1.720 + OCSP_TRACE_TIME("have nextUpdate:", cacheItem->nextUpdate); 1.721 + } 1.722 + 1.723 + if (cacheItem->haveNextUpdate && 1.724 + cacheItem->nextUpdate < latestTimeWhenResponseIsConsideredFresh) { 1.725 + latestTimeWhenResponseIsConsideredFresh = cacheItem->nextUpdate; 1.726 + OCSP_TRACE_TIME("nextUpdate is smaller than latestFresh, setting " 1.727 + "latestTimeWhenResponseIsConsideredFresh:", 1.728 + latestTimeWhenResponseIsConsideredFresh); 1.729 + } 1.730 + 1.731 + earliestAllowedNextFetchAttemptTime = now + 1.732 + OCSP_Global.minimumSecondsToNextFetchAttempt * 1.733 + MICROSECONDS_PER_SECOND; 1.734 + OCSP_TRACE_TIME("earliestAllowedNextFetchAttemptTime:", 1.735 + earliestAllowedNextFetchAttemptTime); 1.736 + 1.737 + if (latestTimeWhenResponseIsConsideredFresh < 1.738 + earliestAllowedNextFetchAttemptTime) { 1.739 + latestTimeWhenResponseIsConsideredFresh = 1.740 + earliestAllowedNextFetchAttemptTime; 1.741 + OCSP_TRACE_TIME("latest < earliest, setting latest to:", 1.742 + latestTimeWhenResponseIsConsideredFresh); 1.743 + } 1.744 + 1.745 + cacheItem->nextFetchAttemptTime = 1.746 + latestTimeWhenResponseIsConsideredFresh; 1.747 + OCSP_TRACE_TIME("nextFetchAttemptTime", 1.748 + latestTimeWhenResponseIsConsideredFresh); 1.749 + 1.750 + PR_ExitMonitor(OCSP_Global.monitor); 1.751 +} 1.752 + 1.753 +static PRBool 1.754 +ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem) 1.755 +{ 1.756 + PRTime now; 1.757 + PRBool fresh; 1.758 + 1.759 + now = PR_Now(); 1.760 + 1.761 + fresh = cacheItem->nextFetchAttemptTime > now; 1.762 + 1.763 + /* Work around broken OCSP responders that return unknown responses for 1.764 + * certificates, especially certificates that were just recently issued. 1.765 + */ 1.766 + if (fresh && cacheItem->certStatusArena && 1.767 + cacheItem->certStatus.certStatusType == ocspCertStatus_unknown) { 1.768 + fresh = PR_FALSE; 1.769 + } 1.770 + 1.771 + OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", fresh)); 1.772 + 1.773 + return fresh; 1.774 +} 1.775 + 1.776 +/* 1.777 + * Status in *certIDWasConsumed will always be correct, regardless of 1.778 + * return value. 1.779 + * If the caller is unable to transfer ownership of certID, 1.780 + * then the caller must set certIDWasConsumed to NULL, 1.781 + * and this function will potentially duplicate the certID object. 1.782 + */ 1.783 +static SECStatus 1.784 +ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache, 1.785 + CERTOCSPCertID *certID, 1.786 + CERTOCSPSingleResponse *single, 1.787 + PRBool *certIDWasConsumed) 1.788 +{ 1.789 + SECStatus rv; 1.790 + OCSPCacheItem *cacheItem; 1.791 + OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n")); 1.792 + 1.793 + if (certIDWasConsumed) 1.794 + *certIDWasConsumed = PR_FALSE; 1.795 + 1.796 + PR_EnterMonitor(OCSP_Global.monitor); 1.797 + PORT_Assert(OCSP_Global.maxCacheEntries >= 0); 1.798 + 1.799 + cacheItem = ocsp_FindCacheEntry(cache, certID); 1.800 + 1.801 + /* Don't replace an unknown or revoked entry with an error entry, even if 1.802 + * the existing entry is expired. Instead, we'll continue to use the 1.803 + * existing (possibly expired) cache entry until we receive a valid signed 1.804 + * response to replace it. 1.805 + */ 1.806 + if (!single && cacheItem && cacheItem->certStatusArena && 1.807 + (cacheItem->certStatus.certStatusType == ocspCertStatus_revoked || 1.808 + cacheItem->certStatus.certStatusType == ocspCertStatus_unknown)) { 1.809 + PR_ExitMonitor(OCSP_Global.monitor); 1.810 + return SECSuccess; 1.811 + } 1.812 + 1.813 + if (!cacheItem) { 1.814 + CERTOCSPCertID *myCertID; 1.815 + if (certIDWasConsumed) { 1.816 + myCertID = certID; 1.817 + *certIDWasConsumed = PR_TRUE; 1.818 + } else { 1.819 + myCertID = cert_DupOCSPCertID(certID); 1.820 + if (!myCertID) { 1.821 + PR_ExitMonitor(OCSP_Global.monitor); 1.822 + PORT_SetError(PR_OUT_OF_MEMORY_ERROR); 1.823 + return SECFailure; 1.824 + } 1.825 + } 1.826 + 1.827 + rv = ocsp_CreateCacheItemAndConsumeCertID(cache, myCertID, 1.828 + &cacheItem); 1.829 + if (rv != SECSuccess) { 1.830 + PR_ExitMonitor(OCSP_Global.monitor); 1.831 + return rv; 1.832 + } 1.833 + } 1.834 + if (single) { 1.835 + PRTime thisUpdate; 1.836 + rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate); 1.837 + 1.838 + if (!cacheItem->haveThisUpdate || 1.839 + (rv == SECSuccess && cacheItem->thisUpdate < thisUpdate)) { 1.840 + rv = ocsp_SetCacheItemResponse(cacheItem, single); 1.841 + if (rv != SECSuccess) { 1.842 + ocsp_RemoveCacheItem(cache, cacheItem); 1.843 + PR_ExitMonitor(OCSP_Global.monitor); 1.844 + return rv; 1.845 + } 1.846 + } else { 1.847 + OCSP_TRACE(("Not caching response because the response is not " 1.848 + "newer than the cache")); 1.849 + } 1.850 + } else { 1.851 + cacheItem->missingResponseError = PORT_GetError(); 1.852 + if (cacheItem->certStatusArena) { 1.853 + PORT_FreeArena(cacheItem->certStatusArena, PR_FALSE); 1.854 + cacheItem->certStatusArena = NULL; 1.855 + } 1.856 + } 1.857 + ocsp_FreshenCacheItemNextFetchAttemptTime(cacheItem); 1.858 + ocsp_CheckCacheSize(cache); 1.859 + 1.860 + PR_ExitMonitor(OCSP_Global.monitor); 1.861 + return SECSuccess; 1.862 +} 1.863 + 1.864 +extern SECStatus 1.865 +CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode) 1.866 +{ 1.867 + switch (ocspFailureMode) { 1.868 + case ocspMode_FailureIsVerificationFailure: 1.869 + case ocspMode_FailureIsNotAVerificationFailure: 1.870 + break; 1.871 + default: 1.872 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.873 + return SECFailure; 1.874 + } 1.875 + 1.876 + PR_EnterMonitor(OCSP_Global.monitor); 1.877 + OCSP_Global.ocspFailureMode = ocspFailureMode; 1.878 + PR_ExitMonitor(OCSP_Global.monitor); 1.879 + return SECSuccess; 1.880 +} 1.881 + 1.882 +SECStatus 1.883 +CERT_OCSPCacheSettings(PRInt32 maxCacheEntries, 1.884 + PRUint32 minimumSecondsToNextFetchAttempt, 1.885 + PRUint32 maximumSecondsToNextFetchAttempt) 1.886 +{ 1.887 + if (minimumSecondsToNextFetchAttempt > maximumSecondsToNextFetchAttempt 1.888 + || maxCacheEntries < -1) { 1.889 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.890 + return SECFailure; 1.891 + } 1.892 + 1.893 + PR_EnterMonitor(OCSP_Global.monitor); 1.894 + 1.895 + if (maxCacheEntries < 0) { 1.896 + OCSP_Global.maxCacheEntries = -1; /* disable cache */ 1.897 + } else if (maxCacheEntries == 0) { 1.898 + OCSP_Global.maxCacheEntries = 0; /* unlimited cache entries */ 1.899 + } else { 1.900 + OCSP_Global.maxCacheEntries = maxCacheEntries; 1.901 + } 1.902 + 1.903 + if (minimumSecondsToNextFetchAttempt < 1.904 + OCSP_Global.minimumSecondsToNextFetchAttempt 1.905 + || maximumSecondsToNextFetchAttempt < 1.906 + OCSP_Global.maximumSecondsToNextFetchAttempt) { 1.907 + /* 1.908 + * Ensure our existing cache entries are not used longer than the 1.909 + * new settings allow, we're lazy and just clear the cache 1.910 + */ 1.911 + CERT_ClearOCSPCache(); 1.912 + } 1.913 + 1.914 + OCSP_Global.minimumSecondsToNextFetchAttempt = 1.915 + minimumSecondsToNextFetchAttempt; 1.916 + OCSP_Global.maximumSecondsToNextFetchAttempt = 1.917 + maximumSecondsToNextFetchAttempt; 1.918 + ocsp_CheckCacheSize(&OCSP_Global.cache); 1.919 + 1.920 + PR_ExitMonitor(OCSP_Global.monitor); 1.921 + return SECSuccess; 1.922 +} 1.923 + 1.924 +SECStatus 1.925 +CERT_SetOCSPTimeout(PRUint32 seconds) 1.926 +{ 1.927 + /* no locking, see bug 406120 */ 1.928 + OCSP_Global.timeoutSeconds = seconds; 1.929 + return SECSuccess; 1.930 +} 1.931 + 1.932 +/* this function is called at NSS initialization time */ 1.933 +SECStatus OCSP_InitGlobal(void) 1.934 +{ 1.935 + SECStatus rv = SECFailure; 1.936 + 1.937 + if (OCSP_Global.monitor == NULL) { 1.938 + OCSP_Global.monitor = PR_NewMonitor(); 1.939 + } 1.940 + if (!OCSP_Global.monitor) 1.941 + return SECFailure; 1.942 + 1.943 + PR_EnterMonitor(OCSP_Global.monitor); 1.944 + if (!OCSP_Global.cache.entries) { 1.945 + OCSP_Global.cache.entries = 1.946 + PL_NewHashTable(0, 1.947 + ocsp_CacheKeyHashFunction, 1.948 + ocsp_CacheKeyCompareFunction, 1.949 + PL_CompareValues, 1.950 + NULL, 1.951 + NULL); 1.952 + OCSP_Global.ocspFailureMode = ocspMode_FailureIsVerificationFailure; 1.953 + OCSP_Global.cache.numberOfEntries = 0; 1.954 + OCSP_Global.cache.MRUitem = NULL; 1.955 + OCSP_Global.cache.LRUitem = NULL; 1.956 + } else { 1.957 + /* 1.958 + * NSS might call this function twice while attempting to init. 1.959 + * But it's not allowed to call this again after any activity. 1.960 + */ 1.961 + PORT_Assert(OCSP_Global.cache.numberOfEntries == 0); 1.962 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.963 + } 1.964 + if (OCSP_Global.cache.entries) 1.965 + rv = SECSuccess; 1.966 + PR_ExitMonitor(OCSP_Global.monitor); 1.967 + return rv; 1.968 +} 1.969 + 1.970 +SECStatus OCSP_ShutdownGlobal(void) 1.971 +{ 1.972 + if (!OCSP_Global.monitor) 1.973 + return SECSuccess; 1.974 + 1.975 + PR_EnterMonitor(OCSP_Global.monitor); 1.976 + if (OCSP_Global.cache.entries) { 1.977 + CERT_ClearOCSPCache(); 1.978 + PL_HashTableDestroy(OCSP_Global.cache.entries); 1.979 + OCSP_Global.cache.entries = NULL; 1.980 + } 1.981 + PORT_Assert(OCSP_Global.cache.numberOfEntries == 0); 1.982 + OCSP_Global.cache.MRUitem = NULL; 1.983 + OCSP_Global.cache.LRUitem = NULL; 1.984 + 1.985 + OCSP_Global.defaultHttpClientFcn = NULL; 1.986 + OCSP_Global.maxCacheEntries = DEFAULT_OCSP_CACHE_SIZE; 1.987 + OCSP_Global.minimumSecondsToNextFetchAttempt = 1.988 + DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT; 1.989 + OCSP_Global.maximumSecondsToNextFetchAttempt = 1.990 + DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT; 1.991 + OCSP_Global.ocspFailureMode = 1.992 + ocspMode_FailureIsVerificationFailure; 1.993 + PR_ExitMonitor(OCSP_Global.monitor); 1.994 + 1.995 + PR_DestroyMonitor(OCSP_Global.monitor); 1.996 + OCSP_Global.monitor = NULL; 1.997 + return SECSuccess; 1.998 +} 1.999 + 1.1000 +/* 1.1001 + * A return value of NULL means: 1.1002 + * The application did not register it's own HTTP client. 1.1003 + */ 1.1004 +const SEC_HttpClientFcn *SEC_GetRegisteredHttpClient(void) 1.1005 +{ 1.1006 + const SEC_HttpClientFcn *retval; 1.1007 + 1.1008 + if (!OCSP_Global.monitor) { 1.1009 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.1010 + return NULL; 1.1011 + } 1.1012 + 1.1013 + PR_EnterMonitor(OCSP_Global.monitor); 1.1014 + retval = OCSP_Global.defaultHttpClientFcn; 1.1015 + PR_ExitMonitor(OCSP_Global.monitor); 1.1016 + 1.1017 + return retval; 1.1018 +} 1.1019 + 1.1020 +/* 1.1021 + * The following structure is only used internally. It is allocated when 1.1022 + * someone turns on OCSP checking, and hangs off of the status-configuration 1.1023 + * structure in the certdb structure. We use it to keep configuration 1.1024 + * information specific to OCSP checking. 1.1025 + */ 1.1026 +typedef struct ocspCheckingContextStr { 1.1027 + PRBool useDefaultResponder; 1.1028 + char *defaultResponderURI; 1.1029 + char *defaultResponderNickname; 1.1030 + CERTCertificate *defaultResponderCert; 1.1031 +} ocspCheckingContext; 1.1032 + 1.1033 +SEC_ASN1_MKSUB(SEC_AnyTemplate) 1.1034 +SEC_ASN1_MKSUB(SEC_IntegerTemplate) 1.1035 +SEC_ASN1_MKSUB(SEC_NullTemplate) 1.1036 +SEC_ASN1_MKSUB(SEC_OctetStringTemplate) 1.1037 +SEC_ASN1_MKSUB(SEC_PointerToAnyTemplate) 1.1038 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1.1039 +SEC_ASN1_MKSUB(SEC_SequenceOfAnyTemplate) 1.1040 +SEC_ASN1_MKSUB(SEC_PointerToGeneralizedTimeTemplate) 1.1041 +SEC_ASN1_MKSUB(SEC_PointerToEnumeratedTemplate) 1.1042 + 1.1043 +/* 1.1044 + * Forward declarations of sub-types, so I can lay out the types in the 1.1045 + * same order as the ASN.1 is laid out in the OCSP spec itself. 1.1046 + * 1.1047 + * These are in alphabetical order (case-insensitive); please keep it that way! 1.1048 + */ 1.1049 +extern const SEC_ASN1Template ocsp_CertIDTemplate[]; 1.1050 +extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[]; 1.1051 +extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[]; 1.1052 +extern const SEC_ASN1Template ocsp_ResponseDataTemplate[]; 1.1053 +extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[]; 1.1054 +extern const SEC_ASN1Template ocsp_SingleRequestTemplate[]; 1.1055 +extern const SEC_ASN1Template ocsp_SingleResponseTemplate[]; 1.1056 +extern const SEC_ASN1Template ocsp_TBSRequestTemplate[]; 1.1057 + 1.1058 + 1.1059 +/* 1.1060 + * Request-related templates... 1.1061 + */ 1.1062 + 1.1063 +/* 1.1064 + * OCSPRequest ::= SEQUENCE { 1.1065 + * tbsRequest TBSRequest, 1.1066 + * optionalSignature [0] EXPLICIT Signature OPTIONAL } 1.1067 + */ 1.1068 +static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = { 1.1069 + { SEC_ASN1_SEQUENCE, 1.1070 + 0, NULL, sizeof(CERTOCSPRequest) }, 1.1071 + { SEC_ASN1_POINTER, 1.1072 + offsetof(CERTOCSPRequest, tbsRequest), 1.1073 + ocsp_TBSRequestTemplate }, 1.1074 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1075 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 1.1076 + offsetof(CERTOCSPRequest, optionalSignature), 1.1077 + ocsp_PointerToSignatureTemplate }, 1.1078 + { 0 } 1.1079 +}; 1.1080 + 1.1081 +/* 1.1082 + * TBSRequest ::= SEQUENCE { 1.1083 + * version [0] EXPLICIT Version DEFAULT v1, 1.1084 + * requestorName [1] EXPLICIT GeneralName OPTIONAL, 1.1085 + * requestList SEQUENCE OF Request, 1.1086 + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } 1.1087 + * 1.1088 + * Version ::= INTEGER { v1(0) } 1.1089 + * 1.1090 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1091 + * was forward-declared above); it is not meant to be exported, but this 1.1092 + * is the only way it will compile. 1.1093 + */ 1.1094 +const SEC_ASN1Template ocsp_TBSRequestTemplate[] = { 1.1095 + { SEC_ASN1_SEQUENCE, 1.1096 + 0, NULL, sizeof(ocspTBSRequest) }, 1.1097 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */ 1.1098 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 1.1099 + offsetof(ocspTBSRequest, version), 1.1100 + SEC_ASN1_SUB(SEC_IntegerTemplate) }, 1.1101 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1102 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, 1.1103 + offsetof(ocspTBSRequest, derRequestorName), 1.1104 + SEC_ASN1_SUB(SEC_PointerToAnyTemplate) }, 1.1105 + { SEC_ASN1_SEQUENCE_OF, 1.1106 + offsetof(ocspTBSRequest, requestList), 1.1107 + ocsp_SingleRequestTemplate }, 1.1108 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1109 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2, 1.1110 + offsetof(ocspTBSRequest, requestExtensions), 1.1111 + CERT_SequenceOfCertExtensionTemplate }, 1.1112 + { 0 } 1.1113 +}; 1.1114 + 1.1115 +/* 1.1116 + * Signature ::= SEQUENCE { 1.1117 + * signatureAlgorithm AlgorithmIdentifier, 1.1118 + * signature BIT STRING, 1.1119 + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } 1.1120 + */ 1.1121 +static const SEC_ASN1Template ocsp_SignatureTemplate[] = { 1.1122 + { SEC_ASN1_SEQUENCE, 1.1123 + 0, NULL, sizeof(ocspSignature) }, 1.1124 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.1125 + offsetof(ocspSignature, signatureAlgorithm), 1.1126 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.1127 + { SEC_ASN1_BIT_STRING, 1.1128 + offsetof(ocspSignature, signature) }, 1.1129 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1130 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 1.1131 + offsetof(ocspSignature, derCerts), 1.1132 + SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) }, 1.1133 + { 0 } 1.1134 +}; 1.1135 + 1.1136 +/* 1.1137 + * This template is just an extra level to use in an explicitly-tagged 1.1138 + * reference to a Signature. 1.1139 + * 1.1140 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1141 + * was forward-declared above); it is not meant to be exported, but this 1.1142 + * is the only way it will compile. 1.1143 + */ 1.1144 +const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = { 1.1145 + { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate } 1.1146 +}; 1.1147 + 1.1148 +/* 1.1149 + * Request ::= SEQUENCE { 1.1150 + * reqCert CertID, 1.1151 + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } 1.1152 + * 1.1153 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1154 + * was forward-declared above); it is not meant to be exported, but this 1.1155 + * is the only way it will compile. 1.1156 + */ 1.1157 +const SEC_ASN1Template ocsp_SingleRequestTemplate[] = { 1.1158 + { SEC_ASN1_SEQUENCE, 1.1159 + 0, NULL, sizeof(ocspSingleRequest) }, 1.1160 + { SEC_ASN1_POINTER, 1.1161 + offsetof(ocspSingleRequest, reqCert), 1.1162 + ocsp_CertIDTemplate }, 1.1163 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1164 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 1.1165 + offsetof(ocspSingleRequest, singleRequestExtensions), 1.1166 + CERT_SequenceOfCertExtensionTemplate }, 1.1167 + { 0 } 1.1168 +}; 1.1169 + 1.1170 + 1.1171 +/* 1.1172 + * This data structure and template (CertID) is used by both OCSP 1.1173 + * requests and responses. It is the only one that is shared. 1.1174 + * 1.1175 + * CertID ::= SEQUENCE { 1.1176 + * hashAlgorithm AlgorithmIdentifier, 1.1177 + * issuerNameHash OCTET STRING, -- Hash of Issuer DN 1.1178 + * issuerKeyHash OCTET STRING, -- Hash of Issuer public key 1.1179 + * serialNumber CertificateSerialNumber } 1.1180 + * 1.1181 + * CertificateSerialNumber ::= INTEGER 1.1182 + * 1.1183 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1184 + * was forward-declared above); it is not meant to be exported, but this 1.1185 + * is the only way it will compile. 1.1186 + */ 1.1187 +const SEC_ASN1Template ocsp_CertIDTemplate[] = { 1.1188 + { SEC_ASN1_SEQUENCE, 1.1189 + 0, NULL, sizeof(CERTOCSPCertID) }, 1.1190 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.1191 + offsetof(CERTOCSPCertID, hashAlgorithm), 1.1192 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.1193 + { SEC_ASN1_OCTET_STRING, 1.1194 + offsetof(CERTOCSPCertID, issuerNameHash) }, 1.1195 + { SEC_ASN1_OCTET_STRING, 1.1196 + offsetof(CERTOCSPCertID, issuerKeyHash) }, 1.1197 + { SEC_ASN1_INTEGER, 1.1198 + offsetof(CERTOCSPCertID, serialNumber) }, 1.1199 + { 0 } 1.1200 +}; 1.1201 + 1.1202 + 1.1203 +/* 1.1204 + * Response-related templates... 1.1205 + */ 1.1206 + 1.1207 +/* 1.1208 + * OCSPResponse ::= SEQUENCE { 1.1209 + * responseStatus OCSPResponseStatus, 1.1210 + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } 1.1211 + */ 1.1212 +const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = { 1.1213 + { SEC_ASN1_SEQUENCE, 1.1214 + 0, NULL, sizeof(CERTOCSPResponse) }, 1.1215 + { SEC_ASN1_ENUMERATED, 1.1216 + offsetof(CERTOCSPResponse, responseStatus) }, 1.1217 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1218 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 1.1219 + offsetof(CERTOCSPResponse, responseBytes), 1.1220 + ocsp_PointerToResponseBytesTemplate }, 1.1221 + { 0 } 1.1222 +}; 1.1223 + 1.1224 +/* 1.1225 + * ResponseBytes ::= SEQUENCE { 1.1226 + * responseType OBJECT IDENTIFIER, 1.1227 + * response OCTET STRING } 1.1228 + */ 1.1229 +const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = { 1.1230 + { SEC_ASN1_SEQUENCE, 1.1231 + 0, NULL, sizeof(ocspResponseBytes) }, 1.1232 + { SEC_ASN1_OBJECT_ID, 1.1233 + offsetof(ocspResponseBytes, responseType) }, 1.1234 + { SEC_ASN1_OCTET_STRING, 1.1235 + offsetof(ocspResponseBytes, response) }, 1.1236 + { 0 } 1.1237 +}; 1.1238 + 1.1239 +/* 1.1240 + * This template is just an extra level to use in an explicitly-tagged 1.1241 + * reference to a ResponseBytes. 1.1242 + * 1.1243 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1244 + * was forward-declared above); it is not meant to be exported, but this 1.1245 + * is the only way it will compile. 1.1246 + */ 1.1247 +const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = { 1.1248 + { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate } 1.1249 +}; 1.1250 + 1.1251 +/* 1.1252 + * BasicOCSPResponse ::= SEQUENCE { 1.1253 + * tbsResponseData ResponseData, 1.1254 + * signatureAlgorithm AlgorithmIdentifier, 1.1255 + * signature BIT STRING, 1.1256 + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } 1.1257 + */ 1.1258 +static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = { 1.1259 + { SEC_ASN1_SEQUENCE, 1.1260 + 0, NULL, sizeof(ocspBasicOCSPResponse) }, 1.1261 + { SEC_ASN1_ANY | SEC_ASN1_SAVE, 1.1262 + offsetof(ocspBasicOCSPResponse, tbsResponseDataDER) }, 1.1263 + { SEC_ASN1_POINTER, 1.1264 + offsetof(ocspBasicOCSPResponse, tbsResponseData), 1.1265 + ocsp_ResponseDataTemplate }, 1.1266 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.1267 + offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm), 1.1268 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.1269 + { SEC_ASN1_BIT_STRING, 1.1270 + offsetof(ocspBasicOCSPResponse, responseSignature.signature) }, 1.1271 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1272 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 1.1273 + offsetof(ocspBasicOCSPResponse, responseSignature.derCerts), 1.1274 + SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) }, 1.1275 + { 0 } 1.1276 +}; 1.1277 + 1.1278 +/* 1.1279 + * ResponseData ::= SEQUENCE { 1.1280 + * version [0] EXPLICIT Version DEFAULT v1, 1.1281 + * responderID ResponderID, 1.1282 + * producedAt GeneralizedTime, 1.1283 + * responses SEQUENCE OF SingleResponse, 1.1284 + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } 1.1285 + * 1.1286 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1287 + * was forward-declared above); it is not meant to be exported, but this 1.1288 + * is the only way it will compile. 1.1289 + */ 1.1290 +const SEC_ASN1Template ocsp_ResponseDataTemplate[] = { 1.1291 + { SEC_ASN1_SEQUENCE, 1.1292 + 0, NULL, sizeof(ocspResponseData) }, 1.1293 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */ 1.1294 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 1.1295 + offsetof(ocspResponseData, version), 1.1296 + SEC_ASN1_SUB(SEC_IntegerTemplate) }, 1.1297 + { SEC_ASN1_ANY, 1.1298 + offsetof(ocspResponseData, derResponderID) }, 1.1299 + { SEC_ASN1_GENERALIZED_TIME, 1.1300 + offsetof(ocspResponseData, producedAt) }, 1.1301 + { SEC_ASN1_SEQUENCE_OF, 1.1302 + offsetof(ocspResponseData, responses), 1.1303 + ocsp_SingleResponseTemplate }, 1.1304 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1305 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 1.1306 + offsetof(ocspResponseData, responseExtensions), 1.1307 + CERT_SequenceOfCertExtensionTemplate }, 1.1308 + { 0 } 1.1309 +}; 1.1310 + 1.1311 +/* 1.1312 + * ResponderID ::= CHOICE { 1.1313 + * byName [1] EXPLICIT Name, 1.1314 + * byKey [2] EXPLICIT KeyHash } 1.1315 + * 1.1316 + * KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key 1.1317 + * (excluding the tag and length fields) 1.1318 + * 1.1319 + * XXX Because the ASN.1 encoder and decoder currently do not provide 1.1320 + * a way to automatically handle a CHOICE, we need to do it in two 1.1321 + * steps, looking at the type tag and feeding the exact choice back 1.1322 + * to the ASN.1 code. Hopefully that will change someday and this 1.1323 + * can all be simplified down into a single template. Anyway, for 1.1324 + * now we list each choice as its own template: 1.1325 + */ 1.1326 +const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = { 1.1327 + { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 1.1328 + offsetof(ocspResponderID, responderIDValue.name), 1.1329 + CERT_NameTemplate } 1.1330 +}; 1.1331 +const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = { 1.1332 + { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1.1333 + SEC_ASN1_XTRN | 2, 1.1334 + offsetof(ocspResponderID, responderIDValue.keyHash), 1.1335 + SEC_ASN1_SUB(SEC_OctetStringTemplate) } 1.1336 +}; 1.1337 +static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = { 1.1338 + { SEC_ASN1_ANY, 1.1339 + offsetof(ocspResponderID, responderIDValue.other) } 1.1340 +}; 1.1341 + 1.1342 +/* Decode choice container, but leave x509 name object encoded */ 1.1343 +static const SEC_ASN1Template ocsp_ResponderIDDerNameTemplate[] = { 1.1344 + { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1.1345 + SEC_ASN1_XTRN | 1, 0, SEC_ASN1_SUB(SEC_AnyTemplate) } 1.1346 +}; 1.1347 + 1.1348 +/* 1.1349 + * SingleResponse ::= SEQUENCE { 1.1350 + * certID CertID, 1.1351 + * certStatus CertStatus, 1.1352 + * thisUpdate GeneralizedTime, 1.1353 + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, 1.1354 + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } 1.1355 + * 1.1356 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1357 + * was forward-declared above); it is not meant to be exported, but this 1.1358 + * is the only way it will compile. 1.1359 + */ 1.1360 +const SEC_ASN1Template ocsp_SingleResponseTemplate[] = { 1.1361 + { SEC_ASN1_SEQUENCE, 1.1362 + 0, NULL, sizeof(CERTOCSPSingleResponse) }, 1.1363 + { SEC_ASN1_POINTER, 1.1364 + offsetof(CERTOCSPSingleResponse, certID), 1.1365 + ocsp_CertIDTemplate }, 1.1366 + { SEC_ASN1_ANY, 1.1367 + offsetof(CERTOCSPSingleResponse, derCertStatus) }, 1.1368 + { SEC_ASN1_GENERALIZED_TIME, 1.1369 + offsetof(CERTOCSPSingleResponse, thisUpdate) }, 1.1370 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1371 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 1.1372 + offsetof(CERTOCSPSingleResponse, nextUpdate), 1.1373 + SEC_ASN1_SUB(SEC_PointerToGeneralizedTimeTemplate) }, 1.1374 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1375 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 1.1376 + offsetof(CERTOCSPSingleResponse, singleExtensions), 1.1377 + CERT_SequenceOfCertExtensionTemplate }, 1.1378 + { 0 } 1.1379 +}; 1.1380 + 1.1381 +/* 1.1382 + * CertStatus ::= CHOICE { 1.1383 + * good [0] IMPLICIT NULL, 1.1384 + * revoked [1] IMPLICIT RevokedInfo, 1.1385 + * unknown [2] IMPLICIT UnknownInfo } 1.1386 + * 1.1387 + * Because the ASN.1 encoder and decoder currently do not provide 1.1388 + * a way to automatically handle a CHOICE, we need to do it in two 1.1389 + * steps, looking at the type tag and feeding the exact choice back 1.1390 + * to the ASN.1 code. Hopefully that will change someday and this 1.1391 + * can all be simplified down into a single template. Anyway, for 1.1392 + * now we list each choice as its own template: 1.1393 + */ 1.1394 +static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = { 1.1395 + { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 1.1396 + offsetof(ocspCertStatus, certStatusInfo.goodInfo), 1.1397 + SEC_ASN1_SUB(SEC_NullTemplate) } 1.1398 +}; 1.1399 +static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = { 1.1400 + { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 1.1401 + offsetof(ocspCertStatus, certStatusInfo.revokedInfo), 1.1402 + ocsp_RevokedInfoTemplate } 1.1403 +}; 1.1404 +static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = { 1.1405 + { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2, 1.1406 + offsetof(ocspCertStatus, certStatusInfo.unknownInfo), 1.1407 + SEC_ASN1_SUB(SEC_NullTemplate) } 1.1408 +}; 1.1409 +static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = { 1.1410 + { SEC_ASN1_POINTER | SEC_ASN1_XTRN, 1.1411 + offsetof(ocspCertStatus, certStatusInfo.otherInfo), 1.1412 + SEC_ASN1_SUB(SEC_AnyTemplate) } 1.1413 +}; 1.1414 + 1.1415 +/* 1.1416 + * RevokedInfo ::= SEQUENCE { 1.1417 + * revocationTime GeneralizedTime, 1.1418 + * revocationReason [0] EXPLICIT CRLReason OPTIONAL } 1.1419 + * 1.1420 + * Note: this should be static but the AIX compiler doesn't like it (because it 1.1421 + * was forward-declared above); it is not meant to be exported, but this 1.1422 + * is the only way it will compile. 1.1423 + */ 1.1424 +const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = { 1.1425 + { SEC_ASN1_SEQUENCE, 1.1426 + 0, NULL, sizeof(ocspRevokedInfo) }, 1.1427 + { SEC_ASN1_GENERALIZED_TIME, 1.1428 + offsetof(ocspRevokedInfo, revocationTime) }, 1.1429 + { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | 1.1430 + SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1.1431 + SEC_ASN1_XTRN | 0, 1.1432 + offsetof(ocspRevokedInfo, revocationReason), 1.1433 + SEC_ASN1_SUB(SEC_PointerToEnumeratedTemplate) }, 1.1434 + { 0 } 1.1435 +}; 1.1436 + 1.1437 + 1.1438 +/* 1.1439 + * OCSP-specific extension templates: 1.1440 + */ 1.1441 + 1.1442 +/* 1.1443 + * ServiceLocator ::= SEQUENCE { 1.1444 + * issuer Name, 1.1445 + * locator AuthorityInfoAccessSyntax OPTIONAL } 1.1446 + */ 1.1447 +static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = { 1.1448 + { SEC_ASN1_SEQUENCE, 1.1449 + 0, NULL, sizeof(ocspServiceLocator) }, 1.1450 + { SEC_ASN1_POINTER, 1.1451 + offsetof(ocspServiceLocator, issuer), 1.1452 + CERT_NameTemplate }, 1.1453 + { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, 1.1454 + offsetof(ocspServiceLocator, locator) }, 1.1455 + { 0 } 1.1456 +}; 1.1457 + 1.1458 + 1.1459 +/* 1.1460 + * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy): 1.1461 + */ 1.1462 + 1.1463 +/* 1.1464 + * FUNCTION: CERT_EncodeOCSPRequest 1.1465 + * DER encodes an OCSP Request, possibly adding a signature as well. 1.1466 + * XXX Signing is not yet supported, however; see comments in code. 1.1467 + * INPUTS: 1.1468 + * PLArenaPool *arena 1.1469 + * The return value is allocated from here. 1.1470 + * If a NULL is passed in, allocation is done from the heap instead. 1.1471 + * CERTOCSPRequest *request 1.1472 + * The request to be encoded. 1.1473 + * void *pwArg 1.1474 + * Pointer to argument for password prompting, if needed. (Definitely 1.1475 + * not needed if not signing.) 1.1476 + * RETURN: 1.1477 + * Returns a NULL on error and a pointer to the SECItem with the 1.1478 + * encoded value otherwise. Any error is likely to be low-level 1.1479 + * (e.g. no memory). 1.1480 + */ 1.1481 +SECItem * 1.1482 +CERT_EncodeOCSPRequest(PLArenaPool *arena, CERTOCSPRequest *request, 1.1483 + void *pwArg) 1.1484 +{ 1.1485 + SECStatus rv; 1.1486 + 1.1487 + /* XXX All of these should generate errors if they fail. */ 1.1488 + PORT_Assert(request); 1.1489 + PORT_Assert(request->tbsRequest); 1.1490 + 1.1491 + if (request->tbsRequest->extensionHandle != NULL) { 1.1492 + rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle); 1.1493 + request->tbsRequest->extensionHandle = NULL; 1.1494 + if (rv != SECSuccess) 1.1495 + return NULL; 1.1496 + } 1.1497 + 1.1498 + /* 1.1499 + * XXX When signed requests are supported and request->optionalSignature 1.1500 + * is not NULL: 1.1501 + * - need to encode tbsRequest->requestorName 1.1502 + * - need to encode tbsRequest 1.1503 + * - need to sign that encoded result (using cert in sig), filling in the 1.1504 + * request->optionalSignature structure with the result, the signing 1.1505 + * algorithm and (perhaps?) the cert (and its chain?) in derCerts 1.1506 + */ 1.1507 + 1.1508 + return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate); 1.1509 +} 1.1510 + 1.1511 + 1.1512 +/* 1.1513 + * FUNCTION: CERT_DecodeOCSPRequest 1.1514 + * Decode a DER encoded OCSP Request. 1.1515 + * INPUTS: 1.1516 + * SECItem *src 1.1517 + * Pointer to a SECItem holding DER encoded OCSP Request. 1.1518 + * RETURN: 1.1519 + * Returns a pointer to a CERTOCSPRequest containing the decoded request. 1.1520 + * On error, returns NULL. Most likely error is trouble decoding 1.1521 + * (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory). 1.1522 + */ 1.1523 +CERTOCSPRequest * 1.1524 +CERT_DecodeOCSPRequest(const SECItem *src) 1.1525 +{ 1.1526 + PLArenaPool *arena = NULL; 1.1527 + SECStatus rv = SECFailure; 1.1528 + CERTOCSPRequest *dest = NULL; 1.1529 + int i; 1.1530 + SECItem newSrc; 1.1531 + 1.1532 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1533 + if (arena == NULL) { 1.1534 + goto loser; 1.1535 + } 1.1536 + dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena, 1.1537 + sizeof(CERTOCSPRequest)); 1.1538 + if (dest == NULL) { 1.1539 + goto loser; 1.1540 + } 1.1541 + dest->arena = arena; 1.1542 + 1.1543 + /* copy the DER into the arena, since Quick DER returns data that points 1.1544 + into the DER input, which may get freed by the caller */ 1.1545 + rv = SECITEM_CopyItem(arena, &newSrc, src); 1.1546 + if ( rv != SECSuccess ) { 1.1547 + goto loser; 1.1548 + } 1.1549 + 1.1550 + rv = SEC_QuickDERDecodeItem(arena, dest, ocsp_OCSPRequestTemplate, &newSrc); 1.1551 + if (rv != SECSuccess) { 1.1552 + if (PORT_GetError() == SEC_ERROR_BAD_DER) 1.1553 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); 1.1554 + goto loser; 1.1555 + } 1.1556 + 1.1557 + /* 1.1558 + * XXX I would like to find a way to get rid of the necessity 1.1559 + * of doing this copying of the arena pointer. 1.1560 + */ 1.1561 + for (i = 0; dest->tbsRequest->requestList[i] != NULL; i++) { 1.1562 + dest->tbsRequest->requestList[i]->arena = arena; 1.1563 + } 1.1564 + 1.1565 + return dest; 1.1566 + 1.1567 +loser: 1.1568 + if (arena != NULL) { 1.1569 + PORT_FreeArena(arena, PR_FALSE); 1.1570 + } 1.1571 + return NULL; 1.1572 +} 1.1573 + 1.1574 +SECStatus 1.1575 +CERT_DestroyOCSPCertID(CERTOCSPCertID* certID) 1.1576 +{ 1.1577 + if (certID && certID->poolp) { 1.1578 + PORT_FreeArena(certID->poolp, PR_FALSE); 1.1579 + return SECSuccess; 1.1580 + } 1.1581 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1582 + return SECFailure; 1.1583 +} 1.1584 + 1.1585 +/* 1.1586 + * Digest data using the specified algorithm. 1.1587 + * The necessary storage for the digest data is allocated. If "fill" is 1.1588 + * non-null, the data is put there, otherwise a SECItem is allocated. 1.1589 + * Allocation from "arena" if it is non-null, heap otherwise. Any problem 1.1590 + * results in a NULL being returned (and an appropriate error set). 1.1591 + */ 1.1592 + 1.1593 +SECItem * 1.1594 +ocsp_DigestValue(PLArenaPool *arena, SECOidTag digestAlg, 1.1595 + SECItem *fill, const SECItem *src) 1.1596 +{ 1.1597 + const SECHashObject *digestObject; 1.1598 + SECItem *result = NULL; 1.1599 + void *mark = NULL; 1.1600 + void *digestBuff = NULL; 1.1601 + 1.1602 + if ( arena != NULL ) { 1.1603 + mark = PORT_ArenaMark(arena); 1.1604 + } 1.1605 + 1.1606 + digestObject = HASH_GetHashObjectByOidTag(digestAlg); 1.1607 + if ( digestObject == NULL ) { 1.1608 + goto loser; 1.1609 + } 1.1610 + 1.1611 + if (fill == NULL || fill->data == NULL) { 1.1612 + result = SECITEM_AllocItem(arena, fill, digestObject->length); 1.1613 + if ( result == NULL ) { 1.1614 + goto loser; 1.1615 + } 1.1616 + digestBuff = result->data; 1.1617 + } else { 1.1618 + if (fill->len < digestObject->length) { 1.1619 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1620 + goto loser; 1.1621 + } 1.1622 + digestBuff = fill->data; 1.1623 + } 1.1624 + 1.1625 + if (PK11_HashBuf(digestAlg, digestBuff, 1.1626 + src->data, src->len) != SECSuccess) { 1.1627 + goto loser; 1.1628 + } 1.1629 + 1.1630 + if ( arena != NULL ) { 1.1631 + PORT_ArenaUnmark(arena, mark); 1.1632 + } 1.1633 + 1.1634 + if (result == NULL) { 1.1635 + result = fill; 1.1636 + } 1.1637 + return result; 1.1638 + 1.1639 +loser: 1.1640 + if (arena != NULL) { 1.1641 + PORT_ArenaRelease(arena, mark); 1.1642 + } else { 1.1643 + if (result != NULL) { 1.1644 + SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE); 1.1645 + } 1.1646 + } 1.1647 + return(NULL); 1.1648 +} 1.1649 + 1.1650 +/* 1.1651 + * Digest the cert's subject public key using the specified algorithm. 1.1652 + * The necessary storage for the digest data is allocated. If "fill" is 1.1653 + * non-null, the data is put there, otherwise a SECItem is allocated. 1.1654 + * Allocation from "arena" if it is non-null, heap otherwise. Any problem 1.1655 + * results in a NULL being returned (and an appropriate error set). 1.1656 + */ 1.1657 +SECItem * 1.1658 +CERT_GetSubjectPublicKeyDigest(PLArenaPool *arena, const CERTCertificate *cert, 1.1659 + SECOidTag digestAlg, SECItem *fill) 1.1660 +{ 1.1661 + SECItem spk; 1.1662 + 1.1663 + /* 1.1664 + * Copy just the length and data pointer (nothing needs to be freed) 1.1665 + * of the subject public key so we can convert the length from bits 1.1666 + * to bytes, which is what the digest function expects. 1.1667 + */ 1.1668 + spk = cert->subjectPublicKeyInfo.subjectPublicKey; 1.1669 + DER_ConvertBitString(&spk); 1.1670 + 1.1671 + return ocsp_DigestValue(arena, digestAlg, fill, &spk); 1.1672 +} 1.1673 + 1.1674 +/* 1.1675 + * Digest the cert's subject name using the specified algorithm. 1.1676 + */ 1.1677 +SECItem * 1.1678 +CERT_GetSubjectNameDigest(PLArenaPool *arena, const CERTCertificate *cert, 1.1679 + SECOidTag digestAlg, SECItem *fill) 1.1680 +{ 1.1681 + SECItem name; 1.1682 + 1.1683 + /* 1.1684 + * Copy just the length and data pointer (nothing needs to be freed) 1.1685 + * of the subject name 1.1686 + */ 1.1687 + name = cert->derSubject; 1.1688 + 1.1689 + return ocsp_DigestValue(arena, digestAlg, fill, &name); 1.1690 +} 1.1691 + 1.1692 +/* 1.1693 + * Create and fill-in a CertID. This function fills in the hash values 1.1694 + * (issuerNameHash and issuerKeyHash), and is hardwired to use SHA1. 1.1695 + * Someday it might need to be more flexible about hash algorithm, but 1.1696 + * for now we have no intention/need to create anything else. 1.1697 + * 1.1698 + * Error causes a null to be returned; most likely cause is trouble 1.1699 + * finding the certificate issuer (SEC_ERROR_UNKNOWN_ISSUER). 1.1700 + * Other errors are low-level problems (no memory, bad database, etc.). 1.1701 + */ 1.1702 +static CERTOCSPCertID * 1.1703 +ocsp_CreateCertID(PLArenaPool *arena, CERTCertificate *cert, PRTime time) 1.1704 +{ 1.1705 + CERTOCSPCertID *certID; 1.1706 + CERTCertificate *issuerCert = NULL; 1.1707 + void *mark = PORT_ArenaMark(arena); 1.1708 + SECStatus rv; 1.1709 + 1.1710 + PORT_Assert(arena != NULL); 1.1711 + 1.1712 + certID = PORT_ArenaZNew(arena, CERTOCSPCertID); 1.1713 + if (certID == NULL) { 1.1714 + goto loser; 1.1715 + } 1.1716 + 1.1717 + rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1, 1.1718 + NULL); 1.1719 + if (rv != SECSuccess) { 1.1720 + goto loser; 1.1721 + } 1.1722 + 1.1723 + issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); 1.1724 + if (issuerCert == NULL) { 1.1725 + goto loser; 1.1726 + } 1.1727 + 1.1728 + if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_SHA1, 1.1729 + &(certID->issuerNameHash)) == NULL) { 1.1730 + goto loser; 1.1731 + } 1.1732 + certID->issuerSHA1NameHash.data = certID->issuerNameHash.data; 1.1733 + certID->issuerSHA1NameHash.len = certID->issuerNameHash.len; 1.1734 + 1.1735 + if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD5, 1.1736 + &(certID->issuerMD5NameHash)) == NULL) { 1.1737 + goto loser; 1.1738 + } 1.1739 + 1.1740 + if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD2, 1.1741 + &(certID->issuerMD2NameHash)) == NULL) { 1.1742 + goto loser; 1.1743 + } 1.1744 + 1.1745 + if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_SHA1, 1.1746 + &certID->issuerKeyHash) == NULL) { 1.1747 + goto loser; 1.1748 + } 1.1749 + certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data; 1.1750 + certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len; 1.1751 + /* cache the other two hash algorithms as well */ 1.1752 + if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_MD5, 1.1753 + &certID->issuerMD5KeyHash) == NULL) { 1.1754 + goto loser; 1.1755 + } 1.1756 + if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_MD2, 1.1757 + &certID->issuerMD2KeyHash) == NULL) { 1.1758 + goto loser; 1.1759 + } 1.1760 + 1.1761 + 1.1762 + /* now we are done with issuerCert */ 1.1763 + CERT_DestroyCertificate(issuerCert); 1.1764 + issuerCert = NULL; 1.1765 + 1.1766 + rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber); 1.1767 + if (rv != SECSuccess) { 1.1768 + goto loser; 1.1769 + } 1.1770 + 1.1771 + PORT_ArenaUnmark(arena, mark); 1.1772 + return certID; 1.1773 + 1.1774 +loser: 1.1775 + if (issuerCert != NULL) { 1.1776 + CERT_DestroyCertificate(issuerCert); 1.1777 + } 1.1778 + PORT_ArenaRelease(arena, mark); 1.1779 + return NULL; 1.1780 +} 1.1781 + 1.1782 +CERTOCSPCertID* 1.1783 +CERT_CreateOCSPCertID(CERTCertificate *cert, PRTime time) 1.1784 +{ 1.1785 + PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1786 + CERTOCSPCertID *certID; 1.1787 + PORT_Assert(arena != NULL); 1.1788 + if (!arena) 1.1789 + return NULL; 1.1790 + 1.1791 + certID = ocsp_CreateCertID(arena, cert, time); 1.1792 + if (!certID) { 1.1793 + PORT_FreeArena(arena, PR_FALSE); 1.1794 + return NULL; 1.1795 + } 1.1796 + certID->poolp = arena; 1.1797 + return certID; 1.1798 +} 1.1799 + 1.1800 +static CERTOCSPCertID * 1.1801 +cert_DupOCSPCertID(const CERTOCSPCertID *src) 1.1802 +{ 1.1803 + CERTOCSPCertID *dest; 1.1804 + PLArenaPool *arena = NULL; 1.1805 + 1.1806 + if (!src) { 1.1807 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1808 + return NULL; 1.1809 + } 1.1810 + 1.1811 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1812 + if (!arena) 1.1813 + goto loser; 1.1814 + 1.1815 + dest = PORT_ArenaZNew(arena, CERTOCSPCertID); 1.1816 + if (!dest) 1.1817 + goto loser; 1.1818 + 1.1819 +#define DUPHELP(element) \ 1.1820 + if (src->element.data && \ 1.1821 + SECITEM_CopyItem(arena, &dest->element, &src->element) \ 1.1822 + != SECSuccess) { \ 1.1823 + goto loser; \ 1.1824 + } 1.1825 + 1.1826 + DUPHELP(hashAlgorithm.algorithm) 1.1827 + DUPHELP(hashAlgorithm.parameters) 1.1828 + DUPHELP(issuerNameHash) 1.1829 + DUPHELP(issuerKeyHash) 1.1830 + DUPHELP(serialNumber) 1.1831 + DUPHELP(issuerSHA1NameHash) 1.1832 + DUPHELP(issuerMD5NameHash) 1.1833 + DUPHELP(issuerMD2NameHash) 1.1834 + DUPHELP(issuerSHA1KeyHash) 1.1835 + DUPHELP(issuerMD5KeyHash) 1.1836 + DUPHELP(issuerMD2KeyHash) 1.1837 + 1.1838 + dest->poolp = arena; 1.1839 + return dest; 1.1840 + 1.1841 +loser: 1.1842 + if (arena) 1.1843 + PORT_FreeArena(arena, PR_FALSE); 1.1844 + PORT_SetError(PR_OUT_OF_MEMORY_ERROR); 1.1845 + return NULL; 1.1846 +} 1.1847 + 1.1848 +/* 1.1849 + * Callback to set Extensions in request object 1.1850 + */ 1.1851 +void SetSingleReqExts(void *object, CERTCertExtension **exts) 1.1852 +{ 1.1853 + ocspSingleRequest *singleRequest = 1.1854 + (ocspSingleRequest *)object; 1.1855 + 1.1856 + singleRequest->singleRequestExtensions = exts; 1.1857 +} 1.1858 + 1.1859 +/* 1.1860 + * Add the Service Locator extension to the singleRequestExtensions 1.1861 + * for the given singleRequest. 1.1862 + * 1.1863 + * All errors are internal or low-level problems (e.g. no memory). 1.1864 + */ 1.1865 +static SECStatus 1.1866 +ocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest, 1.1867 + CERTCertificate *cert) 1.1868 +{ 1.1869 + ocspServiceLocator *serviceLocator = NULL; 1.1870 + void *extensionHandle = NULL; 1.1871 + SECStatus rv = SECFailure; 1.1872 + 1.1873 + serviceLocator = PORT_ZNew(ocspServiceLocator); 1.1874 + if (serviceLocator == NULL) 1.1875 + goto loser; 1.1876 + 1.1877 + /* 1.1878 + * Normally it would be a bad idea to do a direct reference like 1.1879 + * this rather than allocate and copy the name *or* at least dup 1.1880 + * a reference of the cert. But all we need is to be able to read 1.1881 + * the issuer name during the encoding we are about to do, so a 1.1882 + * copy is just a waste of time. 1.1883 + */ 1.1884 + serviceLocator->issuer = &cert->issuer; 1.1885 + 1.1886 + rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS, 1.1887 + &serviceLocator->locator); 1.1888 + if (rv != SECSuccess) { 1.1889 + if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) 1.1890 + goto loser; 1.1891 + } 1.1892 + 1.1893 + /* prepare for following loser gotos */ 1.1894 + rv = SECFailure; 1.1895 + PORT_SetError(0); 1.1896 + 1.1897 + extensionHandle = cert_StartExtensions(singleRequest, 1.1898 + singleRequest->arena, SetSingleReqExts); 1.1899 + if (extensionHandle == NULL) 1.1900 + goto loser; 1.1901 + 1.1902 + rv = CERT_EncodeAndAddExtension(extensionHandle, 1.1903 + SEC_OID_PKIX_OCSP_SERVICE_LOCATOR, 1.1904 + serviceLocator, PR_FALSE, 1.1905 + ocsp_ServiceLocatorTemplate); 1.1906 + 1.1907 +loser: 1.1908 + if (extensionHandle != NULL) { 1.1909 + /* 1.1910 + * Either way we have to finish out the extension context (so it gets 1.1911 + * freed). But careful not to override any already-set bad status. 1.1912 + */ 1.1913 + SECStatus tmprv = CERT_FinishExtensions(extensionHandle); 1.1914 + if (rv == SECSuccess) 1.1915 + rv = tmprv; 1.1916 + } 1.1917 + 1.1918 + /* 1.1919 + * Finally, free the serviceLocator structure itself and we are done. 1.1920 + */ 1.1921 + if (serviceLocator != NULL) { 1.1922 + if (serviceLocator->locator.data != NULL) 1.1923 + SECITEM_FreeItem(&serviceLocator->locator, PR_FALSE); 1.1924 + PORT_Free(serviceLocator); 1.1925 + } 1.1926 + 1.1927 + return rv; 1.1928 +} 1.1929 + 1.1930 +/* 1.1931 + * Creates an array of ocspSingleRequest based on a list of certs. 1.1932 + * Note that the code which later compares the request list with the 1.1933 + * response expects this array to be in the exact same order as the 1.1934 + * certs are found in the list. It would be harder to change that 1.1935 + * order than preserve it, but since the requirement is not obvious, 1.1936 + * it deserves to be mentioned. 1.1937 + * 1.1938 + * Any problem causes a null return and error set: 1.1939 + * SEC_ERROR_UNKNOWN_ISSUER 1.1940 + * Other errors are low-level problems (no memory, bad database, etc.). 1.1941 + */ 1.1942 +static ocspSingleRequest ** 1.1943 +ocsp_CreateSingleRequestList(PLArenaPool *arena, CERTCertList *certList, 1.1944 + PRTime time, PRBool includeLocator) 1.1945 +{ 1.1946 + ocspSingleRequest **requestList = NULL; 1.1947 + CERTCertListNode *node = NULL; 1.1948 + int i, count; 1.1949 + void *mark = PORT_ArenaMark(arena); 1.1950 + 1.1951 + node = CERT_LIST_HEAD(certList); 1.1952 + for (count = 0; !CERT_LIST_END(node, certList); count++) { 1.1953 + node = CERT_LIST_NEXT(node); 1.1954 + } 1.1955 + 1.1956 + if (count == 0) 1.1957 + goto loser; 1.1958 + 1.1959 + requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, count + 1); 1.1960 + if (requestList == NULL) 1.1961 + goto loser; 1.1962 + 1.1963 + node = CERT_LIST_HEAD(certList); 1.1964 + for (i = 0; !CERT_LIST_END(node, certList); i++) { 1.1965 + requestList[i] = PORT_ArenaZNew(arena, ocspSingleRequest); 1.1966 + if (requestList[i] == NULL) 1.1967 + goto loser; 1.1968 + 1.1969 + OCSP_TRACE(("OCSP CERT_CreateOCSPRequest %s\n", node->cert->subjectName)); 1.1970 + requestList[i]->arena = arena; 1.1971 + requestList[i]->reqCert = ocsp_CreateCertID(arena, node->cert, time); 1.1972 + if (requestList[i]->reqCert == NULL) 1.1973 + goto loser; 1.1974 + 1.1975 + if (includeLocator == PR_TRUE) { 1.1976 + SECStatus rv; 1.1977 + 1.1978 + rv = ocsp_AddServiceLocatorExtension(requestList[i], node->cert); 1.1979 + if (rv != SECSuccess) 1.1980 + goto loser; 1.1981 + } 1.1982 + 1.1983 + node = CERT_LIST_NEXT(node); 1.1984 + } 1.1985 + 1.1986 + PORT_Assert(i == count); 1.1987 + 1.1988 + PORT_ArenaUnmark(arena, mark); 1.1989 + requestList[i] = NULL; 1.1990 + return requestList; 1.1991 + 1.1992 +loser: 1.1993 + PORT_ArenaRelease(arena, mark); 1.1994 + return NULL; 1.1995 +} 1.1996 + 1.1997 +static ocspSingleRequest ** 1.1998 +ocsp_CreateRequestFromCert(PLArenaPool *arena, 1.1999 + CERTOCSPCertID *certID, 1.2000 + CERTCertificate *singleCert, 1.2001 + PRTime time, 1.2002 + PRBool includeLocator) 1.2003 +{ 1.2004 + ocspSingleRequest **requestList = NULL; 1.2005 + void *mark = PORT_ArenaMark(arena); 1.2006 + PORT_Assert(certID != NULL && singleCert != NULL); 1.2007 + 1.2008 + /* meaning of value 2: one entry + one end marker */ 1.2009 + requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, 2); 1.2010 + if (requestList == NULL) 1.2011 + goto loser; 1.2012 + requestList[0] = PORT_ArenaZNew(arena, ocspSingleRequest); 1.2013 + if (requestList[0] == NULL) 1.2014 + goto loser; 1.2015 + requestList[0]->arena = arena; 1.2016 + /* certID will live longer than the request */ 1.2017 + requestList[0]->reqCert = certID; 1.2018 + 1.2019 + if (includeLocator == PR_TRUE) { 1.2020 + SECStatus rv; 1.2021 + rv = ocsp_AddServiceLocatorExtension(requestList[0], singleCert); 1.2022 + if (rv != SECSuccess) 1.2023 + goto loser; 1.2024 + } 1.2025 + 1.2026 + PORT_ArenaUnmark(arena, mark); 1.2027 + requestList[1] = NULL; 1.2028 + return requestList; 1.2029 + 1.2030 +loser: 1.2031 + PORT_ArenaRelease(arena, mark); 1.2032 + return NULL; 1.2033 +} 1.2034 + 1.2035 +static CERTOCSPRequest * 1.2036 +ocsp_prepareEmptyOCSPRequest(void) 1.2037 +{ 1.2038 + PLArenaPool *arena = NULL; 1.2039 + CERTOCSPRequest *request = NULL; 1.2040 + ocspTBSRequest *tbsRequest = NULL; 1.2041 + 1.2042 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2043 + if (arena == NULL) { 1.2044 + goto loser; 1.2045 + } 1.2046 + request = PORT_ArenaZNew(arena, CERTOCSPRequest); 1.2047 + if (request == NULL) { 1.2048 + goto loser; 1.2049 + } 1.2050 + request->arena = arena; 1.2051 + 1.2052 + tbsRequest = PORT_ArenaZNew(arena, ocspTBSRequest); 1.2053 + if (tbsRequest == NULL) { 1.2054 + goto loser; 1.2055 + } 1.2056 + request->tbsRequest = tbsRequest; 1.2057 + /* version 1 is the default, so we need not fill in a version number */ 1.2058 + return request; 1.2059 + 1.2060 +loser: 1.2061 + if (arena != NULL) { 1.2062 + PORT_FreeArena(arena, PR_FALSE); 1.2063 + } 1.2064 + return NULL; 1.2065 +} 1.2066 + 1.2067 +CERTOCSPRequest * 1.2068 +cert_CreateSingleCertOCSPRequest(CERTOCSPCertID *certID, 1.2069 + CERTCertificate *singleCert, 1.2070 + PRTime time, 1.2071 + PRBool addServiceLocator, 1.2072 + CERTCertificate *signerCert) 1.2073 +{ 1.2074 + CERTOCSPRequest *request; 1.2075 + OCSP_TRACE(("OCSP cert_CreateSingleCertOCSPRequest %s\n", singleCert->subjectName)); 1.2076 + 1.2077 + /* XXX Support for signerCert may be implemented later, 1.2078 + * see also the comment in CERT_CreateOCSPRequest. 1.2079 + */ 1.2080 + if (signerCert != NULL) { 1.2081 + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1.2082 + return NULL; 1.2083 + } 1.2084 + 1.2085 + request = ocsp_prepareEmptyOCSPRequest(); 1.2086 + if (!request) 1.2087 + return NULL; 1.2088 + /* 1.2089 + * Version 1 is the default, so we need not fill in a version number. 1.2090 + * Now create the list of single requests, one for each cert. 1.2091 + */ 1.2092 + request->tbsRequest->requestList = 1.2093 + ocsp_CreateRequestFromCert(request->arena, 1.2094 + certID, 1.2095 + singleCert, 1.2096 + time, 1.2097 + addServiceLocator); 1.2098 + if (request->tbsRequest->requestList == NULL) { 1.2099 + PORT_FreeArena(request->arena, PR_FALSE); 1.2100 + return NULL; 1.2101 + } 1.2102 + return request; 1.2103 +} 1.2104 + 1.2105 +/* 1.2106 + * FUNCTION: CERT_CreateOCSPRequest 1.2107 + * Creates a CERTOCSPRequest, requesting the status of the certs in 1.2108 + * the given list. 1.2109 + * INPUTS: 1.2110 + * CERTCertList *certList 1.2111 + * A list of certs for which status will be requested. 1.2112 + * Note that all of these certificates should have the same issuer, 1.2113 + * or it's expected the response will be signed by a trusted responder. 1.2114 + * If the certs need to be broken up into multiple requests, that 1.2115 + * must be handled by the caller (and thus by having multiple calls 1.2116 + * to this routine), who knows about where the request(s) are being 1.2117 + * sent and whether there are any trusted responders in place. 1.2118 + * PRTime time 1.2119 + * Indicates the time for which the certificate status is to be 1.2120 + * determined -- this may be used in the search for the cert's issuer 1.2121 + * but has no effect on the request itself. 1.2122 + * PRBool addServiceLocator 1.2123 + * If true, the Service Locator extension should be added to the 1.2124 + * single request(s) for each cert. 1.2125 + * CERTCertificate *signerCert 1.2126 + * If non-NULL, means sign the request using this cert. Otherwise, 1.2127 + * do not sign. 1.2128 + * XXX note that request signing is not yet supported; see comment in code 1.2129 + * RETURN: 1.2130 + * A pointer to a CERTOCSPRequest structure containing an OCSP request 1.2131 + * for the cert list. On error, null is returned, with an error set 1.2132 + * indicating the reason. This is likely SEC_ERROR_UNKNOWN_ISSUER. 1.2133 + * (The issuer is needed to create a request for the certificate.) 1.2134 + * Other errors are low-level problems (no memory, bad database, etc.). 1.2135 + */ 1.2136 +CERTOCSPRequest * 1.2137 +CERT_CreateOCSPRequest(CERTCertList *certList, PRTime time, 1.2138 + PRBool addServiceLocator, 1.2139 + CERTCertificate *signerCert) 1.2140 +{ 1.2141 + CERTOCSPRequest *request = NULL; 1.2142 + 1.2143 + if (!certList) { 1.2144 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.2145 + return NULL; 1.2146 + } 1.2147 + /* 1.2148 + * XXX When we are prepared to put signing of requests back in, 1.2149 + * we will need to allocate a signature 1.2150 + * structure for the request, fill in the "derCerts" field in it, 1.2151 + * save the signerCert there, as well as fill in the "requestorName" 1.2152 + * field of the tbsRequest. 1.2153 + */ 1.2154 + if (signerCert != NULL) { 1.2155 + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1.2156 + return NULL; 1.2157 + } 1.2158 + request = ocsp_prepareEmptyOCSPRequest(); 1.2159 + if (!request) 1.2160 + return NULL; 1.2161 + /* 1.2162 + * Now create the list of single requests, one for each cert. 1.2163 + */ 1.2164 + request->tbsRequest->requestList = 1.2165 + ocsp_CreateSingleRequestList(request->arena, 1.2166 + certList, 1.2167 + time, 1.2168 + addServiceLocator); 1.2169 + if (request->tbsRequest->requestList == NULL) { 1.2170 + PORT_FreeArena(request->arena, PR_FALSE); 1.2171 + return NULL; 1.2172 + } 1.2173 + return request; 1.2174 +} 1.2175 + 1.2176 +/* 1.2177 + * FUNCTION: CERT_AddOCSPAcceptableResponses 1.2178 + * Add the AcceptableResponses extension to an OCSP Request. 1.2179 + * INPUTS: 1.2180 + * CERTOCSPRequest *request 1.2181 + * The request to which the extension should be added. 1.2182 + * ... 1.2183 + * A list (of one or more) of SECOidTag -- each of the response types 1.2184 + * to be added. The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE. 1.2185 + * (This marks the end of the list, and it must be specified because a 1.2186 + * client conforming to the OCSP standard is required to handle the basic 1.2187 + * response type.) The OIDs are not checked in any way. 1.2188 + * RETURN: 1.2189 + * SECSuccess if the extension is added; SECFailure if anything goes wrong. 1.2190 + * All errors are internal or low-level problems (e.g. no memory). 1.2191 + */ 1.2192 + 1.2193 +void SetRequestExts(void *object, CERTCertExtension **exts) 1.2194 +{ 1.2195 + CERTOCSPRequest *request = (CERTOCSPRequest *)object; 1.2196 + 1.2197 + request->tbsRequest->requestExtensions = exts; 1.2198 +} 1.2199 + 1.2200 +SECStatus 1.2201 +CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request, 1.2202 + SECOidTag responseType0, ...) 1.2203 +{ 1.2204 + void *extHandle; 1.2205 + va_list ap; 1.2206 + int i, count; 1.2207 + SECOidTag responseType; 1.2208 + SECOidData *responseOid; 1.2209 + SECItem **acceptableResponses = NULL; 1.2210 + SECStatus rv = SECFailure; 1.2211 + 1.2212 + extHandle = request->tbsRequest->extensionHandle; 1.2213 + if (extHandle == NULL) { 1.2214 + extHandle = cert_StartExtensions(request, request->arena, SetRequestExts); 1.2215 + if (extHandle == NULL) 1.2216 + goto loser; 1.2217 + } 1.2218 + 1.2219 + /* Count number of OIDS going into the extension value. */ 1.2220 + count = 1; 1.2221 + if (responseType0 != SEC_OID_PKIX_OCSP_BASIC_RESPONSE) { 1.2222 + va_start(ap, responseType0); 1.2223 + do { 1.2224 + count++; 1.2225 + responseType = va_arg(ap, SECOidTag); 1.2226 + } while (responseType != SEC_OID_PKIX_OCSP_BASIC_RESPONSE); 1.2227 + va_end(ap); 1.2228 + } 1.2229 + 1.2230 + acceptableResponses = PORT_NewArray(SECItem *, count + 1); 1.2231 + if (acceptableResponses == NULL) 1.2232 + goto loser; 1.2233 + 1.2234 + i = 0; 1.2235 + responseOid = SECOID_FindOIDByTag(responseType0); 1.2236 + acceptableResponses[i++] = &(responseOid->oid); 1.2237 + if (count > 1) { 1.2238 + va_start(ap, responseType0); 1.2239 + for ( ; i < count; i++) { 1.2240 + responseType = va_arg(ap, SECOidTag); 1.2241 + responseOid = SECOID_FindOIDByTag(responseType); 1.2242 + acceptableResponses[i] = &(responseOid->oid); 1.2243 + } 1.2244 + va_end(ap); 1.2245 + } 1.2246 + acceptableResponses[i] = NULL; 1.2247 + 1.2248 + rv = CERT_EncodeAndAddExtension(extHandle, SEC_OID_PKIX_OCSP_RESPONSE, 1.2249 + &acceptableResponses, PR_FALSE, 1.2250 + SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate)); 1.2251 + if (rv != SECSuccess) 1.2252 + goto loser; 1.2253 + 1.2254 + PORT_Free(acceptableResponses); 1.2255 + if (request->tbsRequest->extensionHandle == NULL) 1.2256 + request->tbsRequest->extensionHandle = extHandle; 1.2257 + return SECSuccess; 1.2258 + 1.2259 +loser: 1.2260 + if (acceptableResponses != NULL) 1.2261 + PORT_Free(acceptableResponses); 1.2262 + if (extHandle != NULL) 1.2263 + (void) CERT_FinishExtensions(extHandle); 1.2264 + return rv; 1.2265 +} 1.2266 + 1.2267 + 1.2268 +/* 1.2269 + * FUNCTION: CERT_DestroyOCSPRequest 1.2270 + * Frees an OCSP Request structure. 1.2271 + * INPUTS: 1.2272 + * CERTOCSPRequest *request 1.2273 + * Pointer to CERTOCSPRequest to be freed. 1.2274 + * RETURN: 1.2275 + * No return value; no errors. 1.2276 + */ 1.2277 +void 1.2278 +CERT_DestroyOCSPRequest(CERTOCSPRequest *request) 1.2279 +{ 1.2280 + if (request == NULL) 1.2281 + return; 1.2282 + 1.2283 + if (request->tbsRequest != NULL) { 1.2284 + if (request->tbsRequest->requestorName != NULL) 1.2285 + CERT_DestroyGeneralNameList(request->tbsRequest->requestorName); 1.2286 + if (request->tbsRequest->extensionHandle != NULL) 1.2287 + (void) CERT_FinishExtensions(request->tbsRequest->extensionHandle); 1.2288 + } 1.2289 + 1.2290 + if (request->optionalSignature != NULL) { 1.2291 + if (request->optionalSignature->cert != NULL) 1.2292 + CERT_DestroyCertificate(request->optionalSignature->cert); 1.2293 + 1.2294 + /* 1.2295 + * XXX Need to free derCerts? Or do they come out of arena? 1.2296 + * (Currently we never fill in derCerts, which is why the 1.2297 + * answer is not obvious. Once we do, add any necessary code 1.2298 + * here and remove this comment.) 1.2299 + */ 1.2300 + } 1.2301 + 1.2302 + /* 1.2303 + * We should actually never have a request without an arena, 1.2304 + * but check just in case. (If there isn't one, there is not 1.2305 + * much we can do about it...) 1.2306 + */ 1.2307 + PORT_Assert(request->arena != NULL); 1.2308 + if (request->arena != NULL) 1.2309 + PORT_FreeArena(request->arena, PR_FALSE); 1.2310 +} 1.2311 + 1.2312 + 1.2313 +/* 1.2314 + * RESPONSE SUPPORT FUNCTIONS (encode/create/decode/destroy): 1.2315 + */ 1.2316 + 1.2317 +/* 1.2318 + * Helper function for encoding or decoding a ResponderID -- based on the 1.2319 + * given type, return the associated template for that choice. 1.2320 + */ 1.2321 +static const SEC_ASN1Template * 1.2322 +ocsp_ResponderIDTemplateByType(CERTOCSPResponderIDType responderIDType) 1.2323 +{ 1.2324 + const SEC_ASN1Template *responderIDTemplate; 1.2325 + 1.2326 + switch (responderIDType) { 1.2327 + case ocspResponderID_byName: 1.2328 + responderIDTemplate = ocsp_ResponderIDByNameTemplate; 1.2329 + break; 1.2330 + case ocspResponderID_byKey: 1.2331 + responderIDTemplate = ocsp_ResponderIDByKeyTemplate; 1.2332 + break; 1.2333 + case ocspResponderID_other: 1.2334 + default: 1.2335 + PORT_Assert(responderIDType == ocspResponderID_other); 1.2336 + responderIDTemplate = ocsp_ResponderIDOtherTemplate; 1.2337 + break; 1.2338 + } 1.2339 + 1.2340 + return responderIDTemplate; 1.2341 +} 1.2342 + 1.2343 +/* 1.2344 + * Helper function for encoding or decoding a CertStatus -- based on the 1.2345 + * given type, return the associated template for that choice. 1.2346 + */ 1.2347 +static const SEC_ASN1Template * 1.2348 +ocsp_CertStatusTemplateByType(ocspCertStatusType certStatusType) 1.2349 +{ 1.2350 + const SEC_ASN1Template *certStatusTemplate; 1.2351 + 1.2352 + switch (certStatusType) { 1.2353 + case ocspCertStatus_good: 1.2354 + certStatusTemplate = ocsp_CertStatusGoodTemplate; 1.2355 + break; 1.2356 + case ocspCertStatus_revoked: 1.2357 + certStatusTemplate = ocsp_CertStatusRevokedTemplate; 1.2358 + break; 1.2359 + case ocspCertStatus_unknown: 1.2360 + certStatusTemplate = ocsp_CertStatusUnknownTemplate; 1.2361 + break; 1.2362 + case ocspCertStatus_other: 1.2363 + default: 1.2364 + PORT_Assert(certStatusType == ocspCertStatus_other); 1.2365 + certStatusTemplate = ocsp_CertStatusOtherTemplate; 1.2366 + break; 1.2367 + } 1.2368 + 1.2369 + return certStatusTemplate; 1.2370 +} 1.2371 + 1.2372 +/* 1.2373 + * Helper function for decoding a certStatus -- turn the actual DER tag 1.2374 + * into our local translation. 1.2375 + */ 1.2376 +static ocspCertStatusType 1.2377 +ocsp_CertStatusTypeByTag(int derTag) 1.2378 +{ 1.2379 + ocspCertStatusType certStatusType; 1.2380 + 1.2381 + switch (derTag) { 1.2382 + case 0: 1.2383 + certStatusType = ocspCertStatus_good; 1.2384 + break; 1.2385 + case 1: 1.2386 + certStatusType = ocspCertStatus_revoked; 1.2387 + break; 1.2388 + case 2: 1.2389 + certStatusType = ocspCertStatus_unknown; 1.2390 + break; 1.2391 + default: 1.2392 + certStatusType = ocspCertStatus_other; 1.2393 + break; 1.2394 + } 1.2395 + 1.2396 + return certStatusType; 1.2397 +} 1.2398 + 1.2399 +/* 1.2400 + * Helper function for decoding SingleResponses -- they each contain 1.2401 + * a status which is encoded as CHOICE, which needs to be decoded "by hand". 1.2402 + * 1.2403 + * Note -- on error, this routine does not release the memory it may 1.2404 + * have allocated; it expects its caller to do that. 1.2405 + */ 1.2406 +static SECStatus 1.2407 +ocsp_FinishDecodingSingleResponses(PLArenaPool *reqArena, 1.2408 + CERTOCSPSingleResponse **responses) 1.2409 +{ 1.2410 + ocspCertStatus *certStatus; 1.2411 + ocspCertStatusType certStatusType; 1.2412 + const SEC_ASN1Template *certStatusTemplate; 1.2413 + int derTag; 1.2414 + int i; 1.2415 + SECStatus rv = SECFailure; 1.2416 + 1.2417 + if (!reqArena) { 1.2418 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.2419 + return SECFailure; 1.2420 + } 1.2421 + 1.2422 + if (responses == NULL) /* nothing to do */ 1.2423 + return SECSuccess; 1.2424 + 1.2425 + for (i = 0; responses[i] != NULL; i++) { 1.2426 + SECItem* newStatus; 1.2427 + /* 1.2428 + * The following assert points out internal errors (problems in 1.2429 + * the template definitions or in the ASN.1 decoder itself, etc.). 1.2430 + */ 1.2431 + PORT_Assert(responses[i]->derCertStatus.data != NULL); 1.2432 + 1.2433 + derTag = responses[i]->derCertStatus.data[0] & SEC_ASN1_TAGNUM_MASK; 1.2434 + certStatusType = ocsp_CertStatusTypeByTag(derTag); 1.2435 + certStatusTemplate = ocsp_CertStatusTemplateByType(certStatusType); 1.2436 + 1.2437 + certStatus = PORT_ArenaZAlloc(reqArena, sizeof(ocspCertStatus)); 1.2438 + if (certStatus == NULL) { 1.2439 + goto loser; 1.2440 + } 1.2441 + newStatus = SECITEM_ArenaDupItem(reqArena, &responses[i]->derCertStatus); 1.2442 + if (!newStatus) { 1.2443 + goto loser; 1.2444 + } 1.2445 + rv = SEC_QuickDERDecodeItem(reqArena, certStatus, certStatusTemplate, 1.2446 + newStatus); 1.2447 + if (rv != SECSuccess) { 1.2448 + if (PORT_GetError() == SEC_ERROR_BAD_DER) 1.2449 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.2450 + goto loser; 1.2451 + } 1.2452 + 1.2453 + certStatus->certStatusType = certStatusType; 1.2454 + responses[i]->certStatus = certStatus; 1.2455 + } 1.2456 + 1.2457 + return SECSuccess; 1.2458 + 1.2459 +loser: 1.2460 + return rv; 1.2461 +} 1.2462 + 1.2463 +/* 1.2464 + * Helper function for decoding a responderID -- turn the actual DER tag 1.2465 + * into our local translation. 1.2466 + */ 1.2467 +static CERTOCSPResponderIDType 1.2468 +ocsp_ResponderIDTypeByTag(int derTag) 1.2469 +{ 1.2470 + CERTOCSPResponderIDType responderIDType; 1.2471 + 1.2472 + switch (derTag) { 1.2473 + case 1: 1.2474 + responderIDType = ocspResponderID_byName; 1.2475 + break; 1.2476 + case 2: 1.2477 + responderIDType = ocspResponderID_byKey; 1.2478 + break; 1.2479 + default: 1.2480 + responderIDType = ocspResponderID_other; 1.2481 + break; 1.2482 + } 1.2483 + 1.2484 + return responderIDType; 1.2485 +} 1.2486 + 1.2487 +/* 1.2488 + * Decode "src" as a BasicOCSPResponse, returning the result. 1.2489 + */ 1.2490 +static ocspBasicOCSPResponse * 1.2491 +ocsp_DecodeBasicOCSPResponse(PLArenaPool *arena, SECItem *src) 1.2492 +{ 1.2493 + void *mark; 1.2494 + ocspBasicOCSPResponse *basicResponse; 1.2495 + ocspResponseData *responseData; 1.2496 + ocspResponderID *responderID; 1.2497 + CERTOCSPResponderIDType responderIDType; 1.2498 + const SEC_ASN1Template *responderIDTemplate; 1.2499 + int derTag; 1.2500 + SECStatus rv; 1.2501 + SECItem newsrc; 1.2502 + 1.2503 + mark = PORT_ArenaMark(arena); 1.2504 + 1.2505 + basicResponse = PORT_ArenaZAlloc(arena, sizeof(ocspBasicOCSPResponse)); 1.2506 + if (basicResponse == NULL) { 1.2507 + goto loser; 1.2508 + } 1.2509 + 1.2510 + /* copy the DER into the arena, since Quick DER returns data that points 1.2511 + into the DER input, which may get freed by the caller */ 1.2512 + rv = SECITEM_CopyItem(arena, &newsrc, src); 1.2513 + if ( rv != SECSuccess ) { 1.2514 + goto loser; 1.2515 + } 1.2516 + 1.2517 + rv = SEC_QuickDERDecodeItem(arena, basicResponse, 1.2518 + ocsp_BasicOCSPResponseTemplate, &newsrc); 1.2519 + if (rv != SECSuccess) { 1.2520 + if (PORT_GetError() == SEC_ERROR_BAD_DER) 1.2521 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.2522 + goto loser; 1.2523 + } 1.2524 + 1.2525 + responseData = basicResponse->tbsResponseData; 1.2526 + 1.2527 + /* 1.2528 + * The following asserts point out internal errors (problems in 1.2529 + * the template definitions or in the ASN.1 decoder itself, etc.). 1.2530 + */ 1.2531 + PORT_Assert(responseData != NULL); 1.2532 + PORT_Assert(responseData->derResponderID.data != NULL); 1.2533 + 1.2534 + /* 1.2535 + * XXX Because responderID is a CHOICE, which is not currently handled 1.2536 + * by our ASN.1 decoder, we have to decode it "by hand". 1.2537 + */ 1.2538 + derTag = responseData->derResponderID.data[0] & SEC_ASN1_TAGNUM_MASK; 1.2539 + responderIDType = ocsp_ResponderIDTypeByTag(derTag); 1.2540 + responderIDTemplate = ocsp_ResponderIDTemplateByType(responderIDType); 1.2541 + 1.2542 + responderID = PORT_ArenaZAlloc(arena, sizeof(ocspResponderID)); 1.2543 + if (responderID == NULL) { 1.2544 + goto loser; 1.2545 + } 1.2546 + 1.2547 + rv = SEC_QuickDERDecodeItem(arena, responderID, responderIDTemplate, 1.2548 + &responseData->derResponderID); 1.2549 + if (rv != SECSuccess) { 1.2550 + if (PORT_GetError() == SEC_ERROR_BAD_DER) 1.2551 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.2552 + goto loser; 1.2553 + } 1.2554 + 1.2555 + responderID->responderIDType = responderIDType; 1.2556 + responseData->responderID = responderID; 1.2557 + 1.2558 + /* 1.2559 + * XXX Each SingleResponse also contains a CHOICE, which has to be 1.2560 + * fixed up by hand. 1.2561 + */ 1.2562 + rv = ocsp_FinishDecodingSingleResponses(arena, responseData->responses); 1.2563 + if (rv != SECSuccess) { 1.2564 + goto loser; 1.2565 + } 1.2566 + 1.2567 + PORT_ArenaUnmark(arena, mark); 1.2568 + return basicResponse; 1.2569 + 1.2570 +loser: 1.2571 + PORT_ArenaRelease(arena, mark); 1.2572 + return NULL; 1.2573 +} 1.2574 + 1.2575 + 1.2576 +/* 1.2577 + * Decode the responseBytes based on the responseType found in "rbytes", 1.2578 + * leaving the resulting translated/decoded information in there as well. 1.2579 + */ 1.2580 +static SECStatus 1.2581 +ocsp_DecodeResponseBytes(PLArenaPool *arena, ocspResponseBytes *rbytes) 1.2582 +{ 1.2583 + if (rbytes == NULL) { 1.2584 + PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE); 1.2585 + return SECFailure; 1.2586 + } 1.2587 + 1.2588 + rbytes->responseTypeTag = SECOID_FindOIDTag(&rbytes->responseType); 1.2589 + switch (rbytes->responseTypeTag) { 1.2590 + case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: 1.2591 + { 1.2592 + ocspBasicOCSPResponse *basicResponse; 1.2593 + 1.2594 + basicResponse = ocsp_DecodeBasicOCSPResponse(arena, 1.2595 + &rbytes->response); 1.2596 + if (basicResponse == NULL) 1.2597 + return SECFailure; 1.2598 + 1.2599 + rbytes->decodedResponse.basic = basicResponse; 1.2600 + } 1.2601 + break; 1.2602 + 1.2603 + /* 1.2604 + * Add new/future response types here. 1.2605 + */ 1.2606 + 1.2607 + default: 1.2608 + PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE); 1.2609 + return SECFailure; 1.2610 + } 1.2611 + 1.2612 + return SECSuccess; 1.2613 +} 1.2614 + 1.2615 + 1.2616 +/* 1.2617 + * FUNCTION: CERT_DecodeOCSPResponse 1.2618 + * Decode a DER encoded OCSP Response. 1.2619 + * INPUTS: 1.2620 + * SECItem *src 1.2621 + * Pointer to a SECItem holding DER encoded OCSP Response. 1.2622 + * RETURN: 1.2623 + * Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response); 1.2624 + * the caller is responsible for destroying it. Or NULL if error (either 1.2625 + * response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE), 1.2626 + * it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE), 1.2627 + * or a low-level or internal error occurred). 1.2628 + */ 1.2629 +CERTOCSPResponse * 1.2630 +CERT_DecodeOCSPResponse(const SECItem *src) 1.2631 +{ 1.2632 + PLArenaPool *arena = NULL; 1.2633 + CERTOCSPResponse *response = NULL; 1.2634 + SECStatus rv = SECFailure; 1.2635 + ocspResponseStatus sv; 1.2636 + SECItem newSrc; 1.2637 + 1.2638 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2639 + if (arena == NULL) { 1.2640 + goto loser; 1.2641 + } 1.2642 + response = (CERTOCSPResponse *) PORT_ArenaZAlloc(arena, 1.2643 + sizeof(CERTOCSPResponse)); 1.2644 + if (response == NULL) { 1.2645 + goto loser; 1.2646 + } 1.2647 + response->arena = arena; 1.2648 + 1.2649 + /* copy the DER into the arena, since Quick DER returns data that points 1.2650 + into the DER input, which may get freed by the caller */ 1.2651 + rv = SECITEM_CopyItem(arena, &newSrc, src); 1.2652 + if ( rv != SECSuccess ) { 1.2653 + goto loser; 1.2654 + } 1.2655 + 1.2656 + rv = SEC_QuickDERDecodeItem(arena, response, ocsp_OCSPResponseTemplate, &newSrc); 1.2657 + if (rv != SECSuccess) { 1.2658 + if (PORT_GetError() == SEC_ERROR_BAD_DER) 1.2659 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.2660 + goto loser; 1.2661 + } 1.2662 + 1.2663 + sv = (ocspResponseStatus) DER_GetInteger(&response->responseStatus); 1.2664 + response->statusValue = sv; 1.2665 + if (sv != ocspResponse_successful) { 1.2666 + /* 1.2667 + * If the response status is anything but successful, then we 1.2668 + * are all done with decoding; the status is all there is. 1.2669 + */ 1.2670 + return response; 1.2671 + } 1.2672 + 1.2673 + /* 1.2674 + * A successful response contains much more information, still encoded. 1.2675 + * Now we need to decode that. 1.2676 + */ 1.2677 + rv = ocsp_DecodeResponseBytes(arena, response->responseBytes); 1.2678 + if (rv != SECSuccess) { 1.2679 + goto loser; 1.2680 + } 1.2681 + 1.2682 + return response; 1.2683 + 1.2684 +loser: 1.2685 + if (arena != NULL) { 1.2686 + PORT_FreeArena(arena, PR_FALSE); 1.2687 + } 1.2688 + return NULL; 1.2689 +} 1.2690 + 1.2691 +/* 1.2692 + * The way an OCSPResponse is defined, there are many levels to descend 1.2693 + * before getting to the actual response information. And along the way 1.2694 + * we need to check that the response *type* is recognizable, which for 1.2695 + * now means that it is a BasicOCSPResponse, because that is the only 1.2696 + * type currently defined. Rather than force all routines to perform 1.2697 + * a bunch of sanity checking every time they want to work on a response, 1.2698 + * this function isolates that and gives back the interesting part. 1.2699 + * Note that no copying is done, this just returns a pointer into the 1.2700 + * substructure of the response which is passed in. 1.2701 + * 1.2702 + * XXX This routine only works when a valid response structure is passed 1.2703 + * into it; this is checked with many assertions. Assuming the response 1.2704 + * was creating by decoding, it wouldn't make it this far without being 1.2705 + * okay. That is a sufficient assumption since the entire OCSP interface 1.2706 + * is only used internally. When this interface is officially exported, 1.2707 + * each assertion below will need to be followed-up with setting an error 1.2708 + * and returning (null). 1.2709 + * 1.2710 + * FUNCTION: ocsp_GetResponseData 1.2711 + * Returns ocspResponseData structure and a pointer to tbs response 1.2712 + * data DER from a valid ocsp response. 1.2713 + * INPUTS: 1.2714 + * CERTOCSPResponse *response 1.2715 + * structure of a valid ocsp response 1.2716 + * RETURN: 1.2717 + * Returns a pointer to ocspResponseData structure: decoded OCSP response 1.2718 + * data, and a pointer(tbsResponseDataDER) to its undecoded data DER. 1.2719 + */ 1.2720 +ocspResponseData * 1.2721 +ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER) 1.2722 +{ 1.2723 + ocspBasicOCSPResponse *basic; 1.2724 + ocspResponseData *responseData; 1.2725 + 1.2726 + PORT_Assert(response != NULL); 1.2727 + 1.2728 + PORT_Assert(response->responseBytes != NULL); 1.2729 + 1.2730 + PORT_Assert(response->responseBytes->responseTypeTag 1.2731 + == SEC_OID_PKIX_OCSP_BASIC_RESPONSE); 1.2732 + 1.2733 + basic = response->responseBytes->decodedResponse.basic; 1.2734 + PORT_Assert(basic != NULL); 1.2735 + 1.2736 + responseData = basic->tbsResponseData; 1.2737 + PORT_Assert(responseData != NULL); 1.2738 + 1.2739 + if (tbsResponseDataDER) { 1.2740 + *tbsResponseDataDER = &basic->tbsResponseDataDER; 1.2741 + 1.2742 + PORT_Assert((*tbsResponseDataDER)->data != NULL); 1.2743 + PORT_Assert((*tbsResponseDataDER)->len != 0); 1.2744 + } 1.2745 + 1.2746 + return responseData; 1.2747 +} 1.2748 + 1.2749 +/* 1.2750 + * Much like the routine above, except it returns the response signature. 1.2751 + * Again, no copy is done. 1.2752 + */ 1.2753 +ocspSignature * 1.2754 +ocsp_GetResponseSignature(CERTOCSPResponse *response) 1.2755 +{ 1.2756 + ocspBasicOCSPResponse *basic; 1.2757 + 1.2758 + PORT_Assert(response != NULL); 1.2759 + if (NULL == response->responseBytes) { 1.2760 + return NULL; 1.2761 + } 1.2762 + if (response->responseBytes->responseTypeTag 1.2763 + != SEC_OID_PKIX_OCSP_BASIC_RESPONSE) { 1.2764 + return NULL; 1.2765 + } 1.2766 + basic = response->responseBytes->decodedResponse.basic; 1.2767 + PORT_Assert(basic != NULL); 1.2768 + 1.2769 + return &(basic->responseSignature); 1.2770 +} 1.2771 + 1.2772 + 1.2773 +/* 1.2774 + * FUNCTION: CERT_DestroyOCSPResponse 1.2775 + * Frees an OCSP Response structure. 1.2776 + * INPUTS: 1.2777 + * CERTOCSPResponse *request 1.2778 + * Pointer to CERTOCSPResponse to be freed. 1.2779 + * RETURN: 1.2780 + * No return value; no errors. 1.2781 + */ 1.2782 +void 1.2783 +CERT_DestroyOCSPResponse(CERTOCSPResponse *response) 1.2784 +{ 1.2785 + if (response != NULL) { 1.2786 + ocspSignature *signature = ocsp_GetResponseSignature(response); 1.2787 + if (signature && signature->cert != NULL) 1.2788 + CERT_DestroyCertificate(signature->cert); 1.2789 + 1.2790 + /* 1.2791 + * We should actually never have a response without an arena, 1.2792 + * but check just in case. (If there isn't one, there is not 1.2793 + * much we can do about it...) 1.2794 + */ 1.2795 + PORT_Assert(response->arena != NULL); 1.2796 + if (response->arena != NULL) { 1.2797 + PORT_FreeArena(response->arena, PR_FALSE); 1.2798 + } 1.2799 + } 1.2800 +} 1.2801 + 1.2802 + 1.2803 +/* 1.2804 + * OVERALL OCSP CLIENT SUPPORT (make and send a request, verify a response): 1.2805 + */ 1.2806 + 1.2807 + 1.2808 +/* 1.2809 + * Pick apart a URL, saving the important things in the passed-in pointers. 1.2810 + * 1.2811 + * We expect to find "http://<hostname>[:<port>]/[path]", though we will 1.2812 + * tolerate that final slash character missing, as well as beginning and 1.2813 + * trailing whitespace, and any-case-characters for "http". All of that 1.2814 + * tolerance is what complicates this routine. What we want is just to 1.2815 + * pick out the hostname, the port, and the path. 1.2816 + * 1.2817 + * On a successful return, the caller will need to free the output pieces 1.2818 + * of hostname and path, which are copies of the values found in the url. 1.2819 + */ 1.2820 +static SECStatus 1.2821 +ocsp_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath) 1.2822 +{ 1.2823 + unsigned short port = 80; /* default, in case not in url */ 1.2824 + char *hostname = NULL; 1.2825 + char *path = NULL; 1.2826 + const char *save; 1.2827 + char c; 1.2828 + int len; 1.2829 + 1.2830 + if (url == NULL) 1.2831 + goto loser; 1.2832 + 1.2833 + /* 1.2834 + * Skip beginning whitespace. 1.2835 + */ 1.2836 + c = *url; 1.2837 + while ((c == ' ' || c == '\t') && c != '\0') { 1.2838 + url++; 1.2839 + c = *url; 1.2840 + } 1.2841 + if (c == '\0') 1.2842 + goto loser; 1.2843 + 1.2844 + /* 1.2845 + * Confirm, then skip, protocol. (Since we only know how to do http, 1.2846 + * that is all we will accept). 1.2847 + */ 1.2848 + if (PORT_Strncasecmp(url, "http://", 7) != 0) 1.2849 + goto loser; 1.2850 + url += 7; 1.2851 + 1.2852 + /* 1.2853 + * Whatever comes next is the hostname (or host IP address). We just 1.2854 + * save it aside and then search for its end so we can determine its 1.2855 + * length and copy it. 1.2856 + * 1.2857 + * XXX Note that because we treat a ':' as a terminator character 1.2858 + * (and below, we expect that to mean there is a port specification 1.2859 + * immediately following), we will not handle IPv6 addresses. That is 1.2860 + * apparently an acceptable limitation, for the time being. Some day, 1.2861 + * when there is a clear way to specify a URL with an IPv6 address that 1.2862 + * can be parsed unambiguously, this code should be made to do that. 1.2863 + */ 1.2864 + save = url; 1.2865 + c = *url; 1.2866 + while (c != '/' && c != ':' && c != '\0' && c != ' ' && c != '\t') { 1.2867 + url++; 1.2868 + c = *url; 1.2869 + } 1.2870 + len = url - save; 1.2871 + hostname = PORT_Alloc(len + 1); 1.2872 + if (hostname == NULL) 1.2873 + goto loser; 1.2874 + PORT_Memcpy(hostname, save, len); 1.2875 + hostname[len] = '\0'; 1.2876 + 1.2877 + /* 1.2878 + * Now we figure out if there was a port specified or not. 1.2879 + * If so, we need to parse it (as a number) and skip it. 1.2880 + */ 1.2881 + if (c == ':') { 1.2882 + url++; 1.2883 + port = (unsigned short) PORT_Atoi(url); 1.2884 + c = *url; 1.2885 + while (c != '/' && c != '\0' && c != ' ' && c != '\t') { 1.2886 + if (c < '0' || c > '9') 1.2887 + goto loser; 1.2888 + url++; 1.2889 + c = *url; 1.2890 + } 1.2891 + } 1.2892 + 1.2893 + /* 1.2894 + * Last thing to find is a path. There *should* be a slash, 1.2895 + * if nothing else -- but if there is not we provide one. 1.2896 + */ 1.2897 + if (c == '/') { 1.2898 + save = url; 1.2899 + while (c != '\0' && c != ' ' && c != '\t') { 1.2900 + url++; 1.2901 + c = *url; 1.2902 + } 1.2903 + len = url - save; 1.2904 + path = PORT_Alloc(len + 1); 1.2905 + if (path == NULL) 1.2906 + goto loser; 1.2907 + PORT_Memcpy(path, save, len); 1.2908 + path[len] = '\0'; 1.2909 + } else { 1.2910 + path = PORT_Strdup("/"); 1.2911 + if (path == NULL) 1.2912 + goto loser; 1.2913 + } 1.2914 + 1.2915 + *pHostname = hostname; 1.2916 + *pPort = port; 1.2917 + *pPath = path; 1.2918 + return SECSuccess; 1.2919 + 1.2920 +loser: 1.2921 + if (hostname != NULL) 1.2922 + PORT_Free(hostname); 1.2923 + PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); 1.2924 + return SECFailure; 1.2925 +} 1.2926 + 1.2927 +/* 1.2928 + * Open a socket to the specified host on the specified port, and return it. 1.2929 + * The host is either a hostname or an IP address. 1.2930 + */ 1.2931 +static PRFileDesc * 1.2932 +ocsp_ConnectToHost(const char *host, PRUint16 port) 1.2933 +{ 1.2934 + PRFileDesc *sock = NULL; 1.2935 + PRIntervalTime timeout; 1.2936 + PRNetAddr addr; 1.2937 + char *netdbbuf = NULL; 1.2938 + 1.2939 + // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but 1.2940 + // we want to ensure nothing can ever hit this code in production. 1.2941 +#if 1 1.2942 + printf("Tor Browser BUG: Attempted OSCP direct connect to %s, port %u\n", host, 1.2943 + port); 1.2944 + goto loser; 1.2945 +#endif 1.2946 + 1.2947 + sock = PR_NewTCPSocket(); 1.2948 + if (sock == NULL) 1.2949 + goto loser; 1.2950 + 1.2951 + /* XXX Some day need a way to set (and get?) the following value */ 1.2952 + timeout = PR_SecondsToInterval(30); 1.2953 + 1.2954 + /* 1.2955 + * If the following converts an IP address string in "dot notation" 1.2956 + * into a PRNetAddr. If it fails, we assume that is because we do not 1.2957 + * have such an address, but instead a host *name*. In that case we 1.2958 + * then lookup the host by name. Using the NSPR function this way 1.2959 + * means we do not have to have our own logic for distinguishing a 1.2960 + * valid numerical IP address from a hostname. 1.2961 + */ 1.2962 + if (PR_StringToNetAddr(host, &addr) != PR_SUCCESS) { 1.2963 + PRIntn hostIndex; 1.2964 + PRHostEnt hostEntry; 1.2965 + 1.2966 + netdbbuf = PORT_Alloc(PR_NETDB_BUF_SIZE); 1.2967 + if (netdbbuf == NULL) 1.2968 + goto loser; 1.2969 + 1.2970 + if (PR_GetHostByName(host, netdbbuf, PR_NETDB_BUF_SIZE, 1.2971 + &hostEntry) != PR_SUCCESS) 1.2972 + goto loser; 1.2973 + 1.2974 + hostIndex = 0; 1.2975 + do { 1.2976 + hostIndex = PR_EnumerateHostEnt(hostIndex, &hostEntry, port, &addr); 1.2977 + if (hostIndex <= 0) 1.2978 + goto loser; 1.2979 + } while (PR_Connect(sock, &addr, timeout) != PR_SUCCESS); 1.2980 + 1.2981 + PORT_Free(netdbbuf); 1.2982 + } else { 1.2983 + /* 1.2984 + * First put the port into the address, then connect. 1.2985 + */ 1.2986 + if (PR_InitializeNetAddr(PR_IpAddrNull, port, &addr) != PR_SUCCESS) 1.2987 + goto loser; 1.2988 + if (PR_Connect(sock, &addr, timeout) != PR_SUCCESS) 1.2989 + goto loser; 1.2990 + } 1.2991 + 1.2992 + return sock; 1.2993 + 1.2994 +loser: 1.2995 + if (sock != NULL) 1.2996 + PR_Close(sock); 1.2997 + if (netdbbuf != NULL) 1.2998 + PORT_Free(netdbbuf); 1.2999 + return NULL; 1.3000 +} 1.3001 + 1.3002 +/* 1.3003 + * Sends an encoded OCSP request to the server identified by "location", 1.3004 + * and returns the socket on which it was sent (so can listen for the reply). 1.3005 + * "location" is expected to be a valid URL -- an error parsing it produces 1.3006 + * SEC_ERROR_CERT_BAD_ACCESS_LOCATION. Other errors are likely problems 1.3007 + * connecting to it, or writing to it, or allocating memory, and the low-level 1.3008 + * errors appropriate to the problem will be set. 1.3009 + * if (encodedRequest == NULL) 1.3010 + * then location MUST already include the full request, 1.3011 + * including base64 and urlencode, 1.3012 + * and the request will be sent with GET 1.3013 + * if (encodedRequest != NULL) 1.3014 + * then the request will be sent with POST 1.3015 + */ 1.3016 +static PRFileDesc * 1.3017 +ocsp_SendEncodedRequest(const char *location, const SECItem *encodedRequest) 1.3018 +{ 1.3019 + char *hostname = NULL; 1.3020 + char *path = NULL; 1.3021 + PRUint16 port; 1.3022 + SECStatus rv; 1.3023 + PRFileDesc *sock = NULL; 1.3024 + PRFileDesc *returnSock = NULL; 1.3025 + char *header = NULL; 1.3026 + char portstr[16]; 1.3027 + 1.3028 + /* 1.3029 + * Take apart the location, getting the hostname, port, and path. 1.3030 + */ 1.3031 + rv = ocsp_ParseURL(location, &hostname, &port, &path); 1.3032 + if (rv != SECSuccess) 1.3033 + goto loser; 1.3034 + 1.3035 + PORT_Assert(hostname != NULL); 1.3036 + PORT_Assert(path != NULL); 1.3037 + 1.3038 + sock = ocsp_ConnectToHost(hostname, port); 1.3039 + if (sock == NULL) 1.3040 + goto loser; 1.3041 + 1.3042 + portstr[0] = '\0'; 1.3043 + if (port != 80) { 1.3044 + PR_snprintf(portstr, sizeof(portstr), ":%d", port); 1.3045 + } 1.3046 + 1.3047 + if (!encodedRequest) { 1.3048 + header = PR_smprintf("GET %s HTTP/1.0\r\n" 1.3049 + "Host: %s%s\r\n\r\n", 1.3050 + path, hostname, portstr); 1.3051 + if (header == NULL) 1.3052 + goto loser; 1.3053 + 1.3054 + /* 1.3055 + * The NSPR documentation promises that if it can, it will write the full 1.3056 + * amount; this will not return a partial value expecting us to loop. 1.3057 + */ 1.3058 + if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0) 1.3059 + goto loser; 1.3060 + } 1.3061 + else { 1.3062 + header = PR_smprintf("POST %s HTTP/1.0\r\n" 1.3063 + "Host: %s%s\r\n" 1.3064 + "Content-Type: application/ocsp-request\r\n" 1.3065 + "Content-Length: %u\r\n\r\n", 1.3066 + path, hostname, portstr, encodedRequest->len); 1.3067 + if (header == NULL) 1.3068 + goto loser; 1.3069 + 1.3070 + /* 1.3071 + * The NSPR documentation promises that if it can, it will write the full 1.3072 + * amount; this will not return a partial value expecting us to loop. 1.3073 + */ 1.3074 + if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0) 1.3075 + goto loser; 1.3076 + 1.3077 + if (PR_Write(sock, encodedRequest->data, 1.3078 + (PRInt32) encodedRequest->len) < 0) 1.3079 + goto loser; 1.3080 + } 1.3081 + 1.3082 + returnSock = sock; 1.3083 + sock = NULL; 1.3084 + 1.3085 +loser: 1.3086 + if (header != NULL) 1.3087 + PORT_Free(header); 1.3088 + if (sock != NULL) 1.3089 + PR_Close(sock); 1.3090 + if (path != NULL) 1.3091 + PORT_Free(path); 1.3092 + if (hostname != NULL) 1.3093 + PORT_Free(hostname); 1.3094 + 1.3095 + return returnSock; 1.3096 +} 1.3097 + 1.3098 +/* 1.3099 + * Read from "fd" into "buf" -- expect/attempt to read a given number of bytes 1.3100 + * Obviously, stop if hit end-of-stream. Timeout is passed in. 1.3101 + */ 1.3102 + 1.3103 +static int 1.3104 +ocsp_read(PRFileDesc *fd, char *buf, int toread, PRIntervalTime timeout) 1.3105 +{ 1.3106 + int total = 0; 1.3107 + 1.3108 + while (total < toread) 1.3109 + { 1.3110 + PRInt32 got; 1.3111 + 1.3112 + got = PR_Recv(fd, buf + total, (PRInt32) (toread - total), 0, timeout); 1.3113 + if (got < 0) 1.3114 + { 1.3115 + if (0 == total) 1.3116 + { 1.3117 + total = -1; /* report the error if we didn't read anything yet */ 1.3118 + } 1.3119 + break; 1.3120 + } 1.3121 + else 1.3122 + if (got == 0) 1.3123 + { /* EOS */ 1.3124 + break; 1.3125 + } 1.3126 + 1.3127 + total += got; 1.3128 + } 1.3129 + 1.3130 + return total; 1.3131 +} 1.3132 + 1.3133 +#define OCSP_BUFSIZE 1024 1.3134 + 1.3135 +#define AbortHttpDecode(error) \ 1.3136 +{ \ 1.3137 + if (inBuffer) \ 1.3138 + PORT_Free(inBuffer); \ 1.3139 + PORT_SetError(error); \ 1.3140 + return NULL; \ 1.3141 +} 1.3142 + 1.3143 + 1.3144 +/* 1.3145 + * Reads on the given socket and returns an encoded response when received. 1.3146 + * Properly formatted HTTP/1.0 response headers are expected to be read 1.3147 + * from the socket, preceding a binary-encoded OCSP response. Problems 1.3148 + * with parsing cause the error SEC_ERROR_OCSP_BAD_HTTP_RESPONSE to be 1.3149 + * set; any other problems are likely low-level i/o or memory allocation 1.3150 + * errors. 1.3151 + */ 1.3152 +static SECItem * 1.3153 +ocsp_GetEncodedResponse(PLArenaPool *arena, PRFileDesc *sock) 1.3154 +{ 1.3155 + /* first read HTTP status line and headers */ 1.3156 + 1.3157 + char* inBuffer = NULL; 1.3158 + PRInt32 offset = 0; 1.3159 + PRInt32 inBufsize = 0; 1.3160 + const PRInt32 bufSizeIncrement = OCSP_BUFSIZE; /* 1 KB at a time */ 1.3161 + const PRInt32 maxBufSize = 8 * bufSizeIncrement ; /* 8 KB max */ 1.3162 + const char* CRLF = "\r\n"; 1.3163 + const PRInt32 CRLFlen = strlen(CRLF); 1.3164 + const char* headerEndMark = "\r\n\r\n"; 1.3165 + const PRInt32 markLen = strlen(headerEndMark); 1.3166 + const PRIntervalTime ocsptimeout = 1.3167 + PR_SecondsToInterval(30); /* hardcoded to 30s for now */ 1.3168 + char* headerEnd = NULL; 1.3169 + PRBool EOS = PR_FALSE; 1.3170 + const char* httpprotocol = "HTTP/"; 1.3171 + const PRInt32 httplen = strlen(httpprotocol); 1.3172 + const char* httpcode = NULL; 1.3173 + const char* contenttype = NULL; 1.3174 + PRInt32 contentlength = 0; 1.3175 + PRInt32 bytesRead = 0; 1.3176 + char* statusLineEnd = NULL; 1.3177 + char* space = NULL; 1.3178 + char* nextHeader = NULL; 1.3179 + SECItem* result = NULL; 1.3180 + 1.3181 + /* read up to at least the end of the HTTP headers */ 1.3182 + do 1.3183 + { 1.3184 + inBufsize += bufSizeIncrement; 1.3185 + inBuffer = PORT_Realloc(inBuffer, inBufsize+1); 1.3186 + if (NULL == inBuffer) 1.3187 + { 1.3188 + AbortHttpDecode(SEC_ERROR_NO_MEMORY); 1.3189 + } 1.3190 + bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement, 1.3191 + ocsptimeout); 1.3192 + if (bytesRead > 0) 1.3193 + { 1.3194 + PRInt32 searchOffset = (offset - markLen) >0 ? offset-markLen : 0; 1.3195 + offset += bytesRead; 1.3196 + *(inBuffer + offset) = '\0'; /* NULL termination */ 1.3197 + headerEnd = strstr((const char*)inBuffer + searchOffset, headerEndMark); 1.3198 + if (bytesRead < bufSizeIncrement) 1.3199 + { 1.3200 + /* we read less data than requested, therefore we are at 1.3201 + EOS or there was a read error */ 1.3202 + EOS = PR_TRUE; 1.3203 + } 1.3204 + } 1.3205 + else 1.3206 + { 1.3207 + /* recv error or EOS */ 1.3208 + EOS = PR_TRUE; 1.3209 + } 1.3210 + } while ( (!headerEnd) && (PR_FALSE == EOS) && 1.3211 + (inBufsize < maxBufSize) ); 1.3212 + 1.3213 + if (!headerEnd) 1.3214 + { 1.3215 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3216 + } 1.3217 + 1.3218 + /* parse the HTTP status line */ 1.3219 + statusLineEnd = strstr((const char*)inBuffer, CRLF); 1.3220 + if (!statusLineEnd) 1.3221 + { 1.3222 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3223 + } 1.3224 + *statusLineEnd = '\0'; 1.3225 + 1.3226 + /* check for HTTP/ response */ 1.3227 + space = strchr((const char*)inBuffer, ' '); 1.3228 + if (!space || PORT_Strncasecmp((const char*)inBuffer, httpprotocol, httplen) != 0 ) 1.3229 + { 1.3230 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3231 + } 1.3232 + 1.3233 + /* check the HTTP status code of 200 */ 1.3234 + httpcode = space +1; 1.3235 + space = strchr(httpcode, ' '); 1.3236 + if (!space) 1.3237 + { 1.3238 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3239 + } 1.3240 + *space = 0; 1.3241 + if (0 != strcmp(httpcode, "200")) 1.3242 + { 1.3243 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3244 + } 1.3245 + 1.3246 + /* parse the HTTP headers in the buffer . We only care about 1.3247 + content-type and content-length 1.3248 + */ 1.3249 + 1.3250 + nextHeader = statusLineEnd + CRLFlen; 1.3251 + *headerEnd = '\0'; /* terminate */ 1.3252 + do 1.3253 + { 1.3254 + char* thisHeaderEnd = NULL; 1.3255 + char* value = NULL; 1.3256 + char* colon = strchr(nextHeader, ':'); 1.3257 + 1.3258 + if (!colon) 1.3259 + { 1.3260 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3261 + } 1.3262 + 1.3263 + *colon = '\0'; 1.3264 + value = colon + 1; 1.3265 + 1.3266 + /* jpierre - note : the following code will only handle the basic form 1.3267 + of HTTP/1.0 response headers, of the form "name: value" . Headers 1.3268 + split among multiple lines are not supported. This is not common 1.3269 + and should not be an issue, but it could become one in the 1.3270 + future */ 1.3271 + 1.3272 + if (*value != ' ') 1.3273 + { 1.3274 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3275 + } 1.3276 + 1.3277 + value++; 1.3278 + thisHeaderEnd = strstr(value, CRLF); 1.3279 + if (thisHeaderEnd ) 1.3280 + { 1.3281 + *thisHeaderEnd = '\0'; 1.3282 + } 1.3283 + 1.3284 + if (0 == PORT_Strcasecmp(nextHeader, "content-type")) 1.3285 + { 1.3286 + contenttype = value; 1.3287 + } 1.3288 + else 1.3289 + if (0 == PORT_Strcasecmp(nextHeader, "content-length")) 1.3290 + { 1.3291 + contentlength = atoi(value); 1.3292 + } 1.3293 + 1.3294 + if (thisHeaderEnd ) 1.3295 + { 1.3296 + nextHeader = thisHeaderEnd + CRLFlen; 1.3297 + } 1.3298 + else 1.3299 + { 1.3300 + nextHeader = NULL; 1.3301 + } 1.3302 + 1.3303 + } while (nextHeader && (nextHeader < (headerEnd + CRLFlen) ) ); 1.3304 + 1.3305 + /* check content-type */ 1.3306 + if (!contenttype || 1.3307 + (0 != PORT_Strcasecmp(contenttype, "application/ocsp-response")) ) 1.3308 + { 1.3309 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3310 + } 1.3311 + 1.3312 + /* read the body of the OCSP response */ 1.3313 + offset = offset - (PRInt32) (headerEnd - (const char*)inBuffer) - markLen; 1.3314 + if (offset) 1.3315 + { 1.3316 + /* move all data to the beginning of the buffer */ 1.3317 + PORT_Memmove(inBuffer, headerEnd + markLen, offset); 1.3318 + } 1.3319 + 1.3320 + /* resize buffer to only what's needed to hold the current response */ 1.3321 + inBufsize = (1 + (offset-1) / bufSizeIncrement ) * bufSizeIncrement ; 1.3322 + 1.3323 + while ( (PR_FALSE == EOS) && 1.3324 + ( (contentlength == 0) || (offset < contentlength) ) && 1.3325 + (inBufsize < maxBufSize) 1.3326 + ) 1.3327 + { 1.3328 + /* we still need to receive more body data */ 1.3329 + inBufsize += bufSizeIncrement; 1.3330 + inBuffer = PORT_Realloc(inBuffer, inBufsize+1); 1.3331 + if (NULL == inBuffer) 1.3332 + { 1.3333 + AbortHttpDecode(SEC_ERROR_NO_MEMORY); 1.3334 + } 1.3335 + bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement, 1.3336 + ocsptimeout); 1.3337 + if (bytesRead > 0) 1.3338 + { 1.3339 + offset += bytesRead; 1.3340 + if (bytesRead < bufSizeIncrement) 1.3341 + { 1.3342 + /* we read less data than requested, therefore we are at 1.3343 + EOS or there was a read error */ 1.3344 + EOS = PR_TRUE; 1.3345 + } 1.3346 + } 1.3347 + else 1.3348 + { 1.3349 + /* recv error or EOS */ 1.3350 + EOS = PR_TRUE; 1.3351 + } 1.3352 + } 1.3353 + 1.3354 + if (0 == offset) 1.3355 + { 1.3356 + AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3357 + } 1.3358 + 1.3359 + /* 1.3360 + * Now allocate the item to hold the data. 1.3361 + */ 1.3362 + result = SECITEM_AllocItem(arena, NULL, offset); 1.3363 + if (NULL == result) 1.3364 + { 1.3365 + AbortHttpDecode(SEC_ERROR_NO_MEMORY); 1.3366 + } 1.3367 + 1.3368 + /* 1.3369 + * And copy the data left in the buffer. 1.3370 + */ 1.3371 + PORT_Memcpy(result->data, inBuffer, offset); 1.3372 + 1.3373 + /* and free the temporary buffer */ 1.3374 + PORT_Free(inBuffer); 1.3375 + return result; 1.3376 +} 1.3377 + 1.3378 +SECStatus 1.3379 +CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath) 1.3380 +{ 1.3381 + return ocsp_ParseURL(url, pHostname, pPort, pPath); 1.3382 +} 1.3383 + 1.3384 +/* 1.3385 + * Limit the size of http responses we are willing to accept. 1.3386 + */ 1.3387 +#define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024 1.3388 + 1.3389 +/* if (encodedRequest == NULL) 1.3390 + * then location MUST already include the full request, 1.3391 + * including base64 and urlencode, 1.3392 + * and the request will be sent with GET 1.3393 + * if (encodedRequest != NULL) 1.3394 + * then the request will be sent with POST 1.3395 + */ 1.3396 +static SECItem * 1.3397 +fetchOcspHttpClientV1(PLArenaPool *arena, 1.3398 + const SEC_HttpClientFcnV1 *hcv1, 1.3399 + const char *location, 1.3400 + const SECItem *encodedRequest) 1.3401 +{ 1.3402 + char *hostname = NULL; 1.3403 + char *path = NULL; 1.3404 + PRUint16 port; 1.3405 + SECItem *encodedResponse = NULL; 1.3406 + SEC_HTTP_SERVER_SESSION pServerSession = NULL; 1.3407 + SEC_HTTP_REQUEST_SESSION pRequestSession = NULL; 1.3408 + PRUint16 myHttpResponseCode; 1.3409 + const char *myHttpResponseData; 1.3410 + PRUint32 myHttpResponseDataLen; 1.3411 + 1.3412 + if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) { 1.3413 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); 1.3414 + goto loser; 1.3415 + } 1.3416 + 1.3417 + PORT_Assert(hostname != NULL); 1.3418 + PORT_Assert(path != NULL); 1.3419 + 1.3420 + if ((*hcv1->createSessionFcn)( 1.3421 + hostname, 1.3422 + port, 1.3423 + &pServerSession) != SECSuccess) { 1.3424 + PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); 1.3425 + goto loser; 1.3426 + } 1.3427 + 1.3428 + /* We use a non-zero timeout, which means: 1.3429 + - the client will use blocking I/O 1.3430 + - TryFcn will not return WOULD_BLOCK nor a poll descriptor 1.3431 + - it's sufficient to call TryFcn once 1.3432 + No lock for accessing OCSP_Global.timeoutSeconds, bug 406120 1.3433 + */ 1.3434 + 1.3435 + if ((*hcv1->createFcn)( 1.3436 + pServerSession, 1.3437 + "http", 1.3438 + path, 1.3439 + encodedRequest ? "POST" : "GET", 1.3440 + PR_TicksPerSecond() * OCSP_Global.timeoutSeconds, 1.3441 + &pRequestSession) != SECSuccess) { 1.3442 + PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); 1.3443 + goto loser; 1.3444 + } 1.3445 + 1.3446 + if (encodedRequest && 1.3447 + (*hcv1->setPostDataFcn)( 1.3448 + pRequestSession, 1.3449 + (char*)encodedRequest->data, 1.3450 + encodedRequest->len, 1.3451 + "application/ocsp-request") != SECSuccess) { 1.3452 + PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); 1.3453 + goto loser; 1.3454 + } 1.3455 + 1.3456 + /* we don't want result objects larger than this: */ 1.3457 + myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN; 1.3458 + 1.3459 + OCSP_TRACE(("OCSP trySendAndReceive %s\n", location)); 1.3460 + 1.3461 + if ((*hcv1->trySendAndReceiveFcn)( 1.3462 + pRequestSession, 1.3463 + NULL, 1.3464 + &myHttpResponseCode, 1.3465 + NULL, 1.3466 + NULL, 1.3467 + &myHttpResponseData, 1.3468 + &myHttpResponseDataLen) != SECSuccess) { 1.3469 + PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); 1.3470 + goto loser; 1.3471 + } 1.3472 + 1.3473 + OCSP_TRACE(("OCSP trySendAndReceive result http %d\n", myHttpResponseCode)); 1.3474 + 1.3475 + if (myHttpResponseCode != 200) { 1.3476 + PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); 1.3477 + goto loser; 1.3478 + } 1.3479 + 1.3480 + encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen); 1.3481 + 1.3482 + if (!encodedResponse) { 1.3483 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.3484 + goto loser; 1.3485 + } 1.3486 + 1.3487 + PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen); 1.3488 + 1.3489 +loser: 1.3490 + if (pRequestSession != NULL) 1.3491 + (*hcv1->freeFcn)(pRequestSession); 1.3492 + if (pServerSession != NULL) 1.3493 + (*hcv1->freeSessionFcn)(pServerSession); 1.3494 + if (path != NULL) 1.3495 + PORT_Free(path); 1.3496 + if (hostname != NULL) 1.3497 + PORT_Free(hostname); 1.3498 + 1.3499 + return encodedResponse; 1.3500 +} 1.3501 + 1.3502 +/* 1.3503 + * FUNCTION: CERT_GetEncodedOCSPResponseByMethod 1.3504 + * Creates and sends a request to an OCSP responder, then reads and 1.3505 + * returns the (encoded) response. 1.3506 + * INPUTS: 1.3507 + * PLArenaPool *arena 1.3508 + * Pointer to arena from which return value will be allocated. 1.3509 + * If NULL, result will be allocated from the heap (and thus should 1.3510 + * be freed via SECITEM_FreeItem). 1.3511 + * CERTCertList *certList 1.3512 + * A list of certs for which status will be requested. 1.3513 + * Note that all of these certificates should have the same issuer, 1.3514 + * or it's expected the response will be signed by a trusted responder. 1.3515 + * If the certs need to be broken up into multiple requests, that 1.3516 + * must be handled by the caller (and thus by having multiple calls 1.3517 + * to this routine), who knows about where the request(s) are being 1.3518 + * sent and whether there are any trusted responders in place. 1.3519 + * const char *location 1.3520 + * The location of the OCSP responder (a URL). 1.3521 + * const char *method 1.3522 + * The protocol method used when retrieving the OCSP response. 1.3523 + * Currently support: "GET" (http GET) and "POST" (http POST). 1.3524 + * Additionals methods for http or other protocols might be added 1.3525 + * in the future. 1.3526 + * PRTime time 1.3527 + * Indicates the time for which the certificate status is to be 1.3528 + * determined -- this may be used in the search for the cert's issuer 1.3529 + * but has no other bearing on the operation. 1.3530 + * PRBool addServiceLocator 1.3531 + * If true, the Service Locator extension should be added to the 1.3532 + * single request(s) for each cert. 1.3533 + * CERTCertificate *signerCert 1.3534 + * If non-NULL, means sign the request using this cert. Otherwise, 1.3535 + * do not sign. 1.3536 + * void *pwArg 1.3537 + * Pointer to argument for password prompting, if needed. (Definitely 1.3538 + * not needed if not signing.) 1.3539 + * OUTPUTS: 1.3540 + * CERTOCSPRequest **pRequest 1.3541 + * Pointer in which to store the OCSP request created for the given 1.3542 + * list of certificates. It is only filled in if the entire operation 1.3543 + * is successful and the pointer is not null -- and in that case the 1.3544 + * caller is then reponsible for destroying it. 1.3545 + * RETURN: 1.3546 + * Returns a pointer to the SECItem holding the response. 1.3547 + * On error, returns null with error set describing the reason: 1.3548 + * SEC_ERROR_UNKNOWN_ISSUER 1.3549 + * SEC_ERROR_CERT_BAD_ACCESS_LOCATION 1.3550 + * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE 1.3551 + * Other errors are low-level problems (no memory, bad database, etc.). 1.3552 + */ 1.3553 +SECItem * 1.3554 +CERT_GetEncodedOCSPResponseByMethod(PLArenaPool *arena, CERTCertList *certList, 1.3555 + const char *location, const char *method, 1.3556 + PRTime time, PRBool addServiceLocator, 1.3557 + CERTCertificate *signerCert, void *pwArg, 1.3558 + CERTOCSPRequest **pRequest) 1.3559 +{ 1.3560 + CERTOCSPRequest *request; 1.3561 + request = CERT_CreateOCSPRequest(certList, time, addServiceLocator, 1.3562 + signerCert); 1.3563 + if (!request) 1.3564 + return NULL; 1.3565 + return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, 1.3566 + method, time, addServiceLocator, 1.3567 + pwArg, pRequest); 1.3568 +} 1.3569 + 1.3570 +/* 1.3571 + * FUNCTION: CERT_GetEncodedOCSPResponse 1.3572 + * Creates and sends a request to an OCSP responder, then reads and 1.3573 + * returns the (encoded) response. 1.3574 + * 1.3575 + * This is a legacy API that behaves identically to 1.3576 + * CERT_GetEncodedOCSPResponseByMethod using the "POST" method. 1.3577 + */ 1.3578 +SECItem * 1.3579 +CERT_GetEncodedOCSPResponse(PLArenaPool *arena, CERTCertList *certList, 1.3580 + const char *location, PRTime time, 1.3581 + PRBool addServiceLocator, 1.3582 + CERTCertificate *signerCert, void *pwArg, 1.3583 + CERTOCSPRequest **pRequest) 1.3584 +{ 1.3585 + return CERT_GetEncodedOCSPResponseByMethod(arena, certList, location, 1.3586 + "POST", time, addServiceLocator, 1.3587 + signerCert, pwArg, pRequest); 1.3588 +} 1.3589 + 1.3590 +/* URL encode a buffer that consists of base64-characters, only, 1.3591 + * which means we can use a simple encoding logic. 1.3592 + * 1.3593 + * No output buffer size checking is performed. 1.3594 + * You should call the function twice, to calculate the required buffer size. 1.3595 + * 1.3596 + * If the outpufBuf parameter is NULL, the function will calculate the 1.3597 + * required size, including the trailing zero termination char. 1.3598 + * 1.3599 + * The function returns the number of bytes calculated or produced. 1.3600 + */ 1.3601 +size_t 1.3602 +ocsp_UrlEncodeBase64Buf(const char *base64Buf, char *outputBuf) 1.3603 +{ 1.3604 + const char *walkInput = NULL; 1.3605 + char *walkOutput = outputBuf; 1.3606 + size_t count = 0; 1.3607 + 1.3608 + for (walkInput=base64Buf; *walkInput; ++walkInput) { 1.3609 + char c = *walkInput; 1.3610 + if (isspace(c)) 1.3611 + continue; 1.3612 + switch (c) { 1.3613 + case '+': 1.3614 + if (outputBuf) { 1.3615 + strcpy(walkOutput, "%2B"); 1.3616 + walkOutput += 3; 1.3617 + } 1.3618 + count += 3; 1.3619 + break; 1.3620 + case '/': 1.3621 + if (outputBuf) { 1.3622 + strcpy(walkOutput, "%2F"); 1.3623 + walkOutput += 3; 1.3624 + } 1.3625 + count += 3; 1.3626 + break; 1.3627 + case '=': 1.3628 + if (outputBuf) { 1.3629 + strcpy(walkOutput, "%3D"); 1.3630 + walkOutput += 3; 1.3631 + } 1.3632 + count += 3; 1.3633 + break; 1.3634 + default: 1.3635 + if (outputBuf) { 1.3636 + *walkOutput = *walkInput; 1.3637 + ++walkOutput; 1.3638 + } 1.3639 + ++count; 1.3640 + break; 1.3641 + } 1.3642 + } 1.3643 + if (outputBuf) { 1.3644 + *walkOutput = 0; 1.3645 + } 1.3646 + ++count; 1.3647 + return count; 1.3648 +} 1.3649 + 1.3650 +enum { max_get_request_size = 255 }; /* defined by RFC2560 */ 1.3651 + 1.3652 +static SECItem * 1.3653 +cert_GetOCSPResponse(PLArenaPool *arena, const char *location, 1.3654 + const SECItem *encodedRequest); 1.3655 + 1.3656 +static SECItem * 1.3657 +ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena, 1.3658 + CERTOCSPRequest *request, 1.3659 + const char *location, 1.3660 + const char *method, 1.3661 + PRTime time, 1.3662 + PRBool addServiceLocator, 1.3663 + void *pwArg, 1.3664 + CERTOCSPRequest **pRequest) 1.3665 +{ 1.3666 + SECItem *encodedRequest = NULL; 1.3667 + SECItem *encodedResponse = NULL; 1.3668 + SECStatus rv; 1.3669 + 1.3670 + if (!location || !*location) /* location should be at least one byte */ 1.3671 + goto loser; 1.3672 + 1.3673 + rv = CERT_AddOCSPAcceptableResponses(request, 1.3674 + SEC_OID_PKIX_OCSP_BASIC_RESPONSE); 1.3675 + if (rv != SECSuccess) 1.3676 + goto loser; 1.3677 + 1.3678 + encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg); 1.3679 + if (encodedRequest == NULL) 1.3680 + goto loser; 1.3681 + 1.3682 + if (!strcmp(method, "GET")) { 1.3683 + encodedResponse = cert_GetOCSPResponse(arena, location, encodedRequest); 1.3684 + } 1.3685 + else if (!strcmp(method, "POST")) { 1.3686 + encodedResponse = CERT_PostOCSPRequest(arena, location, encodedRequest); 1.3687 + } 1.3688 + else { 1.3689 + goto loser; 1.3690 + } 1.3691 + 1.3692 + if (encodedResponse != NULL && pRequest != NULL) { 1.3693 + *pRequest = request; 1.3694 + request = NULL; /* avoid destroying below */ 1.3695 + } 1.3696 + 1.3697 +loser: 1.3698 + if (request != NULL) 1.3699 + CERT_DestroyOCSPRequest(request); 1.3700 + if (encodedRequest != NULL) 1.3701 + SECITEM_FreeItem(encodedRequest, PR_TRUE); 1.3702 + return encodedResponse; 1.3703 +} 1.3704 + 1.3705 +static SECItem * 1.3706 +cert_FetchOCSPResponse(PLArenaPool *arena, const char *location, 1.3707 + const SECItem *encodedRequest); 1.3708 + 1.3709 +/* using HTTP GET method */ 1.3710 +static SECItem * 1.3711 +cert_GetOCSPResponse(PLArenaPool *arena, const char *location, 1.3712 + const SECItem *encodedRequest) 1.3713 +{ 1.3714 + char *walkOutput = NULL; 1.3715 + char *fullGetPath = NULL; 1.3716 + size_t pathLength; 1.3717 + PRInt32 urlEncodedBufLength; 1.3718 + size_t base64size; 1.3719 + char b64ReqBuf[max_get_request_size+1]; 1.3720 + size_t slashLengthIfNeeded = 0; 1.3721 + size_t getURLLength; 1.3722 + SECItem *item; 1.3723 + 1.3724 + if (!location || !*location) { 1.3725 + return NULL; 1.3726 + } 1.3727 + 1.3728 + pathLength = strlen(location); 1.3729 + if (location[pathLength-1] != '/') { 1.3730 + slashLengthIfNeeded = 1; 1.3731 + } 1.3732 + 1.3733 + /* Calculation as documented by PL_Base64Encode function. 1.3734 + * Use integer conversion to avoid having to use function ceil(). 1.3735 + */ 1.3736 + base64size = (((encodedRequest->len +2)/3) * 4); 1.3737 + if (base64size > max_get_request_size) { 1.3738 + return NULL; 1.3739 + } 1.3740 + memset(b64ReqBuf, 0, sizeof(b64ReqBuf)); 1.3741 + PL_Base64Encode((const char*)encodedRequest->data, encodedRequest->len, 1.3742 + b64ReqBuf); 1.3743 + 1.3744 + urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL); 1.3745 + getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded; 1.3746 + 1.3747 + /* urlEncodedBufLength already contains room for the zero terminator. 1.3748 + * Add another if we must add the '/' char. 1.3749 + */ 1.3750 + if (arena) { 1.3751 + fullGetPath = (char*)PORT_ArenaAlloc(arena, getURLLength); 1.3752 + } else { 1.3753 + fullGetPath = (char*)PORT_Alloc(getURLLength); 1.3754 + } 1.3755 + if (!fullGetPath) { 1.3756 + return NULL; 1.3757 + } 1.3758 + 1.3759 + strcpy(fullGetPath, location); 1.3760 + walkOutput = fullGetPath + pathLength; 1.3761 + 1.3762 + if (walkOutput > fullGetPath && slashLengthIfNeeded) { 1.3763 + strcpy(walkOutput, "/"); 1.3764 + ++walkOutput; 1.3765 + } 1.3766 + ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput); 1.3767 + 1.3768 + item = cert_FetchOCSPResponse(arena, fullGetPath, NULL); 1.3769 + if (!arena) { 1.3770 + PORT_Free(fullGetPath); 1.3771 + } 1.3772 + return item; 1.3773 +} 1.3774 + 1.3775 +SECItem * 1.3776 +CERT_PostOCSPRequest(PLArenaPool *arena, const char *location, 1.3777 + const SECItem *encodedRequest) 1.3778 +{ 1.3779 + return cert_FetchOCSPResponse(arena, location, encodedRequest); 1.3780 +} 1.3781 + 1.3782 +SECItem * 1.3783 +cert_FetchOCSPResponse(PLArenaPool *arena, const char *location, 1.3784 + const SECItem *encodedRequest) 1.3785 +{ 1.3786 + const SEC_HttpClientFcn *registeredHttpClient; 1.3787 + SECItem *encodedResponse = NULL; 1.3788 + 1.3789 + registeredHttpClient = SEC_GetRegisteredHttpClient(); 1.3790 + 1.3791 + if (registeredHttpClient && registeredHttpClient->version == 1) { 1.3792 + encodedResponse = fetchOcspHttpClientV1( 1.3793 + arena, 1.3794 + ®isteredHttpClient->fcnTable.ftable1, 1.3795 + location, 1.3796 + encodedRequest); 1.3797 + } else { 1.3798 + /* use internal http client */ 1.3799 + PRFileDesc *sock = ocsp_SendEncodedRequest(location, encodedRequest); 1.3800 + if (sock) { 1.3801 + encodedResponse = ocsp_GetEncodedResponse(arena, sock); 1.3802 + PR_Close(sock); 1.3803 + } 1.3804 + } 1.3805 + 1.3806 + return encodedResponse; 1.3807 +} 1.3808 + 1.3809 +static SECItem * 1.3810 +ocsp_GetEncodedOCSPResponseForSingleCert(PLArenaPool *arena, 1.3811 + CERTOCSPCertID *certID, 1.3812 + CERTCertificate *singleCert, 1.3813 + const char *location, 1.3814 + const char *method, 1.3815 + PRTime time, 1.3816 + PRBool addServiceLocator, 1.3817 + void *pwArg, 1.3818 + CERTOCSPRequest **pRequest) 1.3819 +{ 1.3820 + CERTOCSPRequest *request; 1.3821 + request = cert_CreateSingleCertOCSPRequest(certID, singleCert, time, 1.3822 + addServiceLocator, NULL); 1.3823 + if (!request) 1.3824 + return NULL; 1.3825 + return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, 1.3826 + method, time, addServiceLocator, 1.3827 + pwArg, pRequest); 1.3828 +} 1.3829 + 1.3830 +/* Checks a certificate for the key usage extension of OCSP signer. */ 1.3831 +static PRBool 1.3832 +ocsp_CertIsOCSPDesignatedResponder(CERTCertificate *cert) 1.3833 +{ 1.3834 + SECStatus rv; 1.3835 + SECItem extItem; 1.3836 + SECItem **oids; 1.3837 + SECItem *oid; 1.3838 + SECOidTag oidTag; 1.3839 + PRBool retval; 1.3840 + CERTOidSequence *oidSeq = NULL; 1.3841 + 1.3842 + 1.3843 + extItem.data = NULL; 1.3844 + rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem); 1.3845 + if ( rv != SECSuccess ) { 1.3846 + goto loser; 1.3847 + } 1.3848 + 1.3849 + oidSeq = CERT_DecodeOidSequence(&extItem); 1.3850 + if ( oidSeq == NULL ) { 1.3851 + goto loser; 1.3852 + } 1.3853 + 1.3854 + oids = oidSeq->oids; 1.3855 + while ( *oids != NULL ) { 1.3856 + oid = *oids; 1.3857 + 1.3858 + oidTag = SECOID_FindOIDTag(oid); 1.3859 + 1.3860 + if ( oidTag == SEC_OID_OCSP_RESPONDER ) { 1.3861 + goto success; 1.3862 + } 1.3863 + 1.3864 + oids++; 1.3865 + } 1.3866 + 1.3867 +loser: 1.3868 + retval = PR_FALSE; 1.3869 + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); 1.3870 + goto done; 1.3871 +success: 1.3872 + retval = PR_TRUE; 1.3873 +done: 1.3874 + if ( extItem.data != NULL ) { 1.3875 + PORT_Free(extItem.data); 1.3876 + } 1.3877 + if ( oidSeq != NULL ) { 1.3878 + CERT_DestroyOidSequence(oidSeq); 1.3879 + } 1.3880 + 1.3881 + return(retval); 1.3882 +} 1.3883 + 1.3884 + 1.3885 +#ifdef LATER /* 1.3886 + * XXX This function is not currently used, but will 1.3887 + * be needed later when we do revocation checking of 1.3888 + * the responder certificate. Of course, it may need 1.3889 + * revising then, if the cert extension interface has 1.3890 + * changed. (Hopefully it will!) 1.3891 + */ 1.3892 + 1.3893 +/* Checks a certificate to see if it has the OCSP no check extension. */ 1.3894 +static PRBool 1.3895 +ocsp_CertHasNoCheckExtension(CERTCertificate *cert) 1.3896 +{ 1.3897 + SECStatus rv; 1.3898 + 1.3899 + rv = CERT_FindCertExtension(cert, SEC_OID_PKIX_OCSP_NO_CHECK, 1.3900 + NULL); 1.3901 + if (rv == SECSuccess) { 1.3902 + return PR_TRUE; 1.3903 + } 1.3904 + return PR_FALSE; 1.3905 +} 1.3906 +#endif /* LATER */ 1.3907 + 1.3908 +static PRBool 1.3909 +ocsp_matchcert(SECItem *certIndex,CERTCertificate *testCert) 1.3910 +{ 1.3911 + SECItem item; 1.3912 + unsigned char buf[HASH_LENGTH_MAX]; 1.3913 + 1.3914 + item.data = buf; 1.3915 + item.len = SHA1_LENGTH; 1.3916 + 1.3917 + if (CERT_GetSubjectPublicKeyDigest(NULL,testCert,SEC_OID_SHA1, 1.3918 + &item) == NULL) { 1.3919 + return PR_FALSE; 1.3920 + } 1.3921 + if (SECITEM_ItemsAreEqual(certIndex,&item)) { 1.3922 + return PR_TRUE; 1.3923 + } 1.3924 + if (CERT_GetSubjectPublicKeyDigest(NULL,testCert,SEC_OID_MD5, 1.3925 + &item) == NULL) { 1.3926 + return PR_FALSE; 1.3927 + } 1.3928 + if (SECITEM_ItemsAreEqual(certIndex,&item)) { 1.3929 + return PR_TRUE; 1.3930 + } 1.3931 + if (CERT_GetSubjectPublicKeyDigest(NULL,testCert,SEC_OID_MD2, 1.3932 + &item) == NULL) { 1.3933 + return PR_FALSE; 1.3934 + } 1.3935 + if (SECITEM_ItemsAreEqual(certIndex,&item)) { 1.3936 + return PR_TRUE; 1.3937 + } 1.3938 + 1.3939 + return PR_FALSE; 1.3940 +} 1.3941 + 1.3942 +static CERTCertificate * 1.3943 +ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle,CERTOCSPCertID *certID); 1.3944 + 1.3945 +CERTCertificate * 1.3946 +ocsp_GetSignerCertificate(CERTCertDBHandle *handle, ocspResponseData *tbsData, 1.3947 + ocspSignature *signature, CERTCertificate *issuer) 1.3948 +{ 1.3949 + CERTCertificate **certs = NULL; 1.3950 + CERTCertificate *signerCert = NULL; 1.3951 + SECStatus rv = SECFailure; 1.3952 + PRBool lookupByName = PR_TRUE; 1.3953 + void *certIndex = NULL; 1.3954 + int certCount = 0; 1.3955 + 1.3956 + PORT_Assert(tbsData->responderID != NULL); 1.3957 + switch (tbsData->responderID->responderIDType) { 1.3958 + case ocspResponderID_byName: 1.3959 + lookupByName = PR_TRUE; 1.3960 + certIndex = &tbsData->derResponderID; 1.3961 + break; 1.3962 + case ocspResponderID_byKey: 1.3963 + lookupByName = PR_FALSE; 1.3964 + certIndex = &tbsData->responderID->responderIDValue.keyHash; 1.3965 + break; 1.3966 + case ocspResponderID_other: 1.3967 + default: 1.3968 + PORT_Assert(0); 1.3969 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.3970 + return NULL; 1.3971 + } 1.3972 + 1.3973 + /* 1.3974 + * If the signature contains some certificates as well, temporarily 1.3975 + * import them in case they are needed for verification. 1.3976 + * 1.3977 + * Note that the result of this is that each cert in "certs" needs 1.3978 + * to be destroyed. 1.3979 + */ 1.3980 + if (signature->derCerts != NULL) { 1.3981 + for (; signature->derCerts[certCount] != NULL; certCount++) { 1.3982 + /* just counting */ 1.3983 + } 1.3984 + rv = CERT_ImportCerts(handle, certUsageStatusResponder, certCount, 1.3985 + signature->derCerts, &certs, 1.3986 + PR_FALSE, PR_FALSE, NULL); 1.3987 + if (rv != SECSuccess) 1.3988 + goto finish; 1.3989 + } 1.3990 + 1.3991 + /* 1.3992 + * Now look up the certificate that did the signing. 1.3993 + * The signer can be specified either by name or by key hash. 1.3994 + */ 1.3995 + if (lookupByName) { 1.3996 + SECItem *crIndex = (SECItem*)certIndex; 1.3997 + SECItem encodedName; 1.3998 + PLArenaPool *arena; 1.3999 + 1.4000 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.4001 + if (arena != NULL) { 1.4002 + 1.4003 + rv = SEC_QuickDERDecodeItem(arena, &encodedName, 1.4004 + ocsp_ResponderIDDerNameTemplate, 1.4005 + crIndex); 1.4006 + if (rv != SECSuccess) { 1.4007 + if (PORT_GetError() == SEC_ERROR_BAD_DER) 1.4008 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.4009 + } else { 1.4010 + signerCert = CERT_FindCertByName(handle, &encodedName); 1.4011 + } 1.4012 + PORT_FreeArena(arena, PR_FALSE); 1.4013 + } 1.4014 + } else { 1.4015 + /* 1.4016 + * The signer is either 1) a known issuer CA we passed in, 1.4017 + * 2) the default OCSP responder, or 3) an intermediate CA 1.4018 + * passed in the cert list to use. Figure out which it is. 1.4019 + */ 1.4020 + int i; 1.4021 + CERTCertificate *responder = 1.4022 + ocsp_CertGetDefaultResponder(handle, NULL); 1.4023 + if (responder && ocsp_matchcert(certIndex,responder)) { 1.4024 + signerCert = CERT_DupCertificate(responder); 1.4025 + } else if (issuer && ocsp_matchcert(certIndex,issuer)) { 1.4026 + signerCert = CERT_DupCertificate(issuer); 1.4027 + } 1.4028 + for (i=0; (signerCert == NULL) && (i < certCount); i++) { 1.4029 + if (ocsp_matchcert(certIndex,certs[i])) { 1.4030 + signerCert = CERT_DupCertificate(certs[i]); 1.4031 + } 1.4032 + } 1.4033 + if (signerCert == NULL) { 1.4034 + PORT_SetError(SEC_ERROR_UNKNOWN_CERT); 1.4035 + } 1.4036 + } 1.4037 + 1.4038 +finish: 1.4039 + if (certs != NULL) { 1.4040 + CERT_DestroyCertArray(certs, certCount); 1.4041 + } 1.4042 + 1.4043 + return signerCert; 1.4044 +} 1.4045 + 1.4046 +SECStatus 1.4047 +ocsp_VerifyResponseSignature(CERTCertificate *signerCert, 1.4048 + ocspSignature *signature, 1.4049 + SECItem *tbsResponseDataDER, 1.4050 + void *pwArg) 1.4051 +{ 1.4052 + SECKEYPublicKey *signerKey = NULL; 1.4053 + SECStatus rv = SECFailure; 1.4054 + CERTSignedData signedData; 1.4055 + 1.4056 + /* 1.4057 + * Now get the public key from the signer's certificate; we need 1.4058 + * it to perform the verification. 1.4059 + */ 1.4060 + signerKey = CERT_ExtractPublicKey(signerCert); 1.4061 + if (signerKey == NULL) { 1.4062 + return SECFailure; 1.4063 + } 1.4064 + 1.4065 + /* 1.4066 + * We copy the signature data *pointer* and length, so that we can 1.4067 + * modify the length without damaging the original copy. This is a 1.4068 + * simple copy, not a dup, so no destroy/free is necessary. 1.4069 + */ 1.4070 + signedData.signature = signature->signature; 1.4071 + signedData.signatureAlgorithm = signature->signatureAlgorithm; 1.4072 + signedData.data = *tbsResponseDataDER; 1.4073 + 1.4074 + rv = CERT_VerifySignedDataWithPublicKey(&signedData, signerKey, pwArg); 1.4075 + if (rv != SECSuccess && 1.4076 + (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE || 1.4077 + PORT_GetError() == SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED)) { 1.4078 + PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE); 1.4079 + } 1.4080 + 1.4081 + if (signerKey != NULL) { 1.4082 + SECKEY_DestroyPublicKey(signerKey); 1.4083 + } 1.4084 + 1.4085 + return rv; 1.4086 +} 1.4087 + 1.4088 + 1.4089 +/* 1.4090 + * FUNCTION: CERT_VerifyOCSPResponseSignature 1.4091 + * Check the signature on an OCSP Response. Will also perform a 1.4092 + * verification of the signer's certificate. Note, however, that a 1.4093 + * successful verification does not make any statement about the 1.4094 + * signer's *authority* to provide status for the certificate(s), 1.4095 + * that must be checked individually for each certificate. 1.4096 + * INPUTS: 1.4097 + * CERTOCSPResponse *response 1.4098 + * Pointer to response structure with signature to be checked. 1.4099 + * CERTCertDBHandle *handle 1.4100 + * Pointer to CERTCertDBHandle for certificate DB to use for verification. 1.4101 + * void *pwArg 1.4102 + * Pointer to argument for password prompting, if needed. 1.4103 + * OUTPUTS: 1.4104 + * CERTCertificate **pSignerCert 1.4105 + * Pointer in which to store signer's certificate; only filled-in if 1.4106 + * non-null. 1.4107 + * RETURN: 1.4108 + * Returns SECSuccess when signature is valid, anything else means invalid. 1.4109 + * Possible errors set: 1.4110 + * SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID 1.4111 + * SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time 1.4112 + * SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found 1.4113 + * SEC_ERROR_BAD_SIGNATURE - the signature did not verify 1.4114 + * Other errors are any of the many possible failures in cert verification 1.4115 + * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when 1.4116 + * verifying the signer's cert, or low-level problems (no memory, etc.) 1.4117 + */ 1.4118 +SECStatus 1.4119 +CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response, 1.4120 + CERTCertDBHandle *handle, void *pwArg, 1.4121 + CERTCertificate **pSignerCert, 1.4122 + CERTCertificate *issuer) 1.4123 +{ 1.4124 + SECItem *tbsResponseDataDER; 1.4125 + CERTCertificate *signerCert = NULL; 1.4126 + SECStatus rv = SECFailure; 1.4127 + PRTime producedAt; 1.4128 + 1.4129 + /* ocsp_DecodeBasicOCSPResponse will fail if asn1 decoder is unable 1.4130 + * to properly decode tbsData (see the function and 1.4131 + * ocsp_BasicOCSPResponseTemplate). Thus, tbsData can not be 1.4132 + * equal to null */ 1.4133 + ocspResponseData *tbsData = ocsp_GetResponseData(response, 1.4134 + &tbsResponseDataDER); 1.4135 + ocspSignature *signature = ocsp_GetResponseSignature(response); 1.4136 + 1.4137 + if (!signature) { 1.4138 + PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE); 1.4139 + return SECFailure; 1.4140 + } 1.4141 + 1.4142 + /* 1.4143 + * If this signature has already gone through verification, just 1.4144 + * return the cached result. 1.4145 + */ 1.4146 + if (signature->wasChecked) { 1.4147 + if (signature->status == SECSuccess) { 1.4148 + if (pSignerCert != NULL) 1.4149 + *pSignerCert = CERT_DupCertificate(signature->cert); 1.4150 + } else { 1.4151 + PORT_SetError(signature->failureReason); 1.4152 + } 1.4153 + return signature->status; 1.4154 + } 1.4155 + 1.4156 + signerCert = ocsp_GetSignerCertificate(handle, tbsData, 1.4157 + signature, issuer); 1.4158 + if (signerCert == NULL) { 1.4159 + rv = SECFailure; 1.4160 + if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) { 1.4161 + /* Make the error a little more specific. */ 1.4162 + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); 1.4163 + } 1.4164 + goto finish; 1.4165 + } 1.4166 + 1.4167 + /* 1.4168 + * We could mark this true at the top of this function, or always 1.4169 + * below at "finish", but if the problem was just that we could not 1.4170 + * find the signer's cert, leave that as if the signature hasn't 1.4171 + * been checked in case a subsequent call might have better luck. 1.4172 + */ 1.4173 + signature->wasChecked = PR_TRUE; 1.4174 + 1.4175 + /* 1.4176 + * The function will also verify the signer certificate; we 1.4177 + * need to tell it *when* that certificate must be valid -- for our 1.4178 + * purposes we expect it to be valid when the response was signed. 1.4179 + * The value of "producedAt" is the signing time. 1.4180 + */ 1.4181 + rv = DER_GeneralizedTimeToTime(&producedAt, &tbsData->producedAt); 1.4182 + if (rv != SECSuccess) 1.4183 + goto finish; 1.4184 + 1.4185 + /* 1.4186 + * Just because we have a cert does not mean it is any good; check 1.4187 + * it for validity, trust and usage. 1.4188 + */ 1.4189 + if (ocsp_CertIsOCSPDefaultResponder(handle, signerCert)) { 1.4190 + rv = SECSuccess; 1.4191 + } else { 1.4192 + SECCertUsage certUsage; 1.4193 + if (CERT_IsCACert(signerCert, NULL)) { 1.4194 + certUsage = certUsageAnyCA; 1.4195 + } else { 1.4196 + certUsage = certUsageStatusResponder; 1.4197 + } 1.4198 + rv = cert_VerifyCertWithFlags(handle, signerCert, PR_TRUE, certUsage, 1.4199 + producedAt, CERT_VERIFYCERT_SKIP_OCSP, 1.4200 + pwArg, NULL); 1.4201 + if (rv != SECSuccess) { 1.4202 + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); 1.4203 + goto finish; 1.4204 + } 1.4205 + } 1.4206 + 1.4207 + rv = ocsp_VerifyResponseSignature(signerCert, signature, 1.4208 + tbsResponseDataDER, 1.4209 + pwArg); 1.4210 + 1.4211 +finish: 1.4212 + if (signature->wasChecked) 1.4213 + signature->status = rv; 1.4214 + 1.4215 + if (rv != SECSuccess) { 1.4216 + signature->failureReason = PORT_GetError(); 1.4217 + if (signerCert != NULL) 1.4218 + CERT_DestroyCertificate(signerCert); 1.4219 + } else { 1.4220 + /* 1.4221 + * Save signer's certificate in signature. 1.4222 + */ 1.4223 + signature->cert = signerCert; 1.4224 + if (pSignerCert != NULL) { 1.4225 + /* 1.4226 + * Pass pointer to signer's certificate back to our caller, 1.4227 + * who is also now responsible for destroying it. 1.4228 + */ 1.4229 + *pSignerCert = CERT_DupCertificate(signerCert); 1.4230 + } 1.4231 + } 1.4232 + 1.4233 + return rv; 1.4234 +} 1.4235 + 1.4236 +/* 1.4237 + * See if the request's certID and the single response's certID match. 1.4238 + * This can be easy or difficult, depending on whether the same hash 1.4239 + * algorithm was used. 1.4240 + */ 1.4241 +static PRBool 1.4242 +ocsp_CertIDsMatch(CERTOCSPCertID *requestCertID, 1.4243 + CERTOCSPCertID *responseCertID) 1.4244 +{ 1.4245 + PRBool match = PR_FALSE; 1.4246 + SECOidTag hashAlg; 1.4247 + SECItem *keyHash = NULL; 1.4248 + SECItem *nameHash = NULL; 1.4249 + 1.4250 + /* 1.4251 + * In order to match, they must have the same issuer and the same 1.4252 + * serial number. 1.4253 + * 1.4254 + * We just compare the easier things first. 1.4255 + */ 1.4256 + if (SECITEM_CompareItem(&requestCertID->serialNumber, 1.4257 + &responseCertID->serialNumber) != SECEqual) { 1.4258 + goto done; 1.4259 + } 1.4260 + 1.4261 + /* 1.4262 + * Make sure the "parameters" are not too bogus. Since we encoded 1.4263 + * requestCertID->hashAlgorithm, we don't need to check it. 1.4264 + */ 1.4265 + if (responseCertID->hashAlgorithm.parameters.len > 2) { 1.4266 + goto done; 1.4267 + } 1.4268 + if (SECITEM_CompareItem(&requestCertID->hashAlgorithm.algorithm, 1.4269 + &responseCertID->hashAlgorithm.algorithm) == SECEqual) { 1.4270 + /* 1.4271 + * If the hash algorithms match then we can do a simple compare 1.4272 + * of the hash values themselves. 1.4273 + */ 1.4274 + if ((SECITEM_CompareItem(&requestCertID->issuerNameHash, 1.4275 + &responseCertID->issuerNameHash) == SECEqual) 1.4276 + && (SECITEM_CompareItem(&requestCertID->issuerKeyHash, 1.4277 + &responseCertID->issuerKeyHash) == SECEqual)) { 1.4278 + match = PR_TRUE; 1.4279 + } 1.4280 + goto done; 1.4281 + } 1.4282 + 1.4283 + hashAlg = SECOID_FindOIDTag(&responseCertID->hashAlgorithm.algorithm); 1.4284 + switch (hashAlg) { 1.4285 + case SEC_OID_SHA1: 1.4286 + keyHash = &requestCertID->issuerSHA1KeyHash; 1.4287 + nameHash = &requestCertID->issuerSHA1NameHash; 1.4288 + break; 1.4289 + case SEC_OID_MD5: 1.4290 + keyHash = &requestCertID->issuerMD5KeyHash; 1.4291 + nameHash = &requestCertID->issuerMD5NameHash; 1.4292 + break; 1.4293 + case SEC_OID_MD2: 1.4294 + keyHash = &requestCertID->issuerMD2KeyHash; 1.4295 + nameHash = &requestCertID->issuerMD2NameHash; 1.4296 + break; 1.4297 + default: 1.4298 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.4299 + return PR_FALSE; 1.4300 + } 1.4301 + 1.4302 + if ((keyHash != NULL) 1.4303 + && (SECITEM_CompareItem(nameHash, 1.4304 + &responseCertID->issuerNameHash) == SECEqual) 1.4305 + && (SECITEM_CompareItem(keyHash, 1.4306 + &responseCertID->issuerKeyHash) == SECEqual)) { 1.4307 + match = PR_TRUE; 1.4308 + } 1.4309 + 1.4310 +done: 1.4311 + return match; 1.4312 +} 1.4313 + 1.4314 +/* 1.4315 + * Find the single response for the cert specified by certID. 1.4316 + * No copying is done; this just returns a pointer to the appropriate 1.4317 + * response within responses, if it is found (and null otherwise). 1.4318 + * This is fine, of course, since this function is internal-use only. 1.4319 + */ 1.4320 +static CERTOCSPSingleResponse * 1.4321 +ocsp_GetSingleResponseForCertID(CERTOCSPSingleResponse **responses, 1.4322 + CERTCertDBHandle *handle, 1.4323 + CERTOCSPCertID *certID) 1.4324 +{ 1.4325 + CERTOCSPSingleResponse *single; 1.4326 + int i; 1.4327 + 1.4328 + if (responses == NULL) 1.4329 + return NULL; 1.4330 + 1.4331 + for (i = 0; responses[i] != NULL; i++) { 1.4332 + single = responses[i]; 1.4333 + if (ocsp_CertIDsMatch(certID, single->certID)) { 1.4334 + return single; 1.4335 + } 1.4336 + } 1.4337 + 1.4338 + /* 1.4339 + * The OCSP server should have included a response even if it knew 1.4340 + * nothing about the certificate in question. Since it did not, 1.4341 + * this will make it look as if it had. 1.4342 + * 1.4343 + * XXX Should we make this a separate error to notice the server's 1.4344 + * bad behavior? 1.4345 + */ 1.4346 + PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT); 1.4347 + return NULL; 1.4348 +} 1.4349 + 1.4350 +static ocspCheckingContext * 1.4351 +ocsp_GetCheckingContext(CERTCertDBHandle *handle) 1.4352 +{ 1.4353 + CERTStatusConfig *statusConfig; 1.4354 + ocspCheckingContext *ocspcx = NULL; 1.4355 + 1.4356 + statusConfig = CERT_GetStatusConfig(handle); 1.4357 + if (statusConfig != NULL) { 1.4358 + ocspcx = statusConfig->statusContext; 1.4359 + 1.4360 + /* 1.4361 + * This is actually an internal error, because we should never 1.4362 + * have a good statusConfig without a good statusContext, too. 1.4363 + * For lack of anything better, though, we just assert and use 1.4364 + * the same error as if there were no statusConfig (set below). 1.4365 + */ 1.4366 + PORT_Assert(ocspcx != NULL); 1.4367 + } 1.4368 + 1.4369 + if (ocspcx == NULL) 1.4370 + PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED); 1.4371 + 1.4372 + return ocspcx; 1.4373 +} 1.4374 + 1.4375 +/* 1.4376 + * Return cert reference if the given signerCert is the default responder for 1.4377 + * the given certID. If not, or if any error, return NULL. 1.4378 + */ 1.4379 +static CERTCertificate * 1.4380 +ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle, CERTOCSPCertID *certID) 1.4381 +{ 1.4382 + ocspCheckingContext *ocspcx; 1.4383 + 1.4384 + ocspcx = ocsp_GetCheckingContext(handle); 1.4385 + if (ocspcx == NULL) 1.4386 + goto loser; 1.4387 + 1.4388 + /* 1.4389 + * Right now we have only one default responder. It applies to 1.4390 + * all certs when it is used, so the check is simple and certID 1.4391 + * has no bearing on the answer. Someday in the future we may 1.4392 + * allow configuration of different responders for different 1.4393 + * issuers, and then we would have to use the issuer specified 1.4394 + * in certID to determine if signerCert is the right one. 1.4395 + */ 1.4396 + if (ocspcx->useDefaultResponder) { 1.4397 + PORT_Assert(ocspcx->defaultResponderCert != NULL); 1.4398 + return ocspcx->defaultResponderCert; 1.4399 + } 1.4400 + 1.4401 +loser: 1.4402 + return NULL; 1.4403 +} 1.4404 + 1.4405 +/* 1.4406 + * Return true if the cert is one of the default responders configured for 1.4407 + * ocsp context. If not, or if any error, return false. 1.4408 + */ 1.4409 +PRBool 1.4410 +ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert) 1.4411 +{ 1.4412 + ocspCheckingContext *ocspcx; 1.4413 + 1.4414 + ocspcx = ocsp_GetCheckingContext(handle); 1.4415 + if (ocspcx == NULL) 1.4416 + return PR_FALSE; 1.4417 + 1.4418 + /* 1.4419 + * Right now we have only one default responder. It applies to 1.4420 + * all certs when it is used, so the check is simple and certID 1.4421 + * has no bearing on the answer. Someday in the future we may 1.4422 + * allow configuration of different responders for different 1.4423 + * issuers, and then we would have to use the issuer specified 1.4424 + * in certID to determine if signerCert is the right one. 1.4425 + */ 1.4426 + if (ocspcx->useDefaultResponder && 1.4427 + CERT_CompareCerts(ocspcx->defaultResponderCert, cert)) { 1.4428 + return PR_TRUE; 1.4429 + } 1.4430 + 1.4431 + return PR_FALSE; 1.4432 +} 1.4433 + 1.4434 +/* 1.4435 + * Check that the given signer certificate is authorized to sign status 1.4436 + * information for the given certID. Return true if it is, false if not 1.4437 + * (or if there is any error along the way). If false is returned because 1.4438 + * the signer is not authorized, the following error will be set: 1.4439 + * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE 1.4440 + * Other errors are low-level problems (no memory, bad database, etc.). 1.4441 + * 1.4442 + * There are three ways to be authorized. In the order in which we check, 1.4443 + * using the terms used in the OCSP spec, the signer must be one of: 1.4444 + * 1. A "trusted responder" -- it matches a local configuration 1.4445 + * of OCSP signing authority for the certificate in question. 1.4446 + * 2. The CA who issued the certificate in question. 1.4447 + * 3. A "CA designated responder", aka an "authorized responder" -- it 1.4448 + * must be represented by a special cert issued by the CA who issued 1.4449 + * the certificate in question. 1.4450 + */ 1.4451 +static PRBool 1.4452 +ocsp_AuthorizedResponderForCertID(CERTCertDBHandle *handle, 1.4453 + CERTCertificate *signerCert, 1.4454 + CERTOCSPCertID *certID, 1.4455 + PRTime thisUpdate) 1.4456 +{ 1.4457 + CERTCertificate *issuerCert = NULL, *defRespCert; 1.4458 + SECItem *keyHash = NULL; 1.4459 + SECItem *nameHash = NULL; 1.4460 + SECOidTag hashAlg; 1.4461 + PRBool keyHashEQ = PR_FALSE, nameHashEQ = PR_FALSE; 1.4462 + 1.4463 + /* 1.4464 + * Check first for a trusted responder, which overrides everything else. 1.4465 + */ 1.4466 + if ((defRespCert = ocsp_CertGetDefaultResponder(handle, certID)) && 1.4467 + CERT_CompareCerts(defRespCert, signerCert)) { 1.4468 + return PR_TRUE; 1.4469 + } 1.4470 + 1.4471 + /* 1.4472 + * In the other two cases, we need to do an issuer comparison. 1.4473 + * How we do it depends on whether the signer certificate has the 1.4474 + * special extension (for a designated responder) or not. 1.4475 + * 1.4476 + * First, lets check if signer of the response is the actual issuer 1.4477 + * of the cert. For that we will use signer cert key hash and cert subj 1.4478 + * name hash and will compare them with already calculated issuer key 1.4479 + * hash and issuer name hash. The hash algorithm is picked from response 1.4480 + * certID hash to avoid second hash calculation. 1.4481 + */ 1.4482 + 1.4483 + hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm); 1.4484 + 1.4485 + keyHash = CERT_GetSubjectPublicKeyDigest(NULL, signerCert, hashAlg, NULL); 1.4486 + if (keyHash != NULL) { 1.4487 + 1.4488 + keyHashEQ = 1.4489 + (SECITEM_CompareItem(keyHash, 1.4490 + &certID->issuerKeyHash) == SECEqual); 1.4491 + SECITEM_FreeItem(keyHash, PR_TRUE); 1.4492 + } 1.4493 + if (keyHashEQ && 1.4494 + (nameHash = CERT_GetSubjectNameDigest(NULL, signerCert, 1.4495 + hashAlg, NULL))) { 1.4496 + nameHashEQ = 1.4497 + (SECITEM_CompareItem(nameHash, 1.4498 + &certID->issuerNameHash) == SECEqual); 1.4499 + 1.4500 + SECITEM_FreeItem(nameHash, PR_TRUE); 1.4501 + if (nameHashEQ) { 1.4502 + /* The issuer of the cert is the the signer of the response */ 1.4503 + return PR_TRUE; 1.4504 + } 1.4505 + } 1.4506 + 1.4507 + 1.4508 + keyHashEQ = PR_FALSE; 1.4509 + nameHashEQ = PR_FALSE; 1.4510 + 1.4511 + if (!ocsp_CertIsOCSPDesignatedResponder(signerCert)) { 1.4512 + PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); 1.4513 + return PR_FALSE; 1.4514 + } 1.4515 + 1.4516 + /* 1.4517 + * The signer is a designated responder. Its issuer must match 1.4518 + * the issuer of the cert being checked. 1.4519 + */ 1.4520 + issuerCert = CERT_FindCertIssuer(signerCert, thisUpdate, 1.4521 + certUsageAnyCA); 1.4522 + if (issuerCert == NULL) { 1.4523 + /* 1.4524 + * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone, 1.4525 + * but the following will give slightly more information. 1.4526 + * Once we have an error stack, things will be much better. 1.4527 + */ 1.4528 + PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); 1.4529 + return PR_FALSE; 1.4530 + } 1.4531 + 1.4532 + keyHash = CERT_GetSubjectPublicKeyDigest(NULL, issuerCert, hashAlg, NULL); 1.4533 + nameHash = CERT_GetSubjectNameDigest(NULL, issuerCert, hashAlg, NULL); 1.4534 + 1.4535 + CERT_DestroyCertificate(issuerCert); 1.4536 + 1.4537 + if (keyHash != NULL && nameHash != NULL) { 1.4538 + keyHashEQ = 1.4539 + (SECITEM_CompareItem(keyHash, 1.4540 + &certID->issuerKeyHash) == SECEqual); 1.4541 + 1.4542 + nameHashEQ = 1.4543 + (SECITEM_CompareItem(nameHash, 1.4544 + &certID->issuerNameHash) == SECEqual); 1.4545 + } 1.4546 + 1.4547 + if (keyHash) { 1.4548 + SECITEM_FreeItem(keyHash, PR_TRUE); 1.4549 + } 1.4550 + if (nameHash) { 1.4551 + SECITEM_FreeItem(nameHash, PR_TRUE); 1.4552 + } 1.4553 + 1.4554 + if (keyHashEQ && nameHashEQ) { 1.4555 + return PR_TRUE; 1.4556 + } 1.4557 + 1.4558 + PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); 1.4559 + return PR_FALSE; 1.4560 +} 1.4561 + 1.4562 +/* 1.4563 + * We need to check that a responder gives us "recent" information. 1.4564 + * Since a responder can pre-package responses, we need to pick an amount 1.4565 + * of time that is acceptable to us, and reject any response that is 1.4566 + * older than that. 1.4567 + * 1.4568 + * XXX This *should* be based on some configuration parameter, so that 1.4569 + * different usages could specify exactly what constitutes "sufficiently 1.4570 + * recent". But that is not going to happen right away. For now, we 1.4571 + * want something from within the last 24 hours. This macro defines that 1.4572 + * number in seconds. 1.4573 + */ 1.4574 +#define OCSP_ALLOWABLE_LAPSE_SECONDS (24L * 60L * 60L) 1.4575 + 1.4576 +static PRBool 1.4577 +ocsp_TimeIsRecent(PRTime checkTime) 1.4578 +{ 1.4579 + PRTime now = PR_Now(); 1.4580 + PRTime lapse, tmp; 1.4581 + 1.4582 + LL_I2L(lapse, OCSP_ALLOWABLE_LAPSE_SECONDS); 1.4583 + LL_I2L(tmp, PR_USEC_PER_SEC); 1.4584 + LL_MUL(lapse, lapse, tmp); /* allowable lapse in microseconds */ 1.4585 + 1.4586 + LL_ADD(checkTime, checkTime, lapse); 1.4587 + if (LL_CMP(now, >, checkTime)) 1.4588 + return PR_FALSE; 1.4589 + 1.4590 + return PR_TRUE; 1.4591 +} 1.4592 + 1.4593 +#define OCSP_SLOP (5L*60L) /* OCSP responses are allowed to be 5 minutes 1.4594 + in the future by default */ 1.4595 + 1.4596 +static PRUint32 ocspsloptime = OCSP_SLOP; /* seconds */ 1.4597 + 1.4598 +/* 1.4599 + * If an old response contains the revoked certificate status, we want 1.4600 + * to return SECSuccess so the response will be used. 1.4601 + */ 1.4602 +static SECStatus 1.4603 +ocsp_HandleOldSingleResponse(CERTOCSPSingleResponse *single, PRTime time) 1.4604 +{ 1.4605 + SECStatus rv; 1.4606 + ocspCertStatus *status = single->certStatus; 1.4607 + if (status->certStatusType == ocspCertStatus_revoked) { 1.4608 + rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time); 1.4609 + if (rv != SECSuccess && 1.4610 + PORT_GetError() == SEC_ERROR_REVOKED_CERTIFICATE) { 1.4611 + /* 1.4612 + * Return SECSuccess now. The subsequent ocsp_CertRevokedAfter 1.4613 + * call in ocsp_CertHasGoodStatus will cause 1.4614 + * ocsp_CertHasGoodStatus to fail with 1.4615 + * SEC_ERROR_REVOKED_CERTIFICATE. 1.4616 + */ 1.4617 + return SECSuccess; 1.4618 + } 1.4619 + 1.4620 + } 1.4621 + PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE); 1.4622 + return SECFailure; 1.4623 +} 1.4624 + 1.4625 +/* 1.4626 + * Check that this single response is okay. A return of SECSuccess means: 1.4627 + * 1. The signer (represented by "signerCert") is authorized to give status 1.4628 + * for the cert represented by the individual response in "single". 1.4629 + * 2. The value of thisUpdate is earlier than now. 1.4630 + * 3. The value of producedAt is later than or the same as thisUpdate. 1.4631 + * 4. If nextUpdate is given: 1.4632 + * - The value of nextUpdate is later than now. 1.4633 + * - The value of producedAt is earlier than nextUpdate. 1.4634 + * Else if no nextUpdate: 1.4635 + * - The value of thisUpdate is fairly recent. 1.4636 + * - The value of producedAt is fairly recent. 1.4637 + * However we do not need to perform an explicit check for this last 1.4638 + * constraint because it is already guaranteed by checking that 1.4639 + * producedAt is later than thisUpdate and thisUpdate is recent. 1.4640 + * Oh, and any responder is "authorized" to say that a cert is unknown to it. 1.4641 + * 1.4642 + * If any of those checks fail, SECFailure is returned and an error is set: 1.4643 + * SEC_ERROR_OCSP_FUTURE_RESPONSE 1.4644 + * SEC_ERROR_OCSP_OLD_RESPONSE 1.4645 + * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE 1.4646 + * Other errors are low-level problems (no memory, bad database, etc.). 1.4647 + */ 1.4648 +static SECStatus 1.4649 +ocsp_VerifySingleResponse(CERTOCSPSingleResponse *single, 1.4650 + CERTCertDBHandle *handle, 1.4651 + CERTCertificate *signerCert, 1.4652 + PRTime producedAt) 1.4653 +{ 1.4654 + CERTOCSPCertID *certID = single->certID; 1.4655 + PRTime now, thisUpdate, nextUpdate, tmstamp, tmp; 1.4656 + SECStatus rv; 1.4657 + 1.4658 + OCSP_TRACE(("OCSP ocsp_VerifySingleResponse, nextUpdate: %d\n", 1.4659 + ((single->nextUpdate) != 0))); 1.4660 + /* 1.4661 + * If all the responder said was that the given cert was unknown to it, 1.4662 + * that is a valid response. Not very interesting to us, of course, 1.4663 + * but all this function is concerned with is validity of the response, 1.4664 + * not the status of the cert. 1.4665 + */ 1.4666 + PORT_Assert(single->certStatus != NULL); 1.4667 + if (single->certStatus->certStatusType == ocspCertStatus_unknown) 1.4668 + return SECSuccess; 1.4669 + 1.4670 + /* 1.4671 + * We need to extract "thisUpdate" for use below and to pass along 1.4672 + * to AuthorizedResponderForCertID in case it needs it for doing an 1.4673 + * issuer look-up. 1.4674 + */ 1.4675 + rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate); 1.4676 + if (rv != SECSuccess) 1.4677 + return rv; 1.4678 + 1.4679 + /* 1.4680 + * First confirm that signerCert is authorized to give this status. 1.4681 + */ 1.4682 + if (ocsp_AuthorizedResponderForCertID(handle, signerCert, certID, 1.4683 + thisUpdate) != PR_TRUE) 1.4684 + return SECFailure; 1.4685 + 1.4686 + /* 1.4687 + * Now check the time stuff, as described above. 1.4688 + */ 1.4689 + now = PR_Now(); 1.4690 + /* allow slop time for future response */ 1.4691 + LL_UI2L(tmstamp, ocspsloptime); /* get slop time in seconds */ 1.4692 + LL_UI2L(tmp, PR_USEC_PER_SEC); 1.4693 + LL_MUL(tmp, tmstamp, tmp); /* convert the slop time to PRTime */ 1.4694 + LL_ADD(tmstamp, tmp, now); /* add current time to it */ 1.4695 + 1.4696 + if (LL_CMP(thisUpdate, >, tmstamp) || LL_CMP(producedAt, <, thisUpdate)) { 1.4697 + PORT_SetError(SEC_ERROR_OCSP_FUTURE_RESPONSE); 1.4698 + return SECFailure; 1.4699 + } 1.4700 + if (single->nextUpdate != NULL) { 1.4701 + rv = DER_GeneralizedTimeToTime(&nextUpdate, single->nextUpdate); 1.4702 + if (rv != SECSuccess) 1.4703 + return rv; 1.4704 + 1.4705 + LL_ADD(tmp, tmp, nextUpdate); 1.4706 + if (LL_CMP(tmp, <, now) || LL_CMP(producedAt, >, nextUpdate)) 1.4707 + return ocsp_HandleOldSingleResponse(single, now); 1.4708 + } else if (ocsp_TimeIsRecent(thisUpdate) != PR_TRUE) { 1.4709 + return ocsp_HandleOldSingleResponse(single, now); 1.4710 + } 1.4711 + 1.4712 + return SECSuccess; 1.4713 +} 1.4714 + 1.4715 + 1.4716 +/* 1.4717 + * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation 1.4718 + * Get the value of the URI of the OCSP responder for the given cert. 1.4719 + * This is found in the (optional) Authority Information Access extension 1.4720 + * in the cert. 1.4721 + * INPUTS: 1.4722 + * CERTCertificate *cert 1.4723 + * The certificate being examined. 1.4724 + * RETURN: 1.4725 + * char * 1.4726 + * A copy of the URI for the OCSP method, if found. If either the 1.4727 + * extension is not present or it does not contain an entry for OCSP, 1.4728 + * SEC_ERROR_CERT_BAD_ACCESS_LOCATION will be set and a NULL returned. 1.4729 + * Any other error will also result in a NULL being returned. 1.4730 + * 1.4731 + * This result should be freed (via PORT_Free) when no longer in use. 1.4732 + */ 1.4733 +char * 1.4734 +CERT_GetOCSPAuthorityInfoAccessLocation(const CERTCertificate *cert) 1.4735 +{ 1.4736 + CERTGeneralName *locname = NULL; 1.4737 + SECItem *location = NULL; 1.4738 + SECItem *encodedAuthInfoAccess = NULL; 1.4739 + CERTAuthInfoAccess **authInfoAccess = NULL; 1.4740 + char *locURI = NULL; 1.4741 + PLArenaPool *arena = NULL; 1.4742 + SECStatus rv; 1.4743 + int i; 1.4744 + 1.4745 + /* 1.4746 + * Allocate this one from the heap because it will get filled in 1.4747 + * by CERT_FindCertExtension which will also allocate from the heap, 1.4748 + * and we can free the entire thing on our way out. 1.4749 + */ 1.4750 + encodedAuthInfoAccess = SECITEM_AllocItem(NULL, NULL, 0); 1.4751 + if (encodedAuthInfoAccess == NULL) 1.4752 + goto loser; 1.4753 + 1.4754 + rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS, 1.4755 + encodedAuthInfoAccess); 1.4756 + if (rv == SECFailure) { 1.4757 + PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); 1.4758 + goto loser; 1.4759 + } 1.4760 + 1.4761 + /* 1.4762 + * The rest of the things allocated in the routine will come out of 1.4763 + * this arena, which is temporary just for us to decode and get at the 1.4764 + * AIA extension. The whole thing will be destroyed on our way out, 1.4765 + * after we have copied the location string (url) itself (if found). 1.4766 + */ 1.4767 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.4768 + if (arena == NULL) 1.4769 + goto loser; 1.4770 + 1.4771 + authInfoAccess = CERT_DecodeAuthInfoAccessExtension(arena, 1.4772 + encodedAuthInfoAccess); 1.4773 + if (authInfoAccess == NULL) 1.4774 + goto loser; 1.4775 + 1.4776 + for (i = 0; authInfoAccess[i] != NULL; i++) { 1.4777 + if (SECOID_FindOIDTag(&authInfoAccess[i]->method) == SEC_OID_PKIX_OCSP) 1.4778 + locname = authInfoAccess[i]->location; 1.4779 + } 1.4780 + 1.4781 + /* 1.4782 + * If we found an AIA extension, but it did not include an OCSP method, 1.4783 + * that should look to our caller as if we did not find the extension 1.4784 + * at all, because it is only an OCSP method that we care about. 1.4785 + * So set the same error that would be set if the AIA extension was 1.4786 + * not there at all. 1.4787 + */ 1.4788 + if (locname == NULL) { 1.4789 + PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); 1.4790 + goto loser; 1.4791 + } 1.4792 + 1.4793 + /* 1.4794 + * The following is just a pointer back into locname (i.e. not a copy); 1.4795 + * thus it should not be freed. 1.4796 + */ 1.4797 + location = CERT_GetGeneralNameByType(locname, certURI, PR_FALSE); 1.4798 + if (location == NULL) { 1.4799 + /* 1.4800 + * XXX Appears that CERT_GetGeneralNameByType does not set an 1.4801 + * error if there is no name by that type. For lack of anything 1.4802 + * better, act as if the extension was not found. In the future 1.4803 + * this should probably be something more like the extension was 1.4804 + * badly formed. 1.4805 + */ 1.4806 + PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); 1.4807 + goto loser; 1.4808 + } 1.4809 + 1.4810 + /* 1.4811 + * That location is really a string, but it has a specified length 1.4812 + * without a null-terminator. We need a real string that does have 1.4813 + * a null-terminator, and we need a copy of it anyway to return to 1.4814 + * our caller -- so allocate and copy. 1.4815 + */ 1.4816 + locURI = PORT_Alloc(location->len + 1); 1.4817 + if (locURI == NULL) { 1.4818 + goto loser; 1.4819 + } 1.4820 + PORT_Memcpy(locURI, location->data, location->len); 1.4821 + locURI[location->len] = '\0'; 1.4822 + 1.4823 +loser: 1.4824 + if (arena != NULL) 1.4825 + PORT_FreeArena(arena, PR_FALSE); 1.4826 + 1.4827 + if (encodedAuthInfoAccess != NULL) 1.4828 + SECITEM_FreeItem(encodedAuthInfoAccess, PR_TRUE); 1.4829 + 1.4830 + return locURI; 1.4831 +} 1.4832 + 1.4833 + 1.4834 +/* 1.4835 + * Figure out where we should go to find out the status of the given cert 1.4836 + * via OCSP. If allowed to use a default responder uri and a default 1.4837 + * responder is set up, then that is our answer. 1.4838 + * If not, see if the certificate has an Authority Information Access (AIA) 1.4839 + * extension for OCSP, and return the value of that. Otherwise return NULL. 1.4840 + * We also let our caller know whether or not the responder chosen was 1.4841 + * a default responder or not through the output variable isDefault; 1.4842 + * its value has no meaning unless a good (non-null) value is returned 1.4843 + * for the location. 1.4844 + * 1.4845 + * The result needs to be freed (PORT_Free) when no longer in use. 1.4846 + */ 1.4847 +char * 1.4848 +ocsp_GetResponderLocation(CERTCertDBHandle *handle, CERTCertificate *cert, 1.4849 + PRBool canUseDefault, PRBool *isDefault) 1.4850 +{ 1.4851 + ocspCheckingContext *ocspcx = NULL; 1.4852 + char *ocspUrl = NULL; 1.4853 + 1.4854 + if (canUseDefault) { 1.4855 + ocspcx = ocsp_GetCheckingContext(handle); 1.4856 + } 1.4857 + if (ocspcx != NULL && ocspcx->useDefaultResponder) { 1.4858 + /* 1.4859 + * A default responder wins out, if specified. 1.4860 + * XXX Someday this may be a more complicated determination based 1.4861 + * on the cert's issuer. (That is, we could have different default 1.4862 + * responders configured for different issuers.) 1.4863 + */ 1.4864 + PORT_Assert(ocspcx->defaultResponderURI != NULL); 1.4865 + *isDefault = PR_TRUE; 1.4866 + return (PORT_Strdup(ocspcx->defaultResponderURI)); 1.4867 + } 1.4868 + 1.4869 + /* 1.4870 + * No default responder set up, so go see if we can find an AIA 1.4871 + * extension that has a value for OCSP, and get the url from that. 1.4872 + */ 1.4873 + *isDefault = PR_FALSE; 1.4874 + ocspUrl = CERT_GetOCSPAuthorityInfoAccessLocation(cert); 1.4875 + if (!ocspUrl) { 1.4876 + CERT_StringFromCertFcn altFcn; 1.4877 + 1.4878 + PR_EnterMonitor(OCSP_Global.monitor); 1.4879 + altFcn = OCSP_Global.alternateOCSPAIAFcn; 1.4880 + PR_ExitMonitor(OCSP_Global.monitor); 1.4881 + if (altFcn) { 1.4882 + ocspUrl = (*altFcn)(cert); 1.4883 + if (ocspUrl) 1.4884 + *isDefault = PR_TRUE; 1.4885 + } 1.4886 + } 1.4887 + return ocspUrl; 1.4888 +} 1.4889 + 1.4890 +/* 1.4891 + * Return SECSuccess if the cert was revoked *after* "time", 1.4892 + * SECFailure otherwise. 1.4893 + */ 1.4894 +static SECStatus 1.4895 +ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time) 1.4896 +{ 1.4897 + PRTime revokedTime; 1.4898 + SECStatus rv; 1.4899 + 1.4900 + rv = DER_GeneralizedTimeToTime(&revokedTime, &revokedInfo->revocationTime); 1.4901 + if (rv != SECSuccess) 1.4902 + return rv; 1.4903 + 1.4904 + /* 1.4905 + * Set the error even if we will return success; someone might care. 1.4906 + */ 1.4907 + PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); 1.4908 + 1.4909 + if (LL_CMP(revokedTime, >, time)) 1.4910 + return SECSuccess; 1.4911 + 1.4912 + return SECFailure; 1.4913 +} 1.4914 + 1.4915 +/* 1.4916 + * See if the cert represented in the single response had a good status 1.4917 + * at the specified time. 1.4918 + */ 1.4919 +SECStatus 1.4920 +ocsp_CertHasGoodStatus(ocspCertStatus *status, PRTime time) 1.4921 +{ 1.4922 + SECStatus rv; 1.4923 + switch (status->certStatusType) { 1.4924 + case ocspCertStatus_good: 1.4925 + rv = SECSuccess; 1.4926 + break; 1.4927 + case ocspCertStatus_revoked: 1.4928 + rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time); 1.4929 + break; 1.4930 + case ocspCertStatus_unknown: 1.4931 + PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT); 1.4932 + rv = SECFailure; 1.4933 + break; 1.4934 + case ocspCertStatus_other: 1.4935 + default: 1.4936 + PORT_Assert(0); 1.4937 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); 1.4938 + rv = SECFailure; 1.4939 + break; 1.4940 + } 1.4941 + return rv; 1.4942 +} 1.4943 + 1.4944 +static SECStatus 1.4945 +ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse *single, 1.4946 + PRTime time) 1.4947 +{ 1.4948 + return ocsp_CertHasGoodStatus(single->certStatus, time); 1.4949 +} 1.4950 + 1.4951 +/* SECFailure means the arguments were invalid. 1.4952 + * On SECSuccess, the out parameters contain the OCSP status. 1.4953 + * rvOcsp contains the overall result of the OCSP operation. 1.4954 + * Depending on input parameter ignoreGlobalOcspFailureSetting, 1.4955 + * a soft failure might be converted into *rvOcsp=SECSuccess. 1.4956 + * If the cached attempt to obtain OCSP information had resulted 1.4957 + * in a failure, missingResponseError shows the error code of 1.4958 + * that failure. 1.4959 + * cacheFreshness is ocspMissing if no entry was found, 1.4960 + * ocspFresh if a fresh entry was found, or 1.4961 + * ocspStale if a stale entry was found. 1.4962 + */ 1.4963 +SECStatus 1.4964 +ocsp_GetCachedOCSPResponseStatus(CERTOCSPCertID *certID, 1.4965 + PRTime time, 1.4966 + PRBool ignoreGlobalOcspFailureSetting, 1.4967 + SECStatus *rvOcsp, 1.4968 + SECErrorCodes *missingResponseError, 1.4969 + OCSPFreshness *cacheFreshness) 1.4970 +{ 1.4971 + OCSPCacheItem *cacheItem = NULL; 1.4972 + 1.4973 + if (!certID || !missingResponseError || !rvOcsp || !cacheFreshness) { 1.4974 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.4975 + return SECFailure; 1.4976 + } 1.4977 + *rvOcsp = SECFailure; 1.4978 + *missingResponseError = 0; 1.4979 + *cacheFreshness = ocspMissing; 1.4980 + 1.4981 + PR_EnterMonitor(OCSP_Global.monitor); 1.4982 + cacheItem = ocsp_FindCacheEntry(&OCSP_Global.cache, certID); 1.4983 + if (cacheItem) { 1.4984 + *cacheFreshness = ocsp_IsCacheItemFresh(cacheItem) ? ocspFresh 1.4985 + : ocspStale; 1.4986 + /* having an arena means, we have a cached certStatus */ 1.4987 + if (cacheItem->certStatusArena) { 1.4988 + *rvOcsp = ocsp_CertHasGoodStatus(&cacheItem->certStatus, time); 1.4989 + if (*rvOcsp != SECSuccess) { 1.4990 + *missingResponseError = PORT_GetError(); 1.4991 + } 1.4992 + } else { 1.4993 + /* 1.4994 + * No status cached, the previous attempt failed. 1.4995 + * If OCSP is required, we never decide based on a failed attempt 1.4996 + * However, if OCSP is optional, a recent OCSP failure is 1.4997 + * an allowed good state. 1.4998 + */ 1.4999 + if (*cacheFreshness == ocspFresh && 1.5000 + !ignoreGlobalOcspFailureSetting && 1.5001 + OCSP_Global.ocspFailureMode == 1.5002 + ocspMode_FailureIsNotAVerificationFailure) { 1.5003 + *rvOcsp = SECSuccess; 1.5004 + } 1.5005 + *missingResponseError = cacheItem->missingResponseError; 1.5006 + } 1.5007 + } 1.5008 + PR_ExitMonitor(OCSP_Global.monitor); 1.5009 + return SECSuccess; 1.5010 +} 1.5011 + 1.5012 +PRBool 1.5013 +ocsp_FetchingFailureIsVerificationFailure(void) 1.5014 +{ 1.5015 + PRBool isFailure; 1.5016 + 1.5017 + PR_EnterMonitor(OCSP_Global.monitor); 1.5018 + isFailure = 1.5019 + OCSP_Global.ocspFailureMode == ocspMode_FailureIsVerificationFailure; 1.5020 + PR_ExitMonitor(OCSP_Global.monitor); 1.5021 + return isFailure; 1.5022 +} 1.5023 + 1.5024 +/* 1.5025 + * FUNCTION: CERT_CheckOCSPStatus 1.5026 + * Checks the status of a certificate via OCSP. Will only check status for 1.5027 + * a certificate that has an AIA (Authority Information Access) extension 1.5028 + * for OCSP *or* when a "default responder" is specified and enabled. 1.5029 + * (If no AIA extension for OCSP and no default responder in place, the 1.5030 + * cert is considered to have a good status and SECSuccess is returned.) 1.5031 + * INPUTS: 1.5032 + * CERTCertDBHandle *handle 1.5033 + * certificate DB of the cert that is being checked 1.5034 + * CERTCertificate *cert 1.5035 + * the certificate being checked 1.5036 + * XXX in the long term also need a boolean parameter that specifies 1.5037 + * whether to check the cert chain, as well; for now we check only 1.5038 + * the leaf (the specified certificate) 1.5039 + * PRTime time 1.5040 + * time for which status is to be determined 1.5041 + * void *pwArg 1.5042 + * argument for password prompting, if needed 1.5043 + * RETURN: 1.5044 + * Returns SECSuccess if an approved OCSP responder "knows" the cert 1.5045 + * *and* returns a non-revoked status for it; SECFailure otherwise, 1.5046 + * with an error set describing the reason: 1.5047 + * 1.5048 + * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE 1.5049 + * SEC_ERROR_OCSP_FUTURE_RESPONSE 1.5050 + * SEC_ERROR_OCSP_MALFORMED_REQUEST 1.5051 + * SEC_ERROR_OCSP_MALFORMED_RESPONSE 1.5052 + * SEC_ERROR_OCSP_OLD_RESPONSE 1.5053 + * SEC_ERROR_OCSP_REQUEST_NEEDS_SIG 1.5054 + * SEC_ERROR_OCSP_SERVER_ERROR 1.5055 + * SEC_ERROR_OCSP_TRY_SERVER_LATER 1.5056 + * SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST 1.5057 + * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE 1.5058 + * SEC_ERROR_OCSP_UNKNOWN_CERT 1.5059 + * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS 1.5060 + * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE 1.5061 + * 1.5062 + * SEC_ERROR_BAD_SIGNATURE 1.5063 + * SEC_ERROR_CERT_BAD_ACCESS_LOCATION 1.5064 + * SEC_ERROR_INVALID_TIME 1.5065 + * SEC_ERROR_REVOKED_CERTIFICATE 1.5066 + * SEC_ERROR_UNKNOWN_ISSUER 1.5067 + * SEC_ERROR_UNKNOWN_SIGNER 1.5068 + * 1.5069 + * Other errors are any of the many possible failures in cert verification 1.5070 + * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when 1.5071 + * verifying the signer's cert, or low-level problems (error allocating 1.5072 + * memory, error performing ASN.1 decoding, etc.). 1.5073 + */ 1.5074 +SECStatus 1.5075 +CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert, 1.5076 + PRTime time, void *pwArg) 1.5077 +{ 1.5078 + CERTOCSPCertID *certID; 1.5079 + PRBool certIDWasConsumed = PR_FALSE; 1.5080 + SECStatus rv; 1.5081 + SECStatus rvOcsp; 1.5082 + SECErrorCodes cachedErrorCode; 1.5083 + OCSPFreshness cachedResponseFreshness; 1.5084 + 1.5085 + OCSP_TRACE_CERT(cert); 1.5086 + OCSP_TRACE_TIME("## requested validity time:", time); 1.5087 + 1.5088 + certID = CERT_CreateOCSPCertID(cert, time); 1.5089 + if (!certID) 1.5090 + return SECFailure; 1.5091 + rv = ocsp_GetCachedOCSPResponseStatus( 1.5092 + certID, time, PR_FALSE, /* ignoreGlobalOcspFailureSetting */ 1.5093 + &rvOcsp, &cachedErrorCode, &cachedResponseFreshness); 1.5094 + if (rv != SECSuccess) { 1.5095 + CERT_DestroyOCSPCertID(certID); 1.5096 + return SECFailure; 1.5097 + } 1.5098 + if (cachedResponseFreshness == ocspFresh) { 1.5099 + CERT_DestroyOCSPCertID(certID); 1.5100 + if (rvOcsp != SECSuccess) { 1.5101 + PORT_SetError(cachedErrorCode); 1.5102 + } 1.5103 + return rvOcsp; 1.5104 + } 1.5105 + 1.5106 + rv = ocsp_GetOCSPStatusFromNetwork(handle, certID, cert, time, pwArg, 1.5107 + &certIDWasConsumed, 1.5108 + &rvOcsp); 1.5109 + if (rv != SECSuccess) { 1.5110 + PRErrorCode err = PORT_GetError(); 1.5111 + if (ocsp_FetchingFailureIsVerificationFailure()) { 1.5112 + PORT_SetError(err); 1.5113 + rvOcsp = SECFailure; 1.5114 + } else if (cachedResponseFreshness == ocspStale && 1.5115 + (cachedErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT || 1.5116 + cachedErrorCode == SEC_ERROR_REVOKED_CERTIFICATE)) { 1.5117 + /* If we couldn't get a response for a certificate that the OCSP 1.5118 + * responder previously told us was bad, then assume it is still 1.5119 + * bad until we hear otherwise, as it is very unlikely that the 1.5120 + * certificate status has changed from "revoked" to "good" and it 1.5121 + * is also unlikely that the certificate status has changed from 1.5122 + * "unknown" to "good", except for some buggy OCSP responders. 1.5123 + */ 1.5124 + PORT_SetError(cachedErrorCode); 1.5125 + rvOcsp = SECFailure; 1.5126 + } else { 1.5127 + rvOcsp = SECSuccess; 1.5128 + } 1.5129 + } 1.5130 + if (!certIDWasConsumed) { 1.5131 + CERT_DestroyOCSPCertID(certID); 1.5132 + } 1.5133 + return rvOcsp; 1.5134 +} 1.5135 + 1.5136 +/* 1.5137 + * FUNCTION: CERT_CacheOCSPResponseFromSideChannel 1.5138 + * First, this function checks the OCSP cache to see if a good response 1.5139 + * for the given certificate already exists. If it does, then the function 1.5140 + * returns successfully. 1.5141 + * 1.5142 + * If not, then it validates that the given OCSP response is a valid, 1.5143 + * good response for the given certificate and inserts it into the 1.5144 + * cache. 1.5145 + * 1.5146 + * This function is intended for use when OCSP responses are provided via a 1.5147 + * side-channel, i.e. TLS OCSP stapling (a.k.a. the status_request extension). 1.5148 + * 1.5149 + * INPUTS: 1.5150 + * CERTCertDBHandle *handle 1.5151 + * certificate DB of the cert that is being checked 1.5152 + * CERTCertificate *cert 1.5153 + * the certificate being checked 1.5154 + * PRTime time 1.5155 + * time for which status is to be determined 1.5156 + * SECItem *encodedResponse 1.5157 + * the DER encoded bytes of the OCSP response 1.5158 + * void *pwArg 1.5159 + * argument for password prompting, if needed 1.5160 + * RETURN: 1.5161 + * SECSuccess if the cert was found in the cache, or if the OCSP response was 1.5162 + * found to be valid and inserted into the cache. SECFailure otherwise. 1.5163 + */ 1.5164 +SECStatus 1.5165 +CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle, 1.5166 + CERTCertificate *cert, 1.5167 + PRTime time, 1.5168 + const SECItem *encodedResponse, 1.5169 + void *pwArg) 1.5170 +{ 1.5171 + CERTOCSPCertID *certID = NULL; 1.5172 + PRBool certIDWasConsumed = PR_FALSE; 1.5173 + SECStatus rv = SECFailure; 1.5174 + SECStatus rvOcsp = SECFailure; 1.5175 + SECErrorCodes dummy_error_code; /* we ignore this */ 1.5176 + CERTOCSPResponse *decodedResponse = NULL; 1.5177 + CERTOCSPSingleResponse *singleResponse = NULL; 1.5178 + OCSPFreshness freshness; 1.5179 + 1.5180 + /* The OCSP cache can be in three states regarding this certificate: 1.5181 + * + Good (cached, timely, 'good' response, or revoked in the future) 1.5182 + * + Revoked (cached, timely, but doesn't fit in the last category) 1.5183 + * + Miss (no knowledge) 1.5184 + * 1.5185 + * Likewise, the side-channel information can be 1.5186 + * + Good (timely, 'good' response, or revoked in the future) 1.5187 + * + Revoked (timely, but doesn't fit in the last category) 1.5188 + * + Invalid (bad syntax, bad signature, not timely etc) 1.5189 + * 1.5190 + * The common case is that the cache result is Good and so is the 1.5191 + * side-channel information. We want to save processing time in this case 1.5192 + * so we say that any time we see a Good result from the cache we return 1.5193 + * early. 1.5194 + * 1.5195 + * Cache result 1.5196 + * | Good Revoked Miss 1.5197 + * ---+-------------------------------------------- 1.5198 + * G | noop Cache more Cache it 1.5199 + * S | recent result 1.5200 + * i | 1.5201 + * d | 1.5202 + * e | 1.5203 + * R | noop Cache more Cache it 1.5204 + * C | recent result 1.5205 + * h | 1.5206 + * a | 1.5207 + * n | 1.5208 + * n I | noop Noop Noop 1.5209 + * e | 1.5210 + * l | 1.5211 + * 1.5212 + * When we fetch from the network we might choose to cache a negative 1.5213 + * result when the response is invalid. This saves us hammering, uselessly, 1.5214 + * at a broken responder. However, side channels are commonly attacker 1.5215 + * controlled and so we must not cache a negative result for an Invalid 1.5216 + * side channel. 1.5217 + */ 1.5218 + 1.5219 + if (!cert || !encodedResponse) { 1.5220 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5221 + return SECFailure; 1.5222 + } 1.5223 + certID = CERT_CreateOCSPCertID(cert, time); 1.5224 + if (!certID) 1.5225 + return SECFailure; 1.5226 + 1.5227 + /* We pass PR_TRUE for ignoreGlobalOcspFailureSetting so that a cached 1.5228 + * error entry is not interpreted as being a 'Good' entry here. 1.5229 + */ 1.5230 + rv = ocsp_GetCachedOCSPResponseStatus( 1.5231 + certID, time, PR_TRUE, /* ignoreGlobalOcspFailureSetting */ 1.5232 + &rvOcsp, &dummy_error_code, &freshness); 1.5233 + if (rv == SECSuccess && rvOcsp == SECSuccess && freshness == ocspFresh) { 1.5234 + /* The cached value is good. We don't want to waste time validating 1.5235 + * this OCSP response. This is the first column in the table above. */ 1.5236 + CERT_DestroyOCSPCertID(certID); 1.5237 + return rv; 1.5238 + } 1.5239 + 1.5240 + /* The logic for caching the more recent response is handled in 1.5241 + * ocsp_CacheSingleResponse. */ 1.5242 + 1.5243 + rv = ocsp_GetDecodedVerifiedSingleResponseForID(handle, certID, cert, 1.5244 + time, pwArg, 1.5245 + encodedResponse, 1.5246 + &decodedResponse, 1.5247 + &singleResponse); 1.5248 + if (rv == SECSuccess) { 1.5249 + rvOcsp = ocsp_SingleResponseCertHasGoodStatus(singleResponse, time); 1.5250 + /* Cache any valid singleResponse, regardless of status. */ 1.5251 + ocsp_CacheSingleResponse(certID, singleResponse, &certIDWasConsumed); 1.5252 + } 1.5253 + if (decodedResponse) { 1.5254 + CERT_DestroyOCSPResponse(decodedResponse); 1.5255 + } 1.5256 + if (!certIDWasConsumed) { 1.5257 + CERT_DestroyOCSPCertID(certID); 1.5258 + } 1.5259 + return rv == SECSuccess ? rvOcsp : rv; 1.5260 +} 1.5261 + 1.5262 +/* 1.5263 + * Status in *certIDWasConsumed will always be correct, regardless of 1.5264 + * return value. 1.5265 + */ 1.5266 +static SECStatus 1.5267 +ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 1.5268 + CERTOCSPCertID *certID, 1.5269 + CERTCertificate *cert, 1.5270 + PRTime time, 1.5271 + void *pwArg, 1.5272 + PRBool *certIDWasConsumed, 1.5273 + SECStatus *rv_ocsp) 1.5274 +{ 1.5275 + char *location = NULL; 1.5276 + PRBool locationIsDefault; 1.5277 + SECItem *encodedResponse = NULL; 1.5278 + CERTOCSPRequest *request = NULL; 1.5279 + SECStatus rv = SECFailure; 1.5280 + 1.5281 + CERTOCSPResponse *decodedResponse = NULL; 1.5282 + CERTOCSPSingleResponse *singleResponse = NULL; 1.5283 + enum { stageGET, stagePOST } currentStage; 1.5284 + PRBool retry = PR_FALSE; 1.5285 + 1.5286 + if (!certIDWasConsumed || !rv_ocsp) { 1.5287 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5288 + return SECFailure; 1.5289 + } 1.5290 + *certIDWasConsumed = PR_FALSE; 1.5291 + *rv_ocsp = SECFailure; 1.5292 + 1.5293 + if (!OCSP_Global.monitor) { 1.5294 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.5295 + return SECFailure; 1.5296 + } 1.5297 + PR_EnterMonitor(OCSP_Global.monitor); 1.5298 + if (OCSP_Global.forcePost) { 1.5299 + currentStage = stagePOST; 1.5300 + } else { 1.5301 + currentStage = stageGET; 1.5302 + } 1.5303 + PR_ExitMonitor(OCSP_Global.monitor); 1.5304 + 1.5305 + /* 1.5306 + * The first thing we need to do is find the location of the responder. 1.5307 + * This will be the value of the default responder (if enabled), else 1.5308 + * it will come out of the AIA extension in the cert (if present). 1.5309 + * If we have no such location, then this cert does not "deserve" to 1.5310 + * be checked -- that is, we consider it a success and just return. 1.5311 + * The way we tell that is by looking at the error number to see if 1.5312 + * the problem was no AIA extension was found; any other error was 1.5313 + * a true failure that we unfortunately have to treat as an overall 1.5314 + * failure here. 1.5315 + */ 1.5316 + location = ocsp_GetResponderLocation(handle, cert, PR_TRUE, 1.5317 + &locationIsDefault); 1.5318 + if (location == NULL) { 1.5319 + int err = PORT_GetError(); 1.5320 + if (err == SEC_ERROR_EXTENSION_NOT_FOUND || 1.5321 + err == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) { 1.5322 + PORT_SetError(0); 1.5323 + *rv_ocsp = SECSuccess; 1.5324 + return SECSuccess; 1.5325 + } 1.5326 + return SECFailure; 1.5327 + } 1.5328 + 1.5329 + /* 1.5330 + * XXX In the fullness of time, we will want/need to handle a 1.5331 + * certificate chain. This will be done either when a new parameter 1.5332 + * tells us to, or some configuration variable tells us to. In any 1.5333 + * case, handling it is complicated because we may need to send as 1.5334 + * many requests (and receive as many responses) as we have certs 1.5335 + * in the chain. If we are going to talk to a default responder, 1.5336 + * and we only support one default responder, we can put all of the 1.5337 + * certs together into one request. Otherwise, we must break them up 1.5338 + * into multiple requests. (Even if all of the requests will go to 1.5339 + * the same location, the signature on each response will be different, 1.5340 + * because each issuer is different. Carefully read the OCSP spec 1.5341 + * if you do not understand this.) 1.5342 + */ 1.5343 + 1.5344 + /* 1.5345 + * XXX If/when signing of requests is supported, that second NULL 1.5346 + * should be changed to be the signer certificate. Not sure if that 1.5347 + * should be passed into this function or retrieved via some operation 1.5348 + * on the handle/context. 1.5349 + */ 1.5350 + 1.5351 + do { 1.5352 + const char *method; 1.5353 + PRBool validResponseWithAccurateInfo = PR_FALSE; 1.5354 + retry = PR_FALSE; 1.5355 + *rv_ocsp = SECFailure; 1.5356 + 1.5357 + if (currentStage == stageGET) { 1.5358 + method = "GET"; 1.5359 + } else { 1.5360 + PORT_Assert(currentStage == stagePOST); 1.5361 + method = "POST"; 1.5362 + } 1.5363 + 1.5364 + encodedResponse = 1.5365 + ocsp_GetEncodedOCSPResponseForSingleCert(NULL, certID, cert, 1.5366 + location, method, 1.5367 + time, locationIsDefault, 1.5368 + pwArg, &request); 1.5369 + 1.5370 + if (encodedResponse) { 1.5371 + rv = ocsp_GetDecodedVerifiedSingleResponseForID(handle, certID, cert, 1.5372 + time, pwArg, 1.5373 + encodedResponse, 1.5374 + &decodedResponse, 1.5375 + &singleResponse); 1.5376 + if (rv == SECSuccess) { 1.5377 + switch (singleResponse->certStatus->certStatusType) { 1.5378 + case ocspCertStatus_good: 1.5379 + case ocspCertStatus_revoked: 1.5380 + validResponseWithAccurateInfo = PR_TRUE; 1.5381 + break; 1.5382 + default: 1.5383 + break; 1.5384 + } 1.5385 + *rv_ocsp = ocsp_SingleResponseCertHasGoodStatus(singleResponse, time); 1.5386 + } 1.5387 + } 1.5388 + 1.5389 + if (currentStage == stageGET) { 1.5390 + /* only accept GET response if good or revoked */ 1.5391 + if (validResponseWithAccurateInfo) { 1.5392 + ocsp_CacheSingleResponse(certID, singleResponse, 1.5393 + certIDWasConsumed); 1.5394 + } else { 1.5395 + retry = PR_TRUE; 1.5396 + currentStage = stagePOST; 1.5397 + } 1.5398 + } else { 1.5399 + /* cache the POST respone, regardless of status */ 1.5400 + if (!singleResponse) { 1.5401 + cert_RememberOCSPProcessingFailure(certID, certIDWasConsumed); 1.5402 + } else { 1.5403 + ocsp_CacheSingleResponse(certID, singleResponse, 1.5404 + certIDWasConsumed); 1.5405 + } 1.5406 + } 1.5407 + 1.5408 + if (encodedResponse) { 1.5409 + SECITEM_FreeItem(encodedResponse, PR_TRUE); 1.5410 + encodedResponse = NULL; 1.5411 + } 1.5412 + if (request) { 1.5413 + CERT_DestroyOCSPRequest(request); 1.5414 + request = NULL; 1.5415 + } 1.5416 + if (decodedResponse) { 1.5417 + CERT_DestroyOCSPResponse(decodedResponse); 1.5418 + decodedResponse = NULL; 1.5419 + } 1.5420 + singleResponse = NULL; 1.5421 + 1.5422 + } while (retry); 1.5423 + 1.5424 + PORT_Free(location); 1.5425 + return rv; 1.5426 +} 1.5427 + 1.5428 +/* 1.5429 + * FUNCTION: ocsp_GetDecodedVerifiedSingleResponseForID 1.5430 + * This function decodes an OCSP response and checks for a valid response 1.5431 + * concerning the given certificate. 1.5432 + * 1.5433 + * Note: a 'valid' response is one that parses successfully, is not an OCSP 1.5434 + * exception (see RFC 2560 Section 2.3), is correctly signed and is current. 1.5435 + * A 'good' response is a valid response that attests that the certificate 1.5436 + * is not currently revoked (see RFC 2560 Section 2.2). 1.5437 + * 1.5438 + * INPUTS: 1.5439 + * CERTCertDBHandle *handle 1.5440 + * certificate DB of the cert that is being checked 1.5441 + * CERTOCSPCertID *certID 1.5442 + * the cert ID corresponding to |cert| 1.5443 + * CERTCertificate *cert 1.5444 + * the certificate being checked 1.5445 + * PRTime time 1.5446 + * time for which status is to be determined 1.5447 + * void *pwArg 1.5448 + * the opaque argument to the password prompting function. 1.5449 + * SECItem *encodedResponse 1.5450 + * the DER encoded bytes of the OCSP response 1.5451 + * CERTOCSPResponse **pDecodedResponse 1.5452 + * (output) The caller must ALWAYS check for this output parameter, 1.5453 + * and if it's non-null, must destroy it using CERT_DestroyOCSPResponse. 1.5454 + * CERTOCSPSingleResponse **pSingle 1.5455 + * (output) on success, this points to the single response that corresponds 1.5456 + * to the certID parameter. Points to the inside of pDecodedResponse. 1.5457 + * It isn't a copy, don't free it. 1.5458 + * RETURN: 1.5459 + * SECSuccess iff the response is valid. 1.5460 + */ 1.5461 +static SECStatus 1.5462 +ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle *handle, 1.5463 + CERTOCSPCertID *certID, 1.5464 + CERTCertificate *cert, 1.5465 + PRTime time, 1.5466 + void *pwArg, 1.5467 + const SECItem *encodedResponse, 1.5468 + CERTOCSPResponse **pDecodedResponse, 1.5469 + CERTOCSPSingleResponse **pSingle) 1.5470 +{ 1.5471 + CERTCertificate *signerCert = NULL; 1.5472 + CERTCertificate *issuerCert = NULL; 1.5473 + SECStatus rv = SECFailure; 1.5474 + 1.5475 + if (!pSingle || !pDecodedResponse) { 1.5476 + return SECFailure; 1.5477 + } 1.5478 + *pSingle = NULL; 1.5479 + *pDecodedResponse = CERT_DecodeOCSPResponse(encodedResponse); 1.5480 + if (!*pDecodedResponse) { 1.5481 + return SECFailure; 1.5482 + } 1.5483 + 1.5484 + /* 1.5485 + * Okay, we at least have a response that *looks* like a response! 1.5486 + * Now see if the overall response status value is good or not. 1.5487 + * If not, we set an error and give up. (It means that either the 1.5488 + * server had a problem, or it didn't like something about our 1.5489 + * request. Either way there is nothing to do but give up.) 1.5490 + * Otherwise, we continue to find the actual per-cert status 1.5491 + * in the response. 1.5492 + */ 1.5493 + if (CERT_GetOCSPResponseStatus(*pDecodedResponse) != SECSuccess) { 1.5494 + goto loser; 1.5495 + } 1.5496 + 1.5497 + /* 1.5498 + * If we've made it this far, we expect a response with a good signature. 1.5499 + * So, check for that. 1.5500 + */ 1.5501 + issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); 1.5502 + rv = CERT_VerifyOCSPResponseSignature(*pDecodedResponse, handle, pwArg, 1.5503 + &signerCert, issuerCert); 1.5504 + if (rv != SECSuccess) { 1.5505 + goto loser; 1.5506 + } 1.5507 + 1.5508 + PORT_Assert(signerCert != NULL); /* internal consistency check */ 1.5509 + /* XXX probably should set error, return failure if signerCert is null */ 1.5510 + 1.5511 + /* 1.5512 + * Again, we are only doing one request for one cert. 1.5513 + * XXX When we handle cert chains, the following code will obviously 1.5514 + * have to be modified, in coordation with the code above that will 1.5515 + * have to determine how to make multiple requests, etc. 1.5516 + */ 1.5517 + rv = ocsp_GetVerifiedSingleResponseForCertID(handle, *pDecodedResponse, certID, 1.5518 + signerCert, time, pSingle); 1.5519 +loser: 1.5520 + if (issuerCert != NULL) 1.5521 + CERT_DestroyCertificate(issuerCert); 1.5522 + if (signerCert != NULL) 1.5523 + CERT_DestroyCertificate(signerCert); 1.5524 + return rv; 1.5525 +} 1.5526 + 1.5527 +/* 1.5528 + * FUNCTION: ocsp_CacheSingleResponse 1.5529 + * This function requires that the caller has checked that the response 1.5530 + * is valid and verified. 1.5531 + * The (positive or negative) valid response will be used to update the cache. 1.5532 + * INPUTS: 1.5533 + * CERTOCSPCertID *certID 1.5534 + * the cert ID corresponding to |cert| 1.5535 + * PRBool *certIDWasConsumed 1.5536 + * (output) on return, this is true iff |certID| was consumed by this 1.5537 + * function. 1.5538 + */ 1.5539 +void 1.5540 +ocsp_CacheSingleResponse(CERTOCSPCertID *certID, 1.5541 + CERTOCSPSingleResponse *single, 1.5542 + PRBool *certIDWasConsumed) 1.5543 +{ 1.5544 + if (single != NULL) { 1.5545 + PR_EnterMonitor(OCSP_Global.monitor); 1.5546 + if (OCSP_Global.maxCacheEntries >= 0) { 1.5547 + ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single, 1.5548 + certIDWasConsumed); 1.5549 + /* ignore cache update failures */ 1.5550 + } 1.5551 + PR_ExitMonitor(OCSP_Global.monitor); 1.5552 + } 1.5553 +} 1.5554 + 1.5555 +SECStatus 1.5556 +ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, 1.5557 + CERTOCSPResponse *response, 1.5558 + CERTOCSPCertID *certID, 1.5559 + CERTCertificate *signerCert, 1.5560 + PRTime time, 1.5561 + CERTOCSPSingleResponse 1.5562 + **pSingleResponse) 1.5563 +{ 1.5564 + SECStatus rv; 1.5565 + ocspResponseData *responseData; 1.5566 + PRTime producedAt; 1.5567 + CERTOCSPSingleResponse *single; 1.5568 + 1.5569 + /* 1.5570 + * The ResponseData part is the real guts of the response. 1.5571 + */ 1.5572 + responseData = ocsp_GetResponseData(response, NULL); 1.5573 + if (responseData == NULL) { 1.5574 + rv = SECFailure; 1.5575 + goto loser; 1.5576 + } 1.5577 + 1.5578 + /* 1.5579 + * There is one producedAt time for the entire response (and a separate 1.5580 + * thisUpdate time for each individual single response). We need to 1.5581 + * compare them, so get the overall time to pass into the check of each 1.5582 + * single response. 1.5583 + */ 1.5584 + rv = DER_GeneralizedTimeToTime(&producedAt, &responseData->producedAt); 1.5585 + if (rv != SECSuccess) 1.5586 + goto loser; 1.5587 + 1.5588 + single = ocsp_GetSingleResponseForCertID(responseData->responses, 1.5589 + handle, certID); 1.5590 + if (single == NULL) { 1.5591 + rv = SECFailure; 1.5592 + goto loser; 1.5593 + } 1.5594 + 1.5595 + rv = ocsp_VerifySingleResponse(single, handle, signerCert, producedAt); 1.5596 + if (rv != SECSuccess) 1.5597 + goto loser; 1.5598 + *pSingleResponse = single; 1.5599 + 1.5600 +loser: 1.5601 + return rv; 1.5602 +} 1.5603 + 1.5604 +SECStatus 1.5605 +CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle, 1.5606 + CERTOCSPResponse *response, 1.5607 + CERTOCSPCertID *certID, 1.5608 + CERTCertificate *signerCert, 1.5609 + PRTime time) 1.5610 +{ 1.5611 + /* 1.5612 + * We do not update the cache, because: 1.5613 + * 1.5614 + * CERT_GetOCSPStatusForCertID is an old exported API that was introduced 1.5615 + * before the OCSP cache got implemented. 1.5616 + * 1.5617 + * The implementation of helper function cert_ProcessOCSPResponse 1.5618 + * requires the ability to transfer ownership of the the given certID to 1.5619 + * the cache. The external API doesn't allow us to prevent the caller from 1.5620 + * destroying the certID. We don't have the original certificate available, 1.5621 + * therefore we are unable to produce another certID object (that could 1.5622 + * be stored in the cache). 1.5623 + * 1.5624 + * Should we ever implement code to produce a deep copy of certID, 1.5625 + * then this could be changed to allow updating the cache. 1.5626 + * The duplication would have to be done in 1.5627 + * cert_ProcessOCSPResponse, if the out parameter to indicate 1.5628 + * a transfer of ownership is NULL. 1.5629 + */ 1.5630 + return cert_ProcessOCSPResponse(handle, response, certID, 1.5631 + signerCert, time, 1.5632 + NULL, NULL); 1.5633 +} 1.5634 + 1.5635 +/* 1.5636 + * The first 5 parameters match the definition of CERT_GetOCSPStatusForCertID. 1.5637 + */ 1.5638 +SECStatus 1.5639 +cert_ProcessOCSPResponse(CERTCertDBHandle *handle, 1.5640 + CERTOCSPResponse *response, 1.5641 + CERTOCSPCertID *certID, 1.5642 + CERTCertificate *signerCert, 1.5643 + PRTime time, 1.5644 + PRBool *certIDWasConsumed, 1.5645 + SECStatus *cacheUpdateStatus) 1.5646 +{ 1.5647 + SECStatus rv; 1.5648 + SECStatus rv_cache = SECSuccess; 1.5649 + CERTOCSPSingleResponse *single = NULL; 1.5650 + 1.5651 + rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID, 1.5652 + signerCert, time, &single); 1.5653 + if (rv == SECSuccess) { 1.5654 + /* 1.5655 + * Check whether the status says revoked, and if so 1.5656 + * how that compares to the time value passed into this routine. 1.5657 + */ 1.5658 + rv = ocsp_SingleResponseCertHasGoodStatus(single, time); 1.5659 + } 1.5660 + 1.5661 + if (certIDWasConsumed) { 1.5662 + /* 1.5663 + * We don't have copy-of-certid implemented. In order to update 1.5664 + * the cache, the caller must supply an out variable 1.5665 + * certIDWasConsumed, allowing us to return ownership status. 1.5666 + */ 1.5667 + 1.5668 + PR_EnterMonitor(OCSP_Global.monitor); 1.5669 + if (OCSP_Global.maxCacheEntries >= 0) { 1.5670 + /* single == NULL means: remember response failure */ 1.5671 + rv_cache = 1.5672 + ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, 1.5673 + single, certIDWasConsumed); 1.5674 + } 1.5675 + PR_ExitMonitor(OCSP_Global.monitor); 1.5676 + if (cacheUpdateStatus) { 1.5677 + *cacheUpdateStatus = rv_cache; 1.5678 + } 1.5679 + } 1.5680 + 1.5681 + return rv; 1.5682 +} 1.5683 + 1.5684 +SECStatus 1.5685 +cert_RememberOCSPProcessingFailure(CERTOCSPCertID *certID, 1.5686 + PRBool *certIDWasConsumed) 1.5687 +{ 1.5688 + SECStatus rv = SECSuccess; 1.5689 + PR_EnterMonitor(OCSP_Global.monitor); 1.5690 + if (OCSP_Global.maxCacheEntries >= 0) { 1.5691 + rv = ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, NULL, 1.5692 + certIDWasConsumed); 1.5693 + } 1.5694 + PR_ExitMonitor(OCSP_Global.monitor); 1.5695 + return rv; 1.5696 +} 1.5697 + 1.5698 +/* 1.5699 + * Disable status checking and destroy related structures/data. 1.5700 + */ 1.5701 +static SECStatus 1.5702 +ocsp_DestroyStatusChecking(CERTStatusConfig *statusConfig) 1.5703 +{ 1.5704 + ocspCheckingContext *statusContext; 1.5705 + 1.5706 + /* 1.5707 + * Disable OCSP checking 1.5708 + */ 1.5709 + statusConfig->statusChecker = NULL; 1.5710 + 1.5711 + statusContext = statusConfig->statusContext; 1.5712 + PORT_Assert(statusContext != NULL); 1.5713 + if (statusContext == NULL) 1.5714 + return SECFailure; 1.5715 + 1.5716 + if (statusContext->defaultResponderURI != NULL) 1.5717 + PORT_Free(statusContext->defaultResponderURI); 1.5718 + if (statusContext->defaultResponderNickname != NULL) 1.5719 + PORT_Free(statusContext->defaultResponderNickname); 1.5720 + 1.5721 + PORT_Free(statusContext); 1.5722 + statusConfig->statusContext = NULL; 1.5723 + 1.5724 + PORT_Free(statusConfig); 1.5725 + 1.5726 + return SECSuccess; 1.5727 +} 1.5728 + 1.5729 + 1.5730 +/* 1.5731 + * FUNCTION: CERT_DisableOCSPChecking 1.5732 + * Turns off OCSP checking for the given certificate database. 1.5733 + * This routine disables OCSP checking. Though it will return 1.5734 + * SECFailure if OCSP checking is not enabled, it is "safe" to 1.5735 + * call it that way and just ignore the return value, if it is 1.5736 + * easier to just call it than to "remember" whether it is enabled. 1.5737 + * INPUTS: 1.5738 + * CERTCertDBHandle *handle 1.5739 + * Certificate database for which OCSP checking will be disabled. 1.5740 + * RETURN: 1.5741 + * Returns SECFailure if an error occurred (usually means that OCSP 1.5742 + * checking was not enabled or status contexts were not initialized -- 1.5743 + * error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise. 1.5744 + */ 1.5745 +SECStatus 1.5746 +CERT_DisableOCSPChecking(CERTCertDBHandle *handle) 1.5747 +{ 1.5748 + CERTStatusConfig *statusConfig; 1.5749 + ocspCheckingContext *statusContext; 1.5750 + 1.5751 + if (handle == NULL) { 1.5752 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5753 + return SECFailure; 1.5754 + } 1.5755 + 1.5756 + statusConfig = CERT_GetStatusConfig(handle); 1.5757 + statusContext = ocsp_GetCheckingContext(handle); 1.5758 + if (statusContext == NULL) 1.5759 + return SECFailure; 1.5760 + 1.5761 + if (statusConfig->statusChecker != CERT_CheckOCSPStatus) { 1.5762 + /* 1.5763 + * Status configuration is present, but either not currently 1.5764 + * enabled or not for OCSP. 1.5765 + */ 1.5766 + PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED); 1.5767 + return SECFailure; 1.5768 + } 1.5769 + 1.5770 + /* cache no longer necessary */ 1.5771 + CERT_ClearOCSPCache(); 1.5772 + 1.5773 + /* 1.5774 + * This is how we disable status checking. Everything else remains 1.5775 + * in place in case we are enabled again. 1.5776 + */ 1.5777 + statusConfig->statusChecker = NULL; 1.5778 + 1.5779 + return SECSuccess; 1.5780 +} 1.5781 + 1.5782 +/* 1.5783 + * Allocate and initialize the informational structures for status checking. 1.5784 + * This is done when some configuration of OCSP is being done or when OCSP 1.5785 + * checking is being turned on, whichever comes first. 1.5786 + */ 1.5787 +static SECStatus 1.5788 +ocsp_InitStatusChecking(CERTCertDBHandle *handle) 1.5789 +{ 1.5790 + CERTStatusConfig *statusConfig = NULL; 1.5791 + ocspCheckingContext *statusContext = NULL; 1.5792 + 1.5793 + PORT_Assert(CERT_GetStatusConfig(handle) == NULL); 1.5794 + if (CERT_GetStatusConfig(handle) != NULL) { 1.5795 + /* XXX or call statusConfig->statusDestroy and continue? */ 1.5796 + return SECFailure; 1.5797 + } 1.5798 + 1.5799 + statusConfig = PORT_ZNew(CERTStatusConfig); 1.5800 + if (statusConfig == NULL) 1.5801 + goto loser; 1.5802 + 1.5803 + statusContext = PORT_ZNew(ocspCheckingContext); 1.5804 + if (statusContext == NULL) 1.5805 + goto loser; 1.5806 + 1.5807 + statusConfig->statusDestroy = ocsp_DestroyStatusChecking; 1.5808 + statusConfig->statusContext = statusContext; 1.5809 + 1.5810 + CERT_SetStatusConfig(handle, statusConfig); 1.5811 + 1.5812 + return SECSuccess; 1.5813 + 1.5814 +loser: 1.5815 + if (statusConfig != NULL) 1.5816 + PORT_Free(statusConfig); 1.5817 + return SECFailure; 1.5818 +} 1.5819 + 1.5820 + 1.5821 +/* 1.5822 + * FUNCTION: CERT_EnableOCSPChecking 1.5823 + * Turns on OCSP checking for the given certificate database. 1.5824 + * INPUTS: 1.5825 + * CERTCertDBHandle *handle 1.5826 + * Certificate database for which OCSP checking will be enabled. 1.5827 + * RETURN: 1.5828 + * Returns SECFailure if an error occurred (likely only problem 1.5829 + * allocating memory); SECSuccess otherwise. 1.5830 + */ 1.5831 +SECStatus 1.5832 +CERT_EnableOCSPChecking(CERTCertDBHandle *handle) 1.5833 +{ 1.5834 + CERTStatusConfig *statusConfig; 1.5835 + 1.5836 + SECStatus rv; 1.5837 + 1.5838 + if (handle == NULL) { 1.5839 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5840 + return SECFailure; 1.5841 + } 1.5842 + 1.5843 + statusConfig = CERT_GetStatusConfig(handle); 1.5844 + if (statusConfig == NULL) { 1.5845 + rv = ocsp_InitStatusChecking(handle); 1.5846 + if (rv != SECSuccess) 1.5847 + return rv; 1.5848 + 1.5849 + /* Get newly established value */ 1.5850 + statusConfig = CERT_GetStatusConfig(handle); 1.5851 + PORT_Assert(statusConfig != NULL); 1.5852 + } 1.5853 + 1.5854 + /* 1.5855 + * Setting the checker function is what really enables the checking 1.5856 + * when each cert verification is done. 1.5857 + */ 1.5858 + statusConfig->statusChecker = CERT_CheckOCSPStatus; 1.5859 + 1.5860 + return SECSuccess; 1.5861 +} 1.5862 + 1.5863 + 1.5864 +/* 1.5865 + * FUNCTION: CERT_SetOCSPDefaultResponder 1.5866 + * Specify the location and cert of the default responder. 1.5867 + * If OCSP checking is already enabled *and* use of a default responder 1.5868 + * is also already enabled, all OCSP checking from now on will go directly 1.5869 + * to the specified responder. If OCSP checking is not enabled, or if 1.5870 + * it is but use of a default responder is not enabled, the information 1.5871 + * will be recorded and take effect whenever both are enabled. 1.5872 + * INPUTS: 1.5873 + * CERTCertDBHandle *handle 1.5874 + * Cert database on which OCSP checking should use the default responder. 1.5875 + * char *url 1.5876 + * The location of the default responder (e.g. "http://foo.com:80/ocsp") 1.5877 + * Note that the location will not be tested until the first attempt 1.5878 + * to send a request there. 1.5879 + * char *name 1.5880 + * The nickname of the cert to trust (expected) to sign the OCSP responses. 1.5881 + * If the corresponding cert cannot be found, SECFailure is returned. 1.5882 + * RETURN: 1.5883 + * Returns SECFailure if an error occurred; SECSuccess otherwise. 1.5884 + * The most likely error is that the cert for "name" could not be found 1.5885 + * (probably SEC_ERROR_UNKNOWN_CERT). Other errors are low-level (no memory, 1.5886 + * bad database, etc.). 1.5887 + */ 1.5888 +SECStatus 1.5889 +CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle, 1.5890 + const char *url, const char *name) 1.5891 +{ 1.5892 + CERTCertificate *cert; 1.5893 + ocspCheckingContext *statusContext; 1.5894 + char *url_copy = NULL; 1.5895 + char *name_copy = NULL; 1.5896 + SECStatus rv; 1.5897 + 1.5898 + if (handle == NULL || url == NULL || name == NULL) { 1.5899 + /* 1.5900 + * XXX When interface is exported, probably want better errors; 1.5901 + * perhaps different one for each parameter. 1.5902 + */ 1.5903 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.5904 + return SECFailure; 1.5905 + } 1.5906 + 1.5907 + /* 1.5908 + * Find the certificate for the specified nickname. Do this first 1.5909 + * because it seems the most likely to fail. 1.5910 + * 1.5911 + * XXX Shouldn't need that cast if the FindCertByNickname interface 1.5912 + * used const to convey that it does not modify the name. Maybe someday. 1.5913 + */ 1.5914 + cert = CERT_FindCertByNickname(handle, (char *) name); 1.5915 + if (cert == NULL) { 1.5916 + /* 1.5917 + * look for the cert on an external token. 1.5918 + */ 1.5919 + cert = PK11_FindCertFromNickname((char *)name, NULL); 1.5920 + } 1.5921 + if (cert == NULL) 1.5922 + return SECFailure; 1.5923 + 1.5924 + /* 1.5925 + * Make a copy of the url and nickname. 1.5926 + */ 1.5927 + url_copy = PORT_Strdup(url); 1.5928 + name_copy = PORT_Strdup(name); 1.5929 + if (url_copy == NULL || name_copy == NULL) { 1.5930 + rv = SECFailure; 1.5931 + goto loser; 1.5932 + } 1.5933 + 1.5934 + statusContext = ocsp_GetCheckingContext(handle); 1.5935 + 1.5936 + /* 1.5937 + * Allocate and init the context if it doesn't already exist. 1.5938 + */ 1.5939 + if (statusContext == NULL) { 1.5940 + rv = ocsp_InitStatusChecking(handle); 1.5941 + if (rv != SECSuccess) 1.5942 + goto loser; 1.5943 + 1.5944 + statusContext = ocsp_GetCheckingContext(handle); 1.5945 + PORT_Assert(statusContext != NULL); /* extreme paranoia */ 1.5946 + } 1.5947 + 1.5948 + /* 1.5949 + * Note -- we do not touch the status context until after all of 1.5950 + * the steps which could cause errors. If something goes wrong, 1.5951 + * we want to leave things as they were. 1.5952 + */ 1.5953 + 1.5954 + /* 1.5955 + * Get rid of old url and name if there. 1.5956 + */ 1.5957 + if (statusContext->defaultResponderNickname != NULL) 1.5958 + PORT_Free(statusContext->defaultResponderNickname); 1.5959 + if (statusContext->defaultResponderURI != NULL) 1.5960 + PORT_Free(statusContext->defaultResponderURI); 1.5961 + 1.5962 + /* 1.5963 + * And replace them with the new ones. 1.5964 + */ 1.5965 + statusContext->defaultResponderURI = url_copy; 1.5966 + statusContext->defaultResponderNickname = name_copy; 1.5967 + 1.5968 + /* 1.5969 + * If there was already a cert in place, get rid of it and replace it. 1.5970 + * Otherwise, we are not currently enabled, so we don't want to save it; 1.5971 + * it will get re-found and set whenever use of a default responder is 1.5972 + * enabled. 1.5973 + */ 1.5974 + if (statusContext->defaultResponderCert != NULL) { 1.5975 + CERT_DestroyCertificate(statusContext->defaultResponderCert); 1.5976 + statusContext->defaultResponderCert = cert; 1.5977 + /*OCSP enabled, switching responder: clear cache*/ 1.5978 + CERT_ClearOCSPCache(); 1.5979 + } else { 1.5980 + PORT_Assert(statusContext->useDefaultResponder == PR_FALSE); 1.5981 + CERT_DestroyCertificate(cert); 1.5982 + /*OCSP currently not enabled, no need to clear cache*/ 1.5983 + } 1.5984 + 1.5985 + return SECSuccess; 1.5986 + 1.5987 +loser: 1.5988 + CERT_DestroyCertificate(cert); 1.5989 + if (url_copy != NULL) 1.5990 + PORT_Free(url_copy); 1.5991 + if (name_copy != NULL) 1.5992 + PORT_Free(name_copy); 1.5993 + return rv; 1.5994 +} 1.5995 + 1.5996 + 1.5997 +/* 1.5998 + * FUNCTION: CERT_EnableOCSPDefaultResponder 1.5999 + * Turns on use of a default responder when OCSP checking. 1.6000 + * If OCSP checking is already enabled, this will make subsequent checks 1.6001 + * go directly to the default responder. (The location of the responder 1.6002 + * and the nickname of the responder cert must already be specified.) 1.6003 + * If OCSP checking is not enabled, this will be recorded and take effect 1.6004 + * whenever it is enabled. 1.6005 + * INPUTS: 1.6006 + * CERTCertDBHandle *handle 1.6007 + * Cert database on which OCSP checking should use the default responder. 1.6008 + * RETURN: 1.6009 + * Returns SECFailure if an error occurred; SECSuccess otherwise. 1.6010 + * No errors are especially likely unless the caller did not previously 1.6011 + * perform a successful call to SetOCSPDefaultResponder (in which case 1.6012 + * the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER). 1.6013 + */ 1.6014 +SECStatus 1.6015 +CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle) 1.6016 +{ 1.6017 + ocspCheckingContext *statusContext; 1.6018 + CERTCertificate *cert; 1.6019 + SECStatus rv; 1.6020 + SECCertificateUsage usage; 1.6021 + 1.6022 + if (handle == NULL) { 1.6023 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.6024 + return SECFailure; 1.6025 + } 1.6026 + 1.6027 + statusContext = ocsp_GetCheckingContext(handle); 1.6028 + 1.6029 + if (statusContext == NULL) { 1.6030 + /* 1.6031 + * Strictly speaking, the error already set is "correct", 1.6032 + * but cover over it with one more helpful in this context. 1.6033 + */ 1.6034 + PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER); 1.6035 + return SECFailure; 1.6036 + } 1.6037 + 1.6038 + if (statusContext->defaultResponderURI == NULL) { 1.6039 + PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER); 1.6040 + return SECFailure; 1.6041 + } 1.6042 + 1.6043 + if (statusContext->defaultResponderNickname == NULL) { 1.6044 + PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER); 1.6045 + return SECFailure; 1.6046 + } 1.6047 + 1.6048 + /* 1.6049 + * Find the cert for the nickname. 1.6050 + */ 1.6051 + cert = CERT_FindCertByNickname(handle, 1.6052 + statusContext->defaultResponderNickname); 1.6053 + if (cert == NULL) { 1.6054 + cert = PK11_FindCertFromNickname(statusContext->defaultResponderNickname, 1.6055 + NULL); 1.6056 + } 1.6057 + /* 1.6058 + * We should never have trouble finding the cert, because its 1.6059 + * existence should have been proven by SetOCSPDefaultResponder. 1.6060 + */ 1.6061 + PORT_Assert(cert != NULL); 1.6062 + if (cert == NULL) 1.6063 + return SECFailure; 1.6064 + 1.6065 + /* 1.6066 + * Supplied cert should at least have a signing capability in order for us 1.6067 + * to use it as a trusted responder cert. Ability to sign is guaranteed if 1.6068 + * cert is validated to have any set of the usages below. 1.6069 + */ 1.6070 + rv = CERT_VerifyCertificateNow(handle, cert, PR_TRUE, 1.6071 + certificateUsageCheckAllUsages, 1.6072 + NULL, &usage); 1.6073 + if (rv != SECSuccess || (usage & (certificateUsageSSLClient | 1.6074 + certificateUsageSSLServer | 1.6075 + certificateUsageSSLServerWithStepUp | 1.6076 + certificateUsageEmailSigner | 1.6077 + certificateUsageObjectSigner | 1.6078 + certificateUsageStatusResponder | 1.6079 + certificateUsageSSLCA)) == 0) { 1.6080 + PORT_SetError(SEC_ERROR_OCSP_RESPONDER_CERT_INVALID); 1.6081 + return SECFailure; 1.6082 + } 1.6083 + 1.6084 + /* 1.6085 + * And hang onto it. 1.6086 + */ 1.6087 + statusContext->defaultResponderCert = cert; 1.6088 + 1.6089 + /* we don't allow a mix of cache entries from different responders */ 1.6090 + CERT_ClearOCSPCache(); 1.6091 + 1.6092 + /* 1.6093 + * Finally, record the fact that we now have a default responder enabled. 1.6094 + */ 1.6095 + statusContext->useDefaultResponder = PR_TRUE; 1.6096 + return SECSuccess; 1.6097 +} 1.6098 + 1.6099 + 1.6100 +/* 1.6101 + * FUNCTION: CERT_DisableOCSPDefaultResponder 1.6102 + * Turns off use of a default responder when OCSP checking. 1.6103 + * (Does nothing if use of a default responder is not enabled.) 1.6104 + * INPUTS: 1.6105 + * CERTCertDBHandle *handle 1.6106 + * Cert database on which OCSP checking should stop using a default 1.6107 + * responder. 1.6108 + * RETURN: 1.6109 + * Returns SECFailure if an error occurred; SECSuccess otherwise. 1.6110 + * Errors very unlikely (like random memory corruption...). 1.6111 + */ 1.6112 +SECStatus 1.6113 +CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle) 1.6114 +{ 1.6115 + CERTStatusConfig *statusConfig; 1.6116 + ocspCheckingContext *statusContext; 1.6117 + CERTCertificate *tmpCert; 1.6118 + 1.6119 + if (handle == NULL) { 1.6120 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.6121 + return SECFailure; 1.6122 + } 1.6123 + 1.6124 + statusConfig = CERT_GetStatusConfig(handle); 1.6125 + if (statusConfig == NULL) 1.6126 + return SECSuccess; 1.6127 + 1.6128 + statusContext = ocsp_GetCheckingContext(handle); 1.6129 + PORT_Assert(statusContext != NULL); 1.6130 + if (statusContext == NULL) 1.6131 + return SECFailure; 1.6132 + 1.6133 + tmpCert = statusContext->defaultResponderCert; 1.6134 + if (tmpCert) { 1.6135 + statusContext->defaultResponderCert = NULL; 1.6136 + CERT_DestroyCertificate(tmpCert); 1.6137 + /* we don't allow a mix of cache entries from different responders */ 1.6138 + CERT_ClearOCSPCache(); 1.6139 + } 1.6140 + 1.6141 + /* 1.6142 + * Finally, record the fact. 1.6143 + */ 1.6144 + statusContext->useDefaultResponder = PR_FALSE; 1.6145 + return SECSuccess; 1.6146 +} 1.6147 + 1.6148 +SECStatus 1.6149 +CERT_ForcePostMethodForOCSP(PRBool forcePost) 1.6150 +{ 1.6151 + if (!OCSP_Global.monitor) { 1.6152 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 1.6153 + return SECFailure; 1.6154 + } 1.6155 + 1.6156 + PR_EnterMonitor(OCSP_Global.monitor); 1.6157 + OCSP_Global.forcePost = forcePost; 1.6158 + PR_ExitMonitor(OCSP_Global.monitor); 1.6159 + 1.6160 + return SECSuccess; 1.6161 +} 1.6162 + 1.6163 +SECStatus 1.6164 +CERT_GetOCSPResponseStatus(CERTOCSPResponse *response) 1.6165 +{ 1.6166 + PORT_Assert(response); 1.6167 + if (response->statusValue == ocspResponse_successful) 1.6168 + return SECSuccess; 1.6169 + 1.6170 + switch (response->statusValue) { 1.6171 + case ocspResponse_malformedRequest: 1.6172 + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); 1.6173 + break; 1.6174 + case ocspResponse_internalError: 1.6175 + PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); 1.6176 + break; 1.6177 + case ocspResponse_tryLater: 1.6178 + PORT_SetError(SEC_ERROR_OCSP_TRY_SERVER_LATER); 1.6179 + break; 1.6180 + case ocspResponse_sigRequired: 1.6181 + /* XXX We *should* retry with a signature, if possible. */ 1.6182 + PORT_SetError(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG); 1.6183 + break; 1.6184 + case ocspResponse_unauthorized: 1.6185 + PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST); 1.6186 + break; 1.6187 + case ocspResponse_unused: 1.6188 + default: 1.6189 + PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS); 1.6190 + break; 1.6191 + } 1.6192 + return SECFailure; 1.6193 +}