Back to index

lightning-sunbird  0.9+nobinonly
ocsp.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Kai Engert (kengert@redhat.com)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * Implementation of OCSP services, for both client and server.
00040  * (XXX, really, mostly just for client right now, but intended to do both.)
00041  *
00042  * $Id: ocsp.c,v 1.21.2.16 2007/05/25 03:37:37 alexei.volkov.bugs%sun.com Exp $
00043  */
00044 
00045 #include "prerror.h"
00046 #include "prprf.h"
00047 #include "plarena.h"
00048 #include "prnetdb.h"
00049 
00050 #include "seccomon.h"
00051 #include "secitem.h"
00052 #include "secoidt.h"
00053 #include "secasn1.h"
00054 #include "secder.h"
00055 #include "cert.h"
00056 #include "xconst.h"
00057 #include "secerr.h"
00058 #include "secoid.h"
00059 #include "hasht.h"
00060 #include "sechash.h"
00061 #include "secasn1.h"
00062 #include "keyhi.h"
00063 #include "cryptohi.h"
00064 #include "ocsp.h"
00065 #include "ocspti.h"
00066 #include "genname.h"
00067 #include "certxutl.h"
00068 #include "pk11func.h"       /* for PK11_HashBuf */
00069 #include <stdarg.h>
00070 #include <plhash.h>
00071 
00072 #define DEFAULT_OCSP_CACHE_SIZE 1000
00073 #define DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 1*60*60L
00074 #define DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 24*60*60L
00075 #define MICROSECONDS_PER_SECOND 1000000L
00076 
00077 typedef struct OCSPCacheItemStr OCSPCacheItem;
00078 typedef struct OCSPCacheDataStr OCSPCacheData;
00079 
00080 struct OCSPCacheItemStr {
00081     /* LRU linking */
00082     OCSPCacheItem *moreRecent;
00083     OCSPCacheItem *lessRecent;
00084 
00085     /* key */
00086     CERTOCSPCertID *certID;
00087     /* CertID's arena also used to allocate "this" cache item */
00088 
00089     /* cache control information */
00090     PRTime nextFetchAttemptTime;
00091 
00092     /* Cached contents. Use a separate arena, because lifetime is different */
00093     PRArenaPool *certStatusArena; /* NULL means: no cert status cached */
00094     ocspCertStatus certStatus;
00095 
00096     PRPackedBool haveThisUpdate;
00097     PRPackedBool haveNextUpdate;
00098     PRTime thisUpdate;
00099     PRTime nextUpdate;
00100 };
00101 
00102 struct OCSPCacheDataStr {
00103     PLHashTable *entries;
00104     PRUint32 numberOfEntries;
00105     OCSPCacheItem *MRUitem; /* most recently used cache item */
00106     OCSPCacheItem *LRUitem; /* least recently used cache item */
00107 };
00108 
00109 static struct OCSPGlobalStruct {
00110     PRMonitor *monitor;
00111     const SEC_HttpClientFcn *defaultHttpClientFcn;
00112     PRInt32 maxCacheEntries;
00113     PRUint32 minimumSecondsToNextFetchAttempt;
00114     PRUint32 maximumSecondsToNextFetchAttempt;
00115     OCSPCacheData cache;
00116     SEC_OcspFailureMode ocspFailureMode;
00117 } OCSP_Global = { NULL, 
00118                   NULL, 
00119                   DEFAULT_OCSP_CACHE_SIZE, 
00120                   DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
00121                   DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
00122                   {NULL, 0, NULL, NULL},
00123                   ocspMode_FailureIsVerificationFailure
00124                 };
00125 
00126 /* Forward declarations */
00127 static SECItem *
00128 ocsp_GetEncodedOCSPResponseFromRequest(PRArenaPool *arena, 
00129                                        CERTOCSPRequest *request,
00130                                        char *location, int64 time,
00131                                        PRBool addServiceLocator,
00132                                        void *pwArg,
00133                                        CERTOCSPRequest **pRequest);
00134 static SECStatus
00135 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 
00136                               CERTOCSPCertID *certID, 
00137                               CERTCertificate *cert, 
00138                               int64 time, 
00139                               void *pwArg,
00140                               PRBool *certIDWasConsumed,
00141                               SECStatus *rv_ocsp);
00142 static SECStatus
00143 ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, 
00144                                         CERTOCSPResponse *response, 
00145                                         CERTOCSPCertID   *certID,
00146                                         CERTCertificate  *signerCert,
00147                                         int64             time,
00148                                         CERTOCSPSingleResponse **pSingleResponse);
00149 
00150 #ifndef DEBUG
00151 #define OCSP_TRACE(msg)
00152 #define OCSP_TRACE_TIME(msg, time)
00153 #define OCSP_TRACE_CERT(cert)
00154 #else
00155 #define OCSP_TRACE(msg) ocsp_Trace msg
00156 #define OCSP_TRACE_TIME(msg, time) ocsp_dumpStringWithTime(msg, time)
00157 #define OCSP_TRACE_CERT(cert) dumpCertificate(cert)
00158 
00159 #if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) \
00160      || defined(XP_MACOSX)) && !defined(_WIN32_WCE)
00161 #define NSS_HAVE_GETENV 1
00162 #endif
00163 
00164 static PRBool wantOcspTrace()
00165 {
00166     static PRBool firstTime = PR_TRUE;
00167     static PRBool wantTrace = PR_FALSE;
00168 
00169 #ifdef NSS_HAVE_GETENV
00170     if (firstTime) {
00171         char *ev = getenv("NSS_TRACE_OCSP");
00172         if (ev && ev[0]) {
00173             wantTrace = PR_TRUE;
00174         }
00175         firstTime = PR_FALSE;
00176     }
00177 #endif
00178     return wantTrace;
00179 }
00180 
00181 static void
00182 ocsp_Trace(const char *format, ...)
00183 {
00184     char buf[2000];
00185     va_list args;
00186   
00187     if (!wantOcspTrace())
00188         return;
00189     va_start(args, format);
00190     PR_vsnprintf(buf, sizeof(buf), format, args);
00191     va_end(args);
00192     PR_LogPrint("%s", buf);
00193 }
00194 
00195 static void
00196 ocsp_dumpStringWithTime(const char *str, int64 time)
00197 {
00198     PRExplodedTime timePrintable;
00199     char timestr[100];
00200 
00201     if (!wantOcspTrace())
00202         return;
00203     PR_ExplodeTime(time, PR_GMTParameters, &timePrintable);
00204     PR_FormatTime(timestr, 100, "%a %b %d %H:%M:%S %Y", 
00205                   &timePrintable);
00206     ocsp_Trace("OCSP %s %s\n", str, timestr);
00207 }
00208 
00209 static void
00210 printHexString(const char *prefix, SECItem *hexval)
00211 {
00212     unsigned int i;
00213     char *hexbuf = NULL;
00214 
00215     for (i = 0; i < hexval->len; i++) {
00216         if (i != hexval->len - 1) {
00217             PR_sprintf_append(hexbuf, "%02x:", hexval->data[i]);
00218         } else {
00219             PR_sprintf_append(hexbuf, "%02x", hexval->data[i]);
00220         }
00221     }
00222     if (hexbuf) {
00223         ocsp_Trace("%s %s\n", prefix, hexbuf);
00224         PR_smprintf_free(hexbuf);
00225     }
00226 }
00227 
00228 static void
00229 dumpCertificate(CERTCertificate *cert)
00230 {
00231     if (!wantOcspTrace())
00232         return;
00233 
00234     ocsp_Trace("OCSP ----------------\n");
00235     ocsp_Trace("OCSP ## SUBJECT:  %s\n", cert->subjectName);
00236     {
00237         int64 timeBefore, timeAfter;
00238         PRExplodedTime beforePrintable, afterPrintable;
00239         char beforestr[100], afterstr[100];
00240         DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore);
00241         DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter);
00242         PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable);
00243         PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable);
00244         PR_FormatTime(beforestr, 100, "%a %b %d %H:%M:%S %Y", 
00245                       &beforePrintable);
00246         PR_FormatTime(afterstr, 100, "%a %b %d %H:%M:%S %Y", 
00247                       &afterPrintable);
00248         ocsp_Trace("OCSP ## VALIDITY:  %s to %s\n", beforestr, afterstr);
00249     }
00250     ocsp_Trace("OCSP ## ISSUER:  %s\n", cert->issuerName);
00251     printHexString("OCSP ## SERIAL NUMBER:", &cert->serialNumber);
00252 }
00253 #endif
00254 
00255 SECStatus
00256 SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
00257 {
00258     if (!OCSP_Global.monitor) {
00259       PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00260       return SECFailure;
00261     }
00262     
00263     PR_EnterMonitor(OCSP_Global.monitor);
00264     OCSP_Global.defaultHttpClientFcn = fcnTable;
00265     PR_ExitMonitor(OCSP_Global.monitor);
00266     
00267     return SECSuccess;
00268 }
00269 
00270 static PLHashNumber PR_CALLBACK
00271 ocsp_CacheKeyHashFunction(const void *key)
00272 {
00273     CERTOCSPCertID *cid = (CERTOCSPCertID *)key;
00274     PLHashNumber hash = 0;
00275     unsigned int i;
00276     unsigned char *walk;
00277   
00278     /* a very simple hash calculation for the initial coding phase */
00279     walk = (unsigned char*)cid->issuerNameHash.data;
00280     for (i=0; i < cid->issuerNameHash.len; ++i, ++walk) {
00281         hash += *walk;
00282     }
00283     walk = (unsigned char*)cid->issuerKeyHash.data;
00284     for (i=0; i < cid->issuerKeyHash.len; ++i, ++walk) {
00285         hash += *walk;
00286     }
00287     walk = (unsigned char*)cid->serialNumber.data;
00288     for (i=0; i < cid->serialNumber.len; ++i, ++walk) {
00289         hash += *walk;
00290     }
00291     return hash;
00292 }
00293 
00294 static PRIntn PR_CALLBACK
00295 ocsp_CacheKeyCompareFunction(const void *v1, const void *v2)
00296 {
00297     CERTOCSPCertID *cid1 = (CERTOCSPCertID *)v1;
00298     CERTOCSPCertID *cid2 = (CERTOCSPCertID *)v2;
00299   
00300     return (SECEqual == SECITEM_CompareItem(&cid1->issuerNameHash, 
00301                                             &cid2->issuerNameHash)
00302             && SECEqual == SECITEM_CompareItem(&cid1->issuerKeyHash, 
00303                                                &cid2->issuerKeyHash)
00304             && SECEqual == SECITEM_CompareItem(&cid1->serialNumber, 
00305                                                &cid2->serialNumber));
00306 }
00307 
00308 static SECStatus
00309 ocsp_CopyRevokedInfo(PRArenaPool *arena, ocspCertStatus *dest, 
00310                      ocspRevokedInfo *src)
00311 {
00312     SECStatus rv = SECFailure;
00313     void *mark;
00314   
00315     mark = PORT_ArenaMark(arena);
00316   
00317     dest->certStatusInfo.revokedInfo = 
00318         (ocspRevokedInfo *) PORT_ArenaZAlloc(arena, sizeof(ocspRevokedInfo));
00319     if (!dest->certStatusInfo.revokedInfo) {
00320         goto loser;
00321     }
00322   
00323     rv = SECITEM_CopyItem(arena, 
00324                           &dest->certStatusInfo.revokedInfo->revocationTime, 
00325                           &src->revocationTime);
00326     if (rv != SECSuccess) {
00327         goto loser;
00328     }
00329   
00330     if (src->revocationReason) {
00331         dest->certStatusInfo.revokedInfo->revocationReason = 
00332             SECITEM_ArenaDupItem(arena, src->revocationReason);
00333         if (!dest->certStatusInfo.revokedInfo->revocationReason) {
00334             goto loser;
00335         }
00336     }  else {
00337         dest->certStatusInfo.revokedInfo->revocationReason = NULL;
00338     }
00339   
00340     PORT_ArenaUnmark(arena, mark);
00341     return SECSuccess;
00342 
00343 loser:
00344     PORT_ArenaRelease(arena, mark);
00345     return SECFailure;
00346 }
00347 
00348 static SECStatus
00349 ocsp_CopyCertStatus(PRArenaPool *arena, ocspCertStatus *dest, 
00350                     ocspCertStatus*src)
00351 {
00352     SECStatus rv = SECFailure;
00353     dest->certStatusType = src->certStatusType;
00354   
00355     switch (src->certStatusType) {
00356     case ocspCertStatus_good:
00357         dest->certStatusInfo.goodInfo = 
00358             SECITEM_ArenaDupItem(arena, src->certStatusInfo.goodInfo);
00359         if (dest->certStatusInfo.goodInfo != NULL) {
00360             rv = SECSuccess;
00361         }
00362         break;
00363     case ocspCertStatus_revoked:
00364         rv = ocsp_CopyRevokedInfo(arena, dest, 
00365                                   src->certStatusInfo.revokedInfo);
00366         break;
00367     case ocspCertStatus_unknown:
00368         dest->certStatusInfo.unknownInfo = 
00369             SECITEM_ArenaDupItem(arena, src->certStatusInfo.unknownInfo);
00370         if (dest->certStatusInfo.unknownInfo != NULL) {
00371             rv = SECSuccess;
00372         }
00373         break;
00374     case ocspCertStatus_other:
00375     default:
00376         PORT_Assert(src->certStatusType == ocspCertStatus_other);
00377         dest->certStatusInfo.otherInfo = 
00378             SECITEM_ArenaDupItem(arena, src->certStatusInfo.otherInfo);
00379         if (dest->certStatusInfo.otherInfo != NULL) {
00380             rv = SECSuccess;
00381         }
00382         break;
00383     }
00384     return rv;
00385 }
00386 
00387 static void
00388 ocsp_AddCacheItemToLinkedList(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
00389 {
00390     PR_EnterMonitor(OCSP_Global.monitor);
00391 
00392     if (!cache->LRUitem) {
00393         cache->LRUitem = new_most_recent;
00394     }
00395     new_most_recent->lessRecent = cache->MRUitem;
00396     new_most_recent->moreRecent = NULL;
00397 
00398     if (cache->MRUitem) {
00399         cache->MRUitem->moreRecent = new_most_recent;
00400     }
00401     cache->MRUitem = new_most_recent;
00402 
00403     PR_ExitMonitor(OCSP_Global.monitor);
00404 }
00405 
00406 static void
00407 ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData *cache, OCSPCacheItem *item)
00408 {
00409     PR_EnterMonitor(OCSP_Global.monitor);
00410 
00411     if (!item->lessRecent && !item->moreRecent) {
00412         /*
00413          * Fail gracefully on attempts to remove an item from the list,
00414          * which is currently not part of the list.
00415          * But check for the edge case it is the single entry in the list.
00416          */
00417         if (item == cache->LRUitem &&
00418             item == cache->MRUitem) {
00419             /* remove the single entry */
00420             PORT_Assert(cache->numberOfEntries == 1);
00421             PORT_Assert(item->moreRecent == NULL);
00422             cache->MRUitem = NULL;
00423             cache->LRUitem = NULL;
00424         }
00425         PR_ExitMonitor(OCSP_Global.monitor);
00426         return;
00427     }
00428 
00429     PORT_Assert(cache->numberOfEntries > 1);
00430   
00431     if (item == cache->LRUitem) {
00432         PORT_Assert(item != cache->MRUitem);
00433         PORT_Assert(item->lessRecent == NULL);
00434         PORT_Assert(item->moreRecent != NULL);
00435         PORT_Assert(item->moreRecent->lessRecent == item);
00436         cache->LRUitem = item->moreRecent;
00437         cache->LRUitem->lessRecent = NULL;
00438     }
00439     else if (item == cache->MRUitem) {
00440         PORT_Assert(item->moreRecent == NULL);
00441         PORT_Assert(item->lessRecent != NULL);
00442         PORT_Assert(item->lessRecent->moreRecent == item);
00443         cache->MRUitem = item->lessRecent;
00444         cache->MRUitem->moreRecent = NULL;
00445     } else {
00446         /* remove an entry in the middle of the list */
00447         PORT_Assert(item->moreRecent != NULL);
00448         PORT_Assert(item->lessRecent != NULL);
00449         PORT_Assert(item->lessRecent->moreRecent == item);
00450         PORT_Assert(item->moreRecent->lessRecent == item);
00451         item->moreRecent->lessRecent = item->lessRecent;
00452         item->lessRecent->moreRecent = item->moreRecent;
00453     }
00454 
00455     item->lessRecent = NULL;
00456     item->moreRecent = NULL;
00457 
00458     PR_ExitMonitor(OCSP_Global.monitor);
00459 }
00460 
00461 static void
00462 ocsp_MakeCacheEntryMostRecent(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
00463 {
00464     OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent THREADID %p\n", 
00465                 PR_GetCurrentThread()));
00466     PR_EnterMonitor(OCSP_Global.monitor);
00467     if (cache->MRUitem == new_most_recent) {
00468         OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent ALREADY MOST\n"));
00469         PR_ExitMonitor(OCSP_Global.monitor);
00470         return;
00471     }
00472     OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent NEW entry\n"));
00473     ocsp_RemoveCacheItemFromLinkedList(cache, new_most_recent);
00474     ocsp_AddCacheItemToLinkedList(cache, new_most_recent);
00475     PR_ExitMonitor(OCSP_Global.monitor);
00476 }
00477 
00478 static PRBool
00479 ocsp_IsCacheDisabled()
00480 {
00481     /* 
00482      * maxCacheEntries == 0 means unlimited cache entries
00483      * maxCacheEntries  < 0 means cache is disabled
00484      */
00485     PRBool retval;
00486     PR_EnterMonitor(OCSP_Global.monitor);
00487     retval = (OCSP_Global.maxCacheEntries < 0);
00488     PR_ExitMonitor(OCSP_Global.monitor);
00489     return retval;
00490 }
00491 
00492 static OCSPCacheItem *
00493 ocsp_FindCacheEntry(OCSPCacheData *cache, CERTOCSPCertID *certID)
00494 {
00495     OCSPCacheItem *found_ocsp_item = NULL;
00496     OCSP_TRACE(("OCSP ocsp_FindCacheEntry\n"));
00497     PR_EnterMonitor(OCSP_Global.monitor);
00498     if (ocsp_IsCacheDisabled())
00499         goto loser;
00500   
00501     found_ocsp_item = (OCSPCacheItem *)PL_HashTableLookup(
00502                           cache->entries, certID);
00503     if (!found_ocsp_item)
00504         goto loser;
00505   
00506     OCSP_TRACE(("OCSP ocsp_FindCacheEntry FOUND!\n"));
00507     ocsp_MakeCacheEntryMostRecent(cache, found_ocsp_item);
00508 
00509 loser:
00510     PR_ExitMonitor(OCSP_Global.monitor);
00511     return found_ocsp_item;
00512 }
00513 
00514 static void
00515 ocsp_FreeCacheItem(OCSPCacheItem *item)
00516 {
00517     OCSP_TRACE(("OCSP ocsp_FreeCacheItem\n"));
00518     if (item->certStatusArena) {
00519         PORT_FreeArena(item->certStatusArena, PR_FALSE);
00520     }
00521     if (item->certID->poolp) {
00522         /* freeing this poolp arena will also free item */
00523         PORT_FreeArena(item->certID->poolp, PR_FALSE);
00524     }
00525 }
00526 
00527 static void
00528 ocsp_RemoveCacheItem(OCSPCacheData *cache, OCSPCacheItem *item)
00529 {
00530     /* The item we're removing could be either the least recently used item,
00531      * or it could be an item that couldn't get updated with newer status info
00532      * because of an allocation failure, or it could get removed because we're 
00533      * cleaning up.
00534      */
00535     PRBool couldRemoveFromHashTable;
00536     OCSP_TRACE(("OCSP ocsp_RemoveCacheItem, THREADID %p\n", PR_GetCurrentThread()));
00537     PR_EnterMonitor(OCSP_Global.monitor);
00538 
00539     ocsp_RemoveCacheItemFromLinkedList(cache, item);
00540     couldRemoveFromHashTable = PL_HashTableRemove(cache->entries, 
00541                                                   item->certID);
00542     PORT_Assert(couldRemoveFromHashTable);
00543     --cache->numberOfEntries;
00544     ocsp_FreeCacheItem(item);
00545     PR_ExitMonitor(OCSP_Global.monitor);
00546 }
00547 
00548 static void
00549 ocsp_CheckCacheSize(OCSPCacheData *cache)
00550 {
00551     OCSP_TRACE(("OCSP ocsp_CheckCacheSize\n"));
00552     PR_EnterMonitor(OCSP_Global.monitor);
00553     if (OCSP_Global.maxCacheEntries <= 0) /* disabled or unlimited */
00554         return;
00555     while (cache->numberOfEntries > OCSP_Global.maxCacheEntries) {
00556         ocsp_RemoveCacheItem(cache, cache->LRUitem);
00557     }
00558     PR_ExitMonitor(OCSP_Global.monitor);
00559 }
00560 
00561 SECStatus
00562 CERT_ClearOCSPCache()
00563 {
00564     OCSP_TRACE(("OCSP CERT_ClearOCSPCache\n"));
00565     PR_EnterMonitor(OCSP_Global.monitor);
00566     while (OCSP_Global.cache.numberOfEntries > 0) {
00567         ocsp_RemoveCacheItem(&OCSP_Global.cache, 
00568                              OCSP_Global.cache.LRUitem);
00569     }
00570     PR_ExitMonitor(OCSP_Global.monitor);
00571     return SECSuccess;
00572 }
00573 
00574 static SECStatus
00575 ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData *cache,
00576                                      CERTOCSPCertID *certID, 
00577                                      OCSPCacheItem **pCacheItem)
00578 {
00579     PRArenaPool *arena;
00580     void *mark;
00581     PLHashEntry *new_hash_entry;
00582     OCSPCacheItem *item;
00583   
00584     PORT_Assert(pCacheItem != NULL);
00585     *pCacheItem = NULL;
00586 
00587     PR_EnterMonitor(OCSP_Global.monitor);
00588     arena = certID->poolp;
00589     mark = PORT_ArenaMark(arena);
00590   
00591     /* ZAlloc will init all Bools to False and all Pointers to NULL */
00592     item = (OCSPCacheItem *)PORT_ArenaZAlloc(certID->poolp, 
00593                                              sizeof(OCSPCacheItem));
00594     if (!item) {
00595         goto loser; 
00596     }
00597     item->certID = certID;
00598     new_hash_entry = PL_HashTableAdd(cache->entries, item->certID, 
00599                                      item);
00600     if (!new_hash_entry) {
00601         goto loser;
00602     }
00603     ++cache->numberOfEntries;
00604     PORT_ArenaUnmark(arena, mark);
00605     ocsp_AddCacheItemToLinkedList(cache, item);
00606     *pCacheItem = item;
00607 
00608     PR_ExitMonitor(OCSP_Global.monitor);
00609     return SECSuccess;
00610   
00611 loser:
00612     PORT_ArenaRelease(arena, mark);
00613     PR_ExitMonitor(OCSP_Global.monitor);
00614     return SECFailure;
00615 }
00616 
00617 static SECStatus
00618 ocsp_SetCacheItemResponse(OCSPCacheItem *item,
00619                           const CERTOCSPSingleResponse *response)
00620 {
00621     if (item->certStatusArena) {
00622         PORT_FreeArena(item->certStatusArena, PR_FALSE);
00623         item->certStatusArena = NULL;
00624     }
00625     item->haveThisUpdate = item->haveNextUpdate = PR_FALSE;
00626     if (response) {
00627         SECStatus rv;
00628         item->certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00629         if (item->certStatusArena == NULL) {
00630             return SECFailure;
00631         }
00632         rv = ocsp_CopyCertStatus(item->certStatusArena, &item->certStatus, 
00633                                  response->certStatus);
00634         if (rv != SECSuccess) {
00635             PORT_FreeArena(item->certStatusArena, PR_FALSE);
00636             item->certStatusArena = NULL;
00637             return rv;
00638         }
00639         rv = DER_GeneralizedTimeToTime(&item->thisUpdate, 
00640                                        &response->thisUpdate);
00641         item->haveThisUpdate = (rv == SECSuccess);
00642         if (response->nextUpdate) {
00643             rv = DER_GeneralizedTimeToTime(&item->nextUpdate, 
00644                                            response->nextUpdate);
00645             item->haveNextUpdate = (rv == SECSuccess);
00646         } else {
00647             item->haveNextUpdate = PR_FALSE;
00648         }
00649     }
00650     return SECSuccess;
00651 }
00652 
00653 static void
00654 ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem *cacheItem)
00655 {
00656     PRTime now;
00657     PRTime earliestAllowedNextFetchAttemptTime;
00658     PRTime latestTimeWhenResponseIsConsideredFresh;
00659   
00660     OCSP_TRACE(("OCSP ocsp_FreshenCacheItemNextFetchAttemptTime\n"));
00661 
00662     PR_EnterMonitor(OCSP_Global.monitor);
00663   
00664     now = PR_Now();
00665     OCSP_TRACE_TIME("now:", now);
00666   
00667     if (cacheItem->haveThisUpdate) {
00668         OCSP_TRACE_TIME("thisUpdate:", cacheItem->thisUpdate);
00669         latestTimeWhenResponseIsConsideredFresh = cacheItem->thisUpdate +
00670             OCSP_Global.maximumSecondsToNextFetchAttempt * 
00671                 MICROSECONDS_PER_SECOND;
00672         OCSP_TRACE_TIME("latestTimeWhenResponseIsConsideredFresh:", 
00673                         latestTimeWhenResponseIsConsideredFresh);
00674     } else {
00675         latestTimeWhenResponseIsConsideredFresh = now +
00676             OCSP_Global.minimumSecondsToNextFetchAttempt *
00677                 MICROSECONDS_PER_SECOND;
00678         OCSP_TRACE_TIME("no thisUpdate, "
00679                         "latestTimeWhenResponseIsConsideredFresh:", 
00680                         latestTimeWhenResponseIsConsideredFresh);
00681     }
00682   
00683     if (cacheItem->haveNextUpdate) {
00684         OCSP_TRACE_TIME("have nextUpdate:", cacheItem->thisUpdate);
00685     }
00686   
00687     if (cacheItem->haveNextUpdate &&
00688         cacheItem->nextUpdate < latestTimeWhenResponseIsConsideredFresh) {
00689         latestTimeWhenResponseIsConsideredFresh = cacheItem->nextUpdate;
00690         OCSP_TRACE_TIME("nextUpdate is smaller than latestFresh, setting "
00691                         "latestTimeWhenResponseIsConsideredFresh:", 
00692                         latestTimeWhenResponseIsConsideredFresh);
00693     }
00694   
00695     earliestAllowedNextFetchAttemptTime = now +
00696         OCSP_Global.minimumSecondsToNextFetchAttempt * 
00697             MICROSECONDS_PER_SECOND;
00698     OCSP_TRACE_TIME("earliestAllowedNextFetchAttemptTime:", 
00699                     earliestAllowedNextFetchAttemptTime);
00700   
00701     if (latestTimeWhenResponseIsConsideredFresh < 
00702         earliestAllowedNextFetchAttemptTime) {
00703         latestTimeWhenResponseIsConsideredFresh = 
00704             earliestAllowedNextFetchAttemptTime;
00705         OCSP_TRACE_TIME("latest < earliest, setting latest to:", 
00706                         latestTimeWhenResponseIsConsideredFresh);
00707     }
00708   
00709     cacheItem->nextFetchAttemptTime = 
00710         latestTimeWhenResponseIsConsideredFresh;
00711     OCSP_TRACE_TIME("nextFetchAttemptTime", 
00712         latestTimeWhenResponseIsConsideredFresh);
00713 
00714     PR_ExitMonitor(OCSP_Global.monitor);
00715 }
00716 
00717 static PRBool
00718 ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem)
00719 {
00720     PRTime now;
00721     PRBool retval;
00722 
00723     PR_EnterMonitor(OCSP_Global.monitor);
00724     now = PR_Now();
00725     retval = (cacheItem->nextFetchAttemptTime > now);
00726     OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", retval));
00727     PR_ExitMonitor(OCSP_Global.monitor);
00728     return retval;
00729 }
00730 
00731 /*
00732  * Status in *certIDWasConsumed will always be correct, regardless of 
00733  * return value.
00734  */
00735 static SECStatus
00736 ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache, 
00737                               CERTOCSPCertID *certID,
00738                               CERTOCSPSingleResponse *single,
00739                               PRBool *certIDWasConsumed)
00740 {
00741     SECStatus rv;
00742     OCSPCacheItem *cacheItem;
00743     OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n"));
00744   
00745     if (!certIDWasConsumed) {
00746         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00747         return SECFailure;
00748     }
00749     *certIDWasConsumed = PR_FALSE;
00750   
00751     PR_EnterMonitor(OCSP_Global.monitor);
00752     PORT_Assert(OCSP_Global.maxCacheEntries >= 0);
00753   
00754     cacheItem = ocsp_FindCacheEntry(cache, certID);
00755     if (!cacheItem) {
00756         rv = ocsp_CreateCacheItemAndConsumeCertID(cache, certID, 
00757                                                   &cacheItem);
00758         if (rv != SECSuccess) {
00759             PR_ExitMonitor(OCSP_Global.monitor);
00760             return rv;
00761         }
00762         *certIDWasConsumed = PR_TRUE;
00763     }
00764     if (single) {
00765         rv = ocsp_SetCacheItemResponse(cacheItem, single);
00766         if (rv != SECSuccess) {
00767             ocsp_RemoveCacheItem(cache, cacheItem);
00768             PR_ExitMonitor(OCSP_Global.monitor);
00769             return rv;
00770         }
00771     }
00772     ocsp_FreshenCacheItemNextFetchAttemptTime(cacheItem);
00773     ocsp_CheckCacheSize(cache);
00774 
00775     PR_ExitMonitor(OCSP_Global.monitor);
00776     return SECSuccess;
00777 }
00778 
00779 extern SECStatus
00780 CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode)
00781 {
00782     switch (ocspFailureMode) {
00783     case ocspMode_FailureIsVerificationFailure:
00784     case ocspMode_FailureIsNotAVerificationFailure:
00785         break;
00786     default:
00787         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00788         return SECFailure;
00789     }
00790 
00791     PR_EnterMonitor(OCSP_Global.monitor);
00792     OCSP_Global.ocspFailureMode = ocspFailureMode;
00793     PR_ExitMonitor(OCSP_Global.monitor);
00794     return SECSuccess;
00795 }
00796 
00797 SECStatus
00798 CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
00799                        PRUint32 minimumSecondsToNextFetchAttempt,
00800                        PRUint32 maximumSecondsToNextFetchAttempt)
00801 {
00802     if (minimumSecondsToNextFetchAttempt > maximumSecondsToNextFetchAttempt
00803         || maxCacheEntries < -1) {
00804         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00805         return SECFailure;
00806     }
00807   
00808     PR_EnterMonitor(OCSP_Global.monitor);
00809   
00810     if (maxCacheEntries < 0) {
00811         OCSP_Global.maxCacheEntries = -1; /* disable cache */
00812     } else if (maxCacheEntries == 0) {
00813         OCSP_Global.maxCacheEntries = 0; /* unlimited cache entries */
00814     } else {
00815         OCSP_Global.maxCacheEntries = maxCacheEntries;
00816     }
00817   
00818     if (minimumSecondsToNextFetchAttempt < 
00819             OCSP_Global.minimumSecondsToNextFetchAttempt
00820         || maximumSecondsToNextFetchAttempt < 
00821             OCSP_Global.maximumSecondsToNextFetchAttempt) {
00822         /*
00823          * Ensure our existing cache entries are not used longer than the 
00824          * new settings allow, we're lazy and just clear the cache
00825          */
00826         CERT_ClearOCSPCache();
00827     }
00828   
00829     OCSP_Global.minimumSecondsToNextFetchAttempt = 
00830         minimumSecondsToNextFetchAttempt;
00831     OCSP_Global.maximumSecondsToNextFetchAttempt = 
00832         maximumSecondsToNextFetchAttempt;
00833     ocsp_CheckCacheSize(&OCSP_Global.cache);
00834   
00835     PR_ExitMonitor(OCSP_Global.monitor);
00836     return SECSuccess;
00837 }
00838 
00839 /* this function is called at NSS initialization time */
00840 SECStatus OCSP_InitGlobal(void)
00841 {
00842     SECStatus rv = SECFailure;
00843 
00844     if (OCSP_Global.monitor == NULL) {
00845         OCSP_Global.monitor = PR_NewMonitor();
00846     }
00847     if (!OCSP_Global.monitor)
00848         return SECFailure;
00849 
00850     PR_EnterMonitor(OCSP_Global.monitor);
00851     if (!OCSP_Global.cache.entries) {
00852         OCSP_Global.cache.entries = 
00853             PL_NewHashTable(0, 
00854                             ocsp_CacheKeyHashFunction, 
00855                             ocsp_CacheKeyCompareFunction, 
00856                             PL_CompareValues, 
00857                             NULL, 
00858                             NULL);
00859         OCSP_Global.ocspFailureMode = ocspMode_FailureIsVerificationFailure;
00860         OCSP_Global.cache.numberOfEntries = 0;
00861         OCSP_Global.cache.MRUitem = NULL;
00862         OCSP_Global.cache.LRUitem = NULL;
00863     } else {
00864         /*
00865          * NSS might call this function twice while attempting to init.
00866          * But it's not allowed to call this again after any activity.
00867          */
00868         PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
00869         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00870     }
00871     if (OCSP_Global.cache.entries)
00872         rv = SECSuccess;
00873     PR_ExitMonitor(OCSP_Global.monitor);
00874     return rv;
00875 }
00876 
00877 SECStatus OCSP_ShutdownCache(void)
00878 {
00879     if (!OCSP_Global.monitor)
00880         return SECSuccess;
00881 
00882     PR_EnterMonitor(OCSP_Global.monitor);
00883     if (OCSP_Global.cache.entries) {
00884         CERT_ClearOCSPCache();
00885         PL_HashTableDestroy(OCSP_Global.cache.entries);
00886         OCSP_Global.cache.entries = NULL;
00887     }
00888     PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
00889     OCSP_Global.cache.MRUitem = NULL;
00890     OCSP_Global.cache.LRUitem = NULL;
00891     PR_ExitMonitor(OCSP_Global.monitor);
00892     return SECSuccess;
00893 }
00894 
00895 /*
00896  * A return value of NULL means: 
00897  *   The application did not register it's own HTTP client.
00898  */
00899 static const SEC_HttpClientFcn *GetRegisteredHttpClient()
00900 {
00901     const SEC_HttpClientFcn *retval;
00902 
00903     if (!OCSP_Global.monitor) {
00904       PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00905       return NULL;
00906     }
00907 
00908     PR_EnterMonitor(OCSP_Global.monitor);
00909     retval = OCSP_Global.defaultHttpClientFcn;
00910     PR_ExitMonitor(OCSP_Global.monitor);
00911     
00912     return retval;
00913 }
00914 
00915 /*
00916  * The following structure is only used internally.  It is allocated when
00917  * someone turns on OCSP checking, and hangs off of the status-configuration
00918  * structure in the certdb structure.  We use it to keep configuration
00919  * information specific to OCSP checking.
00920  */
00921 typedef struct ocspCheckingContextStr {
00922     PRBool useDefaultResponder;
00923     char *defaultResponderURI;
00924     char *defaultResponderNickname;
00925     CERTCertificate *defaultResponderCert;
00926 } ocspCheckingContext;
00927 
00928 
00929 /*
00930  * Forward declarations of sub-types, so I can lay out the types in the
00931  * same order as the ASN.1 is laid out in the OCSP spec itself.
00932  *
00933  * These are in alphabetical order (case-insensitive); please keep it that way!
00934  */
00935 extern const SEC_ASN1Template ocsp_CertIDTemplate[];
00936 extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[];
00937 extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[];
00938 extern const SEC_ASN1Template ocsp_ResponseDataTemplate[];
00939 extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[];
00940 extern const SEC_ASN1Template ocsp_SingleRequestTemplate[];
00941 extern const SEC_ASN1Template ocsp_SingleResponseTemplate[];
00942 extern const SEC_ASN1Template ocsp_TBSRequestTemplate[];
00943 
00944 
00945 /*
00946  * Request-related templates...
00947  */
00948 
00949 /*
00950  * OCSPRequest       ::=    SEQUENCE {
00951  *     tbsRequest           TBSRequest,
00952  *     optionalSignature    [0] EXPLICIT Signature OPTIONAL }
00953  */
00954 static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = {
00955     { SEC_ASN1_SEQUENCE,
00956        0, NULL, sizeof(CERTOCSPRequest) },
00957     { SEC_ASN1_POINTER,
00958        offsetof(CERTOCSPRequest, tbsRequest),
00959        ocsp_TBSRequestTemplate },
00960     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
00961       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
00962        offsetof(CERTOCSPRequest, optionalSignature),
00963        ocsp_PointerToSignatureTemplate },
00964     { 0 }
00965 };
00966 
00967 /*
00968  * TBSRequest ::=    SEQUENCE {
00969  *     version                     [0] EXPLICIT Version DEFAULT v1,
00970  *     requestorName        [1] EXPLICIT GeneralName OPTIONAL,
00971  *     requestList          SEQUENCE OF Request,
00972  *     requestExtensions    [2] EXPLICIT Extensions OPTIONAL }
00973  *
00974  * Version    ::=    INTEGER { v1(0) }
00975  *
00976  * Note: this should be static but the AIX compiler doesn't like it (because it
00977  * was forward-declared above); it is not meant to be exported, but this
00978  * is the only way it will compile.
00979  */
00980 const SEC_ASN1Template ocsp_TBSRequestTemplate[] = {
00981     { SEC_ASN1_SEQUENCE,
00982        0, NULL, sizeof(ocspTBSRequest) },
00983     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |           /* XXX DER_DEFAULT */
00984       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
00985        offsetof(ocspTBSRequest, version),
00986        SEC_IntegerTemplate },
00987     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
00988       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
00989        offsetof(ocspTBSRequest, derRequestorName),
00990        SEC_PointerToAnyTemplate },
00991     { SEC_ASN1_SEQUENCE_OF,
00992        offsetof(ocspTBSRequest, requestList),
00993        ocsp_SingleRequestTemplate },
00994     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
00995       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
00996        offsetof(ocspTBSRequest, requestExtensions),
00997        CERT_SequenceOfCertExtensionTemplate },
00998     { 0 }
00999 };
01000 
01001 /*
01002  * Signature  ::=    SEQUENCE {
01003  *     signatureAlgorithm   AlgorithmIdentifier,
01004  *     signature            BIT STRING,
01005  *     certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
01006  */
01007 static const SEC_ASN1Template ocsp_SignatureTemplate[] = {
01008     { SEC_ASN1_SEQUENCE,
01009        0, NULL, sizeof(ocspSignature) },
01010     { SEC_ASN1_INLINE,
01011        offsetof(ocspSignature, signatureAlgorithm),
01012        SECOID_AlgorithmIDTemplate },
01013     { SEC_ASN1_BIT_STRING,
01014        offsetof(ocspSignature, signature) },
01015     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01016       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01017        offsetof(ocspSignature, derCerts), 
01018        SEC_SequenceOfAnyTemplate },
01019     { 0 }
01020 };
01021 
01022 /*
01023  * This template is just an extra level to use in an explicitly-tagged
01024  * reference to a Signature.
01025  *
01026  * Note: this should be static but the AIX compiler doesn't like it (because it
01027  * was forward-declared above); it is not meant to be exported, but this
01028  * is the only way it will compile.
01029  */
01030 const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = {
01031     { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate }
01032 };
01033 
01034 /*
01035  * Request    ::=    SEQUENCE {
01036  *     reqCert                     CertID,
01037  *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
01038  *
01039  * Note: this should be static but the AIX compiler doesn't like it (because it
01040  * was forward-declared above); it is not meant to be exported, but this
01041  * is the only way it will compile.
01042  */
01043 const SEC_ASN1Template ocsp_SingleRequestTemplate[] = {
01044     { SEC_ASN1_SEQUENCE, 
01045        0, NULL, sizeof(ocspSingleRequest) },
01046     { SEC_ASN1_POINTER,
01047        offsetof(ocspSingleRequest, reqCert),
01048        ocsp_CertIDTemplate },
01049     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01050       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01051        offsetof(ocspSingleRequest, singleRequestExtensions),
01052        CERT_SequenceOfCertExtensionTemplate },
01053     { 0 }
01054 };
01055 
01056 
01057 /*
01058  * This data structure and template (CertID) is used by both OCSP
01059  * requests and responses.  It is the only one that is shared.
01060  *
01061  * CertID     ::=    SEQUENCE {
01062  *     hashAlgorithm        AlgorithmIdentifier,
01063  *     issuerNameHash              OCTET STRING, -- Hash of Issuer DN
01064  *     issuerKeyHash        OCTET STRING, -- Hash of Issuer public key
01065  *     serialNumber         CertificateSerialNumber }
01066  *
01067  * CertificateSerialNumber ::=     INTEGER
01068  *
01069  * Note: this should be static but the AIX compiler doesn't like it (because it
01070  * was forward-declared above); it is not meant to be exported, but this
01071  * is the only way it will compile.
01072  */
01073 const SEC_ASN1Template ocsp_CertIDTemplate[] = {
01074     { SEC_ASN1_SEQUENCE, 
01075        0, NULL, sizeof(CERTOCSPCertID) },
01076     { SEC_ASN1_INLINE,
01077        offsetof(CERTOCSPCertID, hashAlgorithm),
01078        SECOID_AlgorithmIDTemplate },
01079     { SEC_ASN1_OCTET_STRING,
01080        offsetof(CERTOCSPCertID, issuerNameHash) },
01081     { SEC_ASN1_OCTET_STRING,
01082        offsetof(CERTOCSPCertID, issuerKeyHash) },
01083     { SEC_ASN1_INTEGER, 
01084        offsetof(CERTOCSPCertID, serialNumber) },
01085     { 0 }
01086 };
01087 
01088 
01089 /*
01090  * Response-related templates...
01091  */
01092 
01093 /*
01094  * OCSPResponse      ::=    SEQUENCE {
01095  *     responseStatus              OCSPResponseStatus,
01096  *     responseBytes        [0] EXPLICIT ResponseBytes OPTIONAL }
01097  */
01098 static const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = {
01099     { SEC_ASN1_SEQUENCE, 
01100        0, NULL, sizeof(CERTOCSPResponse) },
01101     { SEC_ASN1_ENUMERATED, 
01102        offsetof(CERTOCSPResponse, responseStatus) },
01103     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01104       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01105        offsetof(CERTOCSPResponse, responseBytes),
01106        ocsp_PointerToResponseBytesTemplate },
01107     { 0 }
01108 };
01109 
01110 /*
01111  * ResponseBytes     ::=    SEQUENCE {
01112  *     responseType         OBJECT IDENTIFIER,
01113  *     response             OCTET STRING }
01114  */
01115 static const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = {
01116     { SEC_ASN1_SEQUENCE,
01117        0, NULL, sizeof(ocspResponseBytes) },
01118     { SEC_ASN1_OBJECT_ID,
01119        offsetof(ocspResponseBytes, responseType) },
01120     { SEC_ASN1_OCTET_STRING,
01121        offsetof(ocspResponseBytes, response) },
01122     { 0 }
01123 };
01124 
01125 /*
01126  * This template is just an extra level to use in an explicitly-tagged
01127  * reference to a ResponseBytes.
01128  *
01129  * Note: this should be static but the AIX compiler doesn't like it (because it
01130  * was forward-declared above); it is not meant to be exported, but this
01131  * is the only way it will compile.
01132  */
01133 const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = {
01134     { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate }
01135 };
01136 
01137 /*
01138  * BasicOCSPResponse ::=    SEQUENCE {
01139  *     tbsResponseData             ResponseData,
01140  *     signatureAlgorithm   AlgorithmIdentifier,
01141  *     signature            BIT STRING,
01142  *     certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
01143  */
01144 static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = {
01145     { SEC_ASN1_SEQUENCE,
01146        0, NULL, sizeof(ocspBasicOCSPResponse) },
01147     { SEC_ASN1_ANY | SEC_ASN1_SAVE,
01148        offsetof(ocspBasicOCSPResponse, tbsResponseDataDER) },
01149     { SEC_ASN1_POINTER,
01150        offsetof(ocspBasicOCSPResponse, tbsResponseData),
01151        ocsp_ResponseDataTemplate },
01152     { SEC_ASN1_INLINE,
01153        offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
01154        SECOID_AlgorithmIDTemplate },
01155     { SEC_ASN1_BIT_STRING,
01156        offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
01157     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01158       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01159        offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
01160        SEC_SequenceOfAnyTemplate },
01161     { 0 }
01162 };
01163 
01164 /*
01165  * ResponseData      ::=    SEQUENCE {
01166  *     version                     [0] EXPLICIT Version DEFAULT v1,
01167  *     responderID          ResponderID,
01168  *     producedAt           GeneralizedTime,
01169  *     responses            SEQUENCE OF SingleResponse,
01170  *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
01171  *
01172  * Note: this should be static but the AIX compiler doesn't like it (because it
01173  * was forward-declared above); it is not meant to be exported, but this
01174  * is the only way it will compile.
01175  */
01176 const SEC_ASN1Template ocsp_ResponseDataTemplate[] = {
01177     { SEC_ASN1_SEQUENCE,
01178        0, NULL, sizeof(ocspResponseData) },
01179     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |           /* XXX DER_DEFAULT */
01180       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01181        offsetof(ocspResponseData, version),
01182        SEC_IntegerTemplate },
01183     { SEC_ASN1_ANY,
01184        offsetof(ocspResponseData, derResponderID) },
01185     { SEC_ASN1_GENERALIZED_TIME,
01186        offsetof(ocspResponseData, producedAt) },
01187     { SEC_ASN1_SEQUENCE_OF,
01188        offsetof(ocspResponseData, responses),
01189        ocsp_SingleResponseTemplate },
01190     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01191       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
01192        offsetof(ocspResponseData, responseExtensions),
01193        CERT_SequenceOfCertExtensionTemplate },
01194     { 0 }
01195 };
01196 
01197 /*
01198  * ResponderID       ::=    CHOICE {
01199  *     byName               [1] EXPLICIT Name,
01200  *     byKey                [2] EXPLICIT KeyHash }
01201  *
01202  * KeyHash ::=       OCTET STRING -- SHA-1 hash of responder's public key
01203  * (excluding the tag and length fields)
01204  *
01205  * XXX Because the ASN.1 encoder and decoder currently do not provide
01206  * a way to automatically handle a CHOICE, we need to do it in two
01207  * steps, looking at the type tag and feeding the exact choice back
01208  * to the ASN.1 code.  Hopefully that will change someday and this
01209  * can all be simplified down into a single template.  Anyway, for
01210  * now we list each choice as its own template:
01211  */
01212 static const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = {
01213     { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
01214        offsetof(ocspResponderID, responderIDValue.name),
01215        CERT_NameTemplate }
01216 };
01217 static const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = {
01218     { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
01219        offsetof(ocspResponderID, responderIDValue.keyHash),
01220        SEC_OctetStringTemplate }
01221 };
01222 static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = {
01223     { SEC_ASN1_ANY,
01224        offsetof(ocspResponderID, responderIDValue.other) }
01225 };
01226 
01227 /* Decode choice container, but leave x509 name object encoded */
01228 static const SEC_ASN1Template ocsp_ResponderIDDerNameTemplate[] = {
01229     { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
01230        0, SEC_AnyTemplate }
01231 };
01232 
01233 /*
01234  * SingleResponse    ::=    SEQUENCE {
01235  *     certID               CertID,
01236  *     certStatus           CertStatus,
01237  *     thisUpdate           GeneralizedTime,
01238  *     nextUpdate           [0] EXPLICIT GeneralizedTime OPTIONAL,
01239  *     singleExtensions     [1] EXPLICIT Extensions OPTIONAL }
01240  *
01241  * Note: this should be static but the AIX compiler doesn't like it (because it
01242  * was forward-declared above); it is not meant to be exported, but this
01243  * is the only way it will compile.
01244  */
01245 const SEC_ASN1Template ocsp_SingleResponseTemplate[] = {
01246     { SEC_ASN1_SEQUENCE,
01247        0, NULL, sizeof(CERTOCSPSingleResponse) },
01248     { SEC_ASN1_POINTER,
01249        offsetof(CERTOCSPSingleResponse, certID),
01250        ocsp_CertIDTemplate },
01251     { SEC_ASN1_ANY,
01252        offsetof(CERTOCSPSingleResponse, derCertStatus) },
01253     { SEC_ASN1_GENERALIZED_TIME,
01254        offsetof(CERTOCSPSingleResponse, thisUpdate) },
01255     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01256       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01257        offsetof(CERTOCSPSingleResponse, nextUpdate),
01258        SEC_PointerToGeneralizedTimeTemplate },
01259     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01260       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
01261        offsetof(CERTOCSPSingleResponse, singleExtensions),
01262        CERT_SequenceOfCertExtensionTemplate },
01263     { 0 }
01264 };
01265 
01266 /*
01267  * CertStatus ::=    CHOICE {
01268  *     good                 [0] IMPLICIT NULL,
01269  *     revoked                     [1] IMPLICIT RevokedInfo,
01270  *     unknown                     [2] IMPLICIT UnknownInfo }
01271  *
01272  * Because the ASN.1 encoder and decoder currently do not provide
01273  * a way to automatically handle a CHOICE, we need to do it in two
01274  * steps, looking at the type tag and feeding the exact choice back
01275  * to the ASN.1 code.  Hopefully that will change someday and this
01276  * can all be simplified down into a single template.  Anyway, for
01277  * now we list each choice as its own template:
01278  */
01279 static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = {
01280     { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01281        offsetof(ocspCertStatus, certStatusInfo.goodInfo),
01282        SEC_NullTemplate }
01283 };
01284 static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = {
01285     { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, 
01286        offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
01287        ocsp_RevokedInfoTemplate }
01288 };
01289 static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = {
01290     { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 2,
01291        offsetof(ocspCertStatus, certStatusInfo.unknownInfo),
01292        SEC_NullTemplate }
01293 };
01294 static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = {
01295     { SEC_ASN1_POINTER,
01296        offsetof(ocspCertStatus, certStatusInfo.otherInfo),
01297        SEC_AnyTemplate }
01298 };
01299 
01300 /*
01301  * RevokedInfo       ::=    SEQUENCE {
01302  *     revocationTime              GeneralizedTime,
01303  *     revocationReason     [0] EXPLICIT CRLReason OPTIONAL }
01304  *
01305  * Note: this should be static but the AIX compiler doesn't like it (because it
01306  * was forward-declared above); it is not meant to be exported, but this
01307  * is the only way it will compile.
01308  */
01309 const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = {
01310     { SEC_ASN1_SEQUENCE,
01311        0, NULL, sizeof(ocspRevokedInfo) },
01312     { SEC_ASN1_GENERALIZED_TIME,
01313        offsetof(ocspRevokedInfo, revocationTime) },
01314     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
01315       SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01316        offsetof(ocspRevokedInfo, revocationReason), 
01317        SEC_PointerToEnumeratedTemplate },
01318     { 0 }
01319 };
01320 
01321 
01322 /*
01323  * OCSP-specific extension templates:
01324  */
01325 
01326 /*
01327  * ServiceLocator    ::=    SEQUENCE {
01328  *     issuer               Name,
01329  *     locator                     AuthorityInfoAccessSyntax OPTIONAL }
01330  */
01331 static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = {
01332     { SEC_ASN1_SEQUENCE,
01333        0, NULL, sizeof(ocspServiceLocator) },
01334     { SEC_ASN1_POINTER,
01335        offsetof(ocspServiceLocator, issuer),
01336        CERT_NameTemplate },
01337     { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
01338        offsetof(ocspServiceLocator, locator) },
01339     { 0 }
01340 };
01341 
01342 
01343 /*
01344  * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy):
01345  */
01346 
01347 /* 
01348  * FUNCTION: CERT_EncodeOCSPRequest
01349  *   DER encodes an OCSP Request, possibly adding a signature as well.
01350  *   XXX Signing is not yet supported, however; see comments in code.
01351  * INPUTS: 
01352  *   PRArenaPool *arena
01353  *     The return value is allocated from here.
01354  *     If a NULL is passed in, allocation is done from the heap instead.
01355  *   CERTOCSPRequest *request
01356  *     The request to be encoded.
01357  *   void *pwArg
01358  *     Pointer to argument for password prompting, if needed.  (Definitely
01359  *     not needed if not signing.)
01360  * RETURN:
01361  *   Returns a NULL on error and a pointer to the SECItem with the
01362  *   encoded value otherwise.  Any error is likely to be low-level
01363  *   (e.g. no memory).
01364  */
01365 SECItem *
01366 CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request, 
01367                      void *pwArg)
01368 {
01369     ocspTBSRequest *tbsRequest;
01370     SECStatus rv;
01371 
01372     /* XXX All of these should generate errors if they fail. */
01373     PORT_Assert(request);
01374     PORT_Assert(request->tbsRequest);
01375 
01376     tbsRequest = request->tbsRequest;
01377 
01378     if (request->tbsRequest->extensionHandle != NULL) {
01379        rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle);
01380        request->tbsRequest->extensionHandle = NULL;
01381        if (rv != SECSuccess)
01382            return NULL;
01383     }
01384 
01385     /*
01386      * XXX When signed requests are supported and request->optionalSignature
01387      * is not NULL:
01388      *  - need to encode tbsRequest->requestorName
01389      *  - need to encode tbsRequest
01390      *  - need to sign that encoded result (using cert in sig), filling in the
01391      *    request->optionalSignature structure with the result, the signing
01392      *    algorithm and (perhaps?) the cert (and its chain?) in derCerts
01393      */
01394 
01395     return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate);
01396 }
01397 
01398 
01399 /*
01400  * FUNCTION: CERT_DecodeOCSPRequest
01401  *   Decode a DER encoded OCSP Request.
01402  * INPUTS:
01403  *   SECItem *src
01404  *     Pointer to a SECItem holding DER encoded OCSP Request.
01405  * RETURN:
01406  *   Returns a pointer to a CERTOCSPRequest containing the decoded request.
01407  *   On error, returns NULL.  Most likely error is trouble decoding
01408  *   (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
01409  */
01410 CERTOCSPRequest *
01411 CERT_DecodeOCSPRequest(SECItem *src)
01412 {
01413     PRArenaPool *arena = NULL;
01414     SECStatus rv = SECFailure;
01415     CERTOCSPRequest *dest = NULL;
01416     int i;
01417     SECItem newSrc;
01418 
01419     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01420     if (arena == NULL) {
01421        goto loser;
01422     }
01423     dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena, 
01424                                           sizeof(CERTOCSPRequest));
01425     if (dest == NULL) {
01426        goto loser;
01427     }
01428     dest->arena = arena;
01429 
01430     /* copy the DER into the arena, since Quick DER returns data that points
01431        into the DER input, which may get freed by the caller */
01432     rv = SECITEM_CopyItem(arena, &newSrc, src);
01433     if ( rv != SECSuccess ) {
01434        goto loser;
01435     }
01436 
01437     rv = SEC_QuickDERDecodeItem(arena, dest, ocsp_OCSPRequestTemplate, &newSrc);
01438     if (rv != SECSuccess) {
01439        if (PORT_GetError() == SEC_ERROR_BAD_DER)
01440            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
01441        goto loser;
01442     }
01443 
01444     /*
01445      * XXX I would like to find a way to get rid of the necessity
01446      * of doing this copying of the arena pointer.
01447      */
01448     for (i = 0; dest->tbsRequest->requestList[i] != NULL; i++) {
01449        dest->tbsRequest->requestList[i]->arena = arena;
01450     }
01451 
01452     return dest;
01453 
01454 loser:
01455     if (arena != NULL) {
01456        PORT_FreeArena(arena, PR_FALSE);
01457     }
01458     return NULL;
01459 }
01460 
01461 SECStatus
01462 CERT_DestroyOCSPCertID(CERTOCSPCertID* certID)
01463 {
01464     if (certID->poolp) {
01465        PORT_FreeArena(certID->poolp, PR_FALSE);
01466        return SECSuccess;
01467     }
01468     return SECFailure;
01469 }
01470 
01471 /*
01472  * Digest data using the specified algorithm.
01473  * The necessary storage for the digest data is allocated.  If "fill" is
01474  * non-null, the data is put there, otherwise a SECItem is allocated.
01475  * Allocation from "arena" if it is non-null, heap otherwise.  Any problem
01476  * results in a NULL being returned (and an appropriate error set).
01477  */
01478 
01479 static SECItem *
01480 ocsp_DigestValue(PRArenaPool *arena, SECOidTag digestAlg, 
01481                  SECItem *fill, const SECItem *src)
01482 {
01483     const SECHashObject *digestObject;
01484     SECItem *result = NULL;
01485     void *mark = NULL;
01486     void *digestBuff = NULL;
01487 
01488     if ( arena != NULL ) {
01489         mark = PORT_ArenaMark(arena);
01490     }
01491 
01492     digestObject = HASH_GetHashObjectByOidTag(digestAlg);
01493     if ( digestObject == NULL ) {
01494         goto loser;
01495     }
01496 
01497     if (fill == NULL || fill->data == NULL) {
01498        result = SECITEM_AllocItem(arena, fill, digestObject->length);
01499        if ( result == NULL ) {
01500           goto loser;
01501        }
01502        digestBuff = result->data;
01503     } else {
01504        if (fill->len < digestObject->length) {
01505            PORT_SetError(SEC_ERROR_INVALID_ARGS);
01506            goto loser;
01507        }
01508        digestBuff = fill->data;
01509     }
01510 
01511     if (PK11_HashBuf(digestAlg, digestBuff,
01512                      src->data, src->len) != SECSuccess) {
01513         goto loser;
01514     }
01515 
01516     if ( arena != NULL ) {
01517         PORT_ArenaUnmark(arena, mark);
01518     }
01519 
01520     if (result == NULL) {
01521         result = fill;
01522     }
01523     return result;
01524 
01525 loser:
01526     if (arena != NULL) {
01527         PORT_ArenaRelease(arena, mark);
01528     } else {
01529         if (result != NULL) {
01530             SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE);
01531         }
01532     }
01533     return(NULL);
01534 }
01535 
01536 /*
01537  * Digest the cert's subject public key using the specified algorithm.
01538  * The necessary storage for the digest data is allocated.  If "fill" is
01539  * non-null, the data is put there, otherwise a SECItem is allocated.
01540  * Allocation from "arena" if it is non-null, heap otherwise.  Any problem
01541  * results in a NULL being returned (and an appropriate error set).
01542  */
01543 SECItem *
01544 cert_GetSPKIDigest(PRArenaPool *arena, const CERTCertificate *cert,
01545                            SECOidTag digestAlg, SECItem *fill)
01546 {
01547     SECItem spk;
01548 
01549     /*
01550      * Copy just the length and data pointer (nothing needs to be freed)
01551      * of the subject public key so we can convert the length from bits
01552      * to bytes, which is what the digest function expects.
01553      */
01554     spk = cert->subjectPublicKeyInfo.subjectPublicKey;
01555     DER_ConvertBitString(&spk);
01556 
01557     return ocsp_DigestValue(arena, digestAlg, fill, &spk);
01558 }
01559 
01560 /*
01561  * Digest the cert's subject name using the specified algorithm.
01562  */
01563 static SECItem *
01564 cert_GetSubjectNameDigest(PRArenaPool *arena, const CERTCertificate *cert,
01565                            SECOidTag digestAlg, SECItem *fill)
01566 {
01567     SECItem name;
01568 
01569     /*
01570      * Copy just the length and data pointer (nothing needs to be freed)
01571      * of the subject name
01572      */
01573     name = cert->derSubject;
01574 
01575     return ocsp_DigestValue(arena, digestAlg, fill, &name);
01576 }
01577 
01578 /*
01579  * Create and fill-in a CertID.  This function fills in the hash values
01580  * (issuerNameHash and issuerKeyHash), and is hardwired to use SHA1.
01581  * Someday it might need to be more flexible about hash algorithm, but
01582  * for now we have no intention/need to create anything else.
01583  *
01584  * Error causes a null to be returned; most likely cause is trouble
01585  * finding the certificate issuer (SEC_ERROR_UNKNOWN_ISSUER).
01586  * Other errors are low-level problems (no memory, bad database, etc.).
01587  */
01588 static CERTOCSPCertID *
01589 ocsp_CreateCertID(PRArenaPool *arena, CERTCertificate *cert, int64 time)
01590 {
01591     CERTOCSPCertID *certID;
01592     CERTCertificate *issuerCert = NULL;
01593     SECItem *tempItem = NULL;
01594     void *mark = PORT_ArenaMark(arena);
01595     SECStatus rv;
01596 
01597     PORT_Assert(arena != NULL);
01598 
01599     certID = PORT_ArenaZNew(arena, CERTOCSPCertID);
01600     if (certID == NULL) {
01601        goto loser;
01602     }
01603 
01604     rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1,
01605                             NULL);
01606     if (rv != SECSuccess) {
01607        goto loser; 
01608     }
01609 
01610     issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
01611     if (issuerCert == NULL) {
01612        goto loser;
01613     }
01614 
01615     if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_SHA1,
01616                                   &(certID->issuerNameHash)) == NULL) {
01617         goto loser;
01618     }
01619     certID->issuerSHA1NameHash.data = certID->issuerNameHash.data;
01620     certID->issuerSHA1NameHash.len = certID->issuerNameHash.len;
01621 
01622     if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD5,
01623                                   &(certID->issuerMD5NameHash)) == NULL) {
01624         goto loser;
01625     }
01626 
01627     if (cert_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD2,
01628                                   &(certID->issuerMD2NameHash)) == NULL) {
01629         goto loser;
01630     }
01631 
01632     if (cert_GetSPKIDigest(arena, issuerCert, SEC_OID_SHA1,
01633                                &(certID->issuerKeyHash)) == NULL) {
01634        goto loser;
01635     }
01636     certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data;
01637     certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len;
01638     /* cache the other two hash algorithms as well */
01639     if (cert_GetSPKIDigest(arena, issuerCert, SEC_OID_MD5,
01640                                &(certID->issuerMD5KeyHash)) == NULL) {
01641        goto loser;
01642     }
01643     if (cert_GetSPKIDigest(arena, issuerCert, SEC_OID_MD2,
01644                                &(certID->issuerMD2KeyHash)) == NULL) {
01645        goto loser;
01646     }
01647 
01648 
01649     /* now we are done with issuerCert */
01650     CERT_DestroyCertificate(issuerCert);
01651     issuerCert = NULL;
01652 
01653     rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber);
01654     if (rv != SECSuccess) {
01655        goto loser; 
01656     }
01657 
01658     PORT_ArenaUnmark(arena, mark);
01659     return certID;
01660 
01661 loser:
01662     if (issuerCert != NULL) {
01663        CERT_DestroyCertificate(issuerCert);
01664     }
01665     if (tempItem != NULL) {
01666        SECITEM_FreeItem(tempItem, PR_TRUE);
01667     }
01668     PORT_ArenaRelease(arena, mark);
01669     return NULL;
01670 }
01671 
01672 CERTOCSPCertID*
01673 CERT_CreateOCSPCertID(CERTCertificate *cert, int64 time)
01674 {
01675     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01676     CERTOCSPCertID *certID;
01677     PORT_Assert(arena != NULL);
01678     if (!arena)
01679        return NULL;
01680     
01681     certID = ocsp_CreateCertID(arena, cert, time);
01682     if (!certID) {
01683        PORT_FreeArena(arena, PR_FALSE);
01684        return NULL;
01685     }
01686     certID->poolp = arena;
01687     return certID;
01688 }
01689 
01690 
01691 
01692 /*
01693  * Callback to set Extensions in request object
01694  */
01695 void SetSingleReqExts(void *object, CERTCertExtension **exts)
01696 {
01697   ocspSingleRequest *singleRequest =
01698     (ocspSingleRequest *)object;
01699 
01700   singleRequest->singleRequestExtensions = exts;
01701 }
01702 
01703 /*
01704  * Add the Service Locator extension to the singleRequestExtensions
01705  * for the given singleRequest.
01706  *
01707  * All errors are internal or low-level problems (e.g. no memory).
01708  */
01709 static SECStatus
01710 ocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest,
01711                             CERTCertificate *cert)
01712 {
01713     ocspServiceLocator *serviceLocator = NULL;
01714     void *extensionHandle = NULL;
01715     SECStatus rv = SECFailure;
01716 
01717     serviceLocator = PORT_ZNew(ocspServiceLocator);
01718     if (serviceLocator == NULL)
01719        goto loser;
01720 
01721     /*
01722      * Normally it would be a bad idea to do a direct reference like
01723      * this rather than allocate and copy the name *or* at least dup
01724      * a reference of the cert.  But all we need is to be able to read
01725      * the issuer name during the encoding we are about to do, so a
01726      * copy is just a waste of time.
01727      */
01728     serviceLocator->issuer = &cert->issuer;
01729 
01730     rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
01731                             &serviceLocator->locator);
01732     if (rv != SECSuccess) {
01733        if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
01734            goto loser;
01735     }
01736 
01737     /* prepare for following loser gotos */
01738     rv = SECFailure;
01739     PORT_SetError(0);
01740 
01741     extensionHandle = cert_StartExtensions(singleRequest,
01742                        singleRequest->arena, SetSingleReqExts);
01743     if (extensionHandle == NULL)
01744        goto loser;
01745 
01746     rv = CERT_EncodeAndAddExtension(extensionHandle,
01747                                 SEC_OID_PKIX_OCSP_SERVICE_LOCATOR,
01748                                 serviceLocator, PR_FALSE,
01749                                 ocsp_ServiceLocatorTemplate);
01750 
01751 loser:
01752     if (extensionHandle != NULL) {
01753        /*
01754         * Either way we have to finish out the extension context (so it gets
01755         * freed).  But careful not to override any already-set bad status.
01756         */
01757        SECStatus tmprv = CERT_FinishExtensions(extensionHandle);
01758        if (rv == SECSuccess)
01759            rv = tmprv;
01760     }
01761 
01762     /*
01763      * Finally, free the serviceLocator structure itself and we are done.
01764      */
01765     if (serviceLocator != NULL) {
01766        if (serviceLocator->locator.data != NULL)
01767            SECITEM_FreeItem(&serviceLocator->locator, PR_FALSE);
01768        PORT_Free(serviceLocator);
01769     }
01770 
01771     return rv;
01772 }
01773 
01774 /*
01775  * Creates an array of ocspSingleRequest based on a list of certs.
01776  * Note that the code which later compares the request list with the
01777  * response expects this array to be in the exact same order as the
01778  * certs are found in the list.  It would be harder to change that
01779  * order than preserve it, but since the requirement is not obvious,
01780  * it deserves to be mentioned.
01781  *
01782  * Any problem causes a null return and error set:
01783  *      SEC_ERROR_UNKNOWN_ISSUER
01784  * Other errors are low-level problems (no memory, bad database, etc.).
01785  */
01786 static ocspSingleRequest **
01787 ocsp_CreateSingleRequestList(PRArenaPool *arena, CERTCertList *certList,
01788                              int64 time, PRBool includeLocator)
01789 {
01790     ocspSingleRequest **requestList = NULL;
01791     CERTCertListNode *node = NULL;
01792     int i, count;
01793     void *mark = PORT_ArenaMark(arena);
01794  
01795     node = CERT_LIST_HEAD(certList);
01796     for (count = 0; !CERT_LIST_END(node, certList); count++) {
01797         node = CERT_LIST_NEXT(node);
01798     }
01799 
01800     if (count == 0)
01801        goto loser;
01802 
01803     requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, count + 1);
01804     if (requestList == NULL)
01805        goto loser;
01806 
01807     node = CERT_LIST_HEAD(certList);
01808     for (i = 0; !CERT_LIST_END(node, certList); i++) {
01809         requestList[i] = PORT_ArenaZNew(arena, ocspSingleRequest);
01810         if (requestList[i] == NULL)
01811             goto loser;
01812 
01813         requestList[i]->arena = arena;
01814         requestList[i]->reqCert = ocsp_CreateCertID(arena, node->cert, time);
01815         if (requestList[i]->reqCert == NULL)
01816             goto loser;
01817 
01818         if (includeLocator == PR_TRUE) {
01819             SECStatus rv;
01820 
01821             rv = ocsp_AddServiceLocatorExtension(requestList[i], node->cert);
01822             if (rv != SECSuccess)
01823                 goto loser;
01824         }
01825 
01826         node = CERT_LIST_NEXT(node);
01827     }
01828 
01829     PORT_Assert(i == count);
01830 
01831     PORT_ArenaUnmark(arena, mark);
01832     requestList[i] = NULL;
01833     return requestList;
01834 
01835 loser:
01836     PORT_ArenaRelease(arena, mark);
01837     return NULL;
01838 }
01839 
01840 static ocspSingleRequest **
01841 ocsp_CreateRequestFromCert(PRArenaPool *arena, 
01842                            CERTOCSPCertID *certID, 
01843                            CERTCertificate *singleCert,
01844                            int64 time, 
01845                            PRBool includeLocator)
01846 {
01847     ocspSingleRequest **requestList = NULL;
01848     void *mark = PORT_ArenaMark(arena);
01849     PORT_Assert(certID != NULL && singleCert != NULL);
01850 
01851     /* meaning of value 2: one entry + one end marker */
01852     requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, 2);
01853     if (requestList == NULL)
01854         goto loser;
01855     requestList[0] = PORT_ArenaZNew(arena, ocspSingleRequest);
01856     if (requestList[0] == NULL)
01857         goto loser;
01858     requestList[0]->arena = arena;
01859     /* certID will live longer than the request */
01860     requestList[0]->reqCert = certID; 
01861 
01862     if (includeLocator == PR_TRUE) {
01863         SECStatus rv;
01864         rv = ocsp_AddServiceLocatorExtension(requestList[0], singleCert);
01865         if (rv != SECSuccess)
01866             goto loser;
01867     }
01868 
01869     PORT_ArenaUnmark(arena, mark);
01870     requestList[1] = NULL;
01871     return requestList;
01872 
01873 loser:
01874     PORT_ArenaRelease(arena, mark);
01875     return NULL;
01876 }
01877 
01878 static CERTOCSPRequest *
01879 ocsp_prepareEmptyOCSPRequest()
01880 {
01881     PRArenaPool *arena = NULL;
01882     CERTOCSPRequest *request = NULL;
01883     ocspTBSRequest *tbsRequest = NULL;
01884 
01885     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01886     if (arena == NULL) {
01887         goto loser;
01888     }
01889     request = PORT_ArenaZNew(arena, CERTOCSPRequest);
01890     if (request == NULL) {
01891         goto loser;
01892     }
01893     request->arena = arena;
01894 
01895     tbsRequest = PORT_ArenaZNew(arena, ocspTBSRequest);
01896     if (tbsRequest == NULL) {
01897         goto loser;
01898     }
01899     request->tbsRequest = tbsRequest;
01900     /* version 1 is the default, so we need not fill in a version number */
01901     return request;
01902 
01903 loser:
01904     if (arena != NULL) {
01905         PORT_FreeArena(arena, PR_FALSE);
01906     }
01907     return NULL;
01908 }
01909 
01910 static CERTOCSPRequest *
01911 cert_CreateSingleCertOCSPRequest(CERTOCSPCertID *certID, 
01912                                  CERTCertificate *singleCert, 
01913                                  int64 time, 
01914                                  PRBool addServiceLocator)
01915 {
01916     CERTOCSPRequest *request;
01917     request = ocsp_prepareEmptyOCSPRequest();
01918     if (!request)
01919         return NULL;
01920     /*
01921      * Version 1 is the default, so we need not fill in a version number.
01922      * Now create the list of single requests, one for each cert.
01923      */
01924     request->tbsRequest->requestList = 
01925         ocsp_CreateRequestFromCert(request->arena, 
01926                                    certID,
01927                                    singleCert,
01928                                    time,
01929                                    addServiceLocator);
01930     if (request->tbsRequest->requestList == NULL) {
01931         PORT_FreeArena(request->arena, PR_FALSE);
01932         return NULL;
01933     }
01934     return request;
01935 }
01936 
01937 /*
01938  * FUNCTION: CERT_CreateOCSPRequest
01939  *   Creates a CERTOCSPRequest, requesting the status of the certs in 
01940  *   the given list.
01941  * INPUTS:
01942  *   CERTCertList *certList
01943  *     A list of certs for which status will be requested.
01944  *     Note that all of these certificates should have the same issuer,
01945  *     or it's expected the response will be signed by a trusted responder.
01946  *     If the certs need to be broken up into multiple requests, that
01947  *     must be handled by the caller (and thus by having multiple calls
01948  *     to this routine), who knows about where the request(s) are being
01949  *     sent and whether there are any trusted responders in place.
01950  *   int64 time
01951  *     Indicates the time for which the certificate status is to be 
01952  *     determined -- this may be used in the search for the cert's issuer
01953  *     but has no effect on the request itself.
01954  *   PRBool addServiceLocator
01955  *     If true, the Service Locator extension should be added to the
01956  *     single request(s) for each cert.
01957  *   CERTCertificate *signerCert
01958  *     If non-NULL, means sign the request using this cert.  Otherwise,
01959  *     do not sign.
01960  *     XXX note that request signing is not yet supported; see comment in code
01961  * RETURN:
01962  *   A pointer to a CERTOCSPRequest structure containing an OCSP request
01963  *   for the cert list.  On error, null is returned, with an error set
01964  *   indicating the reason.  This is likely SEC_ERROR_UNKNOWN_ISSUER.
01965  *   (The issuer is needed to create a request for the certificate.)
01966  *   Other errors are low-level problems (no memory, bad database, etc.).
01967  */
01968 CERTOCSPRequest *
01969 CERT_CreateOCSPRequest(CERTCertList *certList, int64 time, 
01970                      PRBool addServiceLocator,
01971                      CERTCertificate *signerCert)
01972 {
01973     CERTOCSPRequest *request = NULL;
01974 
01975     if (!certList) {
01976         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01977         return NULL;
01978     }
01979     /*
01980      * XXX This should set an error, but since it is only temporary and
01981      * since PSM will not initially provide a way to turn on signing of
01982      * requests anyway, I figure we can just skip defining an error that
01983      * will be obsolete in the next release.  When we are prepared to
01984      * put signing of requests back in, this entire check will go away,
01985      * and later in this function we will need to allocate a signature
01986      * structure for the request, fill in the "derCerts" field in it,
01987      * save the signerCert there, as well as fill in the "requestorName"
01988      * field of the tbsRequest.
01989      */
01990     if (signerCert != NULL) {
01991         return NULL;
01992     }
01993     request = ocsp_prepareEmptyOCSPRequest();
01994     if (!request)
01995         return NULL;
01996     /*
01997      * Now create the list of single requests, one for each cert.
01998      */
01999     request->tbsRequest->requestList = 
02000         ocsp_CreateSingleRequestList(request->arena, 
02001                                      certList,
02002                                      time,
02003                                      addServiceLocator);
02004     if (request->tbsRequest->requestList == NULL) {
02005         PORT_FreeArena(request->arena, PR_FALSE);
02006         return NULL;
02007     }
02008     return request;
02009 }
02010 
02011 /*
02012  * FUNCTION: CERT_AddOCSPAcceptableResponses
02013  *   Add the AcceptableResponses extension to an OCSP Request.
02014  * INPUTS:
02015  *   CERTOCSPRequest *request
02016  *     The request to which the extension should be added.
02017  *   ...
02018  *     A list (of one or more) of SECOidTag -- each of the response types
02019  *     to be added.  The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE.
02020  *     (This marks the end of the list, and it must be specified because a
02021  *     client conforming to the OCSP standard is required to handle the basic
02022  *     response type.)  The OIDs are not checked in any way.
02023  * RETURN:
02024  *   SECSuccess if the extension is added; SECFailure if anything goes wrong.
02025  *   All errors are internal or low-level problems (e.g. no memory).
02026  */
02027 
02028 void SetRequestExts(void *object, CERTCertExtension **exts)
02029 {
02030   CERTOCSPRequest *request = (CERTOCSPRequest *)object;
02031 
02032   request->tbsRequest->requestExtensions = exts;
02033 }
02034 
02035 SECStatus
02036 CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request,
02037                             SECOidTag responseType0, ...)
02038 {
02039     void *extHandle;
02040     va_list ap;
02041     int i, count;
02042     SECOidTag responseType;
02043     SECOidData *responseOid;
02044     SECItem **acceptableResponses = NULL;
02045     SECStatus rv = SECFailure;
02046 
02047     extHandle = request->tbsRequest->extensionHandle;
02048     if (extHandle == NULL) {
02049        extHandle = cert_StartExtensions(request, request->arena, SetRequestExts);
02050        if (extHandle == NULL)
02051            goto loser;
02052     }
02053 
02054     /* Count number of OIDS going into the extension value. */
02055     count = 1;
02056     if (responseType0 != SEC_OID_PKIX_OCSP_BASIC_RESPONSE) {
02057        va_start(ap, responseType0);
02058        do {
02059            count++;
02060            responseType = va_arg(ap, SECOidTag);
02061        } while (responseType != SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
02062        va_end(ap);
02063     }
02064 
02065     acceptableResponses = PORT_NewArray(SECItem *, count + 1);
02066     if (acceptableResponses == NULL)
02067        goto loser;
02068 
02069     i = 0;
02070     responseOid = SECOID_FindOIDByTag(responseType0);
02071     acceptableResponses[i++] = &(responseOid->oid);
02072     if (count > 1) {
02073        va_start(ap, responseType0);
02074        for ( ; i < count; i++) {
02075            responseType = va_arg(ap, SECOidTag);
02076            responseOid = SECOID_FindOIDByTag(responseType);
02077            acceptableResponses[i] = &(responseOid->oid);
02078        }
02079        va_end(ap);
02080     }
02081     acceptableResponses[i] = NULL;
02082 
02083     rv = CERT_EncodeAndAddExtension(extHandle, SEC_OID_PKIX_OCSP_RESPONSE,
02084                                 &acceptableResponses, PR_FALSE,
02085                                 SEC_SequenceOfObjectIDTemplate);
02086     if (rv != SECSuccess)
02087        goto loser;
02088 
02089     PORT_Free(acceptableResponses);
02090     if (request->tbsRequest->extensionHandle == NULL)
02091        request->tbsRequest->extensionHandle = extHandle;
02092     return SECSuccess;
02093 
02094 loser:
02095     if (acceptableResponses != NULL)
02096        PORT_Free(acceptableResponses);
02097     if (extHandle != NULL)
02098        (void) CERT_FinishExtensions(extHandle);
02099     return rv;
02100 }
02101 
02102 
02103 /*
02104  * FUNCTION: CERT_DestroyOCSPRequest
02105  *   Frees an OCSP Request structure.
02106  * INPUTS:
02107  *   CERTOCSPRequest *request
02108  *     Pointer to CERTOCSPRequest to be freed.
02109  * RETURN:
02110  *   No return value; no errors.
02111  */
02112 void
02113 CERT_DestroyOCSPRequest(CERTOCSPRequest *request)
02114 {
02115     if (request == NULL)
02116        return;
02117 
02118     if (request->tbsRequest != NULL) {
02119        if (request->tbsRequest->requestorName != NULL)
02120            CERT_DestroyGeneralNameList(request->tbsRequest->requestorName);
02121        if (request->tbsRequest->extensionHandle != NULL)
02122            (void) CERT_FinishExtensions(request->tbsRequest->extensionHandle);
02123     }
02124 
02125     if (request->optionalSignature != NULL) {
02126        if (request->optionalSignature->cert != NULL)
02127            CERT_DestroyCertificate(request->optionalSignature->cert);
02128 
02129        /*
02130         * XXX Need to free derCerts?  Or do they come out of arena?
02131         * (Currently we never fill in derCerts, which is why the
02132         * answer is not obvious.  Once we do, add any necessary code
02133         * here and remove this comment.)
02134         */
02135     }
02136 
02137     /*
02138      * We should actually never have a request without an arena,
02139      * but check just in case.  (If there isn't one, there is not
02140      * much we can do about it...)
02141      */
02142     PORT_Assert(request->arena != NULL);
02143     if (request->arena != NULL)
02144        PORT_FreeArena(request->arena, PR_FALSE);
02145 }
02146 
02147 
02148 /*
02149  * RESPONSE SUPPORT FUNCTIONS (encode/create/decode/destroy):
02150  */
02151 
02152 /*
02153  * Helper function for encoding or decoding a ResponderID -- based on the
02154  * given type, return the associated template for that choice.
02155  */
02156 static const SEC_ASN1Template *
02157 ocsp_ResponderIDTemplateByType(ocspResponderIDType responderIDType)
02158 {
02159     const SEC_ASN1Template *responderIDTemplate;
02160 
02161     switch (responderIDType) {
02162        case ocspResponderID_byName:
02163            responderIDTemplate = ocsp_ResponderIDByNameTemplate;
02164            break;
02165        case ocspResponderID_byKey:
02166            responderIDTemplate = ocsp_ResponderIDByKeyTemplate;
02167            break;
02168        case ocspResponderID_other:
02169        default:
02170            PORT_Assert(responderIDType == ocspResponderID_other);
02171            responderIDTemplate = ocsp_ResponderIDOtherTemplate;
02172            break;
02173     }
02174 
02175     return responderIDTemplate;
02176 }
02177 
02178 /*
02179  * Helper function for encoding or decoding a CertStatus -- based on the
02180  * given type, return the associated template for that choice.
02181  */
02182 static const SEC_ASN1Template *
02183 ocsp_CertStatusTemplateByType(ocspCertStatusType certStatusType)
02184 {
02185     const SEC_ASN1Template *certStatusTemplate;
02186 
02187     switch (certStatusType) {
02188        case ocspCertStatus_good:
02189            certStatusTemplate = ocsp_CertStatusGoodTemplate;
02190            break;
02191        case ocspCertStatus_revoked:
02192            certStatusTemplate = ocsp_CertStatusRevokedTemplate;
02193            break;
02194        case ocspCertStatus_unknown:
02195            certStatusTemplate = ocsp_CertStatusUnknownTemplate;
02196            break;
02197        case ocspCertStatus_other:
02198        default:
02199            PORT_Assert(certStatusType == ocspCertStatus_other);
02200            certStatusTemplate = ocsp_CertStatusOtherTemplate;
02201            break;
02202     }
02203 
02204     return certStatusTemplate;
02205 }
02206 
02207 /*
02208  * Helper function for decoding a certStatus -- turn the actual DER tag
02209  * into our local translation.
02210  */
02211 static ocspCertStatusType
02212 ocsp_CertStatusTypeByTag(int derTag)
02213 {
02214     ocspCertStatusType certStatusType;
02215 
02216     switch (derTag) {
02217        case 0:
02218            certStatusType = ocspCertStatus_good;
02219            break;
02220        case 1:
02221            certStatusType = ocspCertStatus_revoked;
02222            break;
02223        case 2:
02224            certStatusType = ocspCertStatus_unknown;
02225            break;
02226        default:
02227            certStatusType = ocspCertStatus_other;
02228            break;
02229     }
02230 
02231     return certStatusType;
02232 }
02233 
02234 /*
02235  * Helper function for decoding SingleResponses -- they each contain
02236  * a status which is encoded as CHOICE, which needs to be decoded "by hand".
02237  *
02238  * Note -- on error, this routine does not release the memory it may
02239  * have allocated; it expects its caller to do that.
02240  */
02241 static SECStatus
02242 ocsp_FinishDecodingSingleResponses(PRArenaPool *arena,
02243                                CERTOCSPSingleResponse **responses)
02244 {
02245     ocspCertStatus *certStatus;
02246     ocspCertStatusType certStatusType;
02247     const SEC_ASN1Template *certStatusTemplate;
02248     int derTag;
02249     int i;
02250     SECStatus rv = SECFailure;
02251 
02252     if (responses == NULL)                /* nothing to do */
02253        return SECSuccess;
02254 
02255     for (i = 0; responses[i] != NULL; i++) {
02256        /*
02257         * The following assert points out internal errors (problems in
02258         * the template definitions or in the ASN.1 decoder itself, etc.).
02259         */
02260        PORT_Assert(responses[i]->derCertStatus.data != NULL);
02261 
02262        derTag = responses[i]->derCertStatus.data[0] & SEC_ASN1_TAGNUM_MASK;
02263        certStatusType = ocsp_CertStatusTypeByTag(derTag);
02264        certStatusTemplate = ocsp_CertStatusTemplateByType(certStatusType);
02265 
02266        certStatus = PORT_ArenaZAlloc(arena, sizeof(ocspCertStatus));
02267        if (certStatus == NULL) {
02268            goto loser;
02269        }
02270        rv = SEC_ASN1DecodeItem(arena, certStatus, certStatusTemplate,
02271                             &responses[i]->derCertStatus);
02272        if (rv != SECSuccess) {
02273            if (PORT_GetError() == SEC_ERROR_BAD_DER)
02274               PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
02275            goto loser;
02276        }
02277 
02278        certStatus->certStatusType = certStatusType;
02279        responses[i]->certStatus = certStatus;
02280     }
02281 
02282     return SECSuccess;
02283 
02284 loser:
02285     return rv;
02286 }
02287 
02288 /*
02289  * Helper function for decoding a responderID -- turn the actual DER tag
02290  * into our local translation.
02291  */
02292 static ocspResponderIDType
02293 ocsp_ResponderIDTypeByTag(int derTag)
02294 {
02295     ocspResponderIDType responderIDType;
02296 
02297     switch (derTag) {
02298        case 1:
02299            responderIDType = ocspResponderID_byName;
02300            break;
02301        case 2:
02302            responderIDType = ocspResponderID_byKey;
02303            break;
02304        default:
02305            responderIDType = ocspResponderID_other;
02306            break;
02307     }
02308 
02309     return responderIDType;
02310 }
02311 
02312 /*
02313  * Decode "src" as a BasicOCSPResponse, returning the result.
02314  */
02315 static ocspBasicOCSPResponse *
02316 ocsp_DecodeBasicOCSPResponse(PRArenaPool *arena, SECItem *src)
02317 {
02318     void *mark;
02319     ocspBasicOCSPResponse *basicResponse;
02320     ocspResponseData *responseData;
02321     ocspResponderID *responderID;
02322     ocspResponderIDType responderIDType;
02323     const SEC_ASN1Template *responderIDTemplate;
02324     int derTag;
02325     SECStatus rv;
02326     SECItem newsrc;
02327 
02328     mark = PORT_ArenaMark(arena);
02329 
02330     basicResponse = PORT_ArenaZAlloc(arena, sizeof(ocspBasicOCSPResponse));
02331     if (basicResponse == NULL) {
02332        goto loser;
02333     }
02334 
02335     /* copy the DER into the arena, since Quick DER returns data that points
02336        into the DER input, which may get freed by the caller */
02337     rv = SECITEM_CopyItem(arena, &newsrc, src);
02338     if ( rv != SECSuccess ) {
02339        goto loser;
02340     }
02341 
02342     rv = SEC_QuickDERDecodeItem(arena, basicResponse,
02343                          ocsp_BasicOCSPResponseTemplate, &newsrc);
02344     if (rv != SECSuccess) {
02345        if (PORT_GetError() == SEC_ERROR_BAD_DER)
02346            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
02347        goto loser;
02348     }
02349 
02350     responseData = basicResponse->tbsResponseData;
02351 
02352     /*
02353      * The following asserts point out internal errors (problems in
02354      * the template definitions or in the ASN.1 decoder itself, etc.).
02355      */
02356     PORT_Assert(responseData != NULL);
02357     PORT_Assert(responseData->derResponderID.data != NULL);
02358 
02359     /*
02360      * XXX Because responderID is a CHOICE, which is not currently handled
02361      * by our ASN.1 decoder, we have to decode it "by hand".
02362      */
02363     derTag = responseData->derResponderID.data[0] & SEC_ASN1_TAGNUM_MASK;
02364     responderIDType = ocsp_ResponderIDTypeByTag(derTag);
02365     responderIDTemplate = ocsp_ResponderIDTemplateByType(responderIDType);
02366 
02367     responderID = PORT_ArenaZAlloc(arena, sizeof(ocspResponderID));
02368     if (responderID == NULL) {
02369        goto loser;
02370     }
02371 
02372     rv = SEC_QuickDERDecodeItem(arena, responderID, responderIDTemplate,
02373                          &responseData->derResponderID);
02374     if (rv != SECSuccess) {
02375        if (PORT_GetError() == SEC_ERROR_BAD_DER)
02376            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
02377        goto loser;
02378     }
02379 
02380     responderID->responderIDType = responderIDType;
02381     responseData->responderID = responderID;
02382 
02383     /*
02384      * XXX Each SingleResponse also contains a CHOICE, which has to be
02385      * fixed up by hand.
02386      */
02387     rv = ocsp_FinishDecodingSingleResponses(arena, responseData->responses);
02388     if (rv != SECSuccess) {
02389        goto loser;
02390     }
02391 
02392     PORT_ArenaUnmark(arena, mark);
02393     return basicResponse;
02394 
02395 loser:
02396     PORT_ArenaRelease(arena, mark);
02397     return NULL;
02398 }
02399 
02400 
02401 /*
02402  * Decode the responseBytes based on the responseType found in "rbytes",
02403  * leaving the resulting translated/decoded information in there as well.
02404  */
02405 static SECStatus
02406 ocsp_DecodeResponseBytes(PRArenaPool *arena, ocspResponseBytes *rbytes)
02407 {
02408     PORT_Assert(rbytes != NULL);          /* internal error, really */
02409     if (rbytes == NULL)
02410        PORT_SetError(SEC_ERROR_INVALID_ARGS);    /* XXX set better error? */
02411 
02412     rbytes->responseTypeTag = SECOID_FindOIDTag(&rbytes->responseType);
02413     switch (rbytes->responseTypeTag) {
02414        case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
02415            {
02416               ocspBasicOCSPResponse *basicResponse;
02417 
02418               basicResponse = ocsp_DecodeBasicOCSPResponse(arena,
02419                                                       &rbytes->response);
02420               if (basicResponse == NULL)
02421                   return SECFailure;
02422 
02423               rbytes->decodedResponse.basic = basicResponse;
02424            }
02425            break;
02426 
02427        /*
02428         * Add new/future response types here.
02429         */
02430 
02431        default:
02432            PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE);
02433            return SECFailure;
02434     }
02435 
02436     return SECSuccess;
02437 }
02438 
02439 
02440 /*
02441  * FUNCTION: CERT_DecodeOCSPResponse
02442  *   Decode a DER encoded OCSP Response.
02443  * INPUTS:
02444  *   SECItem *src
02445  *     Pointer to a SECItem holding DER encoded OCSP Response.
02446  * RETURN:
02447  *   Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response);
02448  *   the caller is responsible for destroying it.  Or NULL if error (either
02449  *   response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE),
02450  *   it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE),
02451  *   or a low-level or internal error occurred).
02452  */
02453 CERTOCSPResponse *
02454 CERT_DecodeOCSPResponse(SECItem *src)
02455 {
02456     PRArenaPool *arena = NULL;
02457     CERTOCSPResponse *response = NULL;
02458     SECStatus rv = SECFailure;
02459     ocspResponseStatus sv;
02460     SECItem newSrc;
02461 
02462     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02463     if (arena == NULL) {
02464        goto loser;
02465     }
02466     response = (CERTOCSPResponse *) PORT_ArenaZAlloc(arena,
02467                                                sizeof(CERTOCSPResponse));
02468     if (response == NULL) {
02469        goto loser;
02470     }
02471     response->arena = arena;
02472 
02473     /* copy the DER into the arena, since Quick DER returns data that points
02474        into the DER input, which may get freed by the caller */
02475     rv = SECITEM_CopyItem(arena, &newSrc, src);
02476     if ( rv != SECSuccess ) {
02477        goto loser;
02478     }
02479 
02480     rv = SEC_QuickDERDecodeItem(arena, response, ocsp_OCSPResponseTemplate, &newSrc);
02481     if (rv != SECSuccess) {
02482        if (PORT_GetError() == SEC_ERROR_BAD_DER)
02483            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
02484        goto loser;
02485     }
02486 
02487     sv = (ocspResponseStatus) DER_GetInteger(&response->responseStatus);
02488     response->statusValue = sv;
02489     if (sv != ocspResponse_successful) {
02490        /*
02491         * If the response status is anything but successful, then we
02492         * are all done with decoding; the status is all there is.
02493         */
02494        return response;
02495     }
02496 
02497     /*
02498      * A successful response contains much more information, still encoded.
02499      * Now we need to decode that.
02500      */
02501     rv = ocsp_DecodeResponseBytes(arena, response->responseBytes);
02502     if (rv != SECSuccess) {
02503        goto loser;
02504     }
02505 
02506     return response;
02507 
02508 loser:
02509     if (arena != NULL) {
02510        PORT_FreeArena(arena, PR_FALSE);
02511     }
02512     return NULL;
02513 }
02514 
02515 /*
02516  * The way an OCSPResponse is defined, there are many levels to descend
02517  * before getting to the actual response information.  And along the way
02518  * we need to check that the response *type* is recognizable, which for
02519  * now means that it is a BasicOCSPResponse, because that is the only
02520  * type currently defined.  Rather than force all routines to perform
02521  * a bunch of sanity checking every time they want to work on a response,
02522  * this function isolates that and gives back the interesting part.
02523  * Note that no copying is done, this just returns a pointer into the
02524  * substructure of the response which is passed in.
02525  *
02526  * XXX This routine only works when a valid response structure is passed
02527  * into it; this is checked with many assertions.  Assuming the response
02528  * was creating by decoding, it wouldn't make it this far without being
02529  * okay.  That is a sufficient assumption since the entire OCSP interface
02530  * is only used internally.  When this interface is officially exported,
02531  * each assertion below will need to be followed-up with setting an error
02532  * and returning (null).
02533  *
02534  * FUNCTION: ocsp_GetResponseData
02535  *   Returns ocspResponseData structure and a pointer to tbs response
02536  *   data DER from a valid ocsp response. 
02537  * INPUTS:
02538  *   CERTOCSPResponse *response
02539  *     structure of a valid ocsp response
02540  * RETURN:
02541  *   decoded OCSP response data and a pointer(tbsResponseDataDER) to its
02542  *   undecoded data DER.
02543  */
02544 static ocspResponseData *
02545 ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER)
02546 {
02547     ocspBasicOCSPResponse *basic;
02548     ocspResponseData *responseData;
02549 
02550     PORT_Assert(response != NULL);
02551 
02552     PORT_Assert(response->responseBytes != NULL);
02553 
02554     PORT_Assert(response->responseBytes->responseTypeTag
02555               == SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
02556 
02557     basic = response->responseBytes->decodedResponse.basic;
02558     PORT_Assert(basic != NULL);
02559 
02560     responseData = basic->tbsResponseData;
02561     PORT_Assert(responseData != NULL);
02562 
02563     if (tbsResponseDataDER) {
02564         *tbsResponseDataDER = &basic->tbsResponseDataDER;
02565 
02566         PORT_Assert((*tbsResponseDataDER)->data != NULL);
02567         PORT_Assert((*tbsResponseDataDER)->len != 0);
02568     }
02569 
02570     return responseData;
02571 }
02572 
02573 /*
02574  * Much like the routine above, except it returns the response signature.
02575  * Again, no copy is done.
02576  */
02577 static ocspSignature *
02578 ocsp_GetResponseSignature(CERTOCSPResponse *response)
02579 {
02580     ocspBasicOCSPResponse *basic;
02581 
02582     PORT_Assert(response != NULL);
02583     if (NULL == response->responseBytes) {
02584         return NULL;
02585     }
02586     PORT_Assert(response->responseBytes != NULL);
02587     PORT_Assert(response->responseBytes->responseTypeTag
02588               == SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
02589 
02590     basic = response->responseBytes->decodedResponse.basic;
02591     PORT_Assert(basic != NULL);
02592 
02593     return &(basic->responseSignature);
02594 }
02595 
02596 
02597 /*
02598  * FUNCTION: CERT_DestroyOCSPResponse
02599  *   Frees an OCSP Response structure.
02600  * INPUTS:
02601  *   CERTOCSPResponse *request
02602  *     Pointer to CERTOCSPResponse to be freed.
02603  * RETURN:
02604  *   No return value; no errors.
02605  */
02606 void
02607 CERT_DestroyOCSPResponse(CERTOCSPResponse *response)
02608 {
02609     if (response != NULL) {
02610        ocspSignature *signature = ocsp_GetResponseSignature(response);
02611        if (signature && signature->cert != NULL)
02612            CERT_DestroyCertificate(signature->cert);
02613 
02614        /*
02615         * We should actually never have a response without an arena,
02616         * but check just in case.  (If there isn't one, there is not
02617         * much we can do about it...)
02618         */
02619        PORT_Assert(response->arena != NULL);
02620        if (response->arena != NULL) {
02621            PORT_FreeArena(response->arena, PR_FALSE);
02622        }
02623     }
02624 }
02625 
02626 
02627 /*
02628  * OVERALL OCSP CLIENT SUPPORT (make and send a request, verify a response):
02629  */
02630 
02631 
02632 /*
02633  * Pick apart a URL, saving the important things in the passed-in pointers.
02634  *
02635  * We expect to find "http://<hostname>[:<port>]/[path]", though we will
02636  * tolerate that final slash character missing, as well as beginning and
02637  * trailing whitespace, and any-case-characters for "http".  All of that
02638  * tolerance is what complicates this routine.  What we want is just to
02639  * pick out the hostname, the port, and the path.
02640  *
02641  * On a successful return, the caller will need to free the output pieces
02642  * of hostname and path, which are copies of the values found in the url.
02643  */
02644 static SECStatus
02645 ocsp_ParseURL(char *url, char **pHostname, PRUint16 *pPort, char **pPath)
02646 {
02647     unsigned short port = 80;             /* default, in case not in url */
02648     char *hostname = NULL;
02649     char *path = NULL;
02650     char *save;
02651     char c;
02652     int len;
02653 
02654     if (url == NULL)
02655        goto loser;
02656 
02657     /*
02658      * Skip beginning whitespace.
02659      */
02660     c = *url;
02661     while ((c == ' ' || c == '\t') && c != '\0') {
02662        url++;
02663        c = *url;
02664     }
02665     if (c == '\0')
02666        goto loser;
02667 
02668     /*
02669      * Confirm, then skip, protocol.  (Since we only know how to do http,
02670      * that is all we will accept).
02671      */
02672     if (PORT_Strncasecmp(url, "http://", 7) != 0)
02673        goto loser;
02674     url += 7;
02675 
02676     /*
02677      * Whatever comes next is the hostname (or host IP address).  We just
02678      * save it aside and then search for its end so we can determine its
02679      * length and copy it.
02680      *
02681      * XXX Note that because we treat a ':' as a terminator character
02682      * (and below, we expect that to mean there is a port specification
02683      * immediately following), we will not handle IPv6 addresses.  That is
02684      * apparently an acceptable limitation, for the time being.  Some day,
02685      * when there is a clear way to specify a URL with an IPv6 address that
02686      * can be parsed unambiguously, this code should be made to do that.
02687      */
02688     save = url;
02689     c = *url;
02690     while (c != '/' && c != ':' && c != '\0' && c != ' ' && c != '\t') {
02691        url++;
02692        c = *url;
02693     }
02694     len = url - save;
02695     hostname = PORT_Alloc(len + 1);
02696     if (hostname == NULL)
02697        goto loser;
02698     PORT_Memcpy(hostname, save, len);
02699     hostname[len] = '\0';
02700 
02701     /*
02702      * Now we figure out if there was a port specified or not.
02703      * If so, we need to parse it (as a number) and skip it.
02704      */
02705     if (c == ':') {
02706        url++;
02707        port = (unsigned short) PORT_Atoi(url);
02708        c = *url;
02709        while (c != '/' && c != '\0' && c != ' ' && c != '\t') {
02710            if (c < '0' || c > '9')
02711               goto loser;
02712            url++;
02713            c = *url;
02714        }
02715     }
02716 
02717     /*
02718      * Last thing to find is a path.  There *should* be a slash,
02719      * if nothing else -- but if there is not we provide one.
02720      */
02721     if (c == '/') {
02722        save = url;
02723        while (c != '\0' && c != ' ' && c != '\t') {
02724            url++;
02725            c = *url;
02726        }
02727        len = url - save;
02728        path = PORT_Alloc(len + 1);
02729        if (path == NULL)
02730            goto loser;
02731        PORT_Memcpy(path, save, len);
02732        path[len] = '\0';
02733     } else {
02734        path = PORT_Strdup("/");
02735        if (path == NULL)
02736            goto loser;
02737     }
02738 
02739     *pHostname = hostname;
02740     *pPort = port;
02741     *pPath = path;
02742     return SECSuccess;
02743 
02744 loser:
02745     if (hostname != NULL)
02746        PORT_Free(hostname);
02747     PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
02748     return SECFailure;
02749 }
02750 
02751 /*
02752  * Open a socket to the specified host on the specified port, and return it.
02753  * The host is either a hostname or an IP address.
02754  */
02755 static PRFileDesc *
02756 ocsp_ConnectToHost(const char *host, PRUint16 port)
02757 {
02758     PRFileDesc *sock = NULL;
02759     PRIntervalTime timeout;
02760     PRNetAddr addr;
02761     char *netdbbuf = NULL;
02762 
02763     sock = PR_NewTCPSocket();
02764     if (sock == NULL)
02765        goto loser;
02766 
02767     /* XXX Some day need a way to set (and get?) the following value */
02768     timeout = PR_SecondsToInterval(30);
02769 
02770     /*
02771      * If the following converts an IP address string in "dot notation"
02772      * into a PRNetAddr.  If it fails, we assume that is because we do not
02773      * have such an address, but instead a host *name*.  In that case we
02774      * then lookup the host by name.  Using the NSPR function this way
02775      * means we do not have to have our own logic for distinguishing a
02776      * valid numerical IP address from a hostname.
02777      */
02778     if (PR_StringToNetAddr(host, &addr) != PR_SUCCESS) {
02779        PRIntn hostIndex;
02780        PRHostEnt hostEntry;
02781 
02782        netdbbuf = PORT_Alloc(PR_NETDB_BUF_SIZE);
02783        if (netdbbuf == NULL)
02784            goto loser;
02785 
02786        if (PR_GetHostByName(host, netdbbuf, PR_NETDB_BUF_SIZE,
02787                           &hostEntry) != PR_SUCCESS)
02788            goto loser;
02789 
02790        hostIndex = 0;
02791        do {
02792            hostIndex = PR_EnumerateHostEnt(hostIndex, &hostEntry, port, &addr);
02793            if (hostIndex <= 0)
02794               goto loser;
02795        } while (PR_Connect(sock, &addr, timeout) != PR_SUCCESS);
02796 
02797        PORT_Free(netdbbuf);
02798     } else {
02799        /*
02800         * First put the port into the address, then connect.
02801         */
02802        if (PR_InitializeNetAddr(PR_IpAddrNull, port, &addr) != PR_SUCCESS)
02803            goto loser;
02804        if (PR_Connect(sock, &addr, timeout) != PR_SUCCESS)
02805            goto loser;
02806     }
02807 
02808     return sock;
02809 
02810 loser:
02811     if (sock != NULL)
02812        PR_Close(sock);
02813     if (netdbbuf != NULL)
02814        PORT_Free(netdbbuf);
02815     return NULL;
02816 }
02817 
02818 /*
02819  * Sends an encoded OCSP request to the server identified by "location",
02820  * and returns the socket on which it was sent (so can listen for the reply).
02821  * "location" is expected to be a valid URL -- an error parsing it produces
02822  * SEC_ERROR_CERT_BAD_ACCESS_LOCATION.  Other errors are likely problems
02823  * connecting to it, or writing to it, or allocating memory, and the low-level
02824  * errors appropriate to the problem will be set.
02825  */
02826 static PRFileDesc *
02827 ocsp_SendEncodedRequest(char *location, SECItem *encodedRequest)
02828 {
02829     char *hostname = NULL;
02830     char *path = NULL;
02831     PRUint16 port;
02832     SECStatus rv;
02833     PRFileDesc *sock = NULL;
02834     PRFileDesc *returnSock = NULL;
02835     char *header = NULL;
02836 
02837     /*
02838      * Take apart the location, getting the hostname, port, and path.
02839      */
02840     rv = ocsp_ParseURL(location, &hostname, &port, &path);
02841     if (rv != SECSuccess)
02842        goto loser;
02843 
02844     PORT_Assert(hostname != NULL);
02845     PORT_Assert(path != NULL);
02846 
02847     sock = ocsp_ConnectToHost(hostname, port);
02848     if (sock == NULL)
02849        goto loser;
02850 
02851     header = PR_smprintf("POST %s HTTP/1.0\r\n"
02852                       "Host: %s:%d\r\n"
02853                       "Content-Type: application/ocsp-request\r\n"
02854                       "Content-Length: %u\r\n\r\n",
02855                       path, hostname, port, encodedRequest->len);
02856     if (header == NULL)
02857        goto loser;
02858 
02859     /*
02860      * The NSPR documentation promises that if it can, it will write the full
02861      * amount; this will not return a partial value expecting us to loop.
02862      */
02863     if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0)
02864        goto loser;
02865 
02866     if (PR_Write(sock, encodedRequest->data,
02867                (PRInt32) encodedRequest->len) < 0)
02868        goto loser;
02869 
02870     returnSock = sock;
02871     sock = NULL;
02872 
02873 loser:
02874     if (header != NULL)
02875        PORT_Free(header);
02876     if (sock != NULL)
02877        PR_Close(sock);
02878     if (path != NULL)
02879        PORT_Free(path);
02880     if (hostname != NULL)
02881        PORT_Free(hostname);
02882 
02883     return returnSock;
02884 }
02885 
02886 /*
02887  * Read from "fd" into "buf" -- expect/attempt to read a given number of bytes
02888  * Obviously, stop if hit end-of-stream. Timeout is passed in.
02889  */
02890 
02891 static int
02892 ocsp_read(PRFileDesc *fd, char *buf, int toread, PRIntervalTime timeout)
02893 {
02894     int total = 0;
02895 
02896     while (total < toread)
02897     {
02898         PRInt32 got;
02899 
02900         got = PR_Recv(fd, buf + total, (PRInt32) (toread - total), 0, timeout);
02901         if (got < 0)
02902         {
02903             if (0 == total)
02904             {
02905                 total = -1; /* report the error if we didn't read anything yet */
02906             }
02907             break;
02908         }
02909         else
02910         if (got == 0)
02911         {                   /* EOS */
02912             break;
02913         }
02914 
02915         total += got;
02916     }
02917 
02918     return total;
02919 }
02920 
02921 #define OCSP_BUFSIZE 1024
02922 
02923 #define AbortHttpDecode(error) \
02924 { \
02925         if (inBuffer) \
02926             PORT_Free(inBuffer); \
02927         PORT_SetError(error); \
02928         return NULL; \
02929 }
02930 
02931 
02932 /*
02933  * Reads on the given socket and returns an encoded response when received.
02934  * Properly formatted HTTP/1.0 response headers are expected to be read
02935  * from the socket, preceding a binary-encoded OCSP response.  Problems
02936  * with parsing cause the error SEC_ERROR_OCSP_BAD_HTTP_RESPONSE to be
02937  * set; any other problems are likely low-level i/o or memory allocation
02938  * errors.
02939  */
02940 static SECItem *
02941 ocsp_GetEncodedResponse(PRArenaPool *arena, PRFileDesc *sock)
02942 {
02943     /* first read HTTP status line and headers */
02944 
02945     char* inBuffer = NULL;
02946     PRInt32 offset = 0;
02947     PRInt32 inBufsize = 0;
02948     const PRInt32 bufSizeIncrement = OCSP_BUFSIZE; /* 1 KB at a time */
02949     const PRInt32 maxBufSize = 8 * bufSizeIncrement ; /* 8 KB max */
02950     const char* CRLF = "\r\n";
02951     const PRInt32 CRLFlen = strlen(CRLF);
02952     const char* headerEndMark = "\r\n\r\n";
02953     const PRInt32 markLen = strlen(headerEndMark);
02954     const PRIntervalTime ocsptimeout =
02955         PR_SecondsToInterval(30); /* hardcoded to 30s for now */
02956     char* headerEnd = NULL;
02957     PRBool EOS = PR_FALSE;
02958     const char* httpprotocol = "HTTP/";
02959     const PRInt32 httplen = strlen(httpprotocol);
02960     const char* httpcode = NULL;
02961     const char* contenttype = NULL;
02962     PRInt32 contentlength = 0;
02963     PRInt32 bytesRead = 0;
02964     char* statusLineEnd = NULL;
02965     char* space = NULL;
02966     char* nextHeader = NULL;
02967     SECItem* result = NULL;
02968 
02969     /* read up to at least the end of the HTTP headers */
02970     do
02971     {
02972         inBufsize += bufSizeIncrement;
02973         inBuffer = PORT_Realloc(inBuffer, inBufsize+1);
02974         if (NULL == inBuffer)
02975         {
02976             AbortHttpDecode(SEC_ERROR_NO_MEMORY);
02977         }
02978         bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement,
02979             ocsptimeout);
02980         if (bytesRead > 0)
02981         {
02982             PRInt32 searchOffset = (offset - markLen) >0 ? offset-markLen : 0;
02983             offset += bytesRead;
02984             *(inBuffer + offset) = '\0'; /* NULL termination */
02985             headerEnd = strstr((const char*)inBuffer + searchOffset, headerEndMark);
02986             if (bytesRead < bufSizeIncrement)
02987             {
02988                 /* we read less data than requested, therefore we are at
02989                    EOS or there was a read error */
02990                 EOS = PR_TRUE;
02991             }
02992         }
02993         else
02994         {
02995             /* recv error or EOS */
02996             EOS = PR_TRUE;
02997         }
02998     } while ( (!headerEnd) && (PR_FALSE == EOS) &&
02999               (inBufsize < maxBufSize) );
03000 
03001     if (!headerEnd)
03002     {
03003         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03004     }
03005 
03006     /* parse the HTTP status line  */
03007     statusLineEnd = strstr((const char*)inBuffer, CRLF);
03008     if (!statusLineEnd)
03009     {
03010         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03011     }
03012     *statusLineEnd = '\0';
03013 
03014     /* check for HTTP/ response */
03015     space = strchr((const char*)inBuffer, ' ');
03016     if (!space || PORT_Strncasecmp((const char*)inBuffer, httpprotocol, httplen) != 0 )
03017     {
03018         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03019     }
03020 
03021     /* check the HTTP status code of 200 */
03022     httpcode = space +1;
03023     space = strchr(httpcode, ' ');
03024     if (!space)
03025     {
03026         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03027     }
03028     *space = 0;
03029     if (0 != strcmp(httpcode, "200"))
03030     {
03031         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03032     }
03033 
03034     /* parse the HTTP headers in the buffer . We only care about
03035        content-type and content-length
03036     */
03037 
03038     nextHeader = statusLineEnd + CRLFlen;
03039     *headerEnd = '\0'; /* terminate */
03040     do
03041     {
03042         char* thisHeaderEnd = NULL;
03043         char* value = NULL;
03044         char* colon = strchr(nextHeader, ':');
03045         
03046         if (!colon)
03047         {
03048             AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03049         }
03050 
03051         *colon = '\0';
03052         value = colon + 1;
03053 
03054         /* jpierre - note : the following code will only handle the basic form
03055            of HTTP/1.0 response headers, of the form "name: value" . Headers
03056            split among multiple lines are not supported. This is not common
03057            and should not be an issue, but it could become one in the
03058            future */
03059 
03060         if (*value != ' ')
03061         {
03062             AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03063         }
03064 
03065         value++;
03066         thisHeaderEnd  = strstr(value, CRLF);
03067         if (thisHeaderEnd )
03068         {
03069             *thisHeaderEnd  = '\0';
03070         }
03071 
03072         if (0 == PORT_Strcasecmp(nextHeader, "content-type"))
03073         {
03074             contenttype = value;
03075         }
03076         else
03077         if (0 == PORT_Strcasecmp(nextHeader, "content-length"))
03078         {
03079             contentlength = atoi(value);
03080         }
03081 
03082         if (thisHeaderEnd )
03083         {
03084             nextHeader = thisHeaderEnd + CRLFlen;
03085         }
03086         else
03087         {
03088             nextHeader = NULL;
03089         }
03090 
03091     } while (nextHeader && (nextHeader < (headerEnd + CRLFlen) ) );
03092 
03093     /* check content-type */
03094     if (!contenttype ||
03095         (0 != PORT_Strcasecmp(contenttype, "application/ocsp-response")) )
03096     {
03097         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03098     }
03099 
03100     /* read the body of the OCSP response */
03101     offset = offset - (PRInt32) (headerEnd - (const char*)inBuffer) - markLen;
03102     if (offset)
03103     {
03104         /* move all data to the beginning of the buffer */
03105         PORT_Memmove(inBuffer, headerEnd + markLen, offset);
03106     }
03107 
03108     /* resize buffer to only what's needed to hold the current response */
03109     inBufsize = (1 + (offset-1) / bufSizeIncrement ) * bufSizeIncrement ;
03110 
03111     while ( (PR_FALSE == EOS) &&
03112             ( (contentlength == 0) || (offset < contentlength) ) &&
03113             (inBufsize < maxBufSize)
03114             )
03115     {
03116         /* we still need to receive more body data */
03117         inBufsize += bufSizeIncrement;
03118         inBuffer = PORT_Realloc(inBuffer, inBufsize+1);
03119         if (NULL == inBuffer)
03120         {
03121             AbortHttpDecode(SEC_ERROR_NO_MEMORY);
03122         }
03123         bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement,
03124                               ocsptimeout);
03125         if (bytesRead > 0)
03126         {
03127             offset += bytesRead;
03128             if (bytesRead < bufSizeIncrement)
03129             {
03130                 /* we read less data than requested, therefore we are at
03131                    EOS or there was a read error */
03132                 EOS = PR_TRUE;
03133             }
03134         }
03135         else
03136         {
03137             /* recv error or EOS */
03138             EOS = PR_TRUE;
03139         }
03140     }
03141 
03142     if (0 == offset)
03143     {
03144         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03145     }
03146 
03147     /*
03148      * Now allocate the item to hold the data.
03149      */
03150     result = SECITEM_AllocItem(arena, NULL, offset);
03151     if (NULL == result)
03152     {
03153         AbortHttpDecode(SEC_ERROR_NO_MEMORY);
03154     }
03155 
03156     /*
03157      * And copy the data left in the buffer.
03158     */
03159     PORT_Memcpy(result->data, inBuffer, offset);
03160 
03161     /* and free the temporary buffer */
03162     PORT_Free(inBuffer);
03163     return result;
03164 }
03165 
03166 /*
03167  * Limit the size of http responses we are willing to accept.
03168  */
03169 #define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024
03170 
03171 static SECItem *
03172 fetchOcspHttpClientV1(PRArenaPool *arena, 
03173                       const SEC_HttpClientFcnV1 *hcv1, 
03174                       char *location, 
03175                       SECItem *encodedRequest)
03176 {
03177     char *hostname = NULL;
03178     char *path = NULL;
03179     PRUint16 port;
03180     SECItem *encodedResponse = NULL;
03181     SEC_HTTP_SERVER_SESSION pServerSession = NULL;
03182     SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
03183     PRUint16 myHttpResponseCode;
03184     const char *myHttpResponseData;
03185     PRUint32 myHttpResponseDataLen;
03186 
03187     if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) {
03188         PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
03189         goto loser;
03190     }
03191     
03192     PORT_Assert(hostname != NULL);
03193     PORT_Assert(path != NULL);
03194 
03195     if ((*hcv1->createSessionFcn)(
03196             hostname, 
03197             port, 
03198             &pServerSession) != SECSuccess) {
03199         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
03200         goto loser;
03201     }
03202 
03203     /* We use a non-zero timeout, which means:
03204        - the client will use blocking I/O
03205        - TryFcn will not return WOULD_BLOCK nor a poll descriptor
03206        - it's sufficient to call TryFcn once
03207     */
03208 
03209     if ((*hcv1->createFcn)(
03210             pServerSession,
03211             "http",
03212             path,
03213             "POST",
03214             PR_TicksPerSecond() * 60,
03215             &pRequestSession) != SECSuccess) {
03216         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
03217         goto loser;
03218     }
03219 
03220     if ((*hcv1->setPostDataFcn)(
03221             pRequestSession, 
03222             (char*)encodedRequest->data,
03223             encodedRequest->len,
03224             "application/ocsp-request") != SECSuccess) {
03225         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
03226         goto loser;
03227     }
03228 
03229     /* we don't want result objects larger than this: */
03230     myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN;
03231 
03232     if ((*hcv1->trySendAndReceiveFcn)(
03233             pRequestSession, 
03234             NULL,
03235             &myHttpResponseCode,
03236             NULL,
03237             NULL,
03238             &myHttpResponseData,
03239             &myHttpResponseDataLen) != SECSuccess) {
03240         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
03241         goto loser;
03242     }
03243 
03244     if (myHttpResponseCode != 200) {
03245         PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
03246         goto loser;
03247     }
03248 
03249     encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen);
03250 
03251     if (!encodedResponse) {
03252         PORT_SetError(SEC_ERROR_NO_MEMORY);
03253         goto loser;
03254     }
03255 
03256     PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen);
03257 
03258 loser:
03259     if (pRequestSession != NULL) 
03260         (*hcv1->freeFcn)(pRequestSession);
03261     if (pServerSession != NULL)
03262         (*hcv1->freeSessionFcn)(pServerSession);
03263     if (path != NULL)
03264        PORT_Free(path);
03265     if (hostname != NULL)
03266        PORT_Free(hostname);
03267     
03268     return encodedResponse;
03269 }
03270 
03271 /*
03272  * FUNCTION: CERT_GetEncodedOCSPResponse
03273  *   Creates and sends a request to an OCSP responder, then reads and
03274  *   returns the (encoded) response.
03275  * INPUTS:
03276  *   PRArenaPool *arena
03277  *     Pointer to arena from which return value will be allocated.
03278  *     If NULL, result will be allocated from the heap (and thus should
03279  *     be freed via SECITEM_FreeItem).
03280  *   CERTCertList *certList
03281  *     A list of certs for which status will be requested.
03282  *     Note that all of these certificates should have the same issuer,
03283  *     or it's expected the response will be signed by a trusted responder.
03284  *     If the certs need to be broken up into multiple requests, that
03285  *     must be handled by the caller (and thus by having multiple calls
03286  *     to this routine), who knows about where the request(s) are being
03287  *     sent and whether there are any trusted responders in place.
03288  *   char *location
03289  *     The location of the OCSP responder (a URL).
03290  *   int64 time
03291  *     Indicates the time for which the certificate status is to be 
03292  *     determined -- this may be used in the search for the cert's issuer
03293  *     but has no other bearing on the operation.
03294  *   PRBool addServiceLocator
03295  *     If true, the Service Locator extension should be added to the
03296  *     single request(s) for each cert.
03297  *   CERTCertificate *signerCert
03298  *     If non-NULL, means sign the request using this cert.  Otherwise,
03299  *     do not sign.
03300  *   void *pwArg
03301  *     Pointer to argument for password prompting, if needed.  (Definitely
03302  *     not needed if not signing.)
03303  * OUTPUTS:
03304  *   CERTOCSPRequest **pRequest
03305  *     Pointer in which to store the OCSP request created for the given
03306  *     list of certificates.  It is only filled in if the entire operation
03307  *     is successful and the pointer is not null -- and in that case the
03308  *     caller is then reponsible for destroying it.
03309  * RETURN:
03310  *   Returns a pointer to the SECItem holding the response.
03311  *   On error, returns null with error set describing the reason:
03312  *     SEC_ERROR_UNKNOWN_ISSUER
03313  *     SEC_ERROR_CERT_BAD_ACCESS_LOCATION
03314  *     SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
03315  *   Other errors are low-level problems (no memory, bad database, etc.).
03316  */
03317 SECItem *
03318 CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList,
03319                          char *location, int64 time,
03320                          PRBool addServiceLocator,
03321                          CERTCertificate *signerCert, void *pwArg,
03322                          CERTOCSPRequest **pRequest)
03323 {
03324     CERTOCSPRequest *request;
03325     request = CERT_CreateOCSPRequest(certList, time, addServiceLocator,
03326                                      signerCert);
03327     if (!request)
03328         return NULL;
03329     return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, 
03330                                                   time, addServiceLocator, 
03331                                                   pwArg, pRequest);
03332 }
03333 
03334 static SECItem *
03335 ocsp_GetEncodedOCSPResponseFromRequest(PRArenaPool *arena, 
03336                                        CERTOCSPRequest *request,
03337                                        char *location, int64 time,
03338                                        PRBool addServiceLocator,
03339                                        void *pwArg,
03340                                        CERTOCSPRequest **pRequest)
03341 {
03342     SECItem *encodedRequest = NULL;
03343     SECItem *encodedResponse = NULL;
03344     PRFileDesc *sock = NULL;
03345     SECStatus rv;
03346     const SEC_HttpClientFcn *registeredHttpClient = NULL;
03347 
03348     rv = CERT_AddOCSPAcceptableResponses(request,
03349                                     SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
03350     if (rv != SECSuccess)
03351        goto loser;
03352 
03353     encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg);
03354     if (encodedRequest == NULL)
03355        goto loser;
03356 
03357     registeredHttpClient = GetRegisteredHttpClient();
03358 
03359     if (registeredHttpClient
03360             &&
03361             registeredHttpClient->version == 1) {
03362         encodedResponse = fetchOcspHttpClientV1(
03363                               arena,
03364                               &registeredHttpClient->fcnTable.ftable1,
03365                               location,
03366                               encodedRequest);
03367     }
03368     else {
03369       /* use internal http client */
03370     
03371       sock = ocsp_SendEncodedRequest(location, encodedRequest);
03372       if (sock == NULL)
03373          goto loser;
03374 
03375       encodedResponse = ocsp_GetEncodedResponse(arena, sock);
03376     }
03377 
03378     if (encodedResponse != NULL && pRequest != NULL) {
03379        *pRequest = request;
03380        request = NULL;                    /* avoid destroying below */
03381     }
03382 
03383 loser:
03384     if (request != NULL)
03385        CERT_DestroyOCSPRequest(request);
03386     if (encodedRequest != NULL)
03387        SECITEM_FreeItem(encodedRequest, PR_TRUE);
03388     if (sock != NULL)
03389        PR_Close(sock);
03390 
03391     return encodedResponse;
03392 }
03393 
03394 static SECItem *
03395 ocsp_GetEncodedOCSPResponseForSingleCert(PRArenaPool *arena, 
03396                                          CERTOCSPCertID *certID, 
03397                                          CERTCertificate *singleCert, 
03398                                          char *location, int64 time,
03399                                          PRBool addServiceLocator,
03400                                          void *pwArg,
03401                                          CERTOCSPRequest **pRequest)
03402 {
03403     CERTOCSPRequest *request;
03404     request = cert_CreateSingleCertOCSPRequest(certID, singleCert, time, 
03405                                                addServiceLocator);
03406     if (!request)
03407         return NULL;
03408     return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location, 
03409                                                   time, addServiceLocator, 
03410                                                   pwArg, pRequest);
03411 }
03412 
03413 /* Checks a certificate for the key usage extension of OCSP signer. */
03414 static PRBool
03415 ocsp_CertIsOCSPDesignatedResponder(CERTCertificate *cert)
03416 {
03417     SECStatus rv;
03418     SECItem extItem;
03419     SECItem **oids;
03420     SECItem *oid;
03421     SECOidTag oidTag;
03422     PRBool retval;
03423     CERTOidSequence *oidSeq = NULL;
03424 
03425 
03426     extItem.data = NULL;
03427     rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
03428     if ( rv != SECSuccess ) {
03429        goto loser;
03430     }
03431 
03432     oidSeq = CERT_DecodeOidSequence(&extItem);
03433     if ( oidSeq == NULL ) {
03434        goto loser;
03435     }
03436 
03437     oids = oidSeq->oids;
03438     while ( *oids != NULL ) {
03439        oid = *oids;
03440        
03441        oidTag = SECOID_FindOIDTag(oid);
03442        
03443        if ( oidTag == SEC_OID_OCSP_RESPONDER ) {
03444            goto success;
03445        }
03446        
03447        oids++;
03448     }
03449 
03450 loser:
03451     retval = PR_FALSE;
03452     PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
03453     goto done;
03454 success:
03455     retval = PR_TRUE;
03456 done:
03457     if ( extItem.data != NULL ) {
03458        PORT_Free(extItem.data);
03459     }
03460     if ( oidSeq != NULL ) {
03461        CERT_DestroyOidSequence(oidSeq);
03462     }
03463     
03464     return(retval);
03465 }
03466 
03467 
03468 #ifdef LATER  /*
03469                * XXX This function is not currently used, but will
03470                * be needed later when we do revocation checking of
03471                * the responder certificate.  Of course, it may need
03472                * revising then, if the cert extension interface has
03473                * changed.  (Hopefully it will!)
03474                */
03475 
03476 /* Checks a certificate to see if it has the OCSP no check extension. */
03477 static PRBool
03478 ocsp_CertHasNoCheckExtension(CERTCertificate *cert)
03479 {
03480     SECStatus rv;
03481     
03482     rv = CERT_FindCertExtension(cert, SEC_OID_PKIX_OCSP_NO_CHECK, 
03483                             NULL);
03484     if (rv == SECSuccess) {
03485        return PR_TRUE;
03486     }
03487     return PR_FALSE;
03488 }
03489 #endif /* LATER */
03490 
03491 static PRBool
03492 ocsp_matchcert(SECItem *certIndex,CERTCertificate *testCert)
03493 {
03494     SECItem item;
03495     unsigned char buf[HASH_LENGTH_MAX];
03496 
03497     item.data = buf;
03498     item.len = SHA1_LENGTH;
03499 
03500     if (cert_GetSPKIDigest(NULL,testCert,SEC_OID_SHA1, &item) == NULL) {
03501        return PR_FALSE;
03502     }
03503     if  (SECITEM_ItemsAreEqual(certIndex,&item)) {
03504        return PR_TRUE;
03505     }
03506     if (cert_GetSPKIDigest(NULL,testCert,SEC_OID_MD5, &item) == NULL) {
03507        return PR_FALSE;
03508     }
03509     if  (SECITEM_ItemsAreEqual(certIndex,&item)) {
03510        return PR_TRUE;
03511     }
03512     if (cert_GetSPKIDigest(NULL,testCert,SEC_OID_MD2, &item) == NULL) {
03513        return PR_FALSE;
03514     }
03515     if  (SECITEM_ItemsAreEqual(certIndex,&item)) {
03516        return PR_TRUE;
03517     }
03518 
03519     return PR_FALSE;
03520 }
03521 
03522 static PRBool
03523 ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert);
03524 
03525 static CERTCertificate *
03526 ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle,CERTOCSPCertID *certID);
03527 
03528 /*
03529  * FUNCTION: CERT_VerifyOCSPResponseSignature
03530  *   Check the signature on an OCSP Response.  Will also perform a
03531  *   verification of the signer's certificate.  Note, however, that a
03532  *   successful verification does not make any statement about the
03533  *   signer's *authority* to provide status for the certificate(s),
03534  *   that must be checked individually for each certificate.
03535  * INPUTS:
03536  *   CERTOCSPResponse *response
03537  *     Pointer to response structure with signature to be checked.
03538  *   CERTCertDBHandle *handle
03539  *     Pointer to CERTCertDBHandle for certificate DB to use for verification.
03540  *   void *pwArg
03541  *     Pointer to argument for password prompting, if needed.
03542  * OUTPUTS:
03543  *   CERTCertificate **pSignerCert
03544  *     Pointer in which to store signer's certificate; only filled-in if
03545  *     non-null.
03546  * RETURN:
03547  *   Returns SECSuccess when signature is valid, anything else means invalid.
03548  *   Possible errors set:
03549  *     SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID
03550  *     SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time
03551  *     SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found
03552  *     SEC_ERROR_BAD_SIGNATURE - the signature did not verify
03553  *   Other errors are any of the many possible failures in cert verification
03554  *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
03555  *   verifying the signer's cert, or low-level problems (no memory, etc.)
03556  */
03557 SECStatus
03558 CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,   
03559                              CERTCertDBHandle *handle, void *pwArg,
03560                              CERTCertificate **pSignerCert,
03561                              CERTCertificate *issuer)
03562 {
03563     SECItem rawSignature;
03564     SECItem *tbsResponseDataDER;
03565     CERTCertificate *responder = NULL;
03566     CERTCertificate *signerCert = NULL;
03567     SECKEYPublicKey *signerKey = NULL;
03568     CERTCertificate **certs = NULL;
03569     SECStatus rv = SECFailure;
03570     int certCount = 0;
03571     PRBool lookupByName;
03572     void *certIndex;
03573     int64 producedAt;
03574 
03575     /* ocsp_DecodeBasicOCSPResponse will fail if asn1 decoder is unable
03576      * to properly decode tbsData (see the function and
03577      * ocsp_BasicOCSPResponseTemplate). Thus, tbsData can not be
03578      * equal to null */
03579     ocspResponseData *tbsData = ocsp_GetResponseData(response,
03580                                                      &tbsResponseDataDER);
03581     ocspSignature *signature = ocsp_GetResponseSignature(response);
03582 
03583     if (!signature) {
03584         PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE);
03585         return SECFailure;
03586     }
03587 
03588     /*
03589      * If this signature has already gone through verification, just
03590      * return the cached result.
03591      */
03592     if (signature->wasChecked) {
03593        if (signature->status == SECSuccess) {
03594            if (pSignerCert != NULL)
03595               *pSignerCert = CERT_DupCertificate(signature->cert);
03596        } else {
03597            PORT_SetError(signature->failureReason);
03598        }
03599        return signature->status;
03600     }
03601 
03602     PORT_Assert(tbsData->responderID != NULL);
03603     switch (tbsData->responderID->responderIDType) {
03604     case ocspResponderID_byName:
03605        lookupByName = PR_TRUE;
03606        certIndex = &tbsData->derResponderID;
03607        break;
03608     case ocspResponderID_byKey:
03609        lookupByName = PR_FALSE;
03610        certIndex = &tbsData->responderID->responderIDValue.keyHash;
03611        break;
03612     case ocspResponderID_other:
03613     default:
03614        PORT_Assert(0);
03615        PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
03616        return SECFailure;
03617     }
03618 
03619     /*
03620      * If the signature contains some certificates as well, temporarily
03621      * import them in case they are needed for verification.
03622      *
03623      * Note that the result of this is that each cert in "certs" needs
03624      * to be destroyed.
03625      */
03626     if (signature->derCerts != NULL) {
03627        for (; signature->derCerts[certCount] != NULL; certCount++) {
03628            /* just counting */
03629        }
03630        rv = CERT_ImportCerts(handle, certUsageStatusResponder, certCount,
03631                              signature->derCerts, &certs,
03632                              PR_FALSE, PR_FALSE, NULL);
03633        if (rv != SECSuccess)
03634             goto finish;
03635     }
03636 
03637     /*
03638      * Now look up the certificate that did the signing.
03639      * The signer can be specified either by name or by key hash.
03640      */
03641     if (lookupByName) {
03642        SECItem *crIndex = (SECItem*)certIndex;
03643        SECItem encodedName;
03644        PLArenaPool *arena;
03645 
03646        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
03647        if (arena != NULL) {
03648 
03649            rv = SEC_QuickDERDecodeItem(arena, &encodedName,
03650                                        ocsp_ResponderIDDerNameTemplate,
03651                                        crIndex);
03652            if (rv != SECSuccess) {
03653                if (PORT_GetError() == SEC_ERROR_BAD_DER)
03654                    PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
03655            } else {
03656                    signerCert = CERT_FindCertByName(handle, &encodedName);
03657            }
03658            PORT_FreeArena(arena, PR_FALSE);
03659        }
03660     } else {
03661        /*
03662         * The signer is either 1) a known issuer CA we passed in,
03663         * 2) the default OCSP responder, or 3) an intermediate CA
03664         * passed in the cert list to use. Figure out which it is.
03665         */
03666        int i;
03667        responder = ocsp_CertGetDefaultResponder(handle,NULL);
03668        if (responder && ocsp_matchcert(certIndex,responder)) {
03669            signerCert = CERT_DupCertificate(responder);
03670        } else if (issuer && ocsp_matchcert(certIndex,issuer)) {
03671            signerCert = CERT_DupCertificate(issuer);
03672        } 
03673        for (i=0; (signerCert == NULL) && (i < certCount); i++) {
03674            if (ocsp_matchcert(certIndex,certs[i])) {
03675               signerCert = CERT_DupCertificate(certs[i]);
03676            }
03677        }
03678     }
03679 
03680     if (signerCert == NULL) {
03681        rv = SECFailure;
03682        if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
03683            /* Make the error a little more specific. */
03684            PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
03685        }
03686        goto finish;
03687     }
03688 
03689     /*
03690      * We could mark this true at the top of this function, or always
03691      * below at "finish", but if the problem was just that we could not
03692      * find the signer's cert, leave that as if the signature hasn't
03693      * been checked in case a subsequent call might have better luck.
03694      */
03695     signature->wasChecked = PR_TRUE;
03696 
03697     /*
03698      * The function will also verify the signer certificate; we
03699      * need to tell it *when* that certificate must be valid -- for our
03700      * purposes we expect it to be valid when the response was signed.
03701      * The value of "producedAt" is the signing time.
03702      */
03703     rv = DER_GeneralizedTimeToTime(&producedAt, &tbsData->producedAt);
03704     if (rv != SECSuccess)
03705         goto finish;
03706 
03707     /*
03708      * Just because we have a cert does not mean it is any good; check
03709      * it for validity, trust and usage.
03710      */
03711     if (ocsp_CertIsOCSPDefaultResponder(handle, signerCert)) {
03712         rv = SECSuccess;
03713     } else {
03714         if (CERT_IsCACert(signerCert, NULL)) {
03715             rv = CERT_VerifyCert(handle, signerCert, PR_TRUE,
03716                                  certUsageVerifyCA,
03717                                  producedAt, pwArg, NULL);
03718         } else {
03719             rv = CERT_VerifyCert(handle, signerCert, PR_TRUE,
03720                                  certUsageStatusResponder,
03721                                  producedAt, pwArg, NULL);
03722         }
03723         if (rv != SECSuccess) {
03724             PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
03725             goto finish;
03726         }
03727     }
03728 
03729     /*
03730      * Now get the public key from the signer's certificate; we need
03731      * it to perform the verification.
03732      */
03733     signerKey = CERT_ExtractPublicKey(signerCert);
03734     if (signerKey == NULL)
03735        goto finish;
03736     /*
03737      * We copy the signature data *pointer* and length, so that we can
03738      * modify the length without damaging the original copy.  This is a
03739      * simple copy, not a dup, so no destroy/free is necessary.
03740      */
03741     rawSignature = signature->signature;
03742     /*
03743      * The raw signature is a bit string, but we need to represent its
03744      * length in bytes, because that is what the verify function expects.
03745      */
03746     DER_ConvertBitString(&rawSignature);
03747 
03748     rv = VFY_VerifyDataWithAlgorithmID(tbsResponseDataDER->data,
03749                                        tbsResponseDataDER->len,
03750                                        signerKey, &rawSignature,
03751                                        &signature->signatureAlgorithm,
03752                                        NULL, pwArg);
03753     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) {
03754         PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE);
03755     }
03756 
03757 finish:
03758     if (signature->wasChecked)
03759        signature->status = rv;
03760 
03761     if (rv != SECSuccess) {
03762        signature->failureReason = PORT_GetError();
03763        if (signerCert != NULL)
03764            CERT_DestroyCertificate(signerCert);
03765     } else {
03766        /*
03767         * Save signer's certificate in signature.
03768         */
03769        signature->cert = signerCert;
03770        if (pSignerCert != NULL) {
03771            /*
03772             * Pass pointer to signer's certificate back to our caller,
03773             * who is also now responsible for destroying it.
03774             */
03775            *pSignerCert = CERT_DupCertificate(signerCert);
03776        }
03777     }
03778 
03779     if (signerKey != NULL)
03780        SECKEY_DestroyPublicKey(signerKey);
03781 
03782     if (certs != NULL)
03783        CERT_DestroyCertArray(certs, certCount);
03784        /* Free CERTS from SPKDigest Table */
03785 
03786     return rv;
03787 }
03788 
03789 /*
03790  * See if the request's certID and the single response's certID match.
03791  * This can be easy or difficult, depending on whether the same hash
03792  * algorithm was used.
03793  */
03794 static PRBool
03795 ocsp_CertIDsMatch(CERTCertDBHandle *handle,
03796                 CERTOCSPCertID *requestCertID,
03797                 CERTOCSPCertID *responseCertID)
03798 {
03799     PRBool match = PR_FALSE;
03800     SECOidTag hashAlg;
03801     SECItem *keyHash = NULL;
03802     SECItem *nameHash = NULL;
03803 
03804     /*
03805      * In order to match, they must have the same issuer and the same
03806      * serial number.
03807      *
03808      * We just compare the easier things first.
03809      */
03810     if (SECITEM_CompareItem(&requestCertID->serialNumber,
03811                          &responseCertID->serialNumber) != SECEqual) {
03812        goto done;
03813     }
03814 
03815     /*
03816      * Make sure the "parameters" are not too bogus.  Since we encoded
03817      * requestCertID->hashAlgorithm, we don't need to check it.
03818      */
03819     if (responseCertID->hashAlgorithm.parameters.len > 2) {
03820        goto done;
03821     }
03822     if (SECITEM_CompareItem(&requestCertID->hashAlgorithm.algorithm,
03823               &responseCertID->hashAlgorithm.algorithm) == SECEqual) {
03824        /*
03825         * If the hash algorithms match then we can do a simple compare
03826         * of the hash values themselves.
03827         */
03828        if ((SECITEM_CompareItem(&requestCertID->issuerNameHash,
03829                             &responseCertID->issuerNameHash) == SECEqual)
03830            && (SECITEM_CompareItem(&requestCertID->issuerKeyHash,
03831                             &responseCertID->issuerKeyHash) == SECEqual)) {
03832            match = PR_TRUE;
03833        }
03834        goto done;
03835     }
03836 
03837     hashAlg = SECOID_FindOIDTag(&responseCertID->hashAlgorithm.algorithm);
03838     switch (hashAlg) {
03839     case SEC_OID_SHA1:
03840        keyHash = &requestCertID->issuerSHA1KeyHash;
03841        nameHash = &requestCertID->issuerSHA1NameHash;
03842        break;
03843     case SEC_OID_MD5:
03844        keyHash = &requestCertID->issuerMD5KeyHash;
03845        nameHash = &requestCertID->issuerMD5NameHash;
03846        break;
03847     case SEC_OID_MD2:
03848        keyHash = &requestCertID->issuerMD2KeyHash;
03849        nameHash = &requestCertID->issuerMD2NameHash;
03850        break;
03851     default:
03852        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
03853        return SECFailure;
03854     }
03855 
03856     if ((keyHash != NULL)
03857        && (SECITEM_CompareItem(nameHash,
03858                             &responseCertID->issuerNameHash) == SECEqual)
03859        && (SECITEM_CompareItem(keyHash,
03860                             &responseCertID->issuerKeyHash) == SECEqual)) {
03861        match = PR_TRUE;
03862     }
03863 
03864 done:
03865     return match;
03866 }
03867 
03868 /*
03869  * Find the single response for the cert specified by certID.
03870  * No copying is done; this just returns a pointer to the appropriate
03871  * response within responses, if it is found (and null otherwise).
03872  * This is fine, of course, since this function is internal-use only.
03873  */
03874 static CERTOCSPSingleResponse *
03875 ocsp_GetSingleResponseForCertID(CERTOCSPSingleResponse **responses,
03876                             CERTCertDBHandle *handle,
03877                             CERTOCSPCertID *certID)
03878 {
03879     CERTOCSPSingleResponse *single;
03880     int i;
03881 
03882     if (responses == NULL)
03883        return NULL;
03884 
03885     for (i = 0; responses[i] != NULL; i++) {
03886        single = responses[i];
03887        if (ocsp_CertIDsMatch(handle, certID, single->certID)) {
03888            return single;
03889        }
03890     }
03891 
03892     /*
03893      * The OCSP server should have included a response even if it knew
03894      * nothing about the certificate in question.  Since it did not,
03895      * this will make it look as if it had.
03896      * 
03897      * XXX Should we make this a separate error to notice the server's
03898      * bad behavior?
03899      */
03900     PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT);
03901     return NULL;
03902 }
03903 
03904 static ocspCheckingContext *
03905 ocsp_GetCheckingContext(CERTCertDBHandle *handle)
03906 {
03907     CERTStatusConfig *statusConfig;
03908     ocspCheckingContext *ocspcx = NULL;
03909 
03910     statusConfig = CERT_GetStatusConfig(handle);
03911     if (statusConfig != NULL) {
03912        ocspcx = statusConfig->statusContext;
03913 
03914        /*
03915         * This is actually an internal error, because we should never
03916         * have a good statusConfig without a good statusContext, too.
03917         * For lack of anything better, though, we just assert and use
03918         * the same error as if there were no statusConfig (set below).
03919         */
03920        PORT_Assert(ocspcx != NULL);
03921     }
03922 
03923     if (ocspcx == NULL)
03924        PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED);
03925 
03926     return ocspcx;
03927 }
03928 
03929 /*
03930  * Return cert reference if the given signerCert is the default responder for
03931  * the given certID.  If not, or if any error, return NULL.
03932  */
03933 static CERTCertificate *
03934 ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle, CERTOCSPCertID *certID)
03935 {
03936     ocspCheckingContext *ocspcx;
03937 
03938     ocspcx = ocsp_GetCheckingContext(handle);
03939     if (ocspcx == NULL)
03940        goto loser;
03941 
03942    /*
03943     * Right now we have only one default responder.  It applies to
03944     * all certs when it is used, so the check is simple and certID
03945     * has no bearing on the answer.  Someday in the future we may
03946     * allow configuration of different responders for different
03947     * issuers, and then we would have to use the issuer specified
03948     * in certID to determine if signerCert is the right one.
03949     */
03950     if (ocspcx->useDefaultResponder) {
03951        PORT_Assert(ocspcx->defaultResponderCert != NULL);
03952        return ocspcx->defaultResponderCert;
03953     }
03954 
03955 loser:
03956     return NULL;
03957 }
03958 
03959 /*
03960  * Return true if the cert is one of the default responders configured for
03961  * ocsp context. If not, or if any error, return false.
03962  */
03963 static PRBool
03964 ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert)
03965 {
03966     ocspCheckingContext *ocspcx;
03967 
03968     ocspcx = ocsp_GetCheckingContext(handle);
03969     if (ocspcx == NULL)
03970        return PR_FALSE;
03971 
03972    /*
03973     * Right now we have only one default responder.  It applies to
03974     * all certs when it is used, so the check is simple and certID
03975     * has no bearing on the answer.  Someday in the future we may
03976     * allow configuration of different responders for different
03977     * issuers, and then we would have to use the issuer specified
03978     * in certID to determine if signerCert is the right one.
03979     */
03980     if (ocspcx->useDefaultResponder &&
03981         CERT_CompareCerts(ocspcx->defaultResponderCert, cert)) {
03982        return PR_TRUE;
03983     }
03984 
03985     return PR_FALSE;
03986 }
03987 
03988 /*
03989  * Check that the given signer certificate is authorized to sign status
03990  * information for the given certID.  Return true if it is, false if not
03991  * (or if there is any error along the way).  If false is returned because
03992  * the signer is not authorized, the following error will be set:
03993  *     SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
03994  * Other errors are low-level problems (no memory, bad database, etc.).
03995  *
03996  * There are three ways to be authorized.  In the order in which we check,
03997  * using the terms used in the OCSP spec, the signer must be one of:
03998  *  1.  A "trusted responder" -- it matches a local configuration
03999  *      of OCSP signing authority for the certificate in question.
04000  *  2.  The CA who issued the certificate in question.
04001  *  3.  A "CA designated responder", aka an "authorized responder" -- it
04002  *      must be represented by a special cert issued by the CA who issued
04003  *      the certificate in question.
04004  */
04005 static PRBool
04006 ocsp_AuthorizedResponderForCertID(CERTCertDBHandle *handle,
04007                               CERTCertificate *signerCert,
04008                               CERTOCSPCertID *certID,
04009                               int64 thisUpdate)
04010 {
04011     CERTCertificate *issuerCert = NULL, *defRespCert;
04012     SECItem *keyHash = NULL;
04013     SECItem *nameHash = NULL;
04014     SECOidTag hashAlg;
04015     PRBool keyHashEQ = PR_FALSE, nameHashEQ = PR_FALSE;
04016 
04017     /*
04018      * Check first for a trusted responder, which overrides everything else.
04019      */
04020     if ((defRespCert = ocsp_CertGetDefaultResponder(handle, certID)) &&
04021         CERT_CompareCerts(defRespCert, signerCert)) {
04022         return PR_TRUE;
04023     }
04024 
04025     /*
04026      * In the other two cases, we need to do an issuer comparison.
04027      * How we do it depends on whether the signer certificate has the
04028      * special extension (for a designated responder) or not.
04029      *
04030      * First, lets check if signer of the response is the actual issuer
04031      * of the cert. For that we will use signer cert key hash and cert subj
04032      * name hash and will compare them with already calculated issuer key
04033      * hash and issuer name hash. The hash algorithm is picked from response
04034      * certID hash to avoid second hash calculation.
04035      */
04036 
04037     hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm);
04038 
04039     keyHash = cert_GetSPKIDigest(NULL, signerCert, hashAlg, NULL);
04040     if (keyHash != NULL) {
04041 
04042         keyHashEQ =
04043             (SECITEM_CompareItem(keyHash,
04044                                  &certID->issuerKeyHash) == SECEqual);
04045         SECITEM_FreeItem(keyHash, PR_TRUE);
04046     }
04047     if (keyHashEQ &&
04048         (nameHash = cert_GetSubjectNameDigest(NULL, signerCert,
04049                                               hashAlg, NULL))) {
04050         nameHashEQ =
04051             (SECITEM_CompareItem(nameHash,
04052                                  &certID->issuerNameHash) == SECEqual);
04053             
04054         SECITEM_FreeItem(nameHash, PR_TRUE);
04055         if (nameHashEQ) {
04056             /* The issuer of the cert is the the signer of the response */
04057             return PR_TRUE;
04058         }
04059     }
04060 
04061 
04062     keyHashEQ = PR_FALSE;
04063     nameHashEQ = PR_FALSE;
04064 
04065     if (!ocsp_CertIsOCSPDesignatedResponder(signerCert)) {
04066         PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
04067         return PR_FALSE;
04068     }
04069 
04070     /*
04071      * The signer is a designated responder.  Its issuer must match
04072      * the issuer of the cert being checked.
04073      */
04074     issuerCert = CERT_FindCertIssuer(signerCert, thisUpdate,
04075                                      certUsageAnyCA);
04076     if (issuerCert == NULL) {
04077         /*
04078          * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone,
04079          * but the following will give slightly more information.
04080          * Once we have an error stack, things will be much better.
04081          */
04082         PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
04083         return PR_FALSE;
04084     }
04085 
04086     keyHash = cert_GetSPKIDigest(NULL, issuerCert, hashAlg, NULL);
04087     nameHash = cert_GetSubjectNameDigest(NULL, issuerCert, hashAlg, NULL);
04088 
04089     CERT_DestroyCertificate(issuerCert);
04090 
04091     if (keyHash != NULL && nameHash != NULL) {
04092         keyHashEQ = 
04093             (SECITEM_CompareItem(keyHash,
04094                                  &certID->issuerKeyHash) == SECEqual);
04095 
04096         nameHashEQ =
04097             (SECITEM_CompareItem(nameHash,
04098                                  &certID->issuerNameHash) == SECEqual);
04099     }
04100 
04101     if (keyHash) {
04102         SECITEM_FreeItem(keyHash, PR_TRUE);
04103     }
04104     if (nameHash) {
04105         SECITEM_FreeItem(nameHash, PR_TRUE);
04106     }
04107 
04108     if (keyHashEQ && nameHashEQ) {
04109         return PR_TRUE;
04110     }
04111 
04112     PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
04113     return PR_FALSE;
04114 }
04115 
04116 /*
04117  * We need to check that a responder gives us "recent" information.
04118  * Since a responder can pre-package responses, we need to pick an amount
04119  * of time that is acceptable to us, and reject any response that is
04120  * older than that.
04121  *
04122  * XXX This *should* be based on some configuration parameter, so that
04123  * different usages could specify exactly what constitutes "sufficiently
04124  * recent".  But that is not going to happen right away.  For now, we
04125  * want something from within the last 24 hours.  This macro defines that
04126  * number in seconds.
04127  */
04128 #define OCSP_ALLOWABLE_LAPSE_SECONDS      (24L * 60L * 60L)
04129 
04130 static PRBool
04131 ocsp_TimeIsRecent(int64 checkTime)
04132 {
04133     int64 now = PR_Now();
04134     int64 lapse, tmp;
04135 
04136     LL_I2L(lapse, OCSP_ALLOWABLE_LAPSE_SECONDS);
04137     LL_I2L(tmp, PR_USEC_PER_SEC);
04138     LL_MUL(lapse, lapse, tmp);            /* allowable lapse in microseconds */
04139 
04140     LL_ADD(checkTime, checkTime, lapse);
04141     if (LL_CMP(now, >, checkTime))
04142        return PR_FALSE;
04143 
04144     return PR_TRUE;
04145 }
04146 
04147 #define OCSP_SLOP (5L*60L) /* OCSP responses are allowed to be 5 minutes
04148                               in the future by default */
04149 
04150 static PRUint32 ocspsloptime = OCSP_SLOP; /* seconds */
04151 
04152 /*
04153  * Check that this single response is okay.  A return of SECSuccess means:
04154  *   1. The signer (represented by "signerCert") is authorized to give status
04155  *     for the cert represented by the individual response in "single".
04156  *   2. The value of thisUpdate is earlier than now.
04157  *   3. The value of producedAt is later than or the same as thisUpdate.
04158  *   4. If nextUpdate is given:
04159  *     - The value of nextUpdate is later than now.
04160  *     - The value of producedAt is earlier than nextUpdate.
04161  *     Else if no nextUpdate:
04162  *     - The value of thisUpdate is fairly recent.
04163  *     - The value of producedAt is fairly recent.
04164  *     However we do not need to perform an explicit check for this last
04165  *     constraint because it is already guaranteed by checking that
04166  *     producedAt is later than thisUpdate and thisUpdate is recent.
04167  * Oh, and any responder is "authorized" to say that a cert is unknown to it.
04168  *
04169  * If any of those checks fail, SECFailure is returned and an error is set:
04170  *     SEC_ERROR_OCSP_FUTURE_RESPONSE
04171  *     SEC_ERROR_OCSP_OLD_RESPONSE
04172  *     SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
04173  * Other errors are low-level problems (no memory, bad database, etc.).
04174  */ 
04175 static SECStatus
04176 ocsp_VerifySingleResponse(CERTOCSPSingleResponse *single,
04177                        CERTCertDBHandle *handle,
04178                        CERTCertificate *signerCert,
04179                        int64 producedAt)
04180 {
04181     CERTOCSPCertID *certID = single->certID;
04182     int64 now, thisUpdate, nextUpdate, tmstamp, tmp;
04183     SECStatus rv;
04184 
04185     OCSP_TRACE(("OCSP ocsp_VerifySingleResponse, nextUpdate: %d\n", 
04186                ((single->nextUpdate) != 0)));
04187     /*
04188      * If all the responder said was that the given cert was unknown to it,
04189      * that is a valid response.  Not very interesting to us, of course,
04190      * but all this function is concerned with is validity of the response,
04191      * not the status of the cert.
04192      */
04193     PORT_Assert(single->certStatus != NULL);
04194     if (single->certStatus->certStatusType == ocspCertStatus_unknown)
04195        return SECSuccess;
04196 
04197     /*
04198      * We need to extract "thisUpdate" for use below and to pass along
04199      * to AuthorizedResponderForCertID in case it needs it for doing an
04200      * issuer look-up.
04201      */
04202     rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate);
04203     if (rv != SECSuccess)
04204        return rv;
04205 
04206     /*
04207      * First confirm that signerCert is authorized to give this status.
04208      */
04209     if (ocsp_AuthorizedResponderForCertID(handle, signerCert, certID,
04210                                      thisUpdate) != PR_TRUE)
04211        return SECFailure;
04212 
04213     /*
04214      * Now check the time stuff, as described above.
04215      */
04216     now = PR_Now();
04217     /* allow slop time for future response */
04218     LL_UI2L(tmstamp, ocspsloptime); /* get slop time in seconds */
04219     LL_UI2L(tmp, PR_USEC_PER_SEC);
04220     LL_MUL(tmp, tmstamp, tmp); /* convert the slop time to PRTime */
04221     LL_ADD(tmstamp, tmp, now); /* add current time to it */
04222 
04223     if (LL_CMP(thisUpdate, >, tmstamp) || LL_CMP(producedAt, <, thisUpdate)) {
04224        PORT_SetError(SEC_ERROR_OCSP_FUTURE_RESPONSE);
04225        return SECFailure;
04226     }
04227     if (single->nextUpdate != NULL) {
04228        rv = DER_GeneralizedTimeToTime(&nextUpdate, single->nextUpdate);
04229        if (rv != SECSuccess)
04230            return rv;
04231 
04232        LL_ADD(tmp, tmp, nextUpdate);
04233        if (LL_CMP(tmp, <, now) || LL_CMP(producedAt, >, nextUpdate)) {
04234            PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE);
04235            return SECFailure;
04236        }
04237     } else if (ocsp_TimeIsRecent(thisUpdate) != PR_TRUE) {
04238        PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE);
04239        return SECFailure;
04240     }
04241 
04242     return SECSuccess;
04243 }
04244 
04245 
04246 /*
04247  * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation
04248  *   Get the value of the URI of the OCSP responder for the given cert.
04249  *   This is found in the (optional) Authority Information Access extension
04250  *   in the cert.
04251  * INPUTS:
04252  *   CERTCertificate *cert
04253  *     The certificate being examined.
04254  * RETURN:
04255  *   char *
04256  *     A copy of the URI for the OCSP method, if found.  If either the
04257  *     extension is not present or it does not contain an entry for OCSP,
04258  *     SEC_ERROR_CERT_BAD_ACCESS_LOCATION will be set and a NULL returned.
04259  *     Any other error will also result in a NULL being returned.
04260  *     
04261  *     This result should be freed (via PORT_Free) when no longer in use.
04262  */
04263 char *
04264 CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert)
04265 {
04266     CERTGeneralName *locname = NULL;
04267     SECItem *location = NULL;
04268     SECItem *encodedAuthInfoAccess = NULL;
04269     CERTAuthInfoAccess **authInfoAccess = NULL;
04270     char *locURI = NULL;
04271     PRArenaPool *arena = NULL;
04272     SECStatus rv;
04273     int i;
04274 
04275     /*
04276      * Allocate this one from the heap because it will get filled in
04277      * by CERT_FindCertExtension which will also allocate from the heap,
04278      * and we can free the entire thing on our way out.
04279      */
04280     encodedAuthInfoAccess = SECITEM_AllocItem(NULL, NULL, 0);
04281     if (encodedAuthInfoAccess == NULL)
04282        goto loser;
04283 
04284     rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
04285                             encodedAuthInfoAccess);
04286     if (rv == SECFailure) {
04287        PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
04288        goto loser;
04289     }
04290 
04291     /*
04292      * The rest of the things allocated in the routine will come out of
04293      * this arena, which is temporary just for us to decode and get at the
04294      * AIA extension.  The whole thing will be destroyed on our way out,
04295      * after we have copied the location string (url) itself (if found).
04296      */
04297     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
04298     if (arena == NULL)
04299        goto loser;
04300 
04301     authInfoAccess = CERT_DecodeAuthInfoAccessExtension(arena,
04302                                                  encodedAuthInfoAccess);
04303     if (authInfoAccess == NULL)
04304        goto loser;
04305 
04306     for (i = 0; authInfoAccess[i] != NULL; i++) {
04307        if (SECOID_FindOIDTag(&authInfoAccess[i]->method) == SEC_OID_PKIX_OCSP)
04308            locname = authInfoAccess[i]->location;
04309     }
04310 
04311     /*
04312      * If we found an AIA extension, but it did not include an OCSP method,
04313      * that should look to our caller as if we did not find the extension
04314      * at all, because it is only an OCSP method that we care about.
04315      * So set the same error that would be set if the AIA extension was
04316      * not there at all.
04317      */
04318     if (locname == NULL) {
04319        PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
04320        goto loser;
04321     }
04322 
04323     /*
04324      * The following is just a pointer back into locname (i.e. not a copy);
04325      * thus it should not be freed.
04326      */
04327     location = CERT_GetGeneralNameByType(locname, certURI, PR_FALSE);
04328     if (location == NULL) {
04329        /*
04330         * XXX Appears that CERT_GetGeneralNameByType does not set an
04331         * error if there is no name by that type.  For lack of anything
04332         * better, act as if the extension was not found.  In the future
04333         * this should probably be something more like the extension was
04334         * badly formed.
04335         */
04336        PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
04337        goto loser;
04338     }
04339 
04340     /*
04341      * That location is really a string, but it has a specified length
04342      * without a null-terminator.  We need a real string that does have
04343      * a null-terminator, and we need a copy of it anyway to return to
04344      * our caller -- so allocate and copy.
04345      */
04346     locURI = PORT_Alloc(location->len + 1);
04347     if (locURI == NULL) {
04348        goto loser;
04349     }
04350     PORT_Memcpy(locURI, location->data, location->len);
04351     locURI[location->len] = '\0';
04352 
04353 loser:
04354     if (arena != NULL)
04355        PORT_FreeArena(arena, PR_FALSE);
04356 
04357     if (encodedAuthInfoAccess != NULL)
04358        SECITEM_FreeItem(encodedAuthInfoAccess, PR_TRUE);
04359 
04360     return locURI;
04361 }
04362 
04363 
04364 /*
04365  * Figure out where we should go to find out the status of the given cert
04366  * via OCSP.  If a default responder is set up, that is our answer.
04367  * If not, see if the certificate has an Authority Information Access (AIA)
04368  * extension for OCSP, and return the value of that.  Otherwise return NULL.
04369  * We also let our caller know whether or not the responder chosen was
04370  * a default responder or not through the output variable isDefault;
04371  * its value has no meaning unless a good (non-null) value is returned
04372  * for the location.
04373  *
04374  * The result needs to be freed (PORT_Free) when no longer in use.
04375  */
04376 static char *
04377 ocsp_GetResponderLocation(CERTCertDBHandle *handle, CERTCertificate *cert,
04378                        PRBool *isDefault)
04379 {
04380     ocspCheckingContext *ocspcx;
04381 
04382     ocspcx = ocsp_GetCheckingContext(handle);
04383     if (ocspcx != NULL && ocspcx->useDefaultResponder) {
04384        /*
04385         * A default responder wins out, if specified.
04386         * XXX Someday this may be a more complicated determination based
04387         * on the cert's issuer.  (That is, we could have different default
04388         * responders configured for different issuers.)
04389         */
04390        PORT_Assert(ocspcx->defaultResponderURI != NULL);
04391        *isDefault = PR_TRUE;
04392        return (PORT_Strdup(ocspcx->defaultResponderURI));
04393     }
04394 
04395     /*
04396      * No default responder set up, so go see if we can find an AIA
04397      * extension that has a value for OCSP, and get the url from that.
04398      */
04399     *isDefault = PR_FALSE;
04400     return CERT_GetOCSPAuthorityInfoAccessLocation(cert);
04401 }
04402 
04403 /*
04404  * Return SECSuccess if the cert was revoked *after* "time",
04405  * SECFailure otherwise.
04406  */
04407 static SECStatus
04408 ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, int64 time)
04409 {
04410     int64 revokedTime;
04411     SECStatus rv;
04412 
04413     rv = DER_GeneralizedTimeToTime(&revokedTime, &revokedInfo->revocationTime);
04414     if (rv != SECSuccess)
04415        return rv;
04416 
04417     /*
04418      * Set the error even if we will return success; someone might care.
04419      */
04420     PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
04421 
04422     if (LL_CMP(revokedTime, >, time))
04423        return SECSuccess;
04424 
04425     return SECFailure;
04426 }
04427 
04428 /*
04429  * See if the cert represented in the single response had a good status
04430  * at the specified time.
04431  */
04432 static SECStatus
04433 ocsp_CertHasGoodStatus(ocspCertStatus *status, int64 time)
04434 {
04435     SECStatus rv;
04436     switch (status->certStatusType) {
04437     case ocspCertStatus_good:
04438         rv = SECSuccess;
04439         break;
04440     case ocspCertStatus_revoked:
04441         rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time);
04442         break;
04443     case ocspCertStatus_unknown:
04444         PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT);
04445         rv = SECFailure;
04446         break;
04447     case ocspCertStatus_other:
04448     default:
04449         PORT_Assert(0);
04450         PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
04451         rv = SECFailure;
04452         break;
04453     }
04454     return rv;
04455 }
04456 
04457 static SECStatus
04458 ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse *single, int64 time)
04459 {
04460     return ocsp_CertHasGoodStatus(single->certStatus, time);
04461 }
04462 
04463 /* return value SECFailure means: not found or not fresh */
04464 static SECStatus
04465 ocsp_GetCachedOCSPResponseStatusIfFresh(CERTOCSPCertID *certID, 
04466                                         int64 time, 
04467                                         SECStatus *rv_ocsp)
04468 {
04469     OCSPCacheItem *cacheItem = NULL;
04470     SECStatus rv = SECFailure;
04471   
04472     if (!certID || !rv_ocsp) {
04473         PORT_SetError(SEC_ERROR_INVALID_ARGS);
04474         return SECFailure;
04475     }
04476     *rv_ocsp = SECFailure;
04477   
04478     PR_EnterMonitor(OCSP_Global.monitor);
04479     cacheItem = ocsp_FindCacheEntry(&OCSP_Global.cache, certID);
04480     if (cacheItem && ocsp_IsCacheItemFresh(cacheItem)) {
04481         /* having an arena means, we have a cached certStatus */
04482         if (cacheItem->certStatusArena) {
04483             *rv_ocsp = ocsp_CertHasGoodStatus(&cacheItem->certStatus, time);
04484             rv = SECSuccess;
04485         } else {
04486             /*
04487              * No status cached, the previous attempt failed.
04488              * If OCSP is required, we never decide based on a failed attempt 
04489              * However, if OCSP is optional, a recent OCSP failure is
04490              * an allowed good state.
04491              */
04492             if (OCSP_Global.ocspFailureMode == 
04493                     ocspMode_FailureIsNotAVerificationFailure) {
04494                 rv = SECSuccess;
04495                 *rv_ocsp = SECSuccess;
04496             }
04497         }
04498     }
04499     PR_ExitMonitor(OCSP_Global.monitor);
04500     return rv;
04501 }
04502 
04503 /*
04504  * FUNCTION: CERT_CheckOCSPStatus
04505  *   Checks the status of a certificate via OCSP.  Will only check status for
04506  *   a certificate that has an AIA (Authority Information Access) extension
04507  *   for OCSP *or* when a "default responder" is specified and enabled.
04508  *   (If no AIA extension for OCSP and no default responder in place, the
04509  *   cert is considered to have a good status and SECSuccess is returned.)
04510  * INPUTS:
04511  *   CERTCertDBHandle *handle
04512  *     certificate DB of the cert that is being checked
04513  *   CERTCertificate *cert
04514  *     the certificate being checked
04515  *   XXX in the long term also need a boolean parameter that specifies
04516  *     whether to check the cert chain, as well; for now we check only
04517  *     the leaf (the specified certificate)
04518  *   int64 time
04519  *     time for which status is to be determined
04520  *   void *pwArg
04521  *     argument for password prompting, if needed
04522  * RETURN:
04523  *   Returns SECSuccess if an approved OCSP responder "knows" the cert
04524  *   *and* returns a non-revoked status for it; SECFailure otherwise,
04525  *   with an error set describing the reason:
04526  *
04527  *     SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
04528  *     SEC_ERROR_OCSP_FUTURE_RESPONSE
04529  *     SEC_ERROR_OCSP_MALFORMED_REQUEST
04530  *     SEC_ERROR_OCSP_MALFORMED_RESPONSE
04531  *     SEC_ERROR_OCSP_OLD_RESPONSE
04532  *     SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
04533  *     SEC_ERROR_OCSP_SERVER_ERROR
04534  *     SEC_ERROR_OCSP_TRY_SERVER_LATER
04535  *     SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
04536  *     SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
04537  *     SEC_ERROR_OCSP_UNKNOWN_CERT
04538  *     SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
04539  *     SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE
04540  *
04541  *     SEC_ERROR_BAD_SIGNATURE
04542  *     SEC_ERROR_CERT_BAD_ACCESS_LOCATION
04543  *     SEC_ERROR_INVALID_TIME
04544  *     SEC_ERROR_REVOKED_CERTIFICATE
04545  *     SEC_ERROR_UNKNOWN_ISSUER
04546  *     SEC_ERROR_UNKNOWN_SIGNER
04547  *
04548  *   Other errors are any of the many possible failures in cert verification
04549  *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
04550  *   verifying the signer's cert, or low-level problems (error allocating
04551  *   memory, error performing ASN.1 decoding, etc.).
04552  */    
04553 SECStatus 
04554 CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
04555                    int64 time, void *pwArg)
04556 {
04557     CERTOCSPCertID *certID;
04558     PRBool certIDWasConsumed = PR_FALSE;
04559     SECStatus rv = SECFailure;
04560     SECStatus rv_ocsp;
04561   
04562     OCSP_TRACE_CERT(cert);
04563     OCSP_TRACE_TIME("## requested validity time:", time);
04564   
04565     certID = CERT_CreateOCSPCertID(cert, time);
04566     if (!certID)
04567         return SECFailure;
04568     rv = ocsp_GetCachedOCSPResponseStatusIfFresh(certID, time, &rv_ocsp);
04569     if (rv == SECSuccess) {
04570         CERT_DestroyOCSPCertID(certID);
04571         return rv_ocsp;
04572     }
04573     rv = ocsp_GetOCSPStatusFromNetwork(handle, certID, cert, time, pwArg, 
04574                                        &certIDWasConsumed, &rv_ocsp);
04575     if (rv != SECSuccess) {
04576         /* we were unable to obtain ocsp status */
04577         PR_EnterMonitor(OCSP_Global.monitor);
04578         if (OCSP_Global.ocspFailureMode ==
04579                 ocspMode_FailureIsVerificationFailure) {
04580             rv_ocsp = SECFailure;
04581         } else {
04582             rv_ocsp = SECSuccess;
04583         }
04584         PR_ExitMonitor(OCSP_Global.monitor);
04585     }
04586     if (!certIDWasConsumed) {
04587         CERT_DestroyOCSPCertID(certID);
04588     }
04589     return rv_ocsp;
04590 }
04591 
04592 /*
04593  * Status in *certIDWasConsumed will always be correct, regardless of 
04594  * return value.
04595  */
04596 static SECStatus
04597 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle, 
04598                               CERTOCSPCertID *certID, 
04599                               CERTCertificate *cert, 
04600                               int64 time, 
04601                               void *pwArg,
04602                               PRBool *certIDWasConsumed,
04603                               SECStatus *rv_ocsp)
04604 {
04605     char *location = NULL;
04606     PRBool locationIsDefault;
04607     SECItem *encodedResponse = NULL;
04608     CERTOCSPRequest *request = NULL;
04609     CERTOCSPResponse *response = NULL;
04610     CERTCertificate *signerCert = NULL;
04611     CERTCertificate *issuerCert = NULL;
04612     SECStatus rv = SECFailure;
04613     CERTOCSPSingleResponse *single = NULL;
04614 
04615     if (!certIDWasConsumed || !rv_ocsp) {
04616         PORT_SetError(SEC_ERROR_INVALID_ARGS);
04617         return SECFailure;
04618     }
04619     *certIDWasConsumed = PR_FALSE;
04620     *rv_ocsp = SECFailure;
04621 
04622     /*
04623      * The first thing we need to do is find the location of the responder.
04624      * This will be the value of the default responder (if enabled), else
04625      * it will come out of the AIA extension in the cert (if present).
04626      * If we have no such location, then this cert does not "deserve" to
04627      * be checked -- that is, we consider it a success and just return.
04628      * The way we tell that is by looking at the error number to see if
04629      * the problem was no AIA extension was found; any other error was
04630      * a true failure that we unfortunately have to treat as an overall
04631      * failure here.
04632      */
04633     location = ocsp_GetResponderLocation(handle, cert, &locationIsDefault);
04634     if (location == NULL) {
04635        int err = PORT_GetError();
04636        if (err == SEC_ERROR_EXTENSION_NOT_FOUND ||
04637            err == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) {
04638            PORT_SetError(0);
04639            *rv_ocsp = SECSuccess;
04640            return SECSuccess;
04641        }
04642        return SECFailure;
04643     }
04644 
04645     /*
04646      * XXX In the fullness of time, we will want/need to handle a
04647      * certificate chain.  This will be done either when a new parameter
04648      * tells us to, or some configuration variable tells us to.  In any
04649      * case, handling it is complicated because we may need to send as
04650      * many requests (and receive as many responses) as we have certs
04651      * in the chain.  If we are going to talk to a default responder,
04652      * and we only support one default responder, we can put all of the
04653      * certs together into one request.  Otherwise, we must break them up
04654      * into multiple requests.  (Even if all of the requests will go to
04655      * the same location, the signature on each response will be different,
04656      * because each issuer is different.  Carefully read the OCSP spec
04657      * if you do not understand this.)
04658      */
04659 
04660     /*
04661      * XXX If/when signing of requests is supported, that second NULL
04662      * should be changed to be the signer certificate.  Not sure if that
04663      * should be passed into this function or retrieved via some operation
04664      * on the handle/context.
04665      */
04666     encodedResponse = 
04667         ocsp_GetEncodedOCSPResponseForSingleCert(NULL, certID, cert, location,
04668                                                  time, locationIsDefault,
04669                                                  pwArg, &request);
04670     if (encodedResponse == NULL) {
04671         goto loser;
04672     }
04673 
04674     response = CERT_DecodeOCSPResponse(encodedResponse);
04675     if (response == NULL) {
04676        goto loser;
04677     }
04678 
04679     /*
04680      * Okay, we at least have a response that *looks* like a response!
04681      * Now see if the overall response status value is good or not.
04682      * If not, we set an error and give up.  (It means that either the
04683      * server had a problem, or it didn't like something about our
04684      * request.  Either way there is nothing to do but give up.)
04685      * Otherwise, we continue to find the actual per-cert status
04686      * in the response.
04687      */
04688     if (CERT_GetOCSPResponseStatus(response) != SECSuccess) {
04689        goto loser;
04690     }
04691 
04692     /*
04693      * If we've made it this far, we expect a response with a good signature.
04694      * So, check for that.
04695      */
04696     issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
04697     rv = CERT_VerifyOCSPResponseSignature(response, handle, pwArg, &signerCert,
04698                      issuerCert);
04699     if (rv != SECSuccess)
04700        goto loser;
04701 
04702     PORT_Assert(signerCert != NULL);      /* internal consistency check */
04703     /* XXX probably should set error, return failure if signerCert is null */
04704 
04705 
04706     /*
04707      * Again, we are only doing one request for one cert.
04708      * XXX When we handle cert chains, the following code will obviously
04709      * have to be modified, in coordation with the code above that will
04710      * have to determine how to make multiple requests, etc. 
04711      */
04712 
04713     rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID, 
04714                                                  signerCert, time, &single);
04715     if (rv != SECSuccess)
04716         goto loser;
04717 
04718     *rv_ocsp = ocsp_SingleResponseCertHasGoodStatus(single, time);
04719 
04720 loser:
04721     PR_EnterMonitor(OCSP_Global.monitor);
04722     if (OCSP_Global.maxCacheEntries >= 0) {
04723         /* single == NULL means: remember response failure */
04724         ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single, 
04725                                       certIDWasConsumed);
04726         /* ignore cache update failures */
04727     }
04728     PR_ExitMonitor(OCSP_Global.monitor);
04729 
04730     if (issuerCert != NULL)
04731        CERT_DestroyCertificate(issuerCert);
04732     if (signerCert != NULL)
04733        CERT_DestroyCertificate(signerCert);
04734     if (response != NULL)
04735        CERT_DestroyOCSPResponse(response);
04736     if (request != NULL)
04737        CERT_DestroyOCSPRequest(request);
04738     if (encodedResponse != NULL)
04739        SECITEM_FreeItem(encodedResponse, PR_TRUE);
04740     if (location != NULL)
04741        PORT_Free(location);
04742     return rv;
04743 }
04744 
04745 static SECStatus
04746 ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle, 
04747                                         CERTOCSPResponse *response, 
04748                                         CERTOCSPCertID   *certID,
04749                                         CERTCertificate  *signerCert,
04750                                         int64             time,
04751                                         CERTOCSPSingleResponse 
04752                                             **pSingleResponse)
04753 {
04754     SECStatus rv;
04755     ocspResponseData *responseData;
04756     int64 producedAt;
04757     CERTOCSPSingleResponse *single;
04758 
04759     /*
04760      * The ResponseData part is the real guts of the response.
04761      */
04762     responseData = ocsp_GetResponseData(response, NULL);
04763     if (responseData == NULL) {
04764         rv = SECFailure;
04765         goto loser;
04766     }
04767 
04768     /*
04769      * There is one producedAt time for the entire response (and a separate
04770      * thisUpdate time for each individual single response).  We need to
04771      * compare them, so get the overall time to pass into the check of each
04772      * single response.
04773      */
04774     rv = DER_GeneralizedTimeToTime(&producedAt, &responseData->producedAt);
04775     if (rv != SECSuccess)
04776         goto loser;
04777 
04778     single = ocsp_GetSingleResponseForCertID(responseData->responses,
04779                                              handle, certID);
04780     if (single == NULL) {
04781         rv = SECFailure;
04782         goto loser;
04783     }
04784 
04785     rv = ocsp_VerifySingleResponse(single, handle, signerCert, producedAt);
04786     if (rv != SECSuccess)
04787         goto loser;
04788     *pSingleResponse = single;
04789 
04790 loser:
04791     return rv;
04792 }
04793 
04794 SECStatus
04795 CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle, 
04796                             CERTOCSPResponse *response, 
04797                             CERTOCSPCertID   *certID,
04798                             CERTCertificate  *signerCert,
04799                             int64             time)
04800 {
04801     SECStatus rv;
04802     CERTOCSPSingleResponse *single;
04803 
04804     rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID, 
04805                                                  signerCert, time, &single);
04806     if (rv != SECSuccess)
04807         return rv;
04808     /*
04809      * Okay, the last step is to check whether the status says revoked,
04810      * and if so how that compares to the time value passed into this routine.
04811      */
04812     rv = ocsp_SingleResponseCertHasGoodStatus(single, time);
04813     return rv;
04814 }
04815 
04816 /*
04817  * Disable status checking and destroy related structures/data.
04818  */
04819 static SECStatus
04820 ocsp_DestroyStatusChecking(CERTStatusConfig *statusConfig)
04821 {
04822     ocspCheckingContext *statusContext;
04823 
04824     /*
04825      * Disable OCSP checking
04826      */
04827     statusConfig->statusChecker = NULL;
04828 
04829     statusContext = statusConfig->statusContext;
04830     PORT_Assert(statusContext != NULL);
04831     if (statusContext == NULL)
04832        return SECFailure;
04833 
04834     if (statusContext->defaultResponderURI != NULL)
04835        PORT_Free(statusContext->defaultResponderURI);
04836     if (statusContext->defaultResponderNickname != NULL)
04837        PORT_Free(statusContext->defaultResponderNickname);
04838 
04839     PORT_Free(statusContext);
04840     statusConfig->statusContext = NULL;
04841 
04842     PORT_Free(statusConfig);
04843 
04844     return SECSuccess;
04845 }
04846 
04847 
04848 /*
04849  * FUNCTION: CERT_DisableOCSPChecking
04850  *   Turns off OCSP checking for the given certificate database.
04851  *   This routine disables OCSP checking.  Though it will return
04852  *   SECFailure if OCSP checking is not enabled, it is "safe" to
04853  *   call it that way and just ignore the return value, if it is
04854  *   easier to just call it than to "remember" whether it is enabled.
04855  * INPUTS:
04856  *   CERTCertDBHandle *handle
04857  *     Certificate database for which OCSP checking will be disabled.
04858  * RETURN:
04859  *   Returns SECFailure if an error occurred (usually means that OCSP
04860  *   checking was not enabled or status contexts were not initialized --
04861  *   error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise.
04862  */
04863 SECStatus
04864 CERT_DisableOCSPChecking(CERTCertDBHandle *handle)
04865 {
04866     CERTStatusConfig *statusConfig;
04867     ocspCheckingContext *statusContext;
04868 
04869     if (handle == NULL) {
04870        PORT_SetError(SEC_ERROR_INVALID_ARGS);
04871        return SECFailure;
04872     }
04873 
04874     statusConfig = CERT_GetStatusConfig(handle);
04875     statusContext = ocsp_GetCheckingContext(handle);
04876     if (statusContext == NULL)
04877        return SECFailure;
04878 
04879     if (statusConfig->statusChecker != CERT_CheckOCSPStatus) {
04880        /*
04881         * Status configuration is present, but either not currently
04882         * enabled or not for OCSP.
04883         */
04884        PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED);
04885        return SECFailure;
04886     }
04887 
04888     /* cache no longer necessary */
04889     CERT_ClearOCSPCache();
04890 
04891     /*
04892      * This is how we disable status checking.  Everything else remains
04893      * in place in case we are enabled again.
04894      */
04895     statusConfig->statusChecker = NULL;
04896 
04897     return SECSuccess;
04898 }
04899 
04900 /*
04901  * Allocate and initialize the informational structures for status checking.
04902  * This is done when some configuration of OCSP is being done or when OCSP
04903  * checking is being turned on, whichever comes first.
04904  */
04905 static SECStatus
04906 ocsp_InitStatusChecking(CERTCertDBHandle *handle)
04907 {
04908     CERTStatusConfig *statusConfig = NULL;
04909     ocspCheckingContext *statusContext = NULL;
04910 
04911     PORT_Assert(CERT_GetStatusConfig(handle) == NULL);
04912     if (CERT_GetStatusConfig(handle) != NULL) {
04913        /* XXX or call statusConfig->statusDestroy and continue? */
04914        return SECFailure;
04915     }
04916 
04917     statusConfig = PORT_ZNew(CERTStatusConfig);
04918     if (statusConfig == NULL)
04919        goto loser;
04920 
04921     statusContext = PORT_ZNew(ocspCheckingContext);
04922     if (statusContext == NULL)
04923        goto loser;
04924 
04925     statusConfig->statusDestroy = ocsp_DestroyStatusChecking;
04926     statusConfig->statusContext = statusContext;
04927 
04928     CERT_SetStatusConfig(handle, statusConfig);
04929 
04930     return SECSuccess;
04931 
04932 loser:
04933     if (statusConfig != NULL)
04934        PORT_Free(statusConfig);
04935     return SECFailure;
04936 }
04937 
04938 
04939 /*
04940  * FUNCTION: CERT_EnableOCSPChecking
04941  *   Turns on OCSP checking for the given certificate database.
04942  * INPUTS:
04943  *   CERTCertDBHandle *handle
04944  *     Certificate database for which OCSP checking will be enabled.
04945  * RETURN:
04946  *   Returns SECFailure if an error occurred (likely only problem
04947  *   allocating memory); SECSuccess otherwise.
04948  */
04949 SECStatus
04950 CERT_EnableOCSPChecking(CERTCertDBHandle *handle)
04951 {
04952     CERTStatusConfig *statusConfig;
04953     
04954     SECStatus rv;
04955 
04956     if (handle == NULL) {
04957        PORT_SetError(SEC_ERROR_INVALID_ARGS);
04958        return SECFailure;
04959     }
04960 
04961     statusConfig = CERT_GetStatusConfig(handle);
04962     if (statusConfig == NULL) {
04963        rv = ocsp_InitStatusChecking(handle);
04964        if (rv != SECSuccess)
04965            return rv;
04966 
04967        /* Get newly established value */
04968        statusConfig = CERT_GetStatusConfig(handle);
04969        PORT_Assert(statusConfig != NULL);
04970     }
04971 
04972     /*
04973      * Setting the checker function is what really enables the checking
04974      * when each cert verification is done.
04975      */
04976     statusConfig->statusChecker = CERT_CheckOCSPStatus;
04977 
04978     return SECSuccess;
04979 }
04980 
04981 
04982 /*
04983  * FUNCTION: CERT_SetOCSPDefaultResponder
04984  *   Specify the location and cert of the default responder.
04985  *   If OCSP checking is already enabled *and* use of a default responder
04986  *   is also already enabled, all OCSP checking from now on will go directly
04987  *   to the specified responder.  If OCSP checking is not enabled, or if
04988  *   it is but use of a default responder is not enabled, the information
04989  *   will be recorded and take effect whenever both are enabled.
04990  * INPUTS:
04991  *   CERTCertDBHandle *handle
04992  *     Cert database on which OCSP checking should use the default responder.
04993  *   char *url
04994  *     The location of the default responder (e.g. "http://foo.com:80/ocsp")
04995  *     Note that the location will not be tested until the first attempt
04996  *     to send a request there.
04997  *   char *name
04998  *     The nickname of the cert to trust (expected) to sign the OCSP responses.
04999  *     If the corresponding cert cannot be found, SECFailure is returned.
05000  * RETURN:
05001  *   Returns SECFailure if an error occurred; SECSuccess otherwise.
05002  *   The most likely error is that the cert for "name" could not be found
05003  *   (probably SEC_ERROR_UNKNOWN_CERT).  Other errors are low-level (no memory,
05004  *   bad database, etc.).
05005  */
05006 SECStatus
05007 CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle,
05008                           const char *url, const char *name)
05009 {
05010     CERTCertificate *cert;
05011     ocspCheckingContext *statusContext;
05012     char *url_copy = NULL;
05013     char *name_copy = NULL;
05014     SECStatus rv;
05015 
05016     if (handle == NULL || url == NULL || name == NULL) {
05017        /*
05018         * XXX When interface is exported, probably want better errors;
05019         * perhaps different one for each parameter.
05020         */
05021        PORT_SetError(SEC_ERROR_INVALID_ARGS);
05022        return SECFailure;
05023     }
05024 
05025     /*
05026      * Find the certificate for the specified nickname.  Do this first
05027      * because it seems the most likely to fail.
05028      *
05029      * XXX Shouldn't need that cast if the FindCertByNickname interface
05030      * used const to convey that it does not modify the name.  Maybe someday.
05031      */
05032     cert = CERT_FindCertByNickname(handle, (char *) name);
05033     if (cert == NULL) {
05034       /*
05035        * look for the cert on an external token.
05036        */
05037       cert = PK11_FindCertFromNickname((char *)name, NULL);
05038     }
05039     if (cert == NULL)
05040        return SECFailure;
05041 
05042     /*
05043      * Make a copy of the url and nickname.
05044      */
05045     url_copy = PORT_Strdup(url);
05046     name_copy = PORT_Strdup(name);
05047     if (url_copy == NULL || name_copy == NULL) {
05048        rv = SECFailure;
05049        goto loser;
05050     }
05051 
05052     statusContext = ocsp_GetCheckingContext(handle);
05053 
05054     /*
05055      * Allocate and init the context if it doesn't already exist.
05056      */
05057     if (statusContext == NULL) {
05058        rv = ocsp_InitStatusChecking(handle);
05059        if (rv != SECSuccess)
05060            goto loser;
05061 
05062        statusContext = ocsp_GetCheckingContext(handle);
05063        PORT_Assert(statusContext != NULL);       /* extreme paranoia */
05064     }
05065 
05066     /*
05067      * Note -- we do not touch the status context until after all of
05068      * the steps which could cause errors.  If something goes wrong,
05069      * we want to leave things as they were.
05070      */
05071 
05072     /*
05073      * Get rid of old url and name if there.
05074      */
05075     if (statusContext->defaultResponderNickname != NULL)
05076        PORT_Free(statusContext->defaultResponderNickname);
05077     if (statusContext->defaultResponderURI != NULL)
05078        PORT_Free(statusContext->defaultResponderURI);
05079 
05080     /*
05081      * And replace them with the new ones.
05082      */
05083     statusContext->defaultResponderURI = url_copy;
05084     statusContext->defaultResponderNickname = name_copy;
05085 
05086     /*
05087      * If there was already a cert in place, get rid of it and replace it.
05088      * Otherwise, we are not currently enabled, so we don't want to save it;
05089      * it will get re-found and set whenever use of a default responder is
05090      * enabled.
05091      */
05092     if (statusContext->defaultResponderCert != NULL) {
05093        CERT_DestroyCertificate(statusContext->defaultResponderCert);
05094        statusContext->defaultResponderCert = cert;
05095         /*OCSP enabled, switching responder: clear cache*/
05096         CERT_ClearOCSPCache();
05097     } else {
05098        PORT_Assert(statusContext->useDefaultResponder == PR_FALSE);
05099        CERT_DestroyCertificate(cert);
05100         /*OCSP currently not enabled, no need to clear cache*/
05101     }
05102 
05103     return SECSuccess;
05104 
05105 loser:
05106     CERT_DestroyCertificate(cert);
05107     if (url_copy != NULL)
05108        PORT_Free(url_copy);
05109     if (name_copy != NULL)
05110        PORT_Free(name_copy);
05111     return rv;
05112 }
05113 
05114 
05115 /*
05116  * FUNCTION: CERT_EnableOCSPDefaultResponder
05117  *   Turns on use of a default responder when OCSP checking.
05118  *   If OCSP checking is already enabled, this will make subsequent checks
05119  *   go directly to the default responder.  (The location of the responder
05120  *   and the nickname of the responder cert must already be specified.)
05121  *   If OCSP checking is not enabled, this will be recorded and take effect
05122  *   whenever it is enabled.
05123  * INPUTS:
05124  *   CERTCertDBHandle *handle
05125  *     Cert database on which OCSP checking should use the default responder.
05126  * RETURN:
05127  *   Returns SECFailure if an error occurred; SECSuccess otherwise.
05128  *   No errors are especially likely unless the caller did not previously
05129  *   perform a successful call to SetOCSPDefaultResponder (in which case
05130  *   the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER).
05131  */
05132 SECStatus
05133 CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle)
05134 {
05135     ocspCheckingContext *statusContext;
05136     CERTCertificate *cert;
05137     SECStatus rv;
05138     SECCertificateUsage usage;
05139 
05140     if (handle == NULL) {
05141        PORT_SetError(SEC_ERROR_INVALID_ARGS);
05142        return SECFailure;
05143     }
05144 
05145     statusContext = ocsp_GetCheckingContext(handle);
05146 
05147     if (statusContext == NULL) {
05148        /*
05149         * Strictly speaking, the error already set is "correct",
05150         * but cover over it with one more helpful in this context.
05151         */
05152        PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
05153        return SECFailure;
05154     }
05155 
05156     if (statusContext->defaultResponderURI == NULL) {
05157        PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
05158        return SECFailure;
05159     }
05160 
05161     if (statusContext->defaultResponderNickname == NULL) {
05162        PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
05163        return SECFailure;
05164     }
05165 
05166     /*
05167      * Find the cert for the nickname.
05168      */
05169     cert = CERT_FindCertByNickname(handle,
05170                                statusContext->defaultResponderNickname);
05171     if (cert == NULL) {
05172         cert = PK11_FindCertFromNickname(statusContext->defaultResponderNickname,
05173                                          NULL);
05174     }
05175     /*
05176      * We should never have trouble finding the cert, because its
05177      * existence should have been proven by SetOCSPDefaultResponder.
05178      */
05179     PORT_Assert(cert != NULL);
05180     if (cert == NULL)
05181        return SECFailure;
05182 
05183    /*
05184     * Supplied cert should at least have  a signing capability in order for us
05185     * to use it as a trusted responder cert. Ability to sign is guarantied  if
05186     * cert is validated to have any set of the usages below.
05187     */
05188     rv = CERT_VerifyCertificateNow(handle, cert, PR_TRUE,
05189                                    certificateUsageCheckAllUsages,
05190                                    NULL, &usage);
05191     if (rv != SECSuccess || (usage & (certificateUsageSSLClient |
05192                                       certificateUsageSSLServer |
05193                                       certificateUsageSSLServerWithStepUp |
05194                                       certificateUsageEmailSigner |
05195                                       certificateUsageObjectSigner |
05196                                       certificateUsageStatusResponder |
05197                                       certificateUsageSSLCA)) == 0) {
05198        PORT_SetError(SEC_ERROR_OCSP_RESPONDER_CERT_INVALID);
05199        return SECFailure;
05200     }
05201 
05202     /*
05203      * And hang onto it.
05204      */
05205     statusContext->defaultResponderCert = cert;
05206 
05207     /* we don't allow a mix of cache entries from different responders */
05208     CERT_ClearOCSPCache();
05209 
05210     /*
05211      * Finally, record the fact that we now have a default responder enabled.
05212      */
05213     statusContext->useDefaultResponder = PR_TRUE;
05214     return SECSuccess;
05215 }
05216 
05217 
05218 /*
05219  * FUNCTION: CERT_DisableOCSPDefaultResponder
05220  *   Turns off use of a default responder when OCSP checking.
05221  *   (Does nothing if use of a default responder is not enabled.)
05222  * INPUTS:
05223  *   CERTCertDBHandle *handle
05224  *     Cert database on which OCSP checking should stop using a default
05225  *     responder.
05226  * RETURN:
05227  *   Returns SECFailure if an error occurred; SECSuccess otherwise.
05228  *   Errors very unlikely (like random memory corruption...).
05229  */
05230 SECStatus
05231 CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle)
05232 {
05233     CERTStatusConfig *statusConfig;
05234     ocspCheckingContext *statusContext;
05235     CERTCertificate *tmpCert;
05236 
05237     if (handle == NULL) {
05238        PORT_SetError(SEC_ERROR_INVALID_ARGS);
05239        return SECFailure;
05240     }
05241 
05242     statusConfig = CERT_GetStatusConfig(handle);
05243     if (statusConfig == NULL)
05244        return SECSuccess;
05245 
05246     statusContext = ocsp_GetCheckingContext(handle);
05247     PORT_Assert(statusContext != NULL);
05248     if (statusContext == NULL)
05249        return SECFailure;
05250 
05251     tmpCert = statusContext->defaultResponderCert;
05252     if (tmpCert) {
05253        statusContext->defaultResponderCert = NULL;
05254        CERT_DestroyCertificate(tmpCert);
05255         /* we don't allow a mix of cache entries from different responders */
05256         CERT_ClearOCSPCache();
05257     }
05258 
05259     /*
05260      * Finally, record the fact.
05261      */
05262     statusContext->useDefaultResponder = PR_FALSE;
05263     return SECSuccess;
05264 }
05265 
05266 
05267 SECStatus
05268 CERT_GetOCSPResponseStatus(CERTOCSPResponse *response)
05269 {
05270     PORT_Assert(response);
05271     if (response->statusValue == ocspResponse_successful)
05272        return SECSuccess;
05273 
05274     switch (response->statusValue) {
05275       case ocspResponse_malformedRequest:
05276        PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
05277        break;
05278       case ocspResponse_internalError:
05279        PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
05280        break;
05281       case ocspResponse_tryLater:
05282        PORT_SetError(SEC_ERROR_OCSP_TRY_SERVER_LATER);
05283        break;
05284       case ocspResponse_sigRequired:
05285        /* XXX We *should* retry with a signature, if possible. */
05286        PORT_SetError(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
05287        break;
05288       case ocspResponse_unauthorized:
05289        PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
05290        break;
05291       case ocspResponse_other:
05292       case ocspResponse_unused:
05293       default:
05294        PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
05295        break;
05296     }
05297     return SECFailure;
05298 }