security/nss/lib/certhigh/ocsp.c

changeset 0
6474c204b198
     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 +                              &registeredHttpClient->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 +}

mercurial