PageRenderTime 180ms CodeModel.GetById 22ms app.highlight 119ms RepoModel.GetById 1ms app.codeStats 3ms

/security/nss/lib/certhigh/ocsp.c

http://github.com/zpao/v8monkey
C | 5734 lines | 3549 code | 656 blank | 1529 comment | 913 complexity | 0c459ade7a54e7874d3c23421dab4cb9 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *   Kai Engert (kengert@redhat.com)
  23 *
  24 * Alternatively, the contents of this file may be used under the terms of
  25 * either the GNU General Public License Version 2 or later (the "GPL"), or
  26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27 * in which case the provisions of the GPL or the LGPL are applicable instead
  28 * of those above. If you wish to allow use of your version of this file only
  29 * under the terms of either the GPL or the LGPL, and not to allow others to
  30 * use your version of this file under the terms of the MPL, indicate your
  31 * decision by deleting the provisions above and replace them with the notice
  32 * and other provisions required by the GPL or the LGPL. If you do not delete
  33 * the provisions above, a recipient may use your version of this file under
  34 * the terms of any one of the MPL, the GPL or the LGPL.
  35 *
  36 * ***** END LICENSE BLOCK ***** */
  37
  38/*
  39 * Implementation of OCSP services, for both client and server.
  40 * (XXX, really, mostly just for client right now, but intended to do both.)
  41 *
  42 * $Id: ocsp.c,v 1.67 2011/08/10 12:31:52 kaie%kuix.de Exp $
  43 */
  44
  45#include "prerror.h"
  46#include "prprf.h"
  47#include "plarena.h"
  48#include "prnetdb.h"
  49
  50#include "seccomon.h"
  51#include "secitem.h"
  52#include "secoidt.h"
  53#include "secasn1.h"
  54#include "secder.h"
  55#include "cert.h"
  56#include "xconst.h"
  57#include "secerr.h"
  58#include "secoid.h"
  59#include "hasht.h"
  60#include "sechash.h"
  61#include "secasn1.h"
  62#include "keyhi.h"
  63#include "cryptohi.h"
  64#include "ocsp.h"
  65#include "ocspti.h"
  66#include "ocspi.h"
  67#include "genname.h"
  68#include "certxutl.h"
  69#include "pk11func.h"	/* for PK11_HashBuf */
  70#include <stdarg.h>
  71#include <plhash.h>
  72
  73#define DEFAULT_OCSP_CACHE_SIZE 1000
  74#define DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 1*60*60L
  75#define DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 24*60*60L
  76#define DEFAULT_OSCP_TIMEOUT_SECONDS 60
  77#define MICROSECONDS_PER_SECOND 1000000L
  78
  79typedef struct OCSPCacheItemStr OCSPCacheItem;
  80typedef struct OCSPCacheDataStr OCSPCacheData;
  81
  82struct OCSPCacheItemStr {
  83    /* LRU linking */
  84    OCSPCacheItem *moreRecent;
  85    OCSPCacheItem *lessRecent;
  86
  87    /* key */
  88    CERTOCSPCertID *certID;
  89    /* CertID's arena also used to allocate "this" cache item */
  90
  91    /* cache control information */
  92    PRTime nextFetchAttemptTime;
  93
  94    /* Cached contents. Use a separate arena, because lifetime is different */
  95    PRArenaPool *certStatusArena; /* NULL means: no cert status cached */
  96    ocspCertStatus certStatus;
  97
  98    /* This may contain an error code when no OCSP response is available. */
  99    SECErrorCodes missingResponseError;
 100
 101    PRPackedBool haveThisUpdate;
 102    PRPackedBool haveNextUpdate;
 103    PRTime thisUpdate;
 104    PRTime nextUpdate;
 105};
 106
 107struct OCSPCacheDataStr {
 108    PLHashTable *entries;
 109    PRUint32 numberOfEntries;
 110    OCSPCacheItem *MRUitem; /* most recently used cache item */
 111    OCSPCacheItem *LRUitem; /* least recently used cache item */
 112};
 113
 114static struct OCSPGlobalStruct {
 115    PRMonitor *monitor;
 116    const SEC_HttpClientFcn *defaultHttpClientFcn;
 117    PRInt32 maxCacheEntries;
 118    PRUint32 minimumSecondsToNextFetchAttempt;
 119    PRUint32 maximumSecondsToNextFetchAttempt;
 120    PRUint32 timeoutSeconds;
 121    OCSPCacheData cache;
 122    SEC_OcspFailureMode ocspFailureMode;
 123    CERT_StringFromCertFcn alternateOCSPAIAFcn;
 124} OCSP_Global = { NULL, 
 125                  NULL, 
 126                  DEFAULT_OCSP_CACHE_SIZE, 
 127                  DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
 128                  DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
 129                  DEFAULT_OSCP_TIMEOUT_SECONDS,
 130                  {NULL, 0, NULL, NULL},
 131                  ocspMode_FailureIsVerificationFailure,
 132                  NULL
 133                };
 134
 135
 136
 137/* Forward declarations */
 138static SECItem *
 139ocsp_GetEncodedOCSPResponseFromRequest(PRArenaPool *arena, 
 140                                       CERTOCSPRequest *request,
 141                                       char *location, int64 time,
 142                                       PRBool addServiceLocator,
 143                                       void *pwArg,
 144                                       CERTOCSPRequest **pRequest);
 145static SECStatus
 146ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 
 147                              CERTOCSPCertID *certID, 
 148                              CERTCertificate *cert, 
 149                              int64 time, 
 150                              void *pwArg,
 151                              PRBool *certIDWasConsumed,
 152                              SECStatus *rv_ocsp);
 153
 154static SECStatus
 155ocsp_CacheEncodedOCSPResponse(CERTCertDBHandle *handle,
 156			      CERTOCSPCertID *certID,
 157			      CERTCertificate *cert,
 158			      int64 time,
 159			      void *pwArg,
 160			      SECItem *encodedResponse,
 161			      PRBool *certIDWasConsumed,
 162			      PRBool cacheNegative,
 163			      SECStatus *rv_ocsp);
 164
 165static SECStatus
 166ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, 
 167                                        CERTOCSPResponse *response, 
 168                                        CERTOCSPCertID   *certID,
 169                                        CERTCertificate  *signerCert,
 170                                        int64             time,
 171                                        CERTOCSPSingleResponse **pSingleResponse);
 172
 173static SECStatus
 174ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, int64 time);
 175
 176#ifndef DEBUG
 177#define OCSP_TRACE(msg)
 178#define OCSP_TRACE_TIME(msg, time)
 179#define OCSP_TRACE_CERT(cert)
 180#define OCSP_TRACE_CERTID(certid)
 181#else
 182#define OCSP_TRACE(msg) ocsp_Trace msg
 183#define OCSP_TRACE_TIME(msg, time) ocsp_dumpStringWithTime(msg, time)
 184#define OCSP_TRACE_CERT(cert) dumpCertificate(cert)
 185#define OCSP_TRACE_CERTID(certid) dumpCertID(certid)
 186
 187#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) \
 188     || defined(XP_MACOSX)) && !defined(_WIN32_WCE)
 189#define NSS_HAVE_GETENV 1
 190#endif
 191
 192static PRBool wantOcspTrace()
 193{
 194    static PRBool firstTime = PR_TRUE;
 195    static PRBool wantTrace = PR_FALSE;
 196
 197#ifdef NSS_HAVE_GETENV
 198    if (firstTime) {
 199        char *ev = getenv("NSS_TRACE_OCSP");
 200        if (ev && ev[0]) {
 201            wantTrace = PR_TRUE;
 202        }
 203        firstTime = PR_FALSE;
 204    }
 205#endif
 206    return wantTrace;
 207}
 208
 209static void
 210ocsp_Trace(const char *format, ...)
 211{
 212    char buf[2000];
 213    va_list args;
 214  
 215    if (!wantOcspTrace())
 216        return;
 217    va_start(args, format);
 218    PR_vsnprintf(buf, sizeof(buf), format, args);
 219    va_end(args);
 220    PR_LogPrint("%s", buf);
 221}
 222
 223static void
 224ocsp_dumpStringWithTime(const char *str, int64 time)
 225{
 226    PRExplodedTime timePrintable;
 227    char timestr[256];
 228
 229    if (!wantOcspTrace())
 230        return;
 231    PR_ExplodeTime(time, PR_GMTParameters, &timePrintable);
 232    if (PR_FormatTime(timestr, 256, "%a %b %d %H:%M:%S %Y", &timePrintable)) {
 233        ocsp_Trace("OCSP %s %s\n", str, timestr);
 234    }
 235}
 236
 237static void
 238printHexString(const char *prefix, SECItem *hexval)
 239{
 240    unsigned int i;
 241    char *hexbuf = NULL;
 242
 243    for (i = 0; i < hexval->len; i++) {
 244        if (i != hexval->len - 1) {
 245            hexbuf = PR_sprintf_append(hexbuf, "%02x:", hexval->data[i]);
 246        } else {
 247            hexbuf = PR_sprintf_append(hexbuf, "%02x", hexval->data[i]);
 248        }
 249    }
 250    if (hexbuf) {
 251        ocsp_Trace("%s %s\n", prefix, hexbuf);
 252        PR_smprintf_free(hexbuf);
 253    }
 254}
 255
 256static void
 257dumpCertificate(CERTCertificate *cert)
 258{
 259    if (!wantOcspTrace())
 260        return;
 261
 262    ocsp_Trace("OCSP ----------------\n");
 263    ocsp_Trace("OCSP ## SUBJECT:  %s\n", cert->subjectName);
 264    {
 265        int64 timeBefore, timeAfter;
 266        PRExplodedTime beforePrintable, afterPrintable;
 267        char beforestr[256], afterstr[256];
 268        PRStatus rv1, rv2;
 269        DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore);
 270        DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter);
 271        PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable);
 272        PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable);
 273        rv1 = PR_FormatTime(beforestr, 256, "%a %b %d %H:%M:%S %Y", 
 274                      &beforePrintable);
 275        rv2 = PR_FormatTime(afterstr, 256, "%a %b %d %H:%M:%S %Y", 
 276                      &afterPrintable);
 277        ocsp_Trace("OCSP ## VALIDITY:  %s to %s\n", rv1 ? beforestr : "",
 278                   rv2 ? afterstr : "");
 279    }
 280    ocsp_Trace("OCSP ## ISSUER:  %s\n", cert->issuerName);
 281    printHexString("OCSP ## SERIAL NUMBER:", &cert->serialNumber);
 282}
 283
 284static void
 285dumpCertID(CERTOCSPCertID *certID)
 286{
 287    if (!wantOcspTrace())
 288        return;
 289
 290    printHexString("OCSP certID issuer", &certID->issuerNameHash);
 291    printHexString("OCSP certID serial", &certID->serialNumber);
 292}
 293#endif
 294
 295SECStatus
 296SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
 297{
 298    if (!OCSP_Global.monitor) {
 299      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 300      return SECFailure;
 301    }
 302    
 303    PR_EnterMonitor(OCSP_Global.monitor);
 304    OCSP_Global.defaultHttpClientFcn = fcnTable;
 305    PR_ExitMonitor(OCSP_Global.monitor);
 306    
 307    return SECSuccess;
 308}
 309
 310SECStatus
 311CERT_RegisterAlternateOCSPAIAInfoCallBack(
 312			CERT_StringFromCertFcn   newCallback,
 313			CERT_StringFromCertFcn * oldCallback)
 314{
 315    CERT_StringFromCertFcn old;
 316
 317    if (!OCSP_Global.monitor) {
 318      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 319      return SECFailure;
 320    }
 321
 322    PR_EnterMonitor(OCSP_Global.monitor);
 323    old = OCSP_Global.alternateOCSPAIAFcn;
 324    OCSP_Global.alternateOCSPAIAFcn = newCallback;
 325    PR_ExitMonitor(OCSP_Global.monitor);
 326    if (oldCallback)
 327    	*oldCallback = old;
 328    return SECSuccess;
 329}
 330
 331static PLHashNumber PR_CALLBACK
 332ocsp_CacheKeyHashFunction(const void *key)
 333{
 334    CERTOCSPCertID *cid = (CERTOCSPCertID *)key;
 335    PLHashNumber hash = 0;
 336    unsigned int i;
 337    unsigned char *walk;
 338  
 339    /* a very simple hash calculation for the initial coding phase */
 340    walk = (unsigned char*)cid->issuerNameHash.data;
 341    for (i=0; i < cid->issuerNameHash.len; ++i, ++walk) {
 342        hash += *walk;
 343    }
 344    walk = (unsigned char*)cid->issuerKeyHash.data;
 345    for (i=0; i < cid->issuerKeyHash.len; ++i, ++walk) {
 346        hash += *walk;
 347    }
 348    walk = (unsigned char*)cid->serialNumber.data;
 349    for (i=0; i < cid->serialNumber.len; ++i, ++walk) {
 350        hash += *walk;
 351    }
 352    return hash;
 353}
 354
 355static PRIntn PR_CALLBACK
 356ocsp_CacheKeyCompareFunction(const void *v1, const void *v2)
 357{
 358    CERTOCSPCertID *cid1 = (CERTOCSPCertID *)v1;
 359    CERTOCSPCertID *cid2 = (CERTOCSPCertID *)v2;
 360  
 361    return (SECEqual == SECITEM_CompareItem(&cid1->issuerNameHash, 
 362                                            &cid2->issuerNameHash)
 363            && SECEqual == SECITEM_CompareItem(&cid1->issuerKeyHash, 
 364                                               &cid2->issuerKeyHash)
 365            && SECEqual == SECITEM_CompareItem(&cid1->serialNumber, 
 366                                               &cid2->serialNumber));
 367}
 368
 369static SECStatus
 370ocsp_CopyRevokedInfo(PRArenaPool *arena, ocspCertStatus *dest, 
 371                     ocspRevokedInfo *src)
 372{
 373    SECStatus rv = SECFailure;
 374    void *mark;
 375  
 376    mark = PORT_ArenaMark(arena);
 377  
 378    dest->certStatusInfo.revokedInfo = 
 379        (ocspRevokedInfo *) PORT_ArenaZAlloc(arena, sizeof(ocspRevokedInfo));
 380    if (!dest->certStatusInfo.revokedInfo) {
 381        goto loser;
 382    }
 383  
 384    rv = SECITEM_CopyItem(arena, 
 385                          &dest->certStatusInfo.revokedInfo->revocationTime, 
 386                          &src->revocationTime);
 387    if (rv != SECSuccess) {
 388        goto loser;
 389    }
 390  
 391    if (src->revocationReason) {
 392        dest->certStatusInfo.revokedInfo->revocationReason = 
 393            SECITEM_ArenaDupItem(arena, src->revocationReason);
 394        if (!dest->certStatusInfo.revokedInfo->revocationReason) {
 395            goto loser;
 396        }
 397    }  else {
 398        dest->certStatusInfo.revokedInfo->revocationReason = NULL;
 399    }
 400  
 401    PORT_ArenaUnmark(arena, mark);
 402    return SECSuccess;
 403
 404loser:
 405    PORT_ArenaRelease(arena, mark);
 406    return SECFailure;
 407}
 408
 409static SECStatus
 410ocsp_CopyCertStatus(PRArenaPool *arena, ocspCertStatus *dest, 
 411                    ocspCertStatus*src)
 412{
 413    SECStatus rv = SECFailure;
 414    dest->certStatusType = src->certStatusType;
 415  
 416    switch (src->certStatusType) {
 417    case ocspCertStatus_good:
 418        dest->certStatusInfo.goodInfo = 
 419            SECITEM_ArenaDupItem(arena, src->certStatusInfo.goodInfo);
 420        if (dest->certStatusInfo.goodInfo != NULL) {
 421            rv = SECSuccess;
 422        }
 423        break;
 424    case ocspCertStatus_revoked:
 425        rv = ocsp_CopyRevokedInfo(arena, dest, 
 426                                  src->certStatusInfo.revokedInfo);
 427        break;
 428    case ocspCertStatus_unknown:
 429        dest->certStatusInfo.unknownInfo = 
 430            SECITEM_ArenaDupItem(arena, src->certStatusInfo.unknownInfo);
 431        if (dest->certStatusInfo.unknownInfo != NULL) {
 432            rv = SECSuccess;
 433        }
 434        break;
 435    case ocspCertStatus_other:
 436    default:
 437        PORT_Assert(src->certStatusType == ocspCertStatus_other);
 438        dest->certStatusInfo.otherInfo = 
 439            SECITEM_ArenaDupItem(arena, src->certStatusInfo.otherInfo);
 440        if (dest->certStatusInfo.otherInfo != NULL) {
 441            rv = SECSuccess;
 442        }
 443        break;
 444    }
 445    return rv;
 446}
 447
 448static void
 449ocsp_AddCacheItemToLinkedList(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
 450{
 451    PR_EnterMonitor(OCSP_Global.monitor);
 452
 453    if (!cache->LRUitem) {
 454        cache->LRUitem = new_most_recent;
 455    }
 456    new_most_recent->lessRecent = cache->MRUitem;
 457    new_most_recent->moreRecent = NULL;
 458
 459    if (cache->MRUitem) {
 460        cache->MRUitem->moreRecent = new_most_recent;
 461    }
 462    cache->MRUitem = new_most_recent;
 463
 464    PR_ExitMonitor(OCSP_Global.monitor);
 465}
 466
 467static void
 468ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData *cache, OCSPCacheItem *item)
 469{
 470    PR_EnterMonitor(OCSP_Global.monitor);
 471
 472    if (!item->lessRecent && !item->moreRecent) {
 473        /*
 474         * Fail gracefully on attempts to remove an item from the list,
 475         * which is currently not part of the list.
 476         * But check for the edge case it is the single entry in the list.
 477         */
 478        if (item == cache->LRUitem &&
 479            item == cache->MRUitem) {
 480            /* remove the single entry */
 481            PORT_Assert(cache->numberOfEntries == 1);
 482            PORT_Assert(item->moreRecent == NULL);
 483            cache->MRUitem = NULL;
 484            cache->LRUitem = NULL;
 485        }
 486        PR_ExitMonitor(OCSP_Global.monitor);
 487        return;
 488    }
 489
 490    PORT_Assert(cache->numberOfEntries > 1);
 491  
 492    if (item == cache->LRUitem) {
 493        PORT_Assert(item != cache->MRUitem);
 494        PORT_Assert(item->lessRecent == NULL);
 495        PORT_Assert(item->moreRecent != NULL);
 496        PORT_Assert(item->moreRecent->lessRecent == item);
 497        cache->LRUitem = item->moreRecent;
 498        cache->LRUitem->lessRecent = NULL;
 499    }
 500    else if (item == cache->MRUitem) {
 501        PORT_Assert(item->moreRecent == NULL);
 502        PORT_Assert(item->lessRecent != NULL);
 503        PORT_Assert(item->lessRecent->moreRecent == item);
 504        cache->MRUitem = item->lessRecent;
 505        cache->MRUitem->moreRecent = NULL;
 506    } else {
 507        /* remove an entry in the middle of the list */
 508        PORT_Assert(item->moreRecent != NULL);
 509        PORT_Assert(item->lessRecent != NULL);
 510        PORT_Assert(item->lessRecent->moreRecent == item);
 511        PORT_Assert(item->moreRecent->lessRecent == item);
 512        item->moreRecent->lessRecent = item->lessRecent;
 513        item->lessRecent->moreRecent = item->moreRecent;
 514    }
 515
 516    item->lessRecent = NULL;
 517    item->moreRecent = NULL;
 518
 519    PR_ExitMonitor(OCSP_Global.monitor);
 520}
 521
 522static void
 523ocsp_MakeCacheEntryMostRecent(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
 524{
 525    OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent THREADID %p\n", 
 526                PR_GetCurrentThread()));
 527    PR_EnterMonitor(OCSP_Global.monitor);
 528    if (cache->MRUitem == new_most_recent) {
 529        OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent ALREADY MOST\n"));
 530        PR_ExitMonitor(OCSP_Global.monitor);
 531        return;
 532    }
 533    OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent NEW entry\n"));
 534    ocsp_RemoveCacheItemFromLinkedList(cache, new_most_recent);
 535    ocsp_AddCacheItemToLinkedList(cache, new_most_recent);
 536    PR_ExitMonitor(OCSP_Global.monitor);
 537}
 538
 539static PRBool
 540ocsp_IsCacheDisabled()
 541{
 542    /* 
 543     * maxCacheEntries == 0 means unlimited cache entries
 544     * maxCacheEntries  < 0 means cache is disabled
 545     */
 546    PRBool retval;
 547    PR_EnterMonitor(OCSP_Global.monitor);
 548    retval = (OCSP_Global.maxCacheEntries < 0);
 549    PR_ExitMonitor(OCSP_Global.monitor);
 550    return retval;
 551}
 552
 553static OCSPCacheItem *
 554ocsp_FindCacheEntry(OCSPCacheData *cache, CERTOCSPCertID *certID)
 555{
 556    OCSPCacheItem *found_ocsp_item = NULL;
 557    OCSP_TRACE(("OCSP ocsp_FindCacheEntry\n"));
 558    OCSP_TRACE_CERTID(certID);
 559    PR_EnterMonitor(OCSP_Global.monitor);
 560    if (ocsp_IsCacheDisabled())
 561        goto loser;
 562  
 563    found_ocsp_item = (OCSPCacheItem *)PL_HashTableLookup(
 564                          cache->entries, certID);
 565    if (!found_ocsp_item)
 566        goto loser;
 567  
 568    OCSP_TRACE(("OCSP ocsp_FindCacheEntry FOUND!\n"));
 569    ocsp_MakeCacheEntryMostRecent(cache, found_ocsp_item);
 570
 571loser:
 572    PR_ExitMonitor(OCSP_Global.monitor);
 573    return found_ocsp_item;
 574}
 575
 576static void
 577ocsp_FreeCacheItem(OCSPCacheItem *item)
 578{
 579    OCSP_TRACE(("OCSP ocsp_FreeCacheItem\n"));
 580    if (item->certStatusArena) {
 581        PORT_FreeArena(item->certStatusArena, PR_FALSE);
 582    }
 583    if (item->certID->poolp) {
 584        /* freeing this poolp arena will also free item */
 585        PORT_FreeArena(item->certID->poolp, PR_FALSE);
 586    }
 587}
 588
 589static void
 590ocsp_RemoveCacheItem(OCSPCacheData *cache, OCSPCacheItem *item)
 591{
 592    /* The item we're removing could be either the least recently used item,
 593     * or it could be an item that couldn't get updated with newer status info
 594     * because of an allocation failure, or it could get removed because we're 
 595     * cleaning up.
 596     */
 597    PRBool couldRemoveFromHashTable;
 598    OCSP_TRACE(("OCSP ocsp_RemoveCacheItem, THREADID %p\n", PR_GetCurrentThread()));
 599    PR_EnterMonitor(OCSP_Global.monitor);
 600
 601    ocsp_RemoveCacheItemFromLinkedList(cache, item);
 602    couldRemoveFromHashTable = PL_HashTableRemove(cache->entries, 
 603                                                  item->certID);
 604    PORT_Assert(couldRemoveFromHashTable);
 605    --cache->numberOfEntries;
 606    ocsp_FreeCacheItem(item);
 607    PR_ExitMonitor(OCSP_Global.monitor);
 608}
 609
 610static void
 611ocsp_CheckCacheSize(OCSPCacheData *cache)
 612{
 613    OCSP_TRACE(("OCSP ocsp_CheckCacheSize\n"));
 614    PR_EnterMonitor(OCSP_Global.monitor);
 615    if (OCSP_Global.maxCacheEntries > 0) {
 616        /* Cache is not disabled. Number of cache entries is limited.
 617         * The monitor ensures that maxCacheEntries remains positive.
 618         */
 619        while (cache->numberOfEntries > 
 620                     (PRUint32)OCSP_Global.maxCacheEntries) {
 621            ocsp_RemoveCacheItem(cache, cache->LRUitem);
 622        }
 623    }
 624    PR_ExitMonitor(OCSP_Global.monitor);
 625}
 626
 627SECStatus
 628CERT_ClearOCSPCache()
 629{
 630    OCSP_TRACE(("OCSP CERT_ClearOCSPCache\n"));
 631    PR_EnterMonitor(OCSP_Global.monitor);
 632    while (OCSP_Global.cache.numberOfEntries > 0) {
 633        ocsp_RemoveCacheItem(&OCSP_Global.cache, 
 634                             OCSP_Global.cache.LRUitem);
 635    }
 636    PR_ExitMonitor(OCSP_Global.monitor);
 637    return SECSuccess;
 638}
 639
 640static SECStatus
 641ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData *cache,
 642                                     CERTOCSPCertID *certID, 
 643                                     OCSPCacheItem **pCacheItem)
 644{
 645    PRArenaPool *arena;
 646    void *mark;
 647    PLHashEntry *new_hash_entry;
 648    OCSPCacheItem *item;
 649  
 650    PORT_Assert(pCacheItem != NULL);
 651    *pCacheItem = NULL;
 652
 653    PR_EnterMonitor(OCSP_Global.monitor);
 654    arena = certID->poolp;
 655    mark = PORT_ArenaMark(arena);
 656  
 657    /* ZAlloc will init all Bools to False and all Pointers to NULL
 658       and all error codes to zero/good. */
 659    item = (OCSPCacheItem *)PORT_ArenaZAlloc(certID->poolp, 
 660                                             sizeof(OCSPCacheItem));
 661    if (!item) {
 662        goto loser; 
 663    }
 664    item->certID = certID;
 665    new_hash_entry = PL_HashTableAdd(cache->entries, item->certID, 
 666                                     item);
 667    if (!new_hash_entry) {
 668        goto loser;
 669    }
 670    ++cache->numberOfEntries;
 671    PORT_ArenaUnmark(arena, mark);
 672    ocsp_AddCacheItemToLinkedList(cache, item);
 673    *pCacheItem = item;
 674
 675    PR_ExitMonitor(OCSP_Global.monitor);
 676    return SECSuccess;
 677  
 678loser:
 679    PORT_ArenaRelease(arena, mark);
 680    PR_ExitMonitor(OCSP_Global.monitor);
 681    return SECFailure;
 682}
 683
 684static SECStatus
 685ocsp_SetCacheItemResponse(OCSPCacheItem *item,
 686                          const CERTOCSPSingleResponse *response)
 687{
 688    if (item->certStatusArena) {
 689        PORT_FreeArena(item->certStatusArena, PR_FALSE);
 690        item->certStatusArena = NULL;
 691    }
 692    item->haveThisUpdate = item->haveNextUpdate = PR_FALSE;
 693    if (response) {
 694        SECStatus rv;
 695        item->certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 696        if (item->certStatusArena == NULL) {
 697            return SECFailure;
 698        }
 699        rv = ocsp_CopyCertStatus(item->certStatusArena, &item->certStatus, 
 700                                 response->certStatus);
 701        if (rv != SECSuccess) {
 702            PORT_FreeArena(item->certStatusArena, PR_FALSE);
 703            item->certStatusArena = NULL;
 704            return rv;
 705        }
 706        item->missingResponseError = 0;
 707        rv = DER_GeneralizedTimeToTime(&item->thisUpdate, 
 708                                       &response->thisUpdate);
 709        item->haveThisUpdate = (rv == SECSuccess);
 710        if (response->nextUpdate) {
 711            rv = DER_GeneralizedTimeToTime(&item->nextUpdate, 
 712                                           response->nextUpdate);
 713            item->haveNextUpdate = (rv == SECSuccess);
 714        } else {
 715            item->haveNextUpdate = PR_FALSE;
 716        }
 717    }
 718    return SECSuccess;
 719}
 720
 721static void
 722ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem *cacheItem)
 723{
 724    PRTime now;
 725    PRTime earliestAllowedNextFetchAttemptTime;
 726    PRTime latestTimeWhenResponseIsConsideredFresh;
 727  
 728    OCSP_TRACE(("OCSP ocsp_FreshenCacheItemNextFetchAttemptTime\n"));
 729
 730    PR_EnterMonitor(OCSP_Global.monitor);
 731  
 732    now = PR_Now();
 733    OCSP_TRACE_TIME("now:", now);
 734  
 735    if (cacheItem->haveThisUpdate) {
 736        OCSP_TRACE_TIME("thisUpdate:", cacheItem->thisUpdate);
 737        latestTimeWhenResponseIsConsideredFresh = cacheItem->thisUpdate +
 738            OCSP_Global.maximumSecondsToNextFetchAttempt * 
 739                MICROSECONDS_PER_SECOND;
 740        OCSP_TRACE_TIME("latestTimeWhenResponseIsConsideredFresh:", 
 741                        latestTimeWhenResponseIsConsideredFresh);
 742    } else {
 743        latestTimeWhenResponseIsConsideredFresh = now +
 744            OCSP_Global.minimumSecondsToNextFetchAttempt *
 745                MICROSECONDS_PER_SECOND;
 746        OCSP_TRACE_TIME("no thisUpdate, "
 747                        "latestTimeWhenResponseIsConsideredFresh:", 
 748                        latestTimeWhenResponseIsConsideredFresh);
 749    }
 750  
 751    if (cacheItem->haveNextUpdate) {
 752        OCSP_TRACE_TIME("have nextUpdate:", cacheItem->nextUpdate);
 753    }
 754  
 755    if (cacheItem->haveNextUpdate &&
 756        cacheItem->nextUpdate < latestTimeWhenResponseIsConsideredFresh) {
 757        latestTimeWhenResponseIsConsideredFresh = cacheItem->nextUpdate;
 758        OCSP_TRACE_TIME("nextUpdate is smaller than latestFresh, setting "
 759                        "latestTimeWhenResponseIsConsideredFresh:", 
 760                        latestTimeWhenResponseIsConsideredFresh);
 761    }
 762  
 763    earliestAllowedNextFetchAttemptTime = now +
 764        OCSP_Global.minimumSecondsToNextFetchAttempt * 
 765            MICROSECONDS_PER_SECOND;
 766    OCSP_TRACE_TIME("earliestAllowedNextFetchAttemptTime:", 
 767                    earliestAllowedNextFetchAttemptTime);
 768  
 769    if (latestTimeWhenResponseIsConsideredFresh < 
 770        earliestAllowedNextFetchAttemptTime) {
 771        latestTimeWhenResponseIsConsideredFresh = 
 772            earliestAllowedNextFetchAttemptTime;
 773        OCSP_TRACE_TIME("latest < earliest, setting latest to:", 
 774                        latestTimeWhenResponseIsConsideredFresh);
 775    }
 776  
 777    cacheItem->nextFetchAttemptTime = 
 778        latestTimeWhenResponseIsConsideredFresh;
 779    OCSP_TRACE_TIME("nextFetchAttemptTime", 
 780        latestTimeWhenResponseIsConsideredFresh);
 781
 782    PR_ExitMonitor(OCSP_Global.monitor);
 783}
 784
 785static PRBool
 786ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem)
 787{
 788    PRTime now;
 789    PRBool retval;
 790
 791    PR_EnterMonitor(OCSP_Global.monitor);
 792    now = PR_Now();
 793    retval = (cacheItem->nextFetchAttemptTime > now);
 794    OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", retval));
 795    PR_ExitMonitor(OCSP_Global.monitor);
 796    return retval;
 797}
 798
 799/*
 800 * Status in *certIDWasConsumed will always be correct, regardless of 
 801 * return value.
 802 */
 803static SECStatus
 804ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache, 
 805                              CERTOCSPCertID *certID,
 806                              CERTOCSPSingleResponse *single,
 807                              PRBool *certIDWasConsumed)
 808{
 809    SECStatus rv;
 810    OCSPCacheItem *cacheItem;
 811    OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n"));
 812  
 813    if (!certIDWasConsumed) {
 814        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 815        return SECFailure;
 816    }
 817    *certIDWasConsumed = PR_FALSE;
 818  
 819    PR_EnterMonitor(OCSP_Global.monitor);
 820    PORT_Assert(OCSP_Global.maxCacheEntries >= 0);
 821  
 822    cacheItem = ocsp_FindCacheEntry(cache, certID);
 823    if (!cacheItem) {
 824        rv = ocsp_CreateCacheItemAndConsumeCertID(cache, certID, 
 825                                                  &cacheItem);
 826        if (rv != SECSuccess) {
 827            PR_ExitMonitor(OCSP_Global.monitor);
 828            return rv;
 829        }
 830        *certIDWasConsumed = PR_TRUE;
 831    }
 832    if (single) {
 833        rv = ocsp_SetCacheItemResponse(cacheItem, single);
 834        if (rv != SECSuccess) {
 835            ocsp_RemoveCacheItem(cache, cacheItem);
 836            PR_ExitMonitor(OCSP_Global.monitor);
 837            return rv;
 838        }
 839    } else {
 840        cacheItem->missingResponseError = PORT_GetError();
 841    }
 842    ocsp_FreshenCacheItemNextFetchAttemptTime(cacheItem);
 843    ocsp_CheckCacheSize(cache);
 844
 845    PR_ExitMonitor(OCSP_Global.monitor);
 846    return SECSuccess;
 847}
 848
 849extern SECStatus
 850CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode)
 851{
 852    switch (ocspFailureMode) {
 853    case ocspMode_FailureIsVerificationFailure:
 854    case ocspMode_FailureIsNotAVerificationFailure:
 855        break;
 856    default:
 857        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 858        return SECFailure;
 859    }
 860
 861    PR_EnterMonitor(OCSP_Global.monitor);
 862    OCSP_Global.ocspFailureMode = ocspFailureMode;
 863    PR_ExitMonitor(OCSP_Global.monitor);
 864    return SECSuccess;
 865}
 866
 867SECStatus
 868CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
 869                       PRUint32 minimumSecondsToNextFetchAttempt,
 870                       PRUint32 maximumSecondsToNextFetchAttempt)
 871{
 872    if (minimumSecondsToNextFetchAttempt > maximumSecondsToNextFetchAttempt
 873        || maxCacheEntries < -1) {
 874        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 875        return SECFailure;
 876    }
 877  
 878    PR_EnterMonitor(OCSP_Global.monitor);
 879  
 880    if (maxCacheEntries < 0) {
 881        OCSP_Global.maxCacheEntries = -1; /* disable cache */
 882    } else if (maxCacheEntries == 0) {
 883        OCSP_Global.maxCacheEntries = 0; /* unlimited cache entries */
 884    } else {
 885        OCSP_Global.maxCacheEntries = maxCacheEntries;
 886    }
 887  
 888    if (minimumSecondsToNextFetchAttempt < 
 889            OCSP_Global.minimumSecondsToNextFetchAttempt
 890        || maximumSecondsToNextFetchAttempt < 
 891            OCSP_Global.maximumSecondsToNextFetchAttempt) {
 892        /*
 893         * Ensure our existing cache entries are not used longer than the 
 894         * new settings allow, we're lazy and just clear the cache
 895         */
 896        CERT_ClearOCSPCache();
 897    }
 898  
 899    OCSP_Global.minimumSecondsToNextFetchAttempt = 
 900        minimumSecondsToNextFetchAttempt;
 901    OCSP_Global.maximumSecondsToNextFetchAttempt = 
 902        maximumSecondsToNextFetchAttempt;
 903    ocsp_CheckCacheSize(&OCSP_Global.cache);
 904  
 905    PR_ExitMonitor(OCSP_Global.monitor);
 906    return SECSuccess;
 907}
 908
 909SECStatus
 910CERT_SetOCSPTimeout(PRUint32 seconds)
 911{
 912    /* no locking, see bug 406120 */
 913    OCSP_Global.timeoutSeconds = seconds;
 914    return SECSuccess;
 915}
 916
 917/* this function is called at NSS initialization time */
 918SECStatus OCSP_InitGlobal(void)
 919{
 920    SECStatus rv = SECFailure;
 921
 922    if (OCSP_Global.monitor == NULL) {
 923        OCSP_Global.monitor = PR_NewMonitor();
 924    }
 925    if (!OCSP_Global.monitor)
 926        return SECFailure;
 927
 928    PR_EnterMonitor(OCSP_Global.monitor);
 929    if (!OCSP_Global.cache.entries) {
 930        OCSP_Global.cache.entries = 
 931            PL_NewHashTable(0, 
 932                            ocsp_CacheKeyHashFunction, 
 933                            ocsp_CacheKeyCompareFunction, 
 934                            PL_CompareValues, 
 935                            NULL, 
 936                            NULL);
 937        OCSP_Global.ocspFailureMode = ocspMode_FailureIsVerificationFailure;
 938        OCSP_Global.cache.numberOfEntries = 0;
 939        OCSP_Global.cache.MRUitem = NULL;
 940        OCSP_Global.cache.LRUitem = NULL;
 941    } else {
 942        /*
 943         * NSS might call this function twice while attempting to init.
 944         * But it's not allowed to call this again after any activity.
 945         */
 946        PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
 947        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 948    }
 949    if (OCSP_Global.cache.entries)
 950        rv = SECSuccess;
 951    PR_ExitMonitor(OCSP_Global.monitor);
 952    return rv;
 953}
 954
 955SECStatus OCSP_ShutdownGlobal(void)
 956{
 957    if (!OCSP_Global.monitor)
 958        return SECSuccess;
 959
 960    PR_EnterMonitor(OCSP_Global.monitor);
 961    if (OCSP_Global.cache.entries) {
 962        CERT_ClearOCSPCache();
 963        PL_HashTableDestroy(OCSP_Global.cache.entries);
 964        OCSP_Global.cache.entries = NULL;
 965    }
 966    PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
 967    OCSP_Global.cache.MRUitem = NULL;
 968    OCSP_Global.cache.LRUitem = NULL;
 969
 970    OCSP_Global.defaultHttpClientFcn = NULL;
 971    OCSP_Global.maxCacheEntries = DEFAULT_OCSP_CACHE_SIZE;
 972    OCSP_Global.minimumSecondsToNextFetchAttempt = 
 973      DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
 974    OCSP_Global.maximumSecondsToNextFetchAttempt =
 975      DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
 976    OCSP_Global.ocspFailureMode =
 977      ocspMode_FailureIsVerificationFailure;
 978    PR_ExitMonitor(OCSP_Global.monitor);
 979
 980    PR_DestroyMonitor(OCSP_Global.monitor);
 981    OCSP_Global.monitor = NULL;
 982    return SECSuccess;
 983}
 984
 985/*
 986 * A return value of NULL means: 
 987 *   The application did not register it's own HTTP client.
 988 */
 989const SEC_HttpClientFcn *SEC_GetRegisteredHttpClient()
 990{
 991    const SEC_HttpClientFcn *retval;
 992
 993    if (!OCSP_Global.monitor) {
 994      PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 995      return NULL;
 996    }
 997
 998    PR_EnterMonitor(OCSP_Global.monitor);
 999    retval = OCSP_Global.defaultHttpClientFcn;
1000    PR_ExitMonitor(OCSP_Global.monitor);
1001    
1002    return retval;
1003}
1004
1005/*
1006 * The following structure is only used internally.  It is allocated when
1007 * someone turns on OCSP checking, and hangs off of the status-configuration
1008 * structure in the certdb structure.  We use it to keep configuration
1009 * information specific to OCSP checking.
1010 */
1011typedef struct ocspCheckingContextStr {
1012    PRBool useDefaultResponder;
1013    char *defaultResponderURI;
1014    char *defaultResponderNickname;
1015    CERTCertificate *defaultResponderCert;
1016} ocspCheckingContext;
1017
1018SEC_ASN1_MKSUB(SEC_AnyTemplate)
1019SEC_ASN1_MKSUB(SEC_IntegerTemplate)
1020SEC_ASN1_MKSUB(SEC_NullTemplate)
1021SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
1022SEC_ASN1_MKSUB(SEC_PointerToAnyTemplate)
1023SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
1024SEC_ASN1_MKSUB(SEC_SequenceOfAnyTemplate)
1025SEC_ASN1_MKSUB(SEC_PointerToGeneralizedTimeTemplate)
1026SEC_ASN1_MKSUB(SEC_PointerToEnumeratedTemplate)
1027
1028/*
1029 * Forward declarations of sub-types, so I can lay out the types in the
1030 * same order as the ASN.1 is laid out in the OCSP spec itself.
1031 *
1032 * These are in alphabetical order (case-insensitive); please keep it that way!
1033 */
1034extern const SEC_ASN1Template ocsp_CertIDTemplate[];
1035extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[];
1036extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[];
1037extern const SEC_ASN1Template ocsp_ResponseDataTemplate[];
1038extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[];
1039extern const SEC_ASN1Template ocsp_SingleRequestTemplate[];
1040extern const SEC_ASN1Template ocsp_SingleResponseTemplate[];
1041extern const SEC_ASN1Template ocsp_TBSRequestTemplate[];
1042
1043
1044/*
1045 * Request-related templates...
1046 */
1047
1048/*
1049 * OCSPRequest	::=	SEQUENCE {
1050 *	tbsRequest		TBSRequest,
1051 *	optionalSignature	[0] EXPLICIT Signature OPTIONAL }
1052 */
1053static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = {
1054    { SEC_ASN1_SEQUENCE,
1055	0, NULL, sizeof(CERTOCSPRequest) },
1056    { SEC_ASN1_POINTER,
1057	offsetof(CERTOCSPRequest, tbsRequest),
1058	ocsp_TBSRequestTemplate },
1059    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1060      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
1061	offsetof(CERTOCSPRequest, optionalSignature),
1062	ocsp_PointerToSignatureTemplate },
1063    { 0 }
1064};
1065
1066/*
1067 * TBSRequest	::=	SEQUENCE {
1068 *	version			[0] EXPLICIT Version DEFAULT v1,
1069 *	requestorName		[1] EXPLICIT GeneralName OPTIONAL,
1070 *	requestList		SEQUENCE OF Request,
1071 *	requestExtensions	[2] EXPLICIT Extensions OPTIONAL }
1072 *
1073 * Version	::=	INTEGER { v1(0) }
1074 *
1075 * Note: this should be static but the AIX compiler doesn't like it (because it
1076 * was forward-declared above); it is not meant to be exported, but this
1077 * is the only way it will compile.
1078 */
1079const SEC_ASN1Template ocsp_TBSRequestTemplate[] = {
1080    { SEC_ASN1_SEQUENCE,
1081	0, NULL, sizeof(ocspTBSRequest) },
1082    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |		/* XXX DER_DEFAULT */
1083      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1084	offsetof(ocspTBSRequest, version),
1085	SEC_ASN1_SUB(SEC_IntegerTemplate) },
1086    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1087      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
1088	offsetof(ocspTBSRequest, derRequestorName),
1089	SEC_ASN1_SUB(SEC_PointerToAnyTemplate) },
1090    { SEC_ASN1_SEQUENCE_OF,
1091	offsetof(ocspTBSRequest, requestList),
1092	ocsp_SingleRequestTemplate },
1093    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1094      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
1095	offsetof(ocspTBSRequest, requestExtensions),
1096	CERT_SequenceOfCertExtensionTemplate },
1097    { 0 }
1098};
1099
1100/*
1101 * Signature	::=	SEQUENCE {
1102 *	signatureAlgorithm	AlgorithmIdentifier,
1103 *	signature		BIT STRING,
1104 *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
1105 */
1106static const SEC_ASN1Template ocsp_SignatureTemplate[] = {
1107    { SEC_ASN1_SEQUENCE,
1108	0, NULL, sizeof(ocspSignature) },
1109    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1110	offsetof(ocspSignature, signatureAlgorithm),
1111	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1112    { SEC_ASN1_BIT_STRING,
1113	offsetof(ocspSignature, signature) },
1114    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1115      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1116	offsetof(ocspSignature, derCerts), 
1117	SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
1118    { 0 }
1119};
1120
1121/*
1122 * This template is just an extra level to use in an explicitly-tagged
1123 * reference to a Signature.
1124 *
1125 * Note: this should be static but the AIX compiler doesn't like it (because it
1126 * was forward-declared above); it is not meant to be exported, but this
1127 * is the only way it will compile.
1128 */
1129const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = {
1130    { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate }
1131};
1132
1133/*
1134 * Request	::=	SEQUENCE {
1135 *	reqCert			CertID,
1136 *	singleRequestExtensions	[0] EXPLICIT Extensions OPTIONAL }
1137 *
1138 * Note: this should be static but the AIX compiler doesn't like it (because it
1139 * was forward-declared above); it is not meant to be exported, but this
1140 * is the only way it will compile.
1141 */
1142const SEC_ASN1Template ocsp_SingleRequestTemplate[] = {
1143    { SEC_ASN1_SEQUENCE, 
1144	0, NULL, sizeof(ocspSingleRequest) },
1145    { SEC_ASN1_POINTER,
1146	offsetof(ocspSingleRequest, reqCert),
1147	ocsp_CertIDTemplate },
1148    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1149      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
1150	offsetof(ocspSingleRequest, singleRequestExtensions),
1151	CERT_SequenceOfCertExtensionTemplate },
1152    { 0 }
1153};
1154
1155
1156/*
1157 * This data structure and template (CertID) is used by both OCSP
1158 * requests and responses.  It is the only one that is shared.
1159 *
1160 * CertID	::=	SEQUENCE {
1161 *	hashAlgorithm		AlgorithmIdentifier,
1162 *	issuerNameHash		OCTET STRING,	-- Hash of Issuer DN
1163 *	issuerKeyHash		OCTET STRING,	-- Hash of Issuer public key
1164 *	serialNumber		CertificateSerialNumber }
1165 *
1166 * CertificateSerialNumber ::=	INTEGER
1167 *
1168 * Note: this should be static but the AIX compiler doesn't like it (because it
1169 * was forward-declared above); it is not meant to be exported, but this
1170 * is the only way it will compile.
1171 */
1172const SEC_ASN1Template ocsp_CertIDTemplate[] = {
1173    { SEC_ASN1_SEQUENCE, 
1174	0, NULL, sizeof(CERTOCSPCertID) },
1175    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1176	offsetof(CERTOCSPCertID, hashAlgorithm),
1177	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1178    { SEC_ASN1_OCTET_STRING,
1179	offsetof(CERTOCSPCertID, issuerNameHash) },
1180    { SEC_ASN1_OCTET_STRING,
1181	offsetof(CERTOCSPCertID, issuerKeyHash) },
1182    { SEC_ASN1_INTEGER, 
1183	offsetof(CERTOCSPCertID, serialNumber) },
1184    { 0 }
1185};
1186
1187
1188/*
1189 * Response-related templates...
1190 */
1191
1192/*
1193 * OCSPResponse	::=	SEQUENCE {
1194 *	responseStatus		OCSPResponseStatus,
1195 *	responseBytes		[0] EXPLICIT ResponseBytes OPTIONAL }
1196 */
1197static const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = {
1198    { SEC_ASN1_SEQUENCE, 
1199	0, NULL, sizeof(CERTOCSPResponse) },
1200    { SEC_ASN1_ENUMERATED, 
1201	offsetof(CERTOCSPResponse, responseStatus) },
1202    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1203      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
1204	offsetof(CERTOCSPResponse, responseBytes),
1205	ocsp_PointerToResponseBytesTemplate },
1206    { 0 }
1207};
1208
1209/*
1210 * ResponseBytes	::=	SEQUENCE {
1211 *	responseType		OBJECT IDENTIFIER,
1212 *	response		OCTET STRING }
1213 */
1214static const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = {
1215    { SEC_ASN1_SEQUENCE,
1216	0, NULL, sizeof(ocspResponseBytes) },
1217    { SEC_ASN1_OBJECT_ID,
1218	offsetof(ocspResponseBytes, responseType) },
1219    { SEC_ASN1_OCTET_STRING,
1220	offsetof(ocspResponseBytes, response) },
1221    { 0 }
1222};
1223
1224/*
1225 * This template is just an extra level to use in an explicitly-tagged
1226 * reference to a ResponseBytes.
1227 *
1228 * Note: this should be static but the AIX compiler doesn't like it (because it
1229 * was forward-declared above); it is not meant to be exported, but this
1230 * is the only way it will compile.
1231 */
1232const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = {
1233    { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate }
1234};
1235
1236/*
1237 * BasicOCSPResponse	::=	SEQUENCE {
1238 *	tbsResponseData		ResponseData,
1239 *	signatureAlgorithm	AlgorithmIdentifier,
1240 *	signature		BIT STRING,
1241 *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
1242 */
1243static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = {
1244    { SEC_ASN1_SEQUENCE,
1245	0, NULL, sizeof(ocspBasicOCSPResponse) },
1246    { SEC_ASN1_ANY | SEC_ASN1_SAVE,
1247	offsetof(ocspBasicOCSPResponse, tbsResponseDataDER) },
1248    { SEC_ASN1_POINTER,
1249	offsetof(ocspBasicOCSPResponse, tbsResponseData),
1250	ocsp_ResponseDataTemplate },
1251    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1252	offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
1253	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1254    { SEC_ASN1_BIT_STRING,
1255	offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
1256    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1257      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1258	offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
1259	SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
1260    { 0 }
1261};
1262
1263/*
1264 * ResponseData	::=	SEQUENCE {
1265 *	version			[0] EXPLICIT Version DEFAULT v1,
1266 *	responderID		ResponderID,
1267 *	producedAt		GeneralizedTime,
1268 *	responses		SEQUENCE OF SingleResponse,
1269 *	responseExtensions	[1] EXPLICIT Extensions OPTIONAL }
1270 *
1271 * Note: this should be static but the AIX compiler doesn't like it (because it
1272 * was forward-declared above); it is not meant to be exported, but this
1273 * is the only way it will compile.
1274 */
1275const SEC_ASN1Template ocsp_ResponseDataTemplate[] = {
1276    { SEC_ASN1_SEQUENCE,
1277	0, NULL, sizeof(ocspResponseData) },
1278    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |		/* XXX DER_DEFAULT */
1279      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1280	offsetof(ocspResponseData, version),
1281	SEC_ASN1_SUB(SEC_IntegerTemplate) },
1282    { SEC_ASN1_ANY,
1283	offsetof(ocspResponseData, derResponderID) },
1284    { SEC_ASN1_GENERALIZED_TIME,
1285	offsetof(ocspResponseData, producedAt) },
1286    { SEC_ASN1_SEQUENCE_OF,
1287	offsetof(ocspResponseData, responses),
1288	ocsp_SingleResponseTemplate },
1289    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1290      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1291	offsetof(ocspResponseData, responseExtensions),
1292	CERT_SequenceOfCertExtensionTemplate },
1293    { 0 }
1294};
1295
1296/*
1297 * ResponderID	::=	CHOICE {
1298 *	byName			[1] EXPLICIT Name,
1299 *	byKey			[2] EXPLICIT KeyHash }
1300 *
1301 * KeyHash ::=	OCTET STRING -- SHA-1 hash of responder's public key
1302 * (excluding the tag and length fields)
1303 *
1304 * XXX Because the ASN.1 encoder and decoder currently do not provide
1305 * a way to automatically handle a CHOICE, we need to do it in two
1306 * steps, looking at the type tag and feeding the exact choice back
1307 * to the ASN.1 code.  Hopefully that will change someday and this
1308 * can all be simplified down into a single template.  Anyway, for
1309 * now we list each choice as its own template:
1310 */
1311static const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = {
1312    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1313	offsetof(ocspResponderID, responderIDValue.name),
1314	CERT_NameTemplate }
1315};
1316static const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = {
1317    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
1318        SEC_ASN1_XTRN | 2,
1319	offsetof(ocspResponderID, responderIDValue.keyHash),
1320	SEC_ASN1_SUB(SEC_OctetStringTemplate) }
1321};
1322static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = {
1323    { SEC_ASN1_ANY,
1324	offsetof(ocspResponderID, responderIDValue.other) }
1325};
1326
1327/* Decode choice container, but leave x509 name object encoded */
1328static const SEC_ASN1Template ocsp_ResponderIDDerNameTemplate[] = {
1329    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
1330        SEC_ASN1_XTRN | 1, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
1331};
1332
1333/*
1334 * SingleResponse	::=	SEQUENCE {
1335 *	certID			CertID,
1336 *	certStatus		CertStatus,
1337 *	thisUpdate		GeneralizedTime,
1338 *	nextUpdate		[0] EXPLICIT GeneralizedTime OPTIONAL,
1339 *	singleExtensions	[1] EXPLICIT Extensions OPTIONAL }
1340 *
1341 * Note: this should be static but the AIX compiler doesn't like it (because it
1342 * was forward-declared above); it is not meant to be exported, but this
1343 * is the only way it will compile.
1344 */
1345const SEC_ASN1Template ocsp_SingleResponseTemplate[] = {
1346    { SEC_ASN1_SEQUENCE,
1347	0, NULL, sizeof(CERTOCSPSingleResponse) },
1348    { SEC_ASN1_POINTER,
1349	offsetof(CERTOCSPSingleResponse, certID),
1350	ocsp_CertIDTemplate },
1351    { SEC_ASN1_ANY,
1352	offsetof(CERTOCSPSingleResponse, derCertStatus) },
1353    { SEC_ASN1_GENERALIZED_TIME,
1354	offsetof(CERTOCSPSingleResponse, thisUpdate) },
1355    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1356      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1357	offsetof(CERTOCSPSingleResponse, nextUpdate),
1358	SEC_ASN1_SUB(SEC_PointerToGeneralizedTimeTemplate) },
1359    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1360      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1361	offsetof(CERTOCSPSingleResponse, singleExtensions),
1362	CERT_SequenceOfCertExtensionTemplate },
1363    { 0 }
1364};
1365
1366/*
1367 * CertStatus	::=	CHOICE {
1368 *	good			[0] IMPLICIT NULL,
1369 *	revoked			[1] IMPLICIT RevokedInfo,
1370 *	unknown			[2] IMPLICIT UnknownInfo }
1371 *
1372 * Because the ASN.1 encoder and decoder currently do not provide
1373 * a way to automatically handle a CHOICE, we need to do it in two
1374 * steps, looking at the type tag and feeding the exact choice back
1375 * to the ASN.1 code.  Hopefully that will change someday and this
1376 * can all be simplified down into a single template.  Anyway, for
1377 * now we list each choice as its own template:
1378 */
1379static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = {
1380    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1381	offsetof(ocspCertStatus, certStatusInfo.goodInfo),
1382	SEC_ASN1_SUB(SEC_NullTemplate) }
1383};
1384static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = {
1385    { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 
1386	offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
1387	ocsp_RevokedInfoTemplate }
1388};
1389static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = {
1390    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
1391	offsetof(ocspCertStatus, certStatusInfo.unknownInfo),
1392	SEC_ASN1_SUB(SEC_NullTemplate) }
1393};
1394static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = {
1395    { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
1396	offsetof(ocspCertStatus, certStatusInfo.otherInfo),
1397	SEC_ASN1_SUB(SEC_AnyTemplate) }
1398};
1399
1400/*
1401 * RevokedInfo	::=	SEQUENCE {
1402 *	revocationTime		GeneralizedTime,
1403 *	revocationReason	[0] EXPLICIT CRLReason OPTIONAL }
1404 *
1405 * Note: this should be static but the AIX compiler doesn't like it (because it
1406 * was forward-declared above); it is not meant to be exported, but this
1407 * is the only way it will compile.
1408 */
1409const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = {
1410    { SEC_ASN1_SEQUENCE,
1411	0, NULL, sizeof(ocspRevokedInfo) },
1412    { SEC_ASN1_GENERALIZED_TIME,
1413	offsetof(ocspRevokedInfo, revocationTime) },
1414    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1415      SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
1416        SEC_ASN1_XTRN | 0,
1417	offsetof(ocspRevokedInfo, revocationReason), 
1418	SEC_ASN1_SUB(SEC_PointerToEnumeratedTemplate) },
1419    { 0 }
1420};
1421
1422
1423/*
1424 * OCSP-specific extension templates:
1425 */
1426
1427/*
1428 * ServiceLocator	::=	SEQUENCE {
1429 *	issuer			Name,
1430 *	locator			AuthorityInfoAccessSyntax OPTIONAL }
1431 */
1432static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = {
1433    { SEC_ASN1_SEQUENCE,
1434	0, NULL, sizeof(ocspServiceLocator) },
1435    { SEC_ASN1_POINTER,
1436	offsetof(ocspServiceLocator, issuer),
1437	CERT_NameTemplate },
1438    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
1439	offsetof(ocspServiceLocator, locator) },
1440    { 0 }
1441};
1442
1443
1444/*
1445 * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy):
1446 */
1447
1448/* 
1449 * FUNCTION: CERT_EncodeOCSPRequest
1450 *   DER encodes an OCSP Request, possibly adding a signature as well.
1451 *   XXX Signing is not yet supported, however; see comments in code.
1452 * INPUTS: 
1453 *   PRArenaPool *arena
1454 *     The return value is allocated from here.
1455 *     If a NULL is passed in, allocation is done from the heap instead.
1456 *   CERTOCSPRequest *request
1457 *     The request to be encoded.
1458 *   void *pwArg
1459 *     Pointer to argument for password prompting, if needed.  (Definitely
1460 *     not needed if not signing.)
1461 * RETURN:
1462 *   Returns a NULL on error and a pointer to the SECItem with the
1463 *   encoded value otherwise.  Any error is likely to be low-level
1464 *   (e.g. no memory).
1465 */
1466SECItem *
1467CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request, 
1468		       void *pwArg)
1469{
1470    ocspTBSRequest *tbsRequest;
1471    SECStatus rv;
1472
1473    /* XXX All of these should generate errors if they fail. */
1474    PORT_Assert(request);
1475    PORT_Assert(request->tbsRequest);
1476
1477    tbsRequest = request->tbsRequest;
1478
1479    if (request->tbsRequest->extensionHandle != NULL) {
1480	rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle);
1481	request->tbsRequest->extensionHandle = NULL;
1482	if (rv != SECSuccess)
1483	    return NULL;
1484    }
1485
1486    /*
1487     * XXX When signed requests are supported and request->optionalSignature
1488     * is not NULL:
1489     *  - need to encode tbsRequest->requestorName
1490     *  - need to encode tbsRequest
1491     *  - need to sign that encoded result (using cert in sig), filling in the
1492     *    request->optionalSignature structure with the result, the signing
1493     *    algorithm and (perhaps?) the cert (and its chain?) in derCerts
1494     */
1495
1496    return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate);
1497}
1498
1499
1500/*
1501 * FUNCTION: CERT_DecodeOCSPRequest
1502 *   Decode a DER encoded OCSP Request.
1503 * INPUTS:
1504 *   SECItem *src
1505 *     Pointer to a SECItem holding DER encoded OCSP Request.
1506 * RETURN:
1507 *   Returns a pointer to a CERTOCSPRequest containing the decoded request.
1508 *   On error, returns NULL.  Most likely error is trouble decoding
1509 *   (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
1510 */
1511CERTOCSPRequest *
1512CERT_DecodeOCSPRequest(SECItem *src)
1513{
1514    PRArenaPool *arena = NULL;
1515    SECStatus rv = SECFailure;
1516    CERTOCSPRequest *dest = NULL;
1517    int i;
1518    SECItem newSrc;
1519
1520    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1521    if (arena == NULL) {
1522	goto loser;
1523    }
1524    dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena, 
1525						siz

Large files files are truncated, but you can click here to view the full file