1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /*
6  * Implementation of OCSP services, for both client and server.
7  * (XXX, really, mostly just for client right now, but intended to do both.)
8  */
9 
10 #include "prerror.h"
11 #include "prprf.h"
12 #include "plarena.h"
13 #include "prnetdb.h"
14 
15 #include "seccomon.h"
16 #include "secitem.h"
17 #include "secoidt.h"
18 #include "secasn1.h"
19 #include "secder.h"
20 #include "cert.h"
21 #include "certi.h"
22 #include "xconst.h"
23 #include "secerr.h"
24 #include "secoid.h"
25 #include "hasht.h"
26 #include "sechash.h"
27 #include "secasn1.h"
28 #include "plbase64.h"
29 #include "keyhi.h"
30 #include "cryptohi.h"
31 #include "ocsp.h"
32 #include "ocspti.h"
33 #include "ocspi.h"
34 #include "genname.h"
35 #include "certxutl.h"
36 #include "pk11func.h" /* for PK11_HashBuf */
37 #include <stdarg.h>
38 #include <plhash.h>
39 
40 #define DEFAULT_OCSP_CACHE_SIZE 1000
41 #define DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 1 * 60 * 60L
42 #define DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT 24 * 60 * 60L
43 #define DEFAULT_OSCP_TIMEOUT_SECONDS 60
44 #define MICROSECONDS_PER_SECOND 1000000L
45 
46 typedef struct OCSPCacheItemStr OCSPCacheItem;
47 typedef struct OCSPCacheDataStr OCSPCacheData;
48 
49 struct OCSPCacheItemStr {
50     /* LRU linking */
51     OCSPCacheItem *moreRecent;
52     OCSPCacheItem *lessRecent;
53 
54     /* key */
55     CERTOCSPCertID *certID;
56     /* CertID's arena also used to allocate "this" cache item */
57 
58     /* cache control information */
59     PRTime nextFetchAttemptTime;
60 
61     /* Cached contents. Use a separate arena, because lifetime is different */
62     PLArenaPool *certStatusArena; /* NULL means: no cert status cached */
63     ocspCertStatus certStatus;
64 
65     /* This may contain an error code when no OCSP response is available. */
66     SECErrorCodes missingResponseError;
67 
68     PRPackedBool haveThisUpdate;
69     PRPackedBool haveNextUpdate;
70     PRTime thisUpdate;
71     PRTime nextUpdate;
72 };
73 
74 struct OCSPCacheDataStr {
75     PLHashTable *entries;
76     PRUint32 numberOfEntries;
77     OCSPCacheItem *MRUitem; /* most recently used cache item */
78     OCSPCacheItem *LRUitem; /* least recently used cache item */
79 };
80 
81 static struct OCSPGlobalStruct {
82     PRMonitor *monitor;
83     const SEC_HttpClientFcn *defaultHttpClientFcn;
84     PRInt32 maxCacheEntries;
85     PRUint32 minimumSecondsToNextFetchAttempt;
86     PRUint32 maximumSecondsToNextFetchAttempt;
87     PRUint32 timeoutSeconds;
88     OCSPCacheData cache;
89     SEC_OcspFailureMode ocspFailureMode;
90     CERT_StringFromCertFcn alternateOCSPAIAFcn;
91     PRBool forcePost;
92 } OCSP_Global = { NULL,
93                   NULL,
94                   DEFAULT_OCSP_CACHE_SIZE,
95                   DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
96                   DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT,
97                   DEFAULT_OSCP_TIMEOUT_SECONDS,
98                   { NULL, 0, NULL, NULL },
99                   ocspMode_FailureIsVerificationFailure,
100                   NULL,
101                   PR_FALSE };
102 
103 /* Forward declarations */
104 static SECItem *
105 ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena,
106                                        CERTOCSPRequest *request,
107                                        const char *location,
108                                        const char *method,
109                                        PRTime time,
110                                        PRBool addServiceLocator,
111                                        void *pwArg,
112                                        CERTOCSPRequest **pRequest);
113 static SECStatus
114 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle,
115                               CERTOCSPCertID *certID,
116                               CERTCertificate *cert,
117                               PRTime time,
118                               void *pwArg,
119                               PRBool *certIDWasConsumed,
120                               SECStatus *rv_ocsp);
121 
122 static SECStatus
123 ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle *handle,
124                                            CERTOCSPCertID *certID,
125                                            CERTCertificate *cert,
126                                            PRTime time,
127                                            void *pwArg,
128                                            const SECItem *encodedResponse,
129                                            CERTOCSPResponse **pDecodedResponse,
130                                            CERTOCSPSingleResponse **pSingle);
131 
132 static SECStatus
133 ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time);
134 
135 static CERTOCSPCertID *
136 cert_DupOCSPCertID(const CERTOCSPCertID *src);
137 
138 #ifndef DEBUG
139 #define OCSP_TRACE(msg)
140 #define OCSP_TRACE_TIME(msg, time)
141 #define OCSP_TRACE_CERT(cert)
142 #define OCSP_TRACE_CERTID(certid)
143 #else
144 #define OCSP_TRACE(msg) ocsp_Trace msg
145 #define OCSP_TRACE_TIME(msg, time) ocsp_dumpStringWithTime(msg, time)
146 #define OCSP_TRACE_CERT(cert) dumpCertificate(cert)
147 #define OCSP_TRACE_CERTID(certid) dumpCertID(certid)
148 
149 #if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS) || \
150     defined(XP_MACOSX)
151 #define NSS_HAVE_GETENV 1
152 #endif
153 
154 static PRBool
wantOcspTrace(void)155 wantOcspTrace(void)
156 {
157     static PRBool firstTime = PR_TRUE;
158     static PRBool wantTrace = PR_FALSE;
159 
160 #ifdef NSS_HAVE_GETENV
161     if (firstTime) {
162         char *ev = PR_GetEnvSecure("NSS_TRACE_OCSP");
163         if (ev && ev[0]) {
164             wantTrace = PR_TRUE;
165         }
166         firstTime = PR_FALSE;
167     }
168 #endif
169     return wantTrace;
170 }
171 
172 static void
ocsp_Trace(const char * format,...)173 ocsp_Trace(const char *format, ...)
174 {
175     char buf[2000];
176     va_list args;
177 
178     if (!wantOcspTrace())
179         return;
180     va_start(args, format);
181     PR_vsnprintf(buf, sizeof(buf), format, args);
182     va_end(args);
183     PR_LogPrint("%s", buf);
184 }
185 
186 static void
ocsp_dumpStringWithTime(const char * str,PRTime time)187 ocsp_dumpStringWithTime(const char *str, PRTime time)
188 {
189     PRExplodedTime timePrintable;
190     char timestr[256];
191 
192     if (!wantOcspTrace())
193         return;
194     PR_ExplodeTime(time, PR_GMTParameters, &timePrintable);
195     if (PR_FormatTime(timestr, 256, "%a %b %d %H:%M:%S %Y", &timePrintable)) {
196         ocsp_Trace("OCSP %s %s\n", str, timestr);
197     }
198 }
199 
200 static void
printHexString(const char * prefix,SECItem * hexval)201 printHexString(const char *prefix, SECItem *hexval)
202 {
203     unsigned int i;
204     char *hexbuf = NULL;
205 
206     for (i = 0; i < hexval->len; i++) {
207         if (i != hexval->len - 1) {
208             hexbuf = PR_sprintf_append(hexbuf, "%02x:", hexval->data[i]);
209         } else {
210             hexbuf = PR_sprintf_append(hexbuf, "%02x", hexval->data[i]);
211         }
212     }
213     if (hexbuf) {
214         ocsp_Trace("%s %s\n", prefix, hexbuf);
215         PR_smprintf_free(hexbuf);
216     }
217 }
218 
219 static void
dumpCertificate(CERTCertificate * cert)220 dumpCertificate(CERTCertificate *cert)
221 {
222     if (!wantOcspTrace())
223         return;
224 
225     ocsp_Trace("OCSP ----------------\n");
226     ocsp_Trace("OCSP ## SUBJECT:  %s\n", cert->subjectName);
227     {
228         PRTime timeBefore, timeAfter;
229         PRExplodedTime beforePrintable, afterPrintable;
230         char beforestr[256], afterstr[256];
231         PRStatus rv1, rv2;
232         DER_DecodeTimeChoice(&timeBefore, &cert->validity.notBefore);
233         DER_DecodeTimeChoice(&timeAfter, &cert->validity.notAfter);
234         PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable);
235         PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable);
236         rv1 = PR_FormatTime(beforestr, 256, "%a %b %d %H:%M:%S %Y",
237                             &beforePrintable);
238         rv2 = PR_FormatTime(afterstr, 256, "%a %b %d %H:%M:%S %Y",
239                             &afterPrintable);
240         ocsp_Trace("OCSP ## VALIDITY:  %s to %s\n", rv1 ? beforestr : "",
241                    rv2 ? afterstr : "");
242     }
243     ocsp_Trace("OCSP ## ISSUER:  %s\n", cert->issuerName);
244     printHexString("OCSP ## SERIAL NUMBER:", &cert->serialNumber);
245 }
246 
247 static void
dumpCertID(CERTOCSPCertID * certID)248 dumpCertID(CERTOCSPCertID *certID)
249 {
250     if (!wantOcspTrace())
251         return;
252 
253     printHexString("OCSP certID issuer", &certID->issuerNameHash);
254     printHexString("OCSP certID serial", &certID->serialNumber);
255 }
256 #endif
257 
258 SECStatus
SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn * fcnTable)259 SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
260 {
261     if (!OCSP_Global.monitor) {
262         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
263         return SECFailure;
264     }
265 
266     PR_EnterMonitor(OCSP_Global.monitor);
267     OCSP_Global.defaultHttpClientFcn = fcnTable;
268     PR_ExitMonitor(OCSP_Global.monitor);
269 
270     return SECSuccess;
271 }
272 
273 SECStatus
CERT_RegisterAlternateOCSPAIAInfoCallBack(CERT_StringFromCertFcn newCallback,CERT_StringFromCertFcn * oldCallback)274 CERT_RegisterAlternateOCSPAIAInfoCallBack(
275     CERT_StringFromCertFcn newCallback,
276     CERT_StringFromCertFcn *oldCallback)
277 {
278     CERT_StringFromCertFcn old;
279 
280     if (!OCSP_Global.monitor) {
281         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
282         return SECFailure;
283     }
284 
285     PR_EnterMonitor(OCSP_Global.monitor);
286     old = OCSP_Global.alternateOCSPAIAFcn;
287     OCSP_Global.alternateOCSPAIAFcn = newCallback;
288     PR_ExitMonitor(OCSP_Global.monitor);
289     if (oldCallback)
290         *oldCallback = old;
291     return SECSuccess;
292 }
293 
294 static PLHashNumber PR_CALLBACK
ocsp_CacheKeyHashFunction(const void * key)295 ocsp_CacheKeyHashFunction(const void *key)
296 {
297     CERTOCSPCertID *cid = (CERTOCSPCertID *)key;
298     PLHashNumber hash = 0;
299     unsigned int i;
300     unsigned char *walk;
301 
302     /* a very simple hash calculation for the initial coding phase */
303     walk = (unsigned char *)cid->issuerNameHash.data;
304     for (i = 0; i < cid->issuerNameHash.len; ++i, ++walk) {
305         hash += *walk;
306     }
307     walk = (unsigned char *)cid->issuerKeyHash.data;
308     for (i = 0; i < cid->issuerKeyHash.len; ++i, ++walk) {
309         hash += *walk;
310     }
311     walk = (unsigned char *)cid->serialNumber.data;
312     for (i = 0; i < cid->serialNumber.len; ++i, ++walk) {
313         hash += *walk;
314     }
315     return hash;
316 }
317 
318 static PRIntn PR_CALLBACK
ocsp_CacheKeyCompareFunction(const void * v1,const void * v2)319 ocsp_CacheKeyCompareFunction(const void *v1, const void *v2)
320 {
321     CERTOCSPCertID *cid1 = (CERTOCSPCertID *)v1;
322     CERTOCSPCertID *cid2 = (CERTOCSPCertID *)v2;
323 
324     return (SECEqual == SECITEM_CompareItem(&cid1->issuerNameHash,
325                                             &cid2->issuerNameHash) &&
326             SECEqual == SECITEM_CompareItem(&cid1->issuerKeyHash,
327                                             &cid2->issuerKeyHash) &&
328             SECEqual == SECITEM_CompareItem(&cid1->serialNumber,
329                                             &cid2->serialNumber));
330 }
331 
332 static SECStatus
ocsp_CopyRevokedInfo(PLArenaPool * arena,ocspCertStatus * dest,ocspRevokedInfo * src)333 ocsp_CopyRevokedInfo(PLArenaPool *arena, ocspCertStatus *dest,
334                      ocspRevokedInfo *src)
335 {
336     SECStatus rv = SECFailure;
337     void *mark;
338 
339     mark = PORT_ArenaMark(arena);
340 
341     dest->certStatusInfo.revokedInfo =
342         (ocspRevokedInfo *)PORT_ArenaZAlloc(arena, sizeof(ocspRevokedInfo));
343     if (!dest->certStatusInfo.revokedInfo) {
344         goto loser;
345     }
346 
347     rv = SECITEM_CopyItem(arena,
348                           &dest->certStatusInfo.revokedInfo->revocationTime,
349                           &src->revocationTime);
350     if (rv != SECSuccess) {
351         goto loser;
352     }
353 
354     if (src->revocationReason) {
355         dest->certStatusInfo.revokedInfo->revocationReason =
356             SECITEM_ArenaDupItem(arena, src->revocationReason);
357         if (!dest->certStatusInfo.revokedInfo->revocationReason) {
358             goto loser;
359         }
360     } else {
361         dest->certStatusInfo.revokedInfo->revocationReason = NULL;
362     }
363 
364     PORT_ArenaUnmark(arena, mark);
365     return SECSuccess;
366 
367 loser:
368     PORT_ArenaRelease(arena, mark);
369     return SECFailure;
370 }
371 
372 static SECStatus
ocsp_CopyCertStatus(PLArenaPool * arena,ocspCertStatus * dest,ocspCertStatus * src)373 ocsp_CopyCertStatus(PLArenaPool *arena, ocspCertStatus *dest,
374                     ocspCertStatus *src)
375 {
376     SECStatus rv = SECFailure;
377     dest->certStatusType = src->certStatusType;
378 
379     switch (src->certStatusType) {
380         case ocspCertStatus_good:
381             dest->certStatusInfo.goodInfo =
382                 SECITEM_ArenaDupItem(arena, src->certStatusInfo.goodInfo);
383             if (dest->certStatusInfo.goodInfo != NULL) {
384                 rv = SECSuccess;
385             }
386             break;
387         case ocspCertStatus_revoked:
388             rv = ocsp_CopyRevokedInfo(arena, dest,
389                                       src->certStatusInfo.revokedInfo);
390             break;
391         case ocspCertStatus_unknown:
392             dest->certStatusInfo.unknownInfo =
393                 SECITEM_ArenaDupItem(arena, src->certStatusInfo.unknownInfo);
394             if (dest->certStatusInfo.unknownInfo != NULL) {
395                 rv = SECSuccess;
396             }
397             break;
398         case ocspCertStatus_other:
399         default:
400             PORT_Assert(src->certStatusType == ocspCertStatus_other);
401             dest->certStatusInfo.otherInfo =
402                 SECITEM_ArenaDupItem(arena, src->certStatusInfo.otherInfo);
403             if (dest->certStatusInfo.otherInfo != NULL) {
404                 rv = SECSuccess;
405             }
406             break;
407     }
408     return rv;
409 }
410 
411 static void
ocsp_AddCacheItemToLinkedList(OCSPCacheData * cache,OCSPCacheItem * new_most_recent)412 ocsp_AddCacheItemToLinkedList(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
413 {
414     PR_EnterMonitor(OCSP_Global.monitor);
415 
416     if (!cache->LRUitem) {
417         cache->LRUitem = new_most_recent;
418     }
419     new_most_recent->lessRecent = cache->MRUitem;
420     new_most_recent->moreRecent = NULL;
421 
422     if (cache->MRUitem) {
423         cache->MRUitem->moreRecent = new_most_recent;
424     }
425     cache->MRUitem = new_most_recent;
426 
427     PR_ExitMonitor(OCSP_Global.monitor);
428 }
429 
430 static void
ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData * cache,OCSPCacheItem * item)431 ocsp_RemoveCacheItemFromLinkedList(OCSPCacheData *cache, OCSPCacheItem *item)
432 {
433     PR_EnterMonitor(OCSP_Global.monitor);
434 
435     if (!item->lessRecent && !item->moreRecent) {
436         /*
437          * Fail gracefully on attempts to remove an item from the list,
438          * which is currently not part of the list.
439          * But check for the edge case it is the single entry in the list.
440          */
441         if (item == cache->LRUitem &&
442             item == cache->MRUitem) {
443             /* remove the single entry */
444             PORT_Assert(cache->numberOfEntries == 1);
445             PORT_Assert(item->moreRecent == NULL);
446             cache->MRUitem = NULL;
447             cache->LRUitem = NULL;
448         }
449         PR_ExitMonitor(OCSP_Global.monitor);
450         return;
451     }
452 
453     PORT_Assert(cache->numberOfEntries > 1);
454 
455     if (item == cache->LRUitem) {
456         PORT_Assert(item != cache->MRUitem);
457         PORT_Assert(item->lessRecent == NULL);
458         PORT_Assert(item->moreRecent != NULL);
459         PORT_Assert(item->moreRecent->lessRecent == item);
460         cache->LRUitem = item->moreRecent;
461         cache->LRUitem->lessRecent = NULL;
462     } else if (item == cache->MRUitem) {
463         PORT_Assert(item->moreRecent == NULL);
464         PORT_Assert(item->lessRecent != NULL);
465         PORT_Assert(item->lessRecent->moreRecent == item);
466         cache->MRUitem = item->lessRecent;
467         cache->MRUitem->moreRecent = NULL;
468     } else {
469         /* remove an entry in the middle of the list */
470         PORT_Assert(item->moreRecent != NULL);
471         PORT_Assert(item->lessRecent != NULL);
472         PORT_Assert(item->lessRecent->moreRecent == item);
473         PORT_Assert(item->moreRecent->lessRecent == item);
474         item->moreRecent->lessRecent = item->lessRecent;
475         item->lessRecent->moreRecent = item->moreRecent;
476     }
477 
478     item->lessRecent = NULL;
479     item->moreRecent = NULL;
480 
481     PR_ExitMonitor(OCSP_Global.monitor);
482 }
483 
484 static void
ocsp_MakeCacheEntryMostRecent(OCSPCacheData * cache,OCSPCacheItem * new_most_recent)485 ocsp_MakeCacheEntryMostRecent(OCSPCacheData *cache, OCSPCacheItem *new_most_recent)
486 {
487     OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent THREADID %p\n",
488                 PR_GetCurrentThread()));
489     PR_EnterMonitor(OCSP_Global.monitor);
490     if (cache->MRUitem == new_most_recent) {
491         OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent ALREADY MOST\n"));
492         PR_ExitMonitor(OCSP_Global.monitor);
493         return;
494     }
495     OCSP_TRACE(("OCSP ocsp_MakeCacheEntryMostRecent NEW entry\n"));
496     ocsp_RemoveCacheItemFromLinkedList(cache, new_most_recent);
497     ocsp_AddCacheItemToLinkedList(cache, new_most_recent);
498     PR_ExitMonitor(OCSP_Global.monitor);
499 }
500 
501 static PRBool
ocsp_IsCacheDisabled(void)502 ocsp_IsCacheDisabled(void)
503 {
504     /*
505      * maxCacheEntries == 0 means unlimited cache entries
506      * maxCacheEntries  < 0 means cache is disabled
507      */
508     PRBool retval;
509     PR_EnterMonitor(OCSP_Global.monitor);
510     retval = (OCSP_Global.maxCacheEntries < 0);
511     PR_ExitMonitor(OCSP_Global.monitor);
512     return retval;
513 }
514 
515 static OCSPCacheItem *
ocsp_FindCacheEntry(OCSPCacheData * cache,CERTOCSPCertID * certID)516 ocsp_FindCacheEntry(OCSPCacheData *cache, CERTOCSPCertID *certID)
517 {
518     OCSPCacheItem *found_ocsp_item = NULL;
519     OCSP_TRACE(("OCSP ocsp_FindCacheEntry\n"));
520     OCSP_TRACE_CERTID(certID);
521     PR_EnterMonitor(OCSP_Global.monitor);
522     if (ocsp_IsCacheDisabled())
523         goto loser;
524 
525     found_ocsp_item = (OCSPCacheItem *)PL_HashTableLookup(
526         cache->entries, certID);
527     if (!found_ocsp_item)
528         goto loser;
529 
530     OCSP_TRACE(("OCSP ocsp_FindCacheEntry FOUND!\n"));
531     ocsp_MakeCacheEntryMostRecent(cache, found_ocsp_item);
532 
533 loser:
534     PR_ExitMonitor(OCSP_Global.monitor);
535     return found_ocsp_item;
536 }
537 
538 static void
ocsp_FreeCacheItem(OCSPCacheItem * item)539 ocsp_FreeCacheItem(OCSPCacheItem *item)
540 {
541     OCSP_TRACE(("OCSP ocsp_FreeCacheItem\n"));
542     if (item->certStatusArena) {
543         PORT_FreeArena(item->certStatusArena, PR_FALSE);
544     }
545     if (item->certID->poolp) {
546         /* freeing this poolp arena will also free item */
547         PORT_FreeArena(item->certID->poolp, PR_FALSE);
548     }
549 }
550 
551 static void
ocsp_RemoveCacheItem(OCSPCacheData * cache,OCSPCacheItem * item)552 ocsp_RemoveCacheItem(OCSPCacheData *cache, OCSPCacheItem *item)
553 {
554     /* The item we're removing could be either the least recently used item,
555      * or it could be an item that couldn't get updated with newer status info
556      * because of an allocation failure, or it could get removed because we're
557      * cleaning up.
558      */
559     OCSP_TRACE(("OCSP ocsp_RemoveCacheItem, THREADID %p\n", PR_GetCurrentThread()));
560     PR_EnterMonitor(OCSP_Global.monitor);
561 
562     ocsp_RemoveCacheItemFromLinkedList(cache, item);
563 #ifdef DEBUG
564     {
565         PRBool couldRemoveFromHashTable = PL_HashTableRemove(cache->entries,
566                                                              item->certID);
567         PORT_Assert(couldRemoveFromHashTable);
568     }
569 #else
570     PL_HashTableRemove(cache->entries, item->certID);
571 #endif
572     --cache->numberOfEntries;
573     ocsp_FreeCacheItem(item);
574     PR_ExitMonitor(OCSP_Global.monitor);
575 }
576 
577 static void
ocsp_CheckCacheSize(OCSPCacheData * cache)578 ocsp_CheckCacheSize(OCSPCacheData *cache)
579 {
580     OCSP_TRACE(("OCSP ocsp_CheckCacheSize\n"));
581     PR_EnterMonitor(OCSP_Global.monitor);
582     if (OCSP_Global.maxCacheEntries > 0) {
583         /* Cache is not disabled. Number of cache entries is limited.
584          * The monitor ensures that maxCacheEntries remains positive.
585          */
586         while (cache->numberOfEntries >
587                (PRUint32)OCSP_Global.maxCacheEntries) {
588             ocsp_RemoveCacheItem(cache, cache->LRUitem);
589         }
590     }
591     PR_ExitMonitor(OCSP_Global.monitor);
592 }
593 
594 SECStatus
CERT_ClearOCSPCache(void)595 CERT_ClearOCSPCache(void)
596 {
597     OCSP_TRACE(("OCSP CERT_ClearOCSPCache\n"));
598     PR_EnterMonitor(OCSP_Global.monitor);
599     while (OCSP_Global.cache.numberOfEntries > 0) {
600         ocsp_RemoveCacheItem(&OCSP_Global.cache,
601                              OCSP_Global.cache.LRUitem);
602     }
603     PR_ExitMonitor(OCSP_Global.monitor);
604     return SECSuccess;
605 }
606 
607 static SECStatus
ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData * cache,CERTOCSPCertID * certID,OCSPCacheItem ** pCacheItem)608 ocsp_CreateCacheItemAndConsumeCertID(OCSPCacheData *cache,
609                                      CERTOCSPCertID *certID,
610                                      OCSPCacheItem **pCacheItem)
611 {
612     PLArenaPool *arena;
613     void *mark;
614     PLHashEntry *new_hash_entry;
615     OCSPCacheItem *item;
616 
617     PORT_Assert(pCacheItem != NULL);
618     *pCacheItem = NULL;
619 
620     PR_EnterMonitor(OCSP_Global.monitor);
621     arena = certID->poolp;
622     mark = PORT_ArenaMark(arena);
623 
624     /* ZAlloc will init all Bools to False and all Pointers to NULL
625        and all error codes to zero/good. */
626     item = (OCSPCacheItem *)PORT_ArenaZAlloc(certID->poolp,
627                                              sizeof(OCSPCacheItem));
628     if (!item) {
629         goto loser;
630     }
631     item->certID = certID;
632     new_hash_entry = PL_HashTableAdd(cache->entries, item->certID,
633                                      item);
634     if (!new_hash_entry) {
635         goto loser;
636     }
637     ++cache->numberOfEntries;
638     PORT_ArenaUnmark(arena, mark);
639     ocsp_AddCacheItemToLinkedList(cache, item);
640     *pCacheItem = item;
641 
642     PR_ExitMonitor(OCSP_Global.monitor);
643     return SECSuccess;
644 
645 loser:
646     PORT_ArenaRelease(arena, mark);
647     PR_ExitMonitor(OCSP_Global.monitor);
648     return SECFailure;
649 }
650 
651 static SECStatus
ocsp_SetCacheItemResponse(OCSPCacheItem * item,const CERTOCSPSingleResponse * response)652 ocsp_SetCacheItemResponse(OCSPCacheItem *item,
653                           const CERTOCSPSingleResponse *response)
654 {
655     if (item->certStatusArena) {
656         PORT_FreeArena(item->certStatusArena, PR_FALSE);
657         item->certStatusArena = NULL;
658     }
659     item->haveThisUpdate = item->haveNextUpdate = PR_FALSE;
660     if (response) {
661         SECStatus rv;
662         item->certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
663         if (item->certStatusArena == NULL) {
664             return SECFailure;
665         }
666         rv = ocsp_CopyCertStatus(item->certStatusArena, &item->certStatus,
667                                  response->certStatus);
668         if (rv != SECSuccess) {
669             PORT_FreeArena(item->certStatusArena, PR_FALSE);
670             item->certStatusArena = NULL;
671             return rv;
672         }
673         item->missingResponseError = 0;
674         rv = DER_GeneralizedTimeToTime(&item->thisUpdate,
675                                        &response->thisUpdate);
676         item->haveThisUpdate = (rv == SECSuccess);
677         if (response->nextUpdate) {
678             rv = DER_GeneralizedTimeToTime(&item->nextUpdate,
679                                            response->nextUpdate);
680             item->haveNextUpdate = (rv == SECSuccess);
681         } else {
682             item->haveNextUpdate = PR_FALSE;
683         }
684     }
685     return SECSuccess;
686 }
687 
688 static void
ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem * cacheItem)689 ocsp_FreshenCacheItemNextFetchAttemptTime(OCSPCacheItem *cacheItem)
690 {
691     PRTime now;
692     PRTime earliestAllowedNextFetchAttemptTime;
693     PRTime latestTimeWhenResponseIsConsideredFresh;
694 
695     OCSP_TRACE(("OCSP ocsp_FreshenCacheItemNextFetchAttemptTime\n"));
696 
697     PR_EnterMonitor(OCSP_Global.monitor);
698 
699     now = PR_Now();
700     OCSP_TRACE_TIME("now:", now);
701 
702     if (cacheItem->haveThisUpdate) {
703         OCSP_TRACE_TIME("thisUpdate:", cacheItem->thisUpdate);
704         latestTimeWhenResponseIsConsideredFresh = cacheItem->thisUpdate +
705                                                   OCSP_Global.maximumSecondsToNextFetchAttempt *
706                                                       MICROSECONDS_PER_SECOND;
707         OCSP_TRACE_TIME("latestTimeWhenResponseIsConsideredFresh:",
708                         latestTimeWhenResponseIsConsideredFresh);
709     } else {
710         latestTimeWhenResponseIsConsideredFresh = now +
711                                                   OCSP_Global.minimumSecondsToNextFetchAttempt *
712                                                       MICROSECONDS_PER_SECOND;
713         OCSP_TRACE_TIME("no thisUpdate, "
714                         "latestTimeWhenResponseIsConsideredFresh:",
715                         latestTimeWhenResponseIsConsideredFresh);
716     }
717 
718     if (cacheItem->haveNextUpdate) {
719         OCSP_TRACE_TIME("have nextUpdate:", cacheItem->nextUpdate);
720     }
721 
722     if (cacheItem->haveNextUpdate &&
723         cacheItem->nextUpdate < latestTimeWhenResponseIsConsideredFresh) {
724         latestTimeWhenResponseIsConsideredFresh = cacheItem->nextUpdate;
725         OCSP_TRACE_TIME("nextUpdate is smaller than latestFresh, setting "
726                         "latestTimeWhenResponseIsConsideredFresh:",
727                         latestTimeWhenResponseIsConsideredFresh);
728     }
729 
730     earliestAllowedNextFetchAttemptTime = now +
731                                           OCSP_Global.minimumSecondsToNextFetchAttempt *
732                                               MICROSECONDS_PER_SECOND;
733     OCSP_TRACE_TIME("earliestAllowedNextFetchAttemptTime:",
734                     earliestAllowedNextFetchAttemptTime);
735 
736     if (latestTimeWhenResponseIsConsideredFresh <
737         earliestAllowedNextFetchAttemptTime) {
738         latestTimeWhenResponseIsConsideredFresh =
739             earliestAllowedNextFetchAttemptTime;
740         OCSP_TRACE_TIME("latest < earliest, setting latest to:",
741                         latestTimeWhenResponseIsConsideredFresh);
742     }
743 
744     cacheItem->nextFetchAttemptTime =
745         latestTimeWhenResponseIsConsideredFresh;
746     OCSP_TRACE_TIME("nextFetchAttemptTime",
747                     latestTimeWhenResponseIsConsideredFresh);
748 
749     PR_ExitMonitor(OCSP_Global.monitor);
750 }
751 
752 static PRBool
ocsp_IsCacheItemFresh(OCSPCacheItem * cacheItem)753 ocsp_IsCacheItemFresh(OCSPCacheItem *cacheItem)
754 {
755     PRTime now;
756     PRBool fresh;
757 
758     now = PR_Now();
759 
760     fresh = cacheItem->nextFetchAttemptTime > now;
761 
762     /* Work around broken OCSP responders that return unknown responses for
763      * certificates, especially certificates that were just recently issued.
764      */
765     if (fresh && cacheItem->certStatusArena &&
766         cacheItem->certStatus.certStatusType == ocspCertStatus_unknown) {
767         fresh = PR_FALSE;
768     }
769 
770     OCSP_TRACE(("OCSP ocsp_IsCacheItemFresh: %d\n", fresh));
771 
772     return fresh;
773 }
774 
775 /*
776  * Status in *certIDWasConsumed will always be correct, regardless of
777  * return value.
778  * If the caller is unable to transfer ownership of certID,
779  * then the caller must set certIDWasConsumed to NULL,
780  * and this function will potentially duplicate the certID object.
781  */
782 static SECStatus
ocsp_CreateOrUpdateCacheEntry(OCSPCacheData * cache,CERTOCSPCertID * certID,CERTOCSPSingleResponse * single,PRBool * certIDWasConsumed)783 ocsp_CreateOrUpdateCacheEntry(OCSPCacheData *cache,
784                               CERTOCSPCertID *certID,
785                               CERTOCSPSingleResponse *single,
786                               PRBool *certIDWasConsumed)
787 {
788     SECStatus rv;
789     OCSPCacheItem *cacheItem;
790     OCSP_TRACE(("OCSP ocsp_CreateOrUpdateCacheEntry\n"));
791 
792     if (certIDWasConsumed)
793         *certIDWasConsumed = PR_FALSE;
794 
795     PR_EnterMonitor(OCSP_Global.monitor);
796     PORT_Assert(OCSP_Global.maxCacheEntries >= 0);
797 
798     cacheItem = ocsp_FindCacheEntry(cache, certID);
799 
800     /* Don't replace an unknown or revoked entry with an error entry, even if
801      * the existing entry is expired. Instead, we'll continue to use the
802      * existing (possibly expired) cache entry until we receive a valid signed
803      * response to replace it.
804      */
805     if (!single && cacheItem && cacheItem->certStatusArena &&
806         (cacheItem->certStatus.certStatusType == ocspCertStatus_revoked ||
807          cacheItem->certStatus.certStatusType == ocspCertStatus_unknown)) {
808         PR_ExitMonitor(OCSP_Global.monitor);
809         return SECSuccess;
810     }
811 
812     if (!cacheItem) {
813         CERTOCSPCertID *myCertID;
814         if (certIDWasConsumed) {
815             myCertID = certID;
816             *certIDWasConsumed = PR_TRUE;
817         } else {
818             myCertID = cert_DupOCSPCertID(certID);
819             if (!myCertID) {
820                 PR_ExitMonitor(OCSP_Global.monitor);
821                 PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
822                 return SECFailure;
823             }
824         }
825 
826         rv = ocsp_CreateCacheItemAndConsumeCertID(cache, myCertID,
827                                                   &cacheItem);
828         if (rv != SECSuccess) {
829             PR_ExitMonitor(OCSP_Global.monitor);
830             return rv;
831         }
832     }
833     if (single) {
834         PRTime thisUpdate;
835         rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate);
836 
837         if (!cacheItem->haveThisUpdate ||
838             (rv == SECSuccess && cacheItem->thisUpdate < thisUpdate)) {
839             rv = ocsp_SetCacheItemResponse(cacheItem, single);
840             if (rv != SECSuccess) {
841                 ocsp_RemoveCacheItem(cache, cacheItem);
842                 PR_ExitMonitor(OCSP_Global.monitor);
843                 return rv;
844             }
845         } else {
846             OCSP_TRACE(("Not caching response because the response is not "
847                         "newer than the cache"));
848         }
849     } else {
850         cacheItem->missingResponseError = PORT_GetError();
851         if (cacheItem->certStatusArena) {
852             PORT_FreeArena(cacheItem->certStatusArena, PR_FALSE);
853             cacheItem->certStatusArena = NULL;
854         }
855     }
856     ocsp_FreshenCacheItemNextFetchAttemptTime(cacheItem);
857     ocsp_CheckCacheSize(cache);
858 
859     PR_ExitMonitor(OCSP_Global.monitor);
860     return SECSuccess;
861 }
862 
863 extern SECStatus
CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode)864 CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode)
865 {
866     switch (ocspFailureMode) {
867         case ocspMode_FailureIsVerificationFailure:
868         case ocspMode_FailureIsNotAVerificationFailure:
869             break;
870         default:
871             PORT_SetError(SEC_ERROR_INVALID_ARGS);
872             return SECFailure;
873     }
874 
875     PR_EnterMonitor(OCSP_Global.monitor);
876     OCSP_Global.ocspFailureMode = ocspFailureMode;
877     PR_ExitMonitor(OCSP_Global.monitor);
878     return SECSuccess;
879 }
880 
881 SECStatus
CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,PRUint32 minimumSecondsToNextFetchAttempt,PRUint32 maximumSecondsToNextFetchAttempt)882 CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
883                        PRUint32 minimumSecondsToNextFetchAttempt,
884                        PRUint32 maximumSecondsToNextFetchAttempt)
885 {
886     if (minimumSecondsToNextFetchAttempt > maximumSecondsToNextFetchAttempt ||
887         maxCacheEntries < -1) {
888         PORT_SetError(SEC_ERROR_INVALID_ARGS);
889         return SECFailure;
890     }
891 
892     PR_EnterMonitor(OCSP_Global.monitor);
893 
894     if (maxCacheEntries < 0) {
895         OCSP_Global.maxCacheEntries = -1; /* disable cache */
896     } else if (maxCacheEntries == 0) {
897         OCSP_Global.maxCacheEntries = 0; /* unlimited cache entries */
898     } else {
899         OCSP_Global.maxCacheEntries = maxCacheEntries;
900     }
901 
902     if (minimumSecondsToNextFetchAttempt <
903             OCSP_Global.minimumSecondsToNextFetchAttempt ||
904         maximumSecondsToNextFetchAttempt <
905             OCSP_Global.maximumSecondsToNextFetchAttempt) {
906         /*
907          * Ensure our existing cache entries are not used longer than the
908          * new settings allow, we're lazy and just clear the cache
909          */
910         CERT_ClearOCSPCache();
911     }
912 
913     OCSP_Global.minimumSecondsToNextFetchAttempt =
914         minimumSecondsToNextFetchAttempt;
915     OCSP_Global.maximumSecondsToNextFetchAttempt =
916         maximumSecondsToNextFetchAttempt;
917     ocsp_CheckCacheSize(&OCSP_Global.cache);
918 
919     PR_ExitMonitor(OCSP_Global.monitor);
920     return SECSuccess;
921 }
922 
923 SECStatus
CERT_SetOCSPTimeout(PRUint32 seconds)924 CERT_SetOCSPTimeout(PRUint32 seconds)
925 {
926     /* no locking, see bug 406120 */
927     OCSP_Global.timeoutSeconds = seconds;
928     return SECSuccess;
929 }
930 
931 /* this function is called at NSS initialization time */
932 SECStatus
OCSP_InitGlobal(void)933 OCSP_InitGlobal(void)
934 {
935     SECStatus rv = SECFailure;
936 
937     if (OCSP_Global.monitor == NULL) {
938         OCSP_Global.monitor = PR_NewMonitor();
939     }
940     if (!OCSP_Global.monitor)
941         return SECFailure;
942 
943     PR_EnterMonitor(OCSP_Global.monitor);
944     if (!OCSP_Global.cache.entries) {
945         OCSP_Global.cache.entries =
946             PL_NewHashTable(0,
947                             ocsp_CacheKeyHashFunction,
948                             ocsp_CacheKeyCompareFunction,
949                             PL_CompareValues,
950                             NULL,
951                             NULL);
952         OCSP_Global.ocspFailureMode = ocspMode_FailureIsVerificationFailure;
953         OCSP_Global.cache.numberOfEntries = 0;
954         OCSP_Global.cache.MRUitem = NULL;
955         OCSP_Global.cache.LRUitem = NULL;
956     } else {
957         /*
958          * NSS might call this function twice while attempting to init.
959          * But it's not allowed to call this again after any activity.
960          */
961         PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
962         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
963     }
964     if (OCSP_Global.cache.entries)
965         rv = SECSuccess;
966     PR_ExitMonitor(OCSP_Global.monitor);
967     return rv;
968 }
969 
970 SECStatus
OCSP_ShutdownGlobal(void)971 OCSP_ShutdownGlobal(void)
972 {
973     if (!OCSP_Global.monitor)
974         return SECSuccess;
975 
976     PR_EnterMonitor(OCSP_Global.monitor);
977     if (OCSP_Global.cache.entries) {
978         CERT_ClearOCSPCache();
979         PL_HashTableDestroy(OCSP_Global.cache.entries);
980         OCSP_Global.cache.entries = NULL;
981     }
982     PORT_Assert(OCSP_Global.cache.numberOfEntries == 0);
983     OCSP_Global.cache.MRUitem = NULL;
984     OCSP_Global.cache.LRUitem = NULL;
985 
986     OCSP_Global.defaultHttpClientFcn = NULL;
987     OCSP_Global.maxCacheEntries = DEFAULT_OCSP_CACHE_SIZE;
988     OCSP_Global.minimumSecondsToNextFetchAttempt =
989         DEFAULT_MINIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
990     OCSP_Global.maximumSecondsToNextFetchAttempt =
991         DEFAULT_MAXIMUM_SECONDS_TO_NEXT_OCSP_FETCH_ATTEMPT;
992     OCSP_Global.ocspFailureMode =
993         ocspMode_FailureIsVerificationFailure;
994     PR_ExitMonitor(OCSP_Global.monitor);
995 
996     PR_DestroyMonitor(OCSP_Global.monitor);
997     OCSP_Global.monitor = NULL;
998     return SECSuccess;
999 }
1000 
1001 /*
1002  * A return value of NULL means:
1003  *   The application did not register it's own HTTP client.
1004  */
1005 const SEC_HttpClientFcn *
SEC_GetRegisteredHttpClient(void)1006 SEC_GetRegisteredHttpClient(void)
1007 {
1008     const SEC_HttpClientFcn *retval;
1009 
1010     if (!OCSP_Global.monitor) {
1011         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1012         return NULL;
1013     }
1014 
1015     PR_EnterMonitor(OCSP_Global.monitor);
1016     retval = OCSP_Global.defaultHttpClientFcn;
1017     PR_ExitMonitor(OCSP_Global.monitor);
1018 
1019     return retval;
1020 }
1021 
1022 /*
1023  * The following structure is only used internally.  It is allocated when
1024  * someone turns on OCSP checking, and hangs off of the status-configuration
1025  * structure in the certdb structure.  We use it to keep configuration
1026  * information specific to OCSP checking.
1027  */
1028 typedef struct ocspCheckingContextStr {
1029     PRBool useDefaultResponder;
1030     char *defaultResponderURI;
1031     char *defaultResponderNickname;
1032     CERTCertificate *defaultResponderCert;
1033 } ocspCheckingContext;
1034 
1035 SEC_ASN1_MKSUB(SEC_AnyTemplate)
1036 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
1037 SEC_ASN1_MKSUB(SEC_NullTemplate)
1038 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
1039 SEC_ASN1_MKSUB(SEC_PointerToAnyTemplate)
1040 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
1041 SEC_ASN1_MKSUB(SEC_SequenceOfAnyTemplate)
1042 SEC_ASN1_MKSUB(SEC_PointerToGeneralizedTimeTemplate)
1043 SEC_ASN1_MKSUB(SEC_PointerToEnumeratedTemplate)
1044 
1045 /*
1046  * Forward declarations of sub-types, so I can lay out the types in the
1047  * same order as the ASN.1 is laid out in the OCSP spec itself.
1048  *
1049  * These are in alphabetical order (case-insensitive); please keep it that way!
1050  */
1051 extern const SEC_ASN1Template ocsp_CertIDTemplate[];
1052 extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[];
1053 extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[];
1054 extern const SEC_ASN1Template ocsp_ResponseDataTemplate[];
1055 extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[];
1056 extern const SEC_ASN1Template ocsp_SingleRequestTemplate[];
1057 extern const SEC_ASN1Template ocsp_SingleResponseTemplate[];
1058 extern const SEC_ASN1Template ocsp_TBSRequestTemplate[];
1059 
1060 /*
1061  * Request-related templates...
1062  */
1063 
1064 /*
1065  * OCSPRequest	::=	SEQUENCE {
1066  *	tbsRequest		TBSRequest,
1067  *	optionalSignature	[0] EXPLICIT Signature OPTIONAL }
1068  */
1069 static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = {
1070     { SEC_ASN1_SEQUENCE,
1071       0, NULL, sizeof(CERTOCSPRequest) },
1072     { SEC_ASN1_POINTER,
1073       offsetof(CERTOCSPRequest, tbsRequest),
1074       ocsp_TBSRequestTemplate },
1075     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1076           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
1077       offsetof(CERTOCSPRequest, optionalSignature),
1078       ocsp_PointerToSignatureTemplate },
1079     { 0 }
1080 };
1081 
1082 /*
1083  * TBSRequest	::=	SEQUENCE {
1084  *	version			[0] EXPLICIT Version DEFAULT v1,
1085  *	requestorName		[1] EXPLICIT GeneralName OPTIONAL,
1086  *	requestList		SEQUENCE OF Request,
1087  *	requestExtensions	[2] EXPLICIT Extensions OPTIONAL }
1088  *
1089  * Version	::=	INTEGER { v1(0) }
1090  *
1091  * Note: this should be static but the AIX compiler doesn't like it (because it
1092  * was forward-declared above); it is not meant to be exported, but this
1093  * is the only way it will compile.
1094  */
1095 const SEC_ASN1Template ocsp_TBSRequestTemplate[] = {
1096     { SEC_ASN1_SEQUENCE,
1097       0, NULL, sizeof(ocspTBSRequest) },
1098     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */
1099           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1100       offsetof(ocspTBSRequest, version),
1101       SEC_ASN1_SUB(SEC_IntegerTemplate) },
1102     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1103           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
1104       offsetof(ocspTBSRequest, derRequestorName),
1105       SEC_ASN1_SUB(SEC_PointerToAnyTemplate) },
1106     { SEC_ASN1_SEQUENCE_OF,
1107       offsetof(ocspTBSRequest, requestList),
1108       ocsp_SingleRequestTemplate },
1109     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1110           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
1111       offsetof(ocspTBSRequest, requestExtensions),
1112       CERT_SequenceOfCertExtensionTemplate },
1113     { 0 }
1114 };
1115 
1116 /*
1117  * Signature	::=	SEQUENCE {
1118  *	signatureAlgorithm	AlgorithmIdentifier,
1119  *	signature		BIT STRING,
1120  *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
1121  */
1122 static const SEC_ASN1Template ocsp_SignatureTemplate[] = {
1123     { SEC_ASN1_SEQUENCE,
1124       0, NULL, sizeof(ocspSignature) },
1125     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1126       offsetof(ocspSignature, signatureAlgorithm),
1127       SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1128     { SEC_ASN1_BIT_STRING,
1129       offsetof(ocspSignature, signature) },
1130     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1131           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1132       offsetof(ocspSignature, derCerts),
1133       SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
1134     { 0 }
1135 };
1136 
1137 /*
1138  * This template is just an extra level to use in an explicitly-tagged
1139  * reference to a Signature.
1140  *
1141  * Note: this should be static but the AIX compiler doesn't like it (because it
1142  * was forward-declared above); it is not meant to be exported, but this
1143  * is the only way it will compile.
1144  */
1145 const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = {
1146     { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate }
1147 };
1148 
1149 /*
1150  * Request	::=	SEQUENCE {
1151  *	reqCert			CertID,
1152  *	singleRequestExtensions	[0] EXPLICIT Extensions OPTIONAL }
1153  *
1154  * Note: this should be static but the AIX compiler doesn't like it (because it
1155  * was forward-declared above); it is not meant to be exported, but this
1156  * is the only way it will compile.
1157  */
1158 const SEC_ASN1Template ocsp_SingleRequestTemplate[] = {
1159     { SEC_ASN1_SEQUENCE,
1160       0, NULL, sizeof(ocspSingleRequest) },
1161     { SEC_ASN1_POINTER,
1162       offsetof(ocspSingleRequest, reqCert),
1163       ocsp_CertIDTemplate },
1164     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1165           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
1166       offsetof(ocspSingleRequest, singleRequestExtensions),
1167       CERT_SequenceOfCertExtensionTemplate },
1168     { 0 }
1169 };
1170 
1171 /*
1172  * This data structure and template (CertID) is used by both OCSP
1173  * requests and responses.  It is the only one that is shared.
1174  *
1175  * CertID	::=	SEQUENCE {
1176  *	hashAlgorithm		AlgorithmIdentifier,
1177  *	issuerNameHash		OCTET STRING,	-- Hash of Issuer DN
1178  *	issuerKeyHash		OCTET STRING,	-- Hash of Issuer public key
1179  *	serialNumber		CertificateSerialNumber }
1180  *
1181  * CertificateSerialNumber ::=	INTEGER
1182  *
1183  * Note: this should be static but the AIX compiler doesn't like it (because it
1184  * was forward-declared above); it is not meant to be exported, but this
1185  * is the only way it will compile.
1186  */
1187 const SEC_ASN1Template ocsp_CertIDTemplate[] = {
1188     { SEC_ASN1_SEQUENCE,
1189       0, NULL, sizeof(CERTOCSPCertID) },
1190     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1191       offsetof(CERTOCSPCertID, hashAlgorithm),
1192       SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1193     { SEC_ASN1_OCTET_STRING,
1194       offsetof(CERTOCSPCertID, issuerNameHash) },
1195     { SEC_ASN1_OCTET_STRING,
1196       offsetof(CERTOCSPCertID, issuerKeyHash) },
1197     { SEC_ASN1_INTEGER,
1198       offsetof(CERTOCSPCertID, serialNumber) },
1199     { 0 }
1200 };
1201 
1202 /*
1203  * Response-related templates...
1204  */
1205 
1206 /*
1207  * OCSPResponse	::=	SEQUENCE {
1208  *	responseStatus		OCSPResponseStatus,
1209  *	responseBytes		[0] EXPLICIT ResponseBytes OPTIONAL }
1210  */
1211 const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = {
1212     { SEC_ASN1_SEQUENCE,
1213       0, NULL, sizeof(CERTOCSPResponse) },
1214     { SEC_ASN1_ENUMERATED,
1215       offsetof(CERTOCSPResponse, responseStatus) },
1216     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1217           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
1218       offsetof(CERTOCSPResponse, responseBytes),
1219       ocsp_PointerToResponseBytesTemplate },
1220     { 0 }
1221 };
1222 
1223 /*
1224  * ResponseBytes	::=	SEQUENCE {
1225  *	responseType		OBJECT IDENTIFIER,
1226  *	response		OCTET STRING }
1227  */
1228 const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = {
1229     { SEC_ASN1_SEQUENCE,
1230       0, NULL, sizeof(ocspResponseBytes) },
1231     { SEC_ASN1_OBJECT_ID,
1232       offsetof(ocspResponseBytes, responseType) },
1233     { SEC_ASN1_OCTET_STRING,
1234       offsetof(ocspResponseBytes, response) },
1235     { 0 }
1236 };
1237 
1238 /*
1239  * This template is just an extra level to use in an explicitly-tagged
1240  * reference to a ResponseBytes.
1241  *
1242  * Note: this should be static but the AIX compiler doesn't like it (because it
1243  * was forward-declared above); it is not meant to be exported, but this
1244  * is the only way it will compile.
1245  */
1246 const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = {
1247     { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate }
1248 };
1249 
1250 /*
1251  * BasicOCSPResponse	::=	SEQUENCE {
1252  *	tbsResponseData		ResponseData,
1253  *	signatureAlgorithm	AlgorithmIdentifier,
1254  *	signature		BIT STRING,
1255  *	certs			[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
1256  */
1257 static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = {
1258     { SEC_ASN1_SEQUENCE,
1259       0, NULL, sizeof(ocspBasicOCSPResponse) },
1260     { SEC_ASN1_ANY | SEC_ASN1_SAVE,
1261       offsetof(ocspBasicOCSPResponse, tbsResponseDataDER) },
1262     { SEC_ASN1_POINTER,
1263       offsetof(ocspBasicOCSPResponse, tbsResponseData),
1264       ocsp_ResponseDataTemplate },
1265     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
1266       offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
1267       SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1268     { SEC_ASN1_BIT_STRING,
1269       offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
1270     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1271           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1272       offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
1273       SEC_ASN1_SUB(SEC_SequenceOfAnyTemplate) },
1274     { 0 }
1275 };
1276 
1277 /*
1278  * ResponseData	::=	SEQUENCE {
1279  *	version			[0] EXPLICIT Version DEFAULT v1,
1280  *	responderID		ResponderID,
1281  *	producedAt		GeneralizedTime,
1282  *	responses		SEQUENCE OF SingleResponse,
1283  *	responseExtensions	[1] EXPLICIT Extensions OPTIONAL }
1284  *
1285  * Note: this should be static but the AIX compiler doesn't like it (because it
1286  * was forward-declared above); it is not meant to be exported, but this
1287  * is the only way it will compile.
1288  */
1289 const SEC_ASN1Template ocsp_ResponseDataTemplate[] = {
1290     { SEC_ASN1_SEQUENCE,
1291       0, NULL, sizeof(ocspResponseData) },
1292     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */
1293           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1294       offsetof(ocspResponseData, version),
1295       SEC_ASN1_SUB(SEC_IntegerTemplate) },
1296     { SEC_ASN1_ANY,
1297       offsetof(ocspResponseData, derResponderID) },
1298     { SEC_ASN1_GENERALIZED_TIME,
1299       offsetof(ocspResponseData, producedAt) },
1300     { SEC_ASN1_SEQUENCE_OF,
1301       offsetof(ocspResponseData, responses),
1302       ocsp_SingleResponseTemplate },
1303     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1304           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1305       offsetof(ocspResponseData, responseExtensions),
1306       CERT_SequenceOfCertExtensionTemplate },
1307     { 0 }
1308 };
1309 
1310 /*
1311  * ResponderID	::=	CHOICE {
1312  *	byName			[1] EXPLICIT Name,
1313  *	byKey			[2] EXPLICIT KeyHash }
1314  *
1315  * KeyHash ::=	OCTET STRING -- SHA-1 hash of responder's public key
1316  * (excluding the tag and length fields)
1317  *
1318  * XXX Because the ASN.1 encoder and decoder currently do not provide
1319  * a way to automatically handle a CHOICE, we need to do it in two
1320  * steps, looking at the type tag and feeding the exact choice back
1321  * to the ASN.1 code.  Hopefully that will change someday and this
1322  * can all be simplified down into a single template.  Anyway, for
1323  * now we list each choice as its own template:
1324  */
1325 const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = {
1326     { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1327       offsetof(ocspResponderID, responderIDValue.name),
1328       CERT_NameTemplate }
1329 };
1330 const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = {
1331     { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
1332           SEC_ASN1_XTRN | 2,
1333       offsetof(ocspResponderID, responderIDValue.keyHash),
1334       SEC_ASN1_SUB(SEC_OctetStringTemplate) }
1335 };
1336 static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = {
1337     { SEC_ASN1_ANY,
1338       offsetof(ocspResponderID, responderIDValue.other) }
1339 };
1340 
1341 /* Decode choice container, but leave x509 name object encoded */
1342 static const SEC_ASN1Template ocsp_ResponderIDDerNameTemplate[] = {
1343     { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
1344           SEC_ASN1_XTRN | 1,
1345       0, SEC_ASN1_SUB(SEC_AnyTemplate) }
1346 };
1347 
1348 /*
1349  * SingleResponse	::=	SEQUENCE {
1350  *	certID			CertID,
1351  *	certStatus		CertStatus,
1352  *	thisUpdate		GeneralizedTime,
1353  *	nextUpdate		[0] EXPLICIT GeneralizedTime OPTIONAL,
1354  *	singleExtensions	[1] EXPLICIT Extensions OPTIONAL }
1355  *
1356  * Note: this should be static but the AIX compiler doesn't like it (because it
1357  * was forward-declared above); it is not meant to be exported, but this
1358  * is the only way it will compile.
1359  */
1360 const SEC_ASN1Template ocsp_SingleResponseTemplate[] = {
1361     { SEC_ASN1_SEQUENCE,
1362       0, NULL, sizeof(CERTOCSPSingleResponse) },
1363     { SEC_ASN1_POINTER,
1364       offsetof(CERTOCSPSingleResponse, certID),
1365       ocsp_CertIDTemplate },
1366     { SEC_ASN1_ANY,
1367       offsetof(CERTOCSPSingleResponse, derCertStatus) },
1368     { SEC_ASN1_GENERALIZED_TIME,
1369       offsetof(CERTOCSPSingleResponse, thisUpdate) },
1370     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1371           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1372       offsetof(CERTOCSPSingleResponse, nextUpdate),
1373       SEC_ASN1_SUB(SEC_PointerToGeneralizedTimeTemplate) },
1374     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1375           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1376       offsetof(CERTOCSPSingleResponse, singleExtensions),
1377       CERT_SequenceOfCertExtensionTemplate },
1378     { 0 }
1379 };
1380 
1381 /*
1382  * CertStatus	::=	CHOICE {
1383  *	good			[0] IMPLICIT NULL,
1384  *	revoked			[1] IMPLICIT RevokedInfo,
1385  *	unknown			[2] IMPLICIT UnknownInfo }
1386  *
1387  * Because the ASN.1 encoder and decoder currently do not provide
1388  * a way to automatically handle a CHOICE, we need to do it in two
1389  * steps, looking at the type tag and feeding the exact choice back
1390  * to the ASN.1 code.  Hopefully that will change someday and this
1391  * can all be simplified down into a single template.  Anyway, for
1392  * now we list each choice as its own template:
1393  */
1394 static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = {
1395     { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
1396       offsetof(ocspCertStatus, certStatusInfo.goodInfo),
1397       SEC_ASN1_SUB(SEC_NullTemplate) }
1398 };
1399 static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = {
1400     { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
1401       offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
1402       ocsp_RevokedInfoTemplate }
1403 };
1404 static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = {
1405     { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
1406       offsetof(ocspCertStatus, certStatusInfo.unknownInfo),
1407       SEC_ASN1_SUB(SEC_NullTemplate) }
1408 };
1409 static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = {
1410     { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
1411       offsetof(ocspCertStatus, certStatusInfo.otherInfo),
1412       SEC_ASN1_SUB(SEC_AnyTemplate) }
1413 };
1414 
1415 /*
1416  * RevokedInfo	::=	SEQUENCE {
1417  *	revocationTime		GeneralizedTime,
1418  *	revocationReason	[0] EXPLICIT CRLReason OPTIONAL }
1419  *
1420  * Note: this should be static but the AIX compiler doesn't like it (because it
1421  * was forward-declared above); it is not meant to be exported, but this
1422  * is the only way it will compile.
1423  */
1424 const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = {
1425     { SEC_ASN1_SEQUENCE,
1426       0, NULL, sizeof(ocspRevokedInfo) },
1427     { SEC_ASN1_GENERALIZED_TIME,
1428       offsetof(ocspRevokedInfo, revocationTime) },
1429     { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
1430           SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
1431           SEC_ASN1_XTRN | 0,
1432       offsetof(ocspRevokedInfo, revocationReason),
1433       SEC_ASN1_SUB(SEC_PointerToEnumeratedTemplate) },
1434     { 0 }
1435 };
1436 
1437 /*
1438  * OCSP-specific extension templates:
1439  */
1440 
1441 /*
1442  * ServiceLocator	::=	SEQUENCE {
1443  *	issuer			Name,
1444  *	locator			AuthorityInfoAccessSyntax OPTIONAL }
1445  */
1446 static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = {
1447     { SEC_ASN1_SEQUENCE,
1448       0, NULL, sizeof(ocspServiceLocator) },
1449     { SEC_ASN1_POINTER,
1450       offsetof(ocspServiceLocator, issuer),
1451       CERT_NameTemplate },
1452     { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
1453       offsetof(ocspServiceLocator, locator) },
1454     { 0 }
1455 };
1456 
1457 /*
1458  * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy):
1459  */
1460 
1461 /*
1462  * FUNCTION: CERT_EncodeOCSPRequest
1463  *   DER encodes an OCSP Request, possibly adding a signature as well.
1464  *   XXX Signing is not yet supported, however; see comments in code.
1465  * INPUTS:
1466  *   PLArenaPool *arena
1467  *     The return value is allocated from here.
1468  *     If a NULL is passed in, allocation is done from the heap instead.
1469  *   CERTOCSPRequest *request
1470  *     The request to be encoded.
1471  *   void *pwArg
1472  *     Pointer to argument for password prompting, if needed.  (Definitely
1473  *     not needed if not signing.)
1474  * RETURN:
1475  *   Returns a NULL on error and a pointer to the SECItem with the
1476  *   encoded value otherwise.  Any error is likely to be low-level
1477  *   (e.g. no memory).
1478  */
1479 SECItem *
CERT_EncodeOCSPRequest(PLArenaPool * arena,CERTOCSPRequest * request,void * pwArg)1480 CERT_EncodeOCSPRequest(PLArenaPool *arena, CERTOCSPRequest *request,
1481                        void *pwArg)
1482 {
1483     SECStatus rv;
1484 
1485     /* XXX All of these should generate errors if they fail. */
1486     PORT_Assert(request);
1487     PORT_Assert(request->tbsRequest);
1488 
1489     if (request->tbsRequest->extensionHandle != NULL) {
1490         rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle);
1491         request->tbsRequest->extensionHandle = NULL;
1492         if (rv != SECSuccess)
1493             return NULL;
1494     }
1495 
1496     /*
1497      * XXX When signed requests are supported and request->optionalSignature
1498      * is not NULL:
1499      *  - need to encode tbsRequest->requestorName
1500      *  - need to encode tbsRequest
1501      *  - need to sign that encoded result (using cert in sig), filling in the
1502      *    request->optionalSignature structure with the result, the signing
1503      *    algorithm and (perhaps?) the cert (and its chain?) in derCerts
1504      */
1505 
1506     return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate);
1507 }
1508 
1509 /*
1510  * FUNCTION: CERT_DecodeOCSPRequest
1511  *   Decode a DER encoded OCSP Request.
1512  * INPUTS:
1513  *   SECItem *src
1514  *     Pointer to a SECItem holding DER encoded OCSP Request.
1515  * RETURN:
1516  *   Returns a pointer to a CERTOCSPRequest containing the decoded request.
1517  *   On error, returns NULL.  Most likely error is trouble decoding
1518  *   (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
1519  */
1520 CERTOCSPRequest *
CERT_DecodeOCSPRequest(const SECItem * src)1521 CERT_DecodeOCSPRequest(const SECItem *src)
1522 {
1523     PLArenaPool *arena = NULL;
1524     SECStatus rv = SECFailure;
1525     CERTOCSPRequest *dest = NULL;
1526     int i;
1527     SECItem newSrc;
1528 
1529     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1530     if (arena == NULL) {
1531         goto loser;
1532     }
1533     dest = (CERTOCSPRequest *)PORT_ArenaZAlloc(arena,
1534                                                sizeof(CERTOCSPRequest));
1535     if (dest == NULL) {
1536         goto loser;
1537     }
1538     dest->arena = arena;
1539 
1540     /* copy the DER into the arena, since Quick DER returns data that points
1541        into the DER input, which may get freed by the caller */
1542     rv = SECITEM_CopyItem(arena, &newSrc, src);
1543     if (rv != SECSuccess) {
1544         goto loser;
1545     }
1546 
1547     rv = SEC_QuickDERDecodeItem(arena, dest, ocsp_OCSPRequestTemplate, &newSrc);
1548     if (rv != SECSuccess) {
1549         if (PORT_GetError() == SEC_ERROR_BAD_DER)
1550             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
1551         goto loser;
1552     }
1553 
1554     /*
1555      * XXX I would like to find a way to get rid of the necessity
1556      * of doing this copying of the arena pointer.
1557      */
1558     for (i = 0; dest->tbsRequest->requestList[i] != NULL; i++) {
1559         dest->tbsRequest->requestList[i]->arena = arena;
1560     }
1561 
1562     return dest;
1563 
1564 loser:
1565     if (arena != NULL) {
1566         PORT_FreeArena(arena, PR_FALSE);
1567     }
1568     return NULL;
1569 }
1570 
1571 SECStatus
CERT_DestroyOCSPCertID(CERTOCSPCertID * certID)1572 CERT_DestroyOCSPCertID(CERTOCSPCertID *certID)
1573 {
1574     if (certID && certID->poolp) {
1575         PORT_FreeArena(certID->poolp, PR_FALSE);
1576         return SECSuccess;
1577     }
1578     PORT_SetError(SEC_ERROR_INVALID_ARGS);
1579     return SECFailure;
1580 }
1581 
1582 /*
1583  * Digest data using the specified algorithm.
1584  * The necessary storage for the digest data is allocated.  If "fill" is
1585  * non-null, the data is put there, otherwise a SECItem is allocated.
1586  * Allocation from "arena" if it is non-null, heap otherwise.  Any problem
1587  * results in a NULL being returned (and an appropriate error set).
1588  */
1589 
1590 SECItem *
ocsp_DigestValue(PLArenaPool * arena,SECOidTag digestAlg,SECItem * fill,const SECItem * src)1591 ocsp_DigestValue(PLArenaPool *arena, SECOidTag digestAlg,
1592                  SECItem *fill, const SECItem *src)
1593 {
1594     const SECHashObject *digestObject;
1595     SECItem *result = NULL;
1596     void *mark = NULL;
1597     void *digestBuff = NULL;
1598 
1599     if (arena != NULL) {
1600         mark = PORT_ArenaMark(arena);
1601     }
1602 
1603     digestObject = HASH_GetHashObjectByOidTag(digestAlg);
1604     if (digestObject == NULL) {
1605         goto loser;
1606     }
1607 
1608     if (fill == NULL || fill->data == NULL) {
1609         result = SECITEM_AllocItem(arena, fill, digestObject->length);
1610         if (result == NULL) {
1611             goto loser;
1612         }
1613         digestBuff = result->data;
1614     } else {
1615         if (fill->len < digestObject->length) {
1616             PORT_SetError(SEC_ERROR_INVALID_ARGS);
1617             goto loser;
1618         }
1619         digestBuff = fill->data;
1620     }
1621 
1622     if (PK11_HashBuf(digestAlg, digestBuff,
1623                      src->data, src->len) != SECSuccess) {
1624         goto loser;
1625     }
1626 
1627     if (arena != NULL) {
1628         PORT_ArenaUnmark(arena, mark);
1629     }
1630 
1631     if (result == NULL) {
1632         result = fill;
1633     }
1634     return result;
1635 
1636 loser:
1637     if (arena != NULL) {
1638         PORT_ArenaRelease(arena, mark);
1639     } else {
1640         if (result != NULL) {
1641             SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE);
1642         }
1643     }
1644     return (NULL);
1645 }
1646 
1647 /*
1648  * Digest the cert's subject public key using the specified algorithm.
1649  * The necessary storage for the digest data is allocated.  If "fill" is
1650  * non-null, the data is put there, otherwise a SECItem is allocated.
1651  * Allocation from "arena" if it is non-null, heap otherwise.  Any problem
1652  * results in a NULL being returned (and an appropriate error set).
1653  */
1654 SECItem *
CERT_GetSubjectPublicKeyDigest(PLArenaPool * arena,const CERTCertificate * cert,SECOidTag digestAlg,SECItem * fill)1655 CERT_GetSubjectPublicKeyDigest(PLArenaPool *arena, const CERTCertificate *cert,
1656                                SECOidTag digestAlg, SECItem *fill)
1657 {
1658     SECItem spk;
1659 
1660     /*
1661      * Copy just the length and data pointer (nothing needs to be freed)
1662      * of the subject public key so we can convert the length from bits
1663      * to bytes, which is what the digest function expects.
1664      */
1665     spk = cert->subjectPublicKeyInfo.subjectPublicKey;
1666     DER_ConvertBitString(&spk);
1667 
1668     return ocsp_DigestValue(arena, digestAlg, fill, &spk);
1669 }
1670 
1671 /*
1672  * Digest the cert's subject name using the specified algorithm.
1673  */
1674 SECItem *
CERT_GetSubjectNameDigest(PLArenaPool * arena,const CERTCertificate * cert,SECOidTag digestAlg,SECItem * fill)1675 CERT_GetSubjectNameDigest(PLArenaPool *arena, const CERTCertificate *cert,
1676                           SECOidTag digestAlg, SECItem *fill)
1677 {
1678     SECItem name;
1679 
1680     /*
1681      * Copy just the length and data pointer (nothing needs to be freed)
1682      * of the subject name
1683      */
1684     name = cert->derSubject;
1685 
1686     return ocsp_DigestValue(arena, digestAlg, fill, &name);
1687 }
1688 
1689 /*
1690  * Create and fill-in a CertID.  This function fills in the hash values
1691  * (issuerNameHash and issuerKeyHash), and is hardwired to use SHA1.
1692  * Someday it might need to be more flexible about hash algorithm, but
1693  * for now we have no intention/need to create anything else.
1694  *
1695  * Error causes a null to be returned; most likely cause is trouble
1696  * finding the certificate issuer (SEC_ERROR_UNKNOWN_ISSUER).
1697  * Other errors are low-level problems (no memory, bad database, etc.).
1698  */
1699 static CERTOCSPCertID *
ocsp_CreateCertID(PLArenaPool * arena,CERTCertificate * cert,PRTime time)1700 ocsp_CreateCertID(PLArenaPool *arena, CERTCertificate *cert, PRTime time)
1701 {
1702     CERTOCSPCertID *certID;
1703     CERTCertificate *issuerCert = NULL;
1704     void *mark = PORT_ArenaMark(arena);
1705     SECStatus rv;
1706 
1707     PORT_Assert(arena != NULL);
1708 
1709     certID = PORT_ArenaZNew(arena, CERTOCSPCertID);
1710     if (certID == NULL) {
1711         goto loser;
1712     }
1713 
1714     rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1,
1715                                NULL);
1716     if (rv != SECSuccess) {
1717         goto loser;
1718     }
1719 
1720     issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
1721     if (issuerCert == NULL) {
1722         goto loser;
1723     }
1724 
1725     if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_SHA1,
1726                                   &(certID->issuerNameHash)) == NULL) {
1727         goto loser;
1728     }
1729     certID->issuerSHA1NameHash.data = certID->issuerNameHash.data;
1730     certID->issuerSHA1NameHash.len = certID->issuerNameHash.len;
1731 
1732     if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD5,
1733                                   &(certID->issuerMD5NameHash)) == NULL) {
1734         goto loser;
1735     }
1736 
1737     if (CERT_GetSubjectNameDigest(arena, issuerCert, SEC_OID_MD2,
1738                                   &(certID->issuerMD2NameHash)) == NULL) {
1739         goto loser;
1740     }
1741 
1742     if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_SHA1,
1743                                        &certID->issuerKeyHash) == NULL) {
1744         goto loser;
1745     }
1746     certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data;
1747     certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len;
1748     /* cache the other two hash algorithms as well */
1749     if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_MD5,
1750                                        &certID->issuerMD5KeyHash) == NULL) {
1751         goto loser;
1752     }
1753     if (CERT_GetSubjectPublicKeyDigest(arena, issuerCert, SEC_OID_MD2,
1754                                        &certID->issuerMD2KeyHash) == NULL) {
1755         goto loser;
1756     }
1757 
1758     /* now we are done with issuerCert */
1759     CERT_DestroyCertificate(issuerCert);
1760     issuerCert = NULL;
1761 
1762     rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber);
1763     if (rv != SECSuccess) {
1764         goto loser;
1765     }
1766 
1767     PORT_ArenaUnmark(arena, mark);
1768     return certID;
1769 
1770 loser:
1771     if (issuerCert != NULL) {
1772         CERT_DestroyCertificate(issuerCert);
1773     }
1774     PORT_ArenaRelease(arena, mark);
1775     return NULL;
1776 }
1777 
1778 CERTOCSPCertID *
CERT_CreateOCSPCertID(CERTCertificate * cert,PRTime time)1779 CERT_CreateOCSPCertID(CERTCertificate *cert, PRTime time)
1780 {
1781     PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1782     CERTOCSPCertID *certID;
1783     PORT_Assert(arena != NULL);
1784     if (!arena)
1785         return NULL;
1786 
1787     certID = ocsp_CreateCertID(arena, cert, time);
1788     if (!certID) {
1789         PORT_FreeArena(arena, PR_FALSE);
1790         return NULL;
1791     }
1792     certID->poolp = arena;
1793     return certID;
1794 }
1795 
1796 static CERTOCSPCertID *
cert_DupOCSPCertID(const CERTOCSPCertID * src)1797 cert_DupOCSPCertID(const CERTOCSPCertID *src)
1798 {
1799     CERTOCSPCertID *dest;
1800     PLArenaPool *arena = NULL;
1801 
1802     if (!src) {
1803         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1804         return NULL;
1805     }
1806 
1807     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1808     if (!arena)
1809         goto loser;
1810 
1811     dest = PORT_ArenaZNew(arena, CERTOCSPCertID);
1812     if (!dest)
1813         goto loser;
1814 
1815 #define DUPHELP(element)                                          \
1816     if (src->element.data &&                                      \
1817         SECITEM_CopyItem(arena, &dest->element, &src->element) != \
1818             SECSuccess) {                                         \
1819         goto loser;                                               \
1820     }
1821 
1822     DUPHELP(hashAlgorithm.algorithm)
1823     DUPHELP(hashAlgorithm.parameters)
1824     DUPHELP(issuerNameHash)
1825     DUPHELP(issuerKeyHash)
1826     DUPHELP(serialNumber)
1827     DUPHELP(issuerSHA1NameHash)
1828     DUPHELP(issuerMD5NameHash)
1829     DUPHELP(issuerMD2NameHash)
1830     DUPHELP(issuerSHA1KeyHash)
1831     DUPHELP(issuerMD5KeyHash)
1832     DUPHELP(issuerMD2KeyHash)
1833 
1834     dest->poolp = arena;
1835     return dest;
1836 
1837 loser:
1838     if (arena)
1839         PORT_FreeArena(arena, PR_FALSE);
1840     PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
1841     return NULL;
1842 }
1843 
1844 /*
1845  * Callback to set Extensions in request object
1846  */
1847 void
SetSingleReqExts(void * object,CERTCertExtension ** exts)1848 SetSingleReqExts(void *object, CERTCertExtension **exts)
1849 {
1850     ocspSingleRequest *singleRequest =
1851         (ocspSingleRequest *)object;
1852 
1853     singleRequest->singleRequestExtensions = exts;
1854 }
1855 
1856 /*
1857  * Add the Service Locator extension to the singleRequestExtensions
1858  * for the given singleRequest.
1859  *
1860  * All errors are internal or low-level problems (e.g. no memory).
1861  */
1862 static SECStatus
ocsp_AddServiceLocatorExtension(ocspSingleRequest * singleRequest,CERTCertificate * cert)1863 ocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest,
1864                                 CERTCertificate *cert)
1865 {
1866     ocspServiceLocator *serviceLocator = NULL;
1867     void *extensionHandle = NULL;
1868     SECStatus rv = SECFailure;
1869 
1870     serviceLocator = PORT_ZNew(ocspServiceLocator);
1871     if (serviceLocator == NULL)
1872         goto loser;
1873 
1874     /*
1875      * Normally it would be a bad idea to do a direct reference like
1876      * this rather than allocate and copy the name *or* at least dup
1877      * a reference of the cert.  But all we need is to be able to read
1878      * the issuer name during the encoding we are about to do, so a
1879      * copy is just a waste of time.
1880      */
1881     serviceLocator->issuer = &cert->issuer;
1882 
1883     rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
1884                                 &serviceLocator->locator);
1885     if (rv != SECSuccess) {
1886         if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
1887             goto loser;
1888     }
1889 
1890     /* prepare for following loser gotos */
1891     rv = SECFailure;
1892     PORT_SetError(0);
1893 
1894     extensionHandle = cert_StartExtensions(singleRequest,
1895                                            singleRequest->arena, SetSingleReqExts);
1896     if (extensionHandle == NULL)
1897         goto loser;
1898 
1899     rv = CERT_EncodeAndAddExtension(extensionHandle,
1900                                     SEC_OID_PKIX_OCSP_SERVICE_LOCATOR,
1901                                     serviceLocator, PR_FALSE,
1902                                     ocsp_ServiceLocatorTemplate);
1903 
1904 loser:
1905     if (extensionHandle != NULL) {
1906         /*
1907 	 * Either way we have to finish out the extension context (so it gets
1908 	 * freed).  But careful not to override any already-set bad status.
1909 	 */
1910         SECStatus tmprv = CERT_FinishExtensions(extensionHandle);
1911         if (rv == SECSuccess)
1912             rv = tmprv;
1913     }
1914 
1915     /*
1916      * Finally, free the serviceLocator structure itself and we are done.
1917      */
1918     if (serviceLocator != NULL) {
1919         if (serviceLocator->locator.data != NULL)
1920             SECITEM_FreeItem(&serviceLocator->locator, PR_FALSE);
1921         PORT_Free(serviceLocator);
1922     }
1923 
1924     return rv;
1925 }
1926 
1927 /*
1928  * Creates an array of ocspSingleRequest based on a list of certs.
1929  * Note that the code which later compares the request list with the
1930  * response expects this array to be in the exact same order as the
1931  * certs are found in the list.  It would be harder to change that
1932  * order than preserve it, but since the requirement is not obvious,
1933  * it deserves to be mentioned.
1934  *
1935  * Any problem causes a null return and error set:
1936  *      SEC_ERROR_UNKNOWN_ISSUER
1937  * Other errors are low-level problems (no memory, bad database, etc.).
1938  */
1939 static ocspSingleRequest **
ocsp_CreateSingleRequestList(PLArenaPool * arena,CERTCertList * certList,PRTime time,PRBool includeLocator)1940 ocsp_CreateSingleRequestList(PLArenaPool *arena, CERTCertList *certList,
1941                              PRTime time, PRBool includeLocator)
1942 {
1943     ocspSingleRequest **requestList = NULL;
1944     CERTCertListNode *node = NULL;
1945     int i, count;
1946     void *mark = PORT_ArenaMark(arena);
1947 
1948     node = CERT_LIST_HEAD(certList);
1949     for (count = 0; !CERT_LIST_END(node, certList); count++) {
1950         node = CERT_LIST_NEXT(node);
1951     }
1952 
1953     if (count == 0)
1954         goto loser;
1955 
1956     requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, count + 1);
1957     if (requestList == NULL)
1958         goto loser;
1959 
1960     node = CERT_LIST_HEAD(certList);
1961     for (i = 0; !CERT_LIST_END(node, certList); i++) {
1962         requestList[i] = PORT_ArenaZNew(arena, ocspSingleRequest);
1963         if (requestList[i] == NULL)
1964             goto loser;
1965 
1966         OCSP_TRACE(("OCSP CERT_CreateOCSPRequest %s\n", node->cert->subjectName));
1967         requestList[i]->arena = arena;
1968         requestList[i]->reqCert = ocsp_CreateCertID(arena, node->cert, time);
1969         if (requestList[i]->reqCert == NULL)
1970             goto loser;
1971 
1972         if (includeLocator == PR_TRUE) {
1973             SECStatus rv;
1974 
1975             rv = ocsp_AddServiceLocatorExtension(requestList[i], node->cert);
1976             if (rv != SECSuccess)
1977                 goto loser;
1978         }
1979 
1980         node = CERT_LIST_NEXT(node);
1981     }
1982 
1983     PORT_Assert(i == count);
1984 
1985     PORT_ArenaUnmark(arena, mark);
1986     requestList[i] = NULL;
1987     return requestList;
1988 
1989 loser:
1990     PORT_ArenaRelease(arena, mark);
1991     return NULL;
1992 }
1993 
1994 static ocspSingleRequest **
ocsp_CreateRequestFromCert(PLArenaPool * arena,CERTOCSPCertID * certID,CERTCertificate * singleCert,PRTime time,PRBool includeLocator)1995 ocsp_CreateRequestFromCert(PLArenaPool *arena,
1996                            CERTOCSPCertID *certID,
1997                            CERTCertificate *singleCert,
1998                            PRTime time,
1999                            PRBool includeLocator)
2000 {
2001     ocspSingleRequest **requestList = NULL;
2002     void *mark = PORT_ArenaMark(arena);
2003     PORT_Assert(certID != NULL && singleCert != NULL);
2004 
2005     /* meaning of value 2: one entry + one end marker */
2006     requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, 2);
2007     if (requestList == NULL)
2008         goto loser;
2009     requestList[0] = PORT_ArenaZNew(arena, ocspSingleRequest);
2010     if (requestList[0] == NULL)
2011         goto loser;
2012     requestList[0]->arena = arena;
2013     /* certID will live longer than the request */
2014     requestList[0]->reqCert = certID;
2015 
2016     if (includeLocator == PR_TRUE) {
2017         SECStatus rv;
2018         rv = ocsp_AddServiceLocatorExtension(requestList[0], singleCert);
2019         if (rv != SECSuccess)
2020             goto loser;
2021     }
2022 
2023     PORT_ArenaUnmark(arena, mark);
2024     requestList[1] = NULL;
2025     return requestList;
2026 
2027 loser:
2028     PORT_ArenaRelease(arena, mark);
2029     return NULL;
2030 }
2031 
2032 static CERTOCSPRequest *
ocsp_prepareEmptyOCSPRequest(void)2033 ocsp_prepareEmptyOCSPRequest(void)
2034 {
2035     PLArenaPool *arena = NULL;
2036     CERTOCSPRequest *request = NULL;
2037     ocspTBSRequest *tbsRequest = NULL;
2038 
2039     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2040     if (arena == NULL) {
2041         goto loser;
2042     }
2043     request = PORT_ArenaZNew(arena, CERTOCSPRequest);
2044     if (request == NULL) {
2045         goto loser;
2046     }
2047     request->arena = arena;
2048 
2049     tbsRequest = PORT_ArenaZNew(arena, ocspTBSRequest);
2050     if (tbsRequest == NULL) {
2051         goto loser;
2052     }
2053     request->tbsRequest = tbsRequest;
2054     /* version 1 is the default, so we need not fill in a version number */
2055     return request;
2056 
2057 loser:
2058     if (arena != NULL) {
2059         PORT_FreeArena(arena, PR_FALSE);
2060     }
2061     return NULL;
2062 }
2063 
2064 CERTOCSPRequest *
cert_CreateSingleCertOCSPRequest(CERTOCSPCertID * certID,CERTCertificate * singleCert,PRTime time,PRBool addServiceLocator,CERTCertificate * signerCert)2065 cert_CreateSingleCertOCSPRequest(CERTOCSPCertID *certID,
2066                                  CERTCertificate *singleCert,
2067                                  PRTime time,
2068                                  PRBool addServiceLocator,
2069                                  CERTCertificate *signerCert)
2070 {
2071     CERTOCSPRequest *request;
2072     OCSP_TRACE(("OCSP cert_CreateSingleCertOCSPRequest %s\n", singleCert->subjectName));
2073 
2074     /* XXX Support for signerCert may be implemented later,
2075      * see also the comment in CERT_CreateOCSPRequest.
2076      */
2077     if (signerCert != NULL) {
2078         PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
2079         return NULL;
2080     }
2081 
2082     request = ocsp_prepareEmptyOCSPRequest();
2083     if (!request)
2084         return NULL;
2085     /*
2086      * Version 1 is the default, so we need not fill in a version number.
2087      * Now create the list of single requests, one for each cert.
2088      */
2089     request->tbsRequest->requestList =
2090         ocsp_CreateRequestFromCert(request->arena,
2091                                    certID,
2092                                    singleCert,
2093                                    time,
2094                                    addServiceLocator);
2095     if (request->tbsRequest->requestList == NULL) {
2096         PORT_FreeArena(request->arena, PR_FALSE);
2097         return NULL;
2098     }
2099     return request;
2100 }
2101 
2102 /*
2103  * FUNCTION: CERT_CreateOCSPRequest
2104  *   Creates a CERTOCSPRequest, requesting the status of the certs in
2105  *   the given list.
2106  * INPUTS:
2107  *   CERTCertList *certList
2108  *     A list of certs for which status will be requested.
2109  *     Note that all of these certificates should have the same issuer,
2110  *     or it's expected the response will be signed by a trusted responder.
2111  *     If the certs need to be broken up into multiple requests, that
2112  *     must be handled by the caller (and thus by having multiple calls
2113  *     to this routine), who knows about where the request(s) are being
2114  *     sent and whether there are any trusted responders in place.
2115  *   PRTime time
2116  *     Indicates the time for which the certificate status is to be
2117  *     determined -- this may be used in the search for the cert's issuer
2118  *     but has no effect on the request itself.
2119  *   PRBool addServiceLocator
2120  *     If true, the Service Locator extension should be added to the
2121  *     single request(s) for each cert.
2122  *   CERTCertificate *signerCert
2123  *     If non-NULL, means sign the request using this cert.  Otherwise,
2124  *     do not sign.
2125  *     XXX note that request signing is not yet supported; see comment in code
2126  * RETURN:
2127  *   A pointer to a CERTOCSPRequest structure containing an OCSP request
2128  *   for the cert list.  On error, null is returned, with an error set
2129  *   indicating the reason.  This is likely SEC_ERROR_UNKNOWN_ISSUER.
2130  *   (The issuer is needed to create a request for the certificate.)
2131  *   Other errors are low-level problems (no memory, bad database, etc.).
2132  */
2133 CERTOCSPRequest *
CERT_CreateOCSPRequest(CERTCertList * certList,PRTime time,PRBool addServiceLocator,CERTCertificate * signerCert)2134 CERT_CreateOCSPRequest(CERTCertList *certList, PRTime time,
2135                        PRBool addServiceLocator,
2136                        CERTCertificate *signerCert)
2137 {
2138     CERTOCSPRequest *request = NULL;
2139 
2140     if (!certList) {
2141         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2142         return NULL;
2143     }
2144     /*
2145      * XXX When we are prepared to put signing of requests back in,
2146      * we will need to allocate a signature
2147      * structure for the request, fill in the "derCerts" field in it,
2148      * save the signerCert there, as well as fill in the "requestorName"
2149      * field of the tbsRequest.
2150      */
2151     if (signerCert != NULL) {
2152         PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
2153         return NULL;
2154     }
2155     request = ocsp_prepareEmptyOCSPRequest();
2156     if (!request)
2157         return NULL;
2158     /*
2159      * Now create the list of single requests, one for each cert.
2160      */
2161     request->tbsRequest->requestList =
2162         ocsp_CreateSingleRequestList(request->arena,
2163                                      certList,
2164                                      time,
2165                                      addServiceLocator);
2166     if (request->tbsRequest->requestList == NULL) {
2167         PORT_FreeArena(request->arena, PR_FALSE);
2168         return NULL;
2169     }
2170     return request;
2171 }
2172 
2173 /*
2174  * FUNCTION: CERT_AddOCSPAcceptableResponses
2175  *   Add the AcceptableResponses extension to an OCSP Request.
2176  * INPUTS:
2177  *   CERTOCSPRequest *request
2178  *     The request to which the extension should be added.
2179  *   ...
2180  *     A list (of one or more) of SECOidTag -- each of the response types
2181  *     to be added.  The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE.
2182  *     (This marks the end of the list, and it must be specified because a
2183  *     client conforming to the OCSP standard is required to handle the basic
2184  *     response type.)  The OIDs are not checked in any way.
2185  * RETURN:
2186  *   SECSuccess if the extension is added; SECFailure if anything goes wrong.
2187  *   All errors are internal or low-level problems (e.g. no memory).
2188  */
2189 
2190 void
SetRequestExts(void * object,CERTCertExtension ** exts)2191 SetRequestExts(void *object, CERTCertExtension **exts)
2192 {
2193     CERTOCSPRequest *request = (CERTOCSPRequest *)object;
2194 
2195     request->tbsRequest->requestExtensions = exts;
2196 }
2197 
2198 #if defined(__GNUC__) && !defined(NSS_NO_GCC48)
2199 #pragma GCC diagnostic push
2200 #pragma GCC diagnostic ignored "-Wvarargs"
2201 #endif
2202 SECStatus
CERT_AddOCSPAcceptableResponses(CERTOCSPRequest * request,SECOidTag responseType0,...)2203 CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request,
2204                                 SECOidTag responseType0, ...)
2205 {
2206     void *extHandle;
2207     va_list ap;
2208     int i, count;
2209     SECOidTag responseType;
2210     SECOidData *responseOid;
2211     SECItem **acceptableResponses = NULL;
2212     SECStatus rv = SECFailure;
2213 
2214     extHandle = request->tbsRequest->extensionHandle;
2215     if (extHandle == NULL) {
2216         extHandle = cert_StartExtensions(request, request->arena, SetRequestExts);
2217         if (extHandle == NULL)
2218             goto loser;
2219     }
2220 
2221     /* Count number of OIDS going into the extension value. */
2222     count = 1;
2223     if (responseType0 != SEC_OID_PKIX_OCSP_BASIC_RESPONSE) {
2224         va_start(ap, responseType0);
2225         do {
2226             count++;
2227             responseType = va_arg(ap, SECOidTag);
2228         } while (responseType != SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
2229         va_end(ap);
2230     }
2231 
2232     acceptableResponses = PORT_NewArray(SECItem *, count + 1);
2233     if (acceptableResponses == NULL)
2234         goto loser;
2235 
2236     i = 0;
2237     responseOid = SECOID_FindOIDByTag(responseType0);
2238     acceptableResponses[i++] = &(responseOid->oid);
2239     if (count > 1) {
2240         va_start(ap, responseType0);
2241         for (; i < count; i++) {
2242             responseType = va_arg(ap, SECOidTag);
2243             responseOid = SECOID_FindOIDByTag(responseType);
2244             acceptableResponses[i] = &(responseOid->oid);
2245         }
2246         va_end(ap);
2247     }
2248     acceptableResponses[i] = NULL;
2249 
2250     rv = CERT_EncodeAndAddExtension(extHandle, SEC_OID_PKIX_OCSP_RESPONSE,
2251                                     &acceptableResponses, PR_FALSE,
2252                                     SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate));
2253     if (rv != SECSuccess)
2254         goto loser;
2255 
2256     PORT_Free(acceptableResponses);
2257     if (request->tbsRequest->extensionHandle == NULL)
2258         request->tbsRequest->extensionHandle = extHandle;
2259     return SECSuccess;
2260 
2261 loser:
2262     if (acceptableResponses != NULL)
2263         PORT_Free(acceptableResponses);
2264     if (extHandle != NULL)
2265         (void)CERT_FinishExtensions(extHandle);
2266     return rv;
2267 }
2268 #if defined(__GNUC__) && !defined(NSS_NO_GCC48)
2269 #pragma GCC diagnostic pop
2270 #endif
2271 
2272 /*
2273  * FUNCTION: CERT_DestroyOCSPRequest
2274  *   Frees an OCSP Request structure.
2275  * INPUTS:
2276  *   CERTOCSPRequest *request
2277  *     Pointer to CERTOCSPRequest to be freed.
2278  * RETURN:
2279  *   No return value; no errors.
2280  */
2281 void
CERT_DestroyOCSPRequest(CERTOCSPRequest * request)2282 CERT_DestroyOCSPRequest(CERTOCSPRequest *request)
2283 {
2284     if (request == NULL)
2285         return;
2286 
2287     if (request->tbsRequest != NULL) {
2288         if (request->tbsRequest->requestorName != NULL)
2289             CERT_DestroyGeneralNameList(request->tbsRequest->requestorName);
2290         if (request->tbsRequest->extensionHandle != NULL)
2291             (void)CERT_FinishExtensions(request->tbsRequest->extensionHandle);
2292     }
2293 
2294     if (request->optionalSignature != NULL) {
2295         if (request->optionalSignature->cert != NULL)
2296             CERT_DestroyCertificate(request->optionalSignature->cert);
2297 
2298         /*
2299 	 * XXX Need to free derCerts?  Or do they come out of arena?
2300 	 * (Currently we never fill in derCerts, which is why the
2301 	 * answer is not obvious.  Once we do, add any necessary code
2302 	 * here and remove this comment.)
2303 	 */
2304     }
2305 
2306     /*
2307      * We should actually never have a request without an arena,
2308      * but check just in case.  (If there isn't one, there is not
2309      * much we can do about it...)
2310      */
2311     PORT_Assert(request->arena != NULL);
2312     if (request->arena != NULL)
2313         PORT_FreeArena(request->arena, PR_FALSE);
2314 }
2315 
2316 /*
2317  * RESPONSE SUPPORT FUNCTIONS (encode/create/decode/destroy):
2318  */
2319 
2320 /*
2321  * Helper function for encoding or decoding a ResponderID -- based on the
2322  * given type, return the associated template for that choice.
2323  */
2324 static const SEC_ASN1Template *
ocsp_ResponderIDTemplateByType(CERTOCSPResponderIDType responderIDType)2325 ocsp_ResponderIDTemplateByType(CERTOCSPResponderIDType responderIDType)
2326 {
2327     const SEC_ASN1Template *responderIDTemplate;
2328 
2329     switch (responderIDType) {
2330         case ocspResponderID_byName:
2331             responderIDTemplate = ocsp_ResponderIDByNameTemplate;
2332             break;
2333         case ocspResponderID_byKey:
2334             responderIDTemplate = ocsp_ResponderIDByKeyTemplate;
2335             break;
2336         case ocspResponderID_other:
2337         default:
2338             PORT_Assert(responderIDType == ocspResponderID_other);
2339             responderIDTemplate = ocsp_ResponderIDOtherTemplate;
2340             break;
2341     }
2342 
2343     return responderIDTemplate;
2344 }
2345 
2346 /*
2347  * Helper function for encoding or decoding a CertStatus -- based on the
2348  * given type, return the associated template for that choice.
2349  */
2350 static const SEC_ASN1Template *
ocsp_CertStatusTemplateByType(ocspCertStatusType certStatusType)2351 ocsp_CertStatusTemplateByType(ocspCertStatusType certStatusType)
2352 {
2353     const SEC_ASN1Template *certStatusTemplate;
2354 
2355     switch (certStatusType) {
2356         case ocspCertStatus_good:
2357             certStatusTemplate = ocsp_CertStatusGoodTemplate;
2358             break;
2359         case ocspCertStatus_revoked:
2360             certStatusTemplate = ocsp_CertStatusRevokedTemplate;
2361             break;
2362         case ocspCertStatus_unknown:
2363             certStatusTemplate = ocsp_CertStatusUnknownTemplate;
2364             break;
2365         case ocspCertStatus_other:
2366         default:
2367             PORT_Assert(certStatusType == ocspCertStatus_other);
2368             certStatusTemplate = ocsp_CertStatusOtherTemplate;
2369             break;
2370     }
2371 
2372     return certStatusTemplate;
2373 }
2374 
2375 /*
2376  * Helper function for decoding a certStatus -- turn the actual DER tag
2377  * into our local translation.
2378  */
2379 static ocspCertStatusType
ocsp_CertStatusTypeByTag(int derTag)2380 ocsp_CertStatusTypeByTag(int derTag)
2381 {
2382     ocspCertStatusType certStatusType;
2383 
2384     switch (derTag) {
2385         case 0:
2386             certStatusType = ocspCertStatus_good;
2387             break;
2388         case 1:
2389             certStatusType = ocspCertStatus_revoked;
2390             break;
2391         case 2:
2392             certStatusType = ocspCertStatus_unknown;
2393             break;
2394         default:
2395             certStatusType = ocspCertStatus_other;
2396             break;
2397     }
2398 
2399     return certStatusType;
2400 }
2401 
2402 /*
2403  * Helper function for decoding SingleResponses -- they each contain
2404  * a status which is encoded as CHOICE, which needs to be decoded "by hand".
2405  *
2406  * Note -- on error, this routine does not release the memory it may
2407  * have allocated; it expects its caller to do that.
2408  */
2409 static SECStatus
ocsp_FinishDecodingSingleResponses(PLArenaPool * reqArena,CERTOCSPSingleResponse ** responses)2410 ocsp_FinishDecodingSingleResponses(PLArenaPool *reqArena,
2411                                    CERTOCSPSingleResponse **responses)
2412 {
2413     ocspCertStatus *certStatus;
2414     ocspCertStatusType certStatusType;
2415     const SEC_ASN1Template *certStatusTemplate;
2416     int derTag;
2417     int i;
2418     SECStatus rv = SECFailure;
2419 
2420     if (!reqArena) {
2421         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2422         return SECFailure;
2423     }
2424 
2425     if (responses == NULL) /* nothing to do */
2426         return SECSuccess;
2427 
2428     for (i = 0; responses[i] != NULL; i++) {
2429         SECItem *newStatus;
2430         /*
2431 	 * The following assert points out internal errors (problems in
2432 	 * the template definitions or in the ASN.1 decoder itself, etc.).
2433 	 */
2434         PORT_Assert(responses[i]->derCertStatus.data != NULL);
2435 
2436         derTag = responses[i]->derCertStatus.data[0] & SEC_ASN1_TAGNUM_MASK;
2437         certStatusType = ocsp_CertStatusTypeByTag(derTag);
2438         certStatusTemplate = ocsp_CertStatusTemplateByType(certStatusType);
2439 
2440         certStatus = PORT_ArenaZAlloc(reqArena, sizeof(ocspCertStatus));
2441         if (certStatus == NULL) {
2442             goto loser;
2443         }
2444         newStatus = SECITEM_ArenaDupItem(reqArena, &responses[i]->derCertStatus);
2445         if (!newStatus) {
2446             goto loser;
2447         }
2448         rv = SEC_QuickDERDecodeItem(reqArena, certStatus, certStatusTemplate,
2449                                     newStatus);
2450         if (rv != SECSuccess) {
2451             if (PORT_GetError() == SEC_ERROR_BAD_DER)
2452                 PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
2453             goto loser;
2454         }
2455 
2456         certStatus->certStatusType = certStatusType;
2457         responses[i]->certStatus = certStatus;
2458     }
2459 
2460     return SECSuccess;
2461 
2462 loser:
2463     return rv;
2464 }
2465 
2466 /*
2467  * Helper function for decoding a responderID -- turn the actual DER tag
2468  * into our local translation.
2469  */
2470 static CERTOCSPResponderIDType
ocsp_ResponderIDTypeByTag(int derTag)2471 ocsp_ResponderIDTypeByTag(int derTag)
2472 {
2473     CERTOCSPResponderIDType responderIDType;
2474 
2475     switch (derTag) {
2476         case 1:
2477             responderIDType = ocspResponderID_byName;
2478             break;
2479         case 2:
2480             responderIDType = ocspResponderID_byKey;
2481             break;
2482         default:
2483             responderIDType = ocspResponderID_other;
2484             break;
2485     }
2486 
2487     return responderIDType;
2488 }
2489 
2490 /*
2491  * Decode "src" as a BasicOCSPResponse, returning the result.
2492  */
2493 static ocspBasicOCSPResponse *
ocsp_DecodeBasicOCSPResponse(PLArenaPool * arena,SECItem * src)2494 ocsp_DecodeBasicOCSPResponse(PLArenaPool *arena, SECItem *src)
2495 {
2496     void *mark;
2497     ocspBasicOCSPResponse *basicResponse;
2498     ocspResponseData *responseData;
2499     ocspResponderID *responderID;
2500     CERTOCSPResponderIDType responderIDType;
2501     const SEC_ASN1Template *responderIDTemplate;
2502     int derTag;
2503     SECStatus rv;
2504     SECItem newsrc;
2505 
2506     mark = PORT_ArenaMark(arena);
2507 
2508     basicResponse = PORT_ArenaZAlloc(arena, sizeof(ocspBasicOCSPResponse));
2509     if (basicResponse == NULL) {
2510         goto loser;
2511     }
2512 
2513     /* copy the DER into the arena, since Quick DER returns data that points
2514        into the DER input, which may get freed by the caller */
2515     rv = SECITEM_CopyItem(arena, &newsrc, src);
2516     if (rv != SECSuccess) {
2517         goto loser;
2518     }
2519 
2520     rv = SEC_QuickDERDecodeItem(arena, basicResponse,
2521                                 ocsp_BasicOCSPResponseTemplate, &newsrc);
2522     if (rv != SECSuccess) {
2523         if (PORT_GetError() == SEC_ERROR_BAD_DER)
2524             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
2525         goto loser;
2526     }
2527 
2528     responseData = basicResponse->tbsResponseData;
2529 
2530     /*
2531      * The following asserts point out internal errors (problems in
2532      * the template definitions or in the ASN.1 decoder itself, etc.).
2533      */
2534     PORT_Assert(responseData != NULL);
2535     PORT_Assert(responseData->derResponderID.data != NULL);
2536 
2537     /*
2538      * XXX Because responderID is a CHOICE, which is not currently handled
2539      * by our ASN.1 decoder, we have to decode it "by hand".
2540      */
2541     derTag = responseData->derResponderID.data[0] & SEC_ASN1_TAGNUM_MASK;
2542     responderIDType = ocsp_ResponderIDTypeByTag(derTag);
2543     responderIDTemplate = ocsp_ResponderIDTemplateByType(responderIDType);
2544 
2545     responderID = PORT_ArenaZAlloc(arena, sizeof(ocspResponderID));
2546     if (responderID == NULL) {
2547         goto loser;
2548     }
2549 
2550     rv = SEC_QuickDERDecodeItem(arena, responderID, responderIDTemplate,
2551                                 &responseData->derResponderID);
2552     if (rv != SECSuccess) {
2553         if (PORT_GetError() == SEC_ERROR_BAD_DER)
2554             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
2555         goto loser;
2556     }
2557 
2558     responderID->responderIDType = responderIDType;
2559     responseData->responderID = responderID;
2560 
2561     /*
2562      * XXX Each SingleResponse also contains a CHOICE, which has to be
2563      * fixed up by hand.
2564      */
2565     rv = ocsp_FinishDecodingSingleResponses(arena, responseData->responses);
2566     if (rv != SECSuccess) {
2567         goto loser;
2568     }
2569 
2570     PORT_ArenaUnmark(arena, mark);
2571     return basicResponse;
2572 
2573 loser:
2574     PORT_ArenaRelease(arena, mark);
2575     return NULL;
2576 }
2577 
2578 /*
2579  * Decode the responseBytes based on the responseType found in "rbytes",
2580  * leaving the resulting translated/decoded information in there as well.
2581  */
2582 static SECStatus
ocsp_DecodeResponseBytes(PLArenaPool * arena,ocspResponseBytes * rbytes)2583 ocsp_DecodeResponseBytes(PLArenaPool *arena, ocspResponseBytes *rbytes)
2584 {
2585     if (rbytes == NULL) {
2586         PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE);
2587         return SECFailure;
2588     }
2589 
2590     rbytes->responseTypeTag = SECOID_FindOIDTag(&rbytes->responseType);
2591     switch (rbytes->responseTypeTag) {
2592         case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: {
2593             ocspBasicOCSPResponse *basicResponse;
2594 
2595             basicResponse = ocsp_DecodeBasicOCSPResponse(arena,
2596                                                          &rbytes->response);
2597             if (basicResponse == NULL)
2598                 return SECFailure;
2599 
2600             rbytes->decodedResponse.basic = basicResponse;
2601         } break;
2602 
2603         /*
2604 	 * Add new/future response types here.
2605 	 */
2606 
2607         default:
2608             PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE);
2609             return SECFailure;
2610     }
2611 
2612     return SECSuccess;
2613 }
2614 
2615 /*
2616  * FUNCTION: CERT_DecodeOCSPResponse
2617  *   Decode a DER encoded OCSP Response.
2618  * INPUTS:
2619  *   SECItem *src
2620  *     Pointer to a SECItem holding DER encoded OCSP Response.
2621  * RETURN:
2622  *   Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response);
2623  *   the caller is responsible for destroying it.  Or NULL if error (either
2624  *   response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE),
2625  *   it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE),
2626  *   or a low-level or internal error occurred).
2627  */
2628 CERTOCSPResponse *
CERT_DecodeOCSPResponse(const SECItem * src)2629 CERT_DecodeOCSPResponse(const SECItem *src)
2630 {
2631     PLArenaPool *arena = NULL;
2632     CERTOCSPResponse *response = NULL;
2633     SECStatus rv = SECFailure;
2634     ocspResponseStatus sv;
2635     SECItem newSrc;
2636 
2637     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2638     if (arena == NULL) {
2639         goto loser;
2640     }
2641     response = (CERTOCSPResponse *)PORT_ArenaZAlloc(arena,
2642                                                     sizeof(CERTOCSPResponse));
2643     if (response == NULL) {
2644         goto loser;
2645     }
2646     response->arena = arena;
2647 
2648     /* copy the DER into the arena, since Quick DER returns data that points
2649        into the DER input, which may get freed by the caller */
2650     rv = SECITEM_CopyItem(arena, &newSrc, src);
2651     if (rv != SECSuccess) {
2652         goto loser;
2653     }
2654 
2655     rv = SEC_QuickDERDecodeItem(arena, response, ocsp_OCSPResponseTemplate, &newSrc);
2656     if (rv != SECSuccess) {
2657         if (PORT_GetError() == SEC_ERROR_BAD_DER)
2658             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
2659         goto loser;
2660     }
2661 
2662     sv = (ocspResponseStatus)DER_GetInteger(&response->responseStatus);
2663     response->statusValue = sv;
2664     if (sv != ocspResponse_successful) {
2665         /*
2666 	 * If the response status is anything but successful, then we
2667 	 * are all done with decoding; the status is all there is.
2668 	 */
2669         return response;
2670     }
2671 
2672     /*
2673      * A successful response contains much more information, still encoded.
2674      * Now we need to decode that.
2675      */
2676     rv = ocsp_DecodeResponseBytes(arena, response->responseBytes);
2677     if (rv != SECSuccess) {
2678         goto loser;
2679     }
2680 
2681     return response;
2682 
2683 loser:
2684     if (arena != NULL) {
2685         PORT_FreeArena(arena, PR_FALSE);
2686     }
2687     return NULL;
2688 }
2689 
2690 /*
2691  * The way an OCSPResponse is defined, there are many levels to descend
2692  * before getting to the actual response information.  And along the way
2693  * we need to check that the response *type* is recognizable, which for
2694  * now means that it is a BasicOCSPResponse, because that is the only
2695  * type currently defined.  Rather than force all routines to perform
2696  * a bunch of sanity checking every time they want to work on a response,
2697  * this function isolates that and gives back the interesting part.
2698  * Note that no copying is done, this just returns a pointer into the
2699  * substructure of the response which is passed in.
2700  *
2701  * XXX This routine only works when a valid response structure is passed
2702  * into it; this is checked with many assertions.  Assuming the response
2703  * was creating by decoding, it wouldn't make it this far without being
2704  * okay.  That is a sufficient assumption since the entire OCSP interface
2705  * is only used internally.  When this interface is officially exported,
2706  * each assertion below will need to be followed-up with setting an error
2707  * and returning (null).
2708  *
2709  * FUNCTION: ocsp_GetResponseData
2710  *   Returns ocspResponseData structure and a pointer to tbs response
2711  *   data DER from a valid ocsp response.
2712  * INPUTS:
2713  *   CERTOCSPResponse *response
2714  *     structure of a valid ocsp response
2715  * RETURN:
2716  *   Returns a pointer to ocspResponseData structure: decoded OCSP response
2717  *   data, and a pointer(tbsResponseDataDER) to its undecoded data DER.
2718  */
2719 ocspResponseData *
ocsp_GetResponseData(CERTOCSPResponse * response,SECItem ** tbsResponseDataDER)2720 ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER)
2721 {
2722     ocspBasicOCSPResponse *basic;
2723     ocspResponseData *responseData;
2724 
2725     PORT_Assert(response != NULL);
2726 
2727     PORT_Assert(response->responseBytes != NULL);
2728 
2729     PORT_Assert(response->responseBytes->responseTypeTag ==
2730                 SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
2731 
2732     basic = response->responseBytes->decodedResponse.basic;
2733     PORT_Assert(basic != NULL);
2734 
2735     responseData = basic->tbsResponseData;
2736     PORT_Assert(responseData != NULL);
2737 
2738     if (tbsResponseDataDER) {
2739         *tbsResponseDataDER = &basic->tbsResponseDataDER;
2740 
2741         PORT_Assert((*tbsResponseDataDER)->data != NULL);
2742         PORT_Assert((*tbsResponseDataDER)->len != 0);
2743     }
2744 
2745     return responseData;
2746 }
2747 
2748 /*
2749  * Much like the routine above, except it returns the response signature.
2750  * Again, no copy is done.
2751  */
2752 ocspSignature *
ocsp_GetResponseSignature(CERTOCSPResponse * response)2753 ocsp_GetResponseSignature(CERTOCSPResponse *response)
2754 {
2755     ocspBasicOCSPResponse *basic;
2756 
2757     PORT_Assert(response != NULL);
2758     if (NULL == response->responseBytes) {
2759         return NULL;
2760     }
2761     if (response->responseBytes->responseTypeTag !=
2762         SEC_OID_PKIX_OCSP_BASIC_RESPONSE) {
2763         return NULL;
2764     }
2765     basic = response->responseBytes->decodedResponse.basic;
2766     PORT_Assert(basic != NULL);
2767 
2768     return &(basic->responseSignature);
2769 }
2770 
2771 /*
2772  * FUNCTION: CERT_DestroyOCSPResponse
2773  *   Frees an OCSP Response structure.
2774  * INPUTS:
2775  *   CERTOCSPResponse *request
2776  *     Pointer to CERTOCSPResponse to be freed.
2777  * RETURN:
2778  *   No return value; no errors.
2779  */
2780 void
CERT_DestroyOCSPResponse(CERTOCSPResponse * response)2781 CERT_DestroyOCSPResponse(CERTOCSPResponse *response)
2782 {
2783     if (response != NULL) {
2784         ocspSignature *signature = ocsp_GetResponseSignature(response);
2785         if (signature && signature->cert != NULL)
2786             CERT_DestroyCertificate(signature->cert);
2787 
2788         /*
2789 	 * We should actually never have a response without an arena,
2790 	 * but check just in case.  (If there isn't one, there is not
2791 	 * much we can do about it...)
2792 	 */
2793         PORT_Assert(response->arena != NULL);
2794         if (response->arena != NULL) {
2795             PORT_FreeArena(response->arena, PR_FALSE);
2796         }
2797     }
2798 }
2799 
2800 /*
2801  * OVERALL OCSP CLIENT SUPPORT (make and send a request, verify a response):
2802  */
2803 
2804 /*
2805  * Pick apart a URL, saving the important things in the passed-in pointers.
2806  *
2807  * We expect to find "http://<hostname>[:<port>]/[path]", though we will
2808  * tolerate that final slash character missing, as well as beginning and
2809  * trailing whitespace, and any-case-characters for "http".  All of that
2810  * tolerance is what complicates this routine.  What we want is just to
2811  * pick out the hostname, the port, and the path.
2812  *
2813  * On a successful return, the caller will need to free the output pieces
2814  * of hostname and path, which are copies of the values found in the url.
2815  */
2816 static SECStatus
ocsp_ParseURL(const char * url,char ** pHostname,PRUint16 * pPort,char ** pPath)2817 ocsp_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath)
2818 {
2819     unsigned short port = 80; /* default, in case not in url */
2820     char *hostname = NULL;
2821     char *path = NULL;
2822     const char *save;
2823     char c;
2824     int len;
2825 
2826     if (url == NULL)
2827         goto loser;
2828 
2829     /*
2830      * Skip beginning whitespace.
2831      */
2832     c = *url;
2833     while ((c == ' ' || c == '\t') && c != '\0') {
2834         url++;
2835         c = *url;
2836     }
2837     if (c == '\0')
2838         goto loser;
2839 
2840     /*
2841      * Confirm, then skip, protocol.  (Since we only know how to do http,
2842      * that is all we will accept).
2843      */
2844     if (PORT_Strncasecmp(url, "http://", 7) != 0)
2845         goto loser;
2846     url += 7;
2847 
2848     /*
2849      * Whatever comes next is the hostname (or host IP address).  We just
2850      * save it aside and then search for its end so we can determine its
2851      * length and copy it.
2852      *
2853      * XXX Note that because we treat a ':' as a terminator character
2854      * (and below, we expect that to mean there is a port specification
2855      * immediately following), we will not handle IPv6 addresses.  That is
2856      * apparently an acceptable limitation, for the time being.  Some day,
2857      * when there is a clear way to specify a URL with an IPv6 address that
2858      * can be parsed unambiguously, this code should be made to do that.
2859      */
2860     save = url;
2861     c = *url;
2862     while (c != '/' && c != ':' && c != '\0' && c != ' ' && c != '\t') {
2863         url++;
2864         c = *url;
2865     }
2866     len = url - save;
2867     hostname = PORT_Alloc(len + 1);
2868     if (hostname == NULL)
2869         goto loser;
2870     PORT_Memcpy(hostname, save, len);
2871     hostname[len] = '\0';
2872 
2873     /*
2874      * Now we figure out if there was a port specified or not.
2875      * If so, we need to parse it (as a number) and skip it.
2876      */
2877     if (c == ':') {
2878         url++;
2879         port = (unsigned short)PORT_Atoi(url);
2880         c = *url;
2881         while (c != '/' && c != '\0' && c != ' ' && c != '\t') {
2882             if (c < '0' || c > '9')
2883                 goto loser;
2884             url++;
2885             c = *url;
2886         }
2887     }
2888 
2889     /*
2890      * Last thing to find is a path.  There *should* be a slash,
2891      * if nothing else -- but if there is not we provide one.
2892      */
2893     if (c == '/') {
2894         save = url;
2895         while (c != '\0' && c != ' ' && c != '\t') {
2896             url++;
2897             c = *url;
2898         }
2899         len = url - save;
2900         path = PORT_Alloc(len + 1);
2901         if (path == NULL)
2902             goto loser;
2903         PORT_Memcpy(path, save, len);
2904         path[len] = '\0';
2905     } else {
2906         path = PORT_Strdup("/");
2907         if (path == NULL)
2908             goto loser;
2909     }
2910 
2911     *pHostname = hostname;
2912     *pPort = port;
2913     *pPath = path;
2914     return SECSuccess;
2915 
2916 loser:
2917     if (hostname != NULL)
2918         PORT_Free(hostname);
2919     PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
2920     return SECFailure;
2921 }
2922 
2923 /*
2924  * Open a socket to the specified host on the specified port, and return it.
2925  * The host is either a hostname or an IP address.
2926  */
2927 static PRFileDesc *
ocsp_ConnectToHost(const char * host,PRUint16 port)2928 ocsp_ConnectToHost(const char *host, PRUint16 port)
2929 {
2930     PRFileDesc *sock = NULL;
2931     PRIntervalTime timeout;
2932     PRNetAddr addr;
2933     char *netdbbuf = NULL;
2934 
2935     sock = PR_NewTCPSocket();
2936     if (sock == NULL)
2937         goto loser;
2938 
2939     /* XXX Some day need a way to set (and get?) the following value */
2940     timeout = PR_SecondsToInterval(30);
2941 
2942     /*
2943      * If the following converts an IP address string in "dot notation"
2944      * into a PRNetAddr.  If it fails, we assume that is because we do not
2945      * have such an address, but instead a host *name*.  In that case we
2946      * then lookup the host by name.  Using the NSPR function this way
2947      * means we do not have to have our own logic for distinguishing a
2948      * valid numerical IP address from a hostname.
2949      */
2950     if (PR_StringToNetAddr(host, &addr) != PR_SUCCESS) {
2951         PRIntn hostIndex;
2952         PRHostEnt hostEntry;
2953 
2954         netdbbuf = PORT_Alloc(PR_NETDB_BUF_SIZE);
2955         if (netdbbuf == NULL)
2956             goto loser;
2957 
2958         if (PR_GetHostByName(host, netdbbuf, PR_NETDB_BUF_SIZE,
2959                              &hostEntry) != PR_SUCCESS)
2960             goto loser;
2961 
2962         hostIndex = 0;
2963         do {
2964             hostIndex = PR_EnumerateHostEnt(hostIndex, &hostEntry, port, &addr);
2965             if (hostIndex <= 0)
2966                 goto loser;
2967         } while (PR_Connect(sock, &addr, timeout) != PR_SUCCESS);
2968 
2969         PORT_Free(netdbbuf);
2970     } else {
2971         /*
2972 	 * First put the port into the address, then connect.
2973 	 */
2974         if (PR_InitializeNetAddr(PR_IpAddrNull, port, &addr) != PR_SUCCESS)
2975             goto loser;
2976         if (PR_Connect(sock, &addr, timeout) != PR_SUCCESS)
2977             goto loser;
2978     }
2979 
2980     return sock;
2981 
2982 loser:
2983     if (sock != NULL)
2984         PR_Close(sock);
2985     if (netdbbuf != NULL)
2986         PORT_Free(netdbbuf);
2987     return NULL;
2988 }
2989 
2990 /*
2991  * Sends an encoded OCSP request to the server identified by "location",
2992  * and returns the socket on which it was sent (so can listen for the reply).
2993  * "location" is expected to be a valid URL -- an error parsing it produces
2994  * SEC_ERROR_CERT_BAD_ACCESS_LOCATION.  Other errors are likely problems
2995  * connecting to it, or writing to it, or allocating memory, and the low-level
2996  * errors appropriate to the problem will be set.
2997  * if (encodedRequest == NULL)
2998  *   then location MUST already include the full request,
2999  *        including base64 and urlencode,
3000  *        and the request will be sent with GET
3001  * if (encodedRequest != NULL)
3002  *   then the request will be sent with POST
3003  */
3004 static PRFileDesc *
ocsp_SendEncodedRequest(const char * location,const SECItem * encodedRequest)3005 ocsp_SendEncodedRequest(const char *location, const SECItem *encodedRequest)
3006 {
3007     char *hostname = NULL;
3008     char *path = NULL;
3009     PRUint16 port;
3010     SECStatus rv;
3011     PRFileDesc *sock = NULL;
3012     PRFileDesc *returnSock = NULL;
3013     char *header = NULL;
3014     char portstr[16];
3015 
3016     /*
3017      * Take apart the location, getting the hostname, port, and path.
3018      */
3019     rv = ocsp_ParseURL(location, &hostname, &port, &path);
3020     if (rv != SECSuccess)
3021         goto loser;
3022 
3023     PORT_Assert(hostname != NULL);
3024     PORT_Assert(path != NULL);
3025 
3026     sock = ocsp_ConnectToHost(hostname, port);
3027     if (sock == NULL)
3028         goto loser;
3029 
3030     portstr[0] = '\0';
3031     if (port != 80) {
3032         PR_snprintf(portstr, sizeof(portstr), ":%d", port);
3033     }
3034 
3035     if (!encodedRequest) {
3036         header = PR_smprintf("GET %s HTTP/1.0\r\n"
3037                              "Host: %s%s\r\n\r\n",
3038                              path, hostname, portstr);
3039         if (header == NULL)
3040             goto loser;
3041 
3042         /*
3043          * The NSPR documentation promises that if it can, it will write the full
3044          * amount; this will not return a partial value expecting us to loop.
3045          */
3046         if (PR_Write(sock, header, (PRInt32)PORT_Strlen(header)) < 0)
3047             goto loser;
3048     } else {
3049         header = PR_smprintf("POST %s HTTP/1.0\r\n"
3050                              "Host: %s%s\r\n"
3051                              "Content-Type: application/ocsp-request\r\n"
3052                              "Content-Length: %u\r\n\r\n",
3053                              path, hostname, portstr, encodedRequest->len);
3054         if (header == NULL)
3055             goto loser;
3056 
3057         /*
3058          * The NSPR documentation promises that if it can, it will write the full
3059          * amount; this will not return a partial value expecting us to loop.
3060          */
3061         if (PR_Write(sock, header, (PRInt32)PORT_Strlen(header)) < 0)
3062             goto loser;
3063 
3064         if (PR_Write(sock, encodedRequest->data,
3065                      (PRInt32)encodedRequest->len) < 0)
3066             goto loser;
3067     }
3068 
3069     returnSock = sock;
3070     sock = NULL;
3071 
3072 loser:
3073     if (header != NULL)
3074         PORT_Free(header);
3075     if (sock != NULL)
3076         PR_Close(sock);
3077     if (path != NULL)
3078         PORT_Free(path);
3079     if (hostname != NULL)
3080         PORT_Free(hostname);
3081 
3082     return returnSock;
3083 }
3084 
3085 /*
3086  * Read from "fd" into "buf" -- expect/attempt to read a given number of bytes
3087  * Obviously, stop if hit end-of-stream. Timeout is passed in.
3088  */
3089 
3090 static int
ocsp_read(PRFileDesc * fd,char * buf,int toread,PRIntervalTime timeout)3091 ocsp_read(PRFileDesc *fd, char *buf, int toread, PRIntervalTime timeout)
3092 {
3093     int total = 0;
3094 
3095     while (total < toread) {
3096         PRInt32 got;
3097 
3098         got = PR_Recv(fd, buf + total, (PRInt32)(toread - total), 0, timeout);
3099         if (got < 0) {
3100             if (0 == total) {
3101                 total = -1; /* report the error if we didn't read anything yet */
3102             }
3103             break;
3104         } else if (got == 0) { /* EOS */
3105             break;
3106         }
3107 
3108         total += got;
3109     }
3110 
3111     return total;
3112 }
3113 
3114 #define OCSP_BUFSIZE 1024
3115 
3116 #define AbortHttpDecode(error)   \
3117     {                            \
3118         if (inBuffer)            \
3119             PORT_Free(inBuffer); \
3120         PORT_SetError(error);    \
3121         return NULL;             \
3122     }
3123 
3124 /*
3125  * Reads on the given socket and returns an encoded response when received.
3126  * Properly formatted HTTP/1.0 response headers are expected to be read
3127  * from the socket, preceding a binary-encoded OCSP response.  Problems
3128  * with parsing cause the error SEC_ERROR_OCSP_BAD_HTTP_RESPONSE to be
3129  * set; any other problems are likely low-level i/o or memory allocation
3130  * errors.
3131  */
3132 static SECItem *
ocsp_GetEncodedResponse(PLArenaPool * arena,PRFileDesc * sock)3133 ocsp_GetEncodedResponse(PLArenaPool *arena, PRFileDesc *sock)
3134 {
3135     /* first read HTTP status line and headers */
3136 
3137     char *inBuffer = NULL;
3138     PRInt32 offset = 0;
3139     PRInt32 inBufsize = 0;
3140     const PRInt32 bufSizeIncrement = OCSP_BUFSIZE;   /* 1 KB at a time */
3141     const PRInt32 maxBufSize = 8 * bufSizeIncrement; /* 8 KB max */
3142     const char *CRLF = "\r\n";
3143     const PRInt32 CRLFlen = strlen(CRLF);
3144     const char *headerEndMark = "\r\n\r\n";
3145     const PRInt32 markLen = strlen(headerEndMark);
3146     const PRIntervalTime ocsptimeout =
3147         PR_SecondsToInterval(30); /* hardcoded to 30s for now */
3148     char *headerEnd = NULL;
3149     PRBool EOS = PR_FALSE;
3150     const char *httpprotocol = "HTTP/";
3151     const PRInt32 httplen = strlen(httpprotocol);
3152     const char *httpcode = NULL;
3153     const char *contenttype = NULL;
3154     PRInt32 contentlength = 0;
3155     PRInt32 bytesRead = 0;
3156     char *statusLineEnd = NULL;
3157     char *space = NULL;
3158     char *nextHeader = NULL;
3159     SECItem *result = NULL;
3160 
3161     /* read up to at least the end of the HTTP headers */
3162     do {
3163         inBufsize += bufSizeIncrement;
3164         inBuffer = PORT_Realloc(inBuffer, inBufsize + 1);
3165         if (NULL == inBuffer) {
3166             AbortHttpDecode(SEC_ERROR_NO_MEMORY);
3167         }
3168         bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement,
3169                               ocsptimeout);
3170         if (bytesRead > 0) {
3171             PRInt32 searchOffset = (offset - markLen) > 0 ? offset - markLen : 0;
3172             offset += bytesRead;
3173             *(inBuffer + offset) = '\0'; /* NULL termination */
3174             headerEnd = strstr((const char *)inBuffer + searchOffset, headerEndMark);
3175             if (bytesRead < bufSizeIncrement) {
3176                 /* we read less data than requested, therefore we are at
3177                    EOS or there was a read error */
3178                 EOS = PR_TRUE;
3179             }
3180         } else {
3181             /* recv error or EOS */
3182             EOS = PR_TRUE;
3183         }
3184     } while ((!headerEnd) && (PR_FALSE == EOS) &&
3185              (inBufsize < maxBufSize));
3186 
3187     if (!headerEnd) {
3188         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3189     }
3190 
3191     /* parse the HTTP status line  */
3192     statusLineEnd = strstr((const char *)inBuffer, CRLF);
3193     if (!statusLineEnd) {
3194         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3195     }
3196     *statusLineEnd = '\0';
3197 
3198     /* check for HTTP/ response */
3199     space = strchr((const char *)inBuffer, ' ');
3200     if (!space || PORT_Strncasecmp((const char *)inBuffer, httpprotocol, httplen) != 0) {
3201         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3202     }
3203 
3204     /* check the HTTP status code of 200 */
3205     httpcode = space + 1;
3206     space = strchr(httpcode, ' ');
3207     if (!space) {
3208         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3209     }
3210     *space = 0;
3211     if (0 != strcmp(httpcode, "200")) {
3212         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3213     }
3214 
3215     /* parse the HTTP headers in the buffer . We only care about
3216        content-type and content-length
3217     */
3218 
3219     nextHeader = statusLineEnd + CRLFlen;
3220     *headerEnd = '\0'; /* terminate */
3221     do {
3222         char *thisHeaderEnd = NULL;
3223         char *value = NULL;
3224         char *colon = strchr(nextHeader, ':');
3225 
3226         if (!colon) {
3227             AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3228         }
3229 
3230         *colon = '\0';
3231         value = colon + 1;
3232 
3233         /* jpierre - note : the following code will only handle the basic form
3234            of HTTP/1.0 response headers, of the form "name: value" . Headers
3235            split among multiple lines are not supported. This is not common
3236            and should not be an issue, but it could become one in the
3237            future */
3238 
3239         if (*value != ' ') {
3240             AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3241         }
3242 
3243         value++;
3244         thisHeaderEnd = strstr(value, CRLF);
3245         if (thisHeaderEnd) {
3246             *thisHeaderEnd = '\0';
3247         }
3248 
3249         if (0 == PORT_Strcasecmp(nextHeader, "content-type")) {
3250             contenttype = value;
3251         } else if (0 == PORT_Strcasecmp(nextHeader, "content-length")) {
3252             contentlength = atoi(value);
3253         }
3254 
3255         if (thisHeaderEnd) {
3256             nextHeader = thisHeaderEnd + CRLFlen;
3257         } else {
3258             nextHeader = NULL;
3259         }
3260 
3261     } while (nextHeader && (nextHeader < (headerEnd + CRLFlen)));
3262 
3263     /* check content-type */
3264     if (!contenttype ||
3265         (0 != PORT_Strcasecmp(contenttype, "application/ocsp-response"))) {
3266         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3267     }
3268 
3269     /* read the body of the OCSP response */
3270     offset = offset - (PRInt32)(headerEnd - (const char *)inBuffer) - markLen;
3271     if (offset) {
3272         /* move all data to the beginning of the buffer */
3273         PORT_Memmove(inBuffer, headerEnd + markLen, offset);
3274     }
3275 
3276     /* resize buffer to only what's needed to hold the current response */
3277     inBufsize = (1 + (offset - 1) / bufSizeIncrement) * bufSizeIncrement;
3278 
3279     while ((PR_FALSE == EOS) &&
3280            ((contentlength == 0) || (offset < contentlength)) &&
3281            (inBufsize < maxBufSize)) {
3282         /* we still need to receive more body data */
3283         inBufsize += bufSizeIncrement;
3284         inBuffer = PORT_Realloc(inBuffer, inBufsize + 1);
3285         if (NULL == inBuffer) {
3286             AbortHttpDecode(SEC_ERROR_NO_MEMORY);
3287         }
3288         bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement,
3289                               ocsptimeout);
3290         if (bytesRead > 0) {
3291             offset += bytesRead;
3292             if (bytesRead < bufSizeIncrement) {
3293                 /* we read less data than requested, therefore we are at
3294                    EOS or there was a read error */
3295                 EOS = PR_TRUE;
3296             }
3297         } else {
3298             /* recv error or EOS */
3299             EOS = PR_TRUE;
3300         }
3301     }
3302 
3303     if (0 == offset) {
3304         AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3305     }
3306 
3307     /*
3308      * Now allocate the item to hold the data.
3309      */
3310     result = SECITEM_AllocItem(arena, NULL, offset);
3311     if (NULL == result) {
3312         AbortHttpDecode(SEC_ERROR_NO_MEMORY);
3313     }
3314 
3315     /*
3316      * And copy the data left in the buffer.
3317      */
3318     PORT_Memcpy(result->data, inBuffer, offset);
3319 
3320     /* and free the temporary buffer */
3321     PORT_Free(inBuffer);
3322     return result;
3323 }
3324 
3325 SECStatus
CERT_ParseURL(const char * url,char ** pHostname,PRUint16 * pPort,char ** pPath)3326 CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath)
3327 {
3328     return ocsp_ParseURL(url, pHostname, pPort, pPath);
3329 }
3330 
3331 /*
3332  * Limit the size of http responses we are willing to accept.
3333  */
3334 #define MAX_WANTED_OCSP_RESPONSE_LEN 64 * 1024
3335 
3336 /* if (encodedRequest == NULL)
3337  *   then location MUST already include the full request,
3338  *        including base64 and urlencode,
3339  *        and the request will be sent with GET
3340  * if (encodedRequest != NULL)
3341  *   then the request will be sent with POST
3342  */
3343 static SECItem *
fetchOcspHttpClientV1(PLArenaPool * arena,const SEC_HttpClientFcnV1 * hcv1,const char * location,const SECItem * encodedRequest)3344 fetchOcspHttpClientV1(PLArenaPool *arena,
3345                       const SEC_HttpClientFcnV1 *hcv1,
3346                       const char *location,
3347                       const SECItem *encodedRequest)
3348 {
3349     char *hostname = NULL;
3350     char *path = NULL;
3351     PRUint16 port;
3352     SECItem *encodedResponse = NULL;
3353     SEC_HTTP_SERVER_SESSION pServerSession = NULL;
3354     SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
3355     PRUint16 myHttpResponseCode;
3356     const char *myHttpResponseData;
3357     PRUint32 myHttpResponseDataLen;
3358 
3359     if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) {
3360         PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
3361         goto loser;
3362     }
3363 
3364     PORT_Assert(hostname != NULL);
3365     PORT_Assert(path != NULL);
3366 
3367     if ((*hcv1->createSessionFcn)(
3368             hostname,
3369             port,
3370             &pServerSession) != SECSuccess) {
3371         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
3372         goto loser;
3373     }
3374 
3375     /* We use a non-zero timeout, which means:
3376        - the client will use blocking I/O
3377        - TryFcn will not return WOULD_BLOCK nor a poll descriptor
3378        - it's sufficient to call TryFcn once
3379        No lock for accessing OCSP_Global.timeoutSeconds, bug 406120
3380     */
3381 
3382     if ((*hcv1->createFcn)(
3383             pServerSession,
3384             "http",
3385             path,
3386             encodedRequest ? "POST" : "GET",
3387             PR_TicksPerSecond() * OCSP_Global.timeoutSeconds,
3388             &pRequestSession) != SECSuccess) {
3389         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
3390         goto loser;
3391     }
3392 
3393     if (encodedRequest &&
3394         (*hcv1->setPostDataFcn)(
3395             pRequestSession,
3396             (char *)encodedRequest->data,
3397             encodedRequest->len,
3398             "application/ocsp-request") != SECSuccess) {
3399         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
3400         goto loser;
3401     }
3402 
3403     /* we don't want result objects larger than this: */
3404     myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN;
3405 
3406     OCSP_TRACE(("OCSP trySendAndReceive %s\n", location));
3407 
3408     if ((*hcv1->trySendAndReceiveFcn)(
3409             pRequestSession,
3410             NULL,
3411             &myHttpResponseCode,
3412             NULL,
3413             NULL,
3414             &myHttpResponseData,
3415             &myHttpResponseDataLen) != SECSuccess) {
3416         PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
3417         goto loser;
3418     }
3419 
3420     OCSP_TRACE(("OCSP trySendAndReceive result http %d\n", myHttpResponseCode));
3421 
3422     if (myHttpResponseCode != 200) {
3423         PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
3424         goto loser;
3425     }
3426 
3427     encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen);
3428 
3429     if (!encodedResponse) {
3430         PORT_SetError(SEC_ERROR_NO_MEMORY);
3431         goto loser;
3432     }
3433 
3434     PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen);
3435 
3436 loser:
3437     if (pRequestSession != NULL)
3438         (*hcv1->freeFcn)(pRequestSession);
3439     if (pServerSession != NULL)
3440         (*hcv1->freeSessionFcn)(pServerSession);
3441     if (path != NULL)
3442         PORT_Free(path);
3443     if (hostname != NULL)
3444         PORT_Free(hostname);
3445 
3446     return encodedResponse;
3447 }
3448 
3449 /*
3450  * FUNCTION: CERT_GetEncodedOCSPResponseByMethod
3451  *   Creates and sends a request to an OCSP responder, then reads and
3452  *   returns the (encoded) response.
3453  * INPUTS:
3454  *   PLArenaPool *arena
3455  *     Pointer to arena from which return value will be allocated.
3456  *     If NULL, result will be allocated from the heap (and thus should
3457  *     be freed via SECITEM_FreeItem).
3458  *   CERTCertList *certList
3459  *     A list of certs for which status will be requested.
3460  *     Note that all of these certificates should have the same issuer,
3461  *     or it's expected the response will be signed by a trusted responder.
3462  *     If the certs need to be broken up into multiple requests, that
3463  *     must be handled by the caller (and thus by having multiple calls
3464  *     to this routine), who knows about where the request(s) are being
3465  *     sent and whether there are any trusted responders in place.
3466  *   const char *location
3467  *     The location of the OCSP responder (a URL).
3468  *   const char *method
3469  *     The protocol method used when retrieving the OCSP response.
3470  *     Currently support: "GET" (http GET) and "POST" (http POST).
3471  *     Additionals methods for http or other protocols might be added
3472  *     in the future.
3473  *   PRTime time
3474  *     Indicates the time for which the certificate status is to be
3475  *     determined -- this may be used in the search for the cert's issuer
3476  *     but has no other bearing on the operation.
3477  *   PRBool addServiceLocator
3478  *     If true, the Service Locator extension should be added to the
3479  *     single request(s) for each cert.
3480  *   CERTCertificate *signerCert
3481  *     If non-NULL, means sign the request using this cert.  Otherwise,
3482  *     do not sign.
3483  *   void *pwArg
3484  *     Pointer to argument for password prompting, if needed.  (Definitely
3485  *     not needed if not signing.)
3486  * OUTPUTS:
3487  *   CERTOCSPRequest **pRequest
3488  *     Pointer in which to store the OCSP request created for the given
3489  *     list of certificates.  It is only filled in if the entire operation
3490  *     is successful and the pointer is not null -- and in that case the
3491  *     caller is then reponsible for destroying it.
3492  * RETURN:
3493  *   Returns a pointer to the SECItem holding the response.
3494  *   On error, returns null with error set describing the reason:
3495  *	SEC_ERROR_UNKNOWN_ISSUER
3496  *	SEC_ERROR_CERT_BAD_ACCESS_LOCATION
3497  *	SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
3498  *   Other errors are low-level problems (no memory, bad database, etc.).
3499  */
3500 SECItem *
CERT_GetEncodedOCSPResponseByMethod(PLArenaPool * arena,CERTCertList * certList,const char * location,const char * method,PRTime time,PRBool addServiceLocator,CERTCertificate * signerCert,void * pwArg,CERTOCSPRequest ** pRequest)3501 CERT_GetEncodedOCSPResponseByMethod(PLArenaPool *arena, CERTCertList *certList,
3502                                     const char *location, const char *method,
3503                                     PRTime time, PRBool addServiceLocator,
3504                                     CERTCertificate *signerCert, void *pwArg,
3505                                     CERTOCSPRequest **pRequest)
3506 {
3507     CERTOCSPRequest *request;
3508     request = CERT_CreateOCSPRequest(certList, time, addServiceLocator,
3509                                      signerCert);
3510     if (!request)
3511         return NULL;
3512     return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location,
3513                                                   method, time, addServiceLocator,
3514                                                   pwArg, pRequest);
3515 }
3516 
3517 /*
3518  * FUNCTION: CERT_GetEncodedOCSPResponse
3519  *   Creates and sends a request to an OCSP responder, then reads and
3520  *   returns the (encoded) response.
3521  *
3522  * This is a legacy API that behaves identically to
3523  * CERT_GetEncodedOCSPResponseByMethod using the "POST" method.
3524  */
3525 SECItem *
CERT_GetEncodedOCSPResponse(PLArenaPool * arena,CERTCertList * certList,const char * location,PRTime time,PRBool addServiceLocator,CERTCertificate * signerCert,void * pwArg,CERTOCSPRequest ** pRequest)3526 CERT_GetEncodedOCSPResponse(PLArenaPool *arena, CERTCertList *certList,
3527                             const char *location, PRTime time,
3528                             PRBool addServiceLocator,
3529                             CERTCertificate *signerCert, void *pwArg,
3530                             CERTOCSPRequest **pRequest)
3531 {
3532     return CERT_GetEncodedOCSPResponseByMethod(arena, certList, location,
3533                                                "POST", time, addServiceLocator,
3534                                                signerCert, pwArg, pRequest);
3535 }
3536 
3537 /* URL encode a buffer that consists of base64-characters, only,
3538  * which means we can use a simple encoding logic.
3539  *
3540  * No output buffer size checking is performed.
3541  * You should call the function twice, to calculate the required buffer size.
3542  *
3543  * If the outpufBuf parameter is NULL, the function will calculate the
3544  * required size, including the trailing zero termination char.
3545  *
3546  * The function returns the number of bytes calculated or produced.
3547  */
3548 size_t
ocsp_UrlEncodeBase64Buf(const char * base64Buf,char * outputBuf)3549 ocsp_UrlEncodeBase64Buf(const char *base64Buf, char *outputBuf)
3550 {
3551     const char *walkInput = NULL;
3552     char *walkOutput = outputBuf;
3553     size_t count = 0;
3554 
3555     for (walkInput = base64Buf; *walkInput; ++walkInput) {
3556         char c = *walkInput;
3557         if (isspace(c))
3558             continue;
3559         switch (c) {
3560             case '+':
3561                 if (outputBuf) {
3562                     strcpy(walkOutput, "%2B");
3563                     walkOutput += 3;
3564                 }
3565                 count += 3;
3566                 break;
3567             case '/':
3568                 if (outputBuf) {
3569                     strcpy(walkOutput, "%2F");
3570                     walkOutput += 3;
3571                 }
3572                 count += 3;
3573                 break;
3574             case '=':
3575                 if (outputBuf) {
3576                     strcpy(walkOutput, "%3D");
3577                     walkOutput += 3;
3578                 }
3579                 count += 3;
3580                 break;
3581             default:
3582                 if (outputBuf) {
3583                     *walkOutput = *walkInput;
3584                     ++walkOutput;
3585                 }
3586                 ++count;
3587                 break;
3588         }
3589     }
3590     if (outputBuf) {
3591         *walkOutput = 0;
3592     }
3593     ++count;
3594     return count;
3595 }
3596 
3597 enum { max_get_request_size = 255 }; /* defined by RFC2560 */
3598 
3599 static SECItem *
3600 cert_GetOCSPResponse(PLArenaPool *arena, const char *location,
3601                      const SECItem *encodedRequest);
3602 
3603 static SECItem *
ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool * arena,CERTOCSPRequest * request,const char * location,const char * method,PRTime time,PRBool addServiceLocator,void * pwArg,CERTOCSPRequest ** pRequest)3604 ocsp_GetEncodedOCSPResponseFromRequest(PLArenaPool *arena,
3605                                        CERTOCSPRequest *request,
3606                                        const char *location,
3607                                        const char *method,
3608                                        PRTime time,
3609                                        PRBool addServiceLocator,
3610                                        void *pwArg,
3611                                        CERTOCSPRequest **pRequest)
3612 {
3613     SECItem *encodedRequest = NULL;
3614     SECItem *encodedResponse = NULL;
3615     SECStatus rv;
3616 
3617     if (!location || !*location) /* location should be at least one byte */
3618         goto loser;
3619 
3620     rv = CERT_AddOCSPAcceptableResponses(request,
3621                                          SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
3622     if (rv != SECSuccess)
3623         goto loser;
3624 
3625     encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg);
3626     if (encodedRequest == NULL)
3627         goto loser;
3628 
3629     if (!strcmp(method, "GET")) {
3630         encodedResponse = cert_GetOCSPResponse(arena, location, encodedRequest);
3631     } else if (!strcmp(method, "POST")) {
3632         encodedResponse = CERT_PostOCSPRequest(arena, location, encodedRequest);
3633     } else {
3634         goto loser;
3635     }
3636 
3637     if (encodedResponse != NULL && pRequest != NULL) {
3638         *pRequest = request;
3639         request = NULL; /* avoid destroying below */
3640     }
3641 
3642 loser:
3643     if (request != NULL)
3644         CERT_DestroyOCSPRequest(request);
3645     if (encodedRequest != NULL)
3646         SECITEM_FreeItem(encodedRequest, PR_TRUE);
3647     return encodedResponse;
3648 }
3649 
3650 static SECItem *
3651 cert_FetchOCSPResponse(PLArenaPool *arena, const char *location,
3652                        const SECItem *encodedRequest);
3653 
3654 /* using HTTP GET method */
3655 static SECItem *
cert_GetOCSPResponse(PLArenaPool * arena,const char * location,const SECItem * encodedRequest)3656 cert_GetOCSPResponse(PLArenaPool *arena, const char *location,
3657                      const SECItem *encodedRequest)
3658 {
3659     char *walkOutput = NULL;
3660     char *fullGetPath = NULL;
3661     size_t pathLength;
3662     PRInt32 urlEncodedBufLength;
3663     size_t base64size;
3664     char b64ReqBuf[max_get_request_size + 1];
3665     size_t slashLengthIfNeeded = 0;
3666     size_t getURLLength;
3667     SECItem *item;
3668 
3669     if (!location || !*location) {
3670         return NULL;
3671     }
3672 
3673     pathLength = strlen(location);
3674     if (location[pathLength - 1] != '/') {
3675         slashLengthIfNeeded = 1;
3676     }
3677 
3678     /* Calculation as documented by PL_Base64Encode function.
3679      * Use integer conversion to avoid having to use function ceil().
3680      */
3681     base64size = (((encodedRequest->len + 2) / 3) * 4);
3682     if (base64size > max_get_request_size) {
3683         return NULL;
3684     }
3685     memset(b64ReqBuf, 0, sizeof(b64ReqBuf));
3686     PL_Base64Encode((const char *)encodedRequest->data, encodedRequest->len,
3687                     b64ReqBuf);
3688 
3689     urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL);
3690     getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded;
3691 
3692     /* urlEncodedBufLength already contains room for the zero terminator.
3693      * Add another if we must add the '/' char.
3694      */
3695     if (arena) {
3696         fullGetPath = (char *)PORT_ArenaAlloc(arena, getURLLength);
3697     } else {
3698         fullGetPath = (char *)PORT_Alloc(getURLLength);
3699     }
3700     if (!fullGetPath) {
3701         return NULL;
3702     }
3703 
3704     strcpy(fullGetPath, location);
3705     walkOutput = fullGetPath + pathLength;
3706 
3707     if (walkOutput > fullGetPath && slashLengthIfNeeded) {
3708         strcpy(walkOutput, "/");
3709         ++walkOutput;
3710     }
3711     ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput);
3712 
3713     item = cert_FetchOCSPResponse(arena, fullGetPath, NULL);
3714     if (!arena) {
3715         PORT_Free(fullGetPath);
3716     }
3717     return item;
3718 }
3719 
3720 SECItem *
CERT_PostOCSPRequest(PLArenaPool * arena,const char * location,const SECItem * encodedRequest)3721 CERT_PostOCSPRequest(PLArenaPool *arena, const char *location,
3722                      const SECItem *encodedRequest)
3723 {
3724     return cert_FetchOCSPResponse(arena, location, encodedRequest);
3725 }
3726 
3727 SECItem *
cert_FetchOCSPResponse(PLArenaPool * arena,const char * location,const SECItem * encodedRequest)3728 cert_FetchOCSPResponse(PLArenaPool *arena, const char *location,
3729                        const SECItem *encodedRequest)
3730 {
3731     const SEC_HttpClientFcn *registeredHttpClient;
3732     SECItem *encodedResponse = NULL;
3733 
3734     registeredHttpClient = SEC_GetRegisteredHttpClient();
3735 
3736     if (registeredHttpClient && registeredHttpClient->version == 1) {
3737         encodedResponse = fetchOcspHttpClientV1(
3738             arena,
3739             &registeredHttpClient->fcnTable.ftable1,
3740             location,
3741             encodedRequest);
3742     } else {
3743         /* use internal http client */
3744         PRFileDesc *sock = ocsp_SendEncodedRequest(location, encodedRequest);
3745         if (sock) {
3746             encodedResponse = ocsp_GetEncodedResponse(arena, sock);
3747             PR_Close(sock);
3748         }
3749     }
3750 
3751     return encodedResponse;
3752 }
3753 
3754 static SECItem *
ocsp_GetEncodedOCSPResponseForSingleCert(PLArenaPool * arena,CERTOCSPCertID * certID,CERTCertificate * singleCert,const char * location,const char * method,PRTime time,PRBool addServiceLocator,void * pwArg,CERTOCSPRequest ** pRequest)3755 ocsp_GetEncodedOCSPResponseForSingleCert(PLArenaPool *arena,
3756                                          CERTOCSPCertID *certID,
3757                                          CERTCertificate *singleCert,
3758                                          const char *location,
3759                                          const char *method,
3760                                          PRTime time,
3761                                          PRBool addServiceLocator,
3762                                          void *pwArg,
3763                                          CERTOCSPRequest **pRequest)
3764 {
3765     CERTOCSPRequest *request;
3766     request = cert_CreateSingleCertOCSPRequest(certID, singleCert, time,
3767                                                addServiceLocator, NULL);
3768     if (!request)
3769         return NULL;
3770     return ocsp_GetEncodedOCSPResponseFromRequest(arena, request, location,
3771                                                   method, time, addServiceLocator,
3772                                                   pwArg, pRequest);
3773 }
3774 
3775 /* Checks a certificate for the key usage extension of OCSP signer. */
3776 static PRBool
ocsp_CertIsOCSPDesignatedResponder(CERTCertificate * cert)3777 ocsp_CertIsOCSPDesignatedResponder(CERTCertificate *cert)
3778 {
3779     SECStatus rv;
3780     SECItem extItem;
3781     SECItem **oids;
3782     SECItem *oid;
3783     SECOidTag oidTag;
3784     PRBool retval;
3785     CERTOidSequence *oidSeq = NULL;
3786 
3787     extItem.data = NULL;
3788     rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
3789     if (rv != SECSuccess) {
3790         goto loser;
3791     }
3792 
3793     oidSeq = CERT_DecodeOidSequence(&extItem);
3794     if (oidSeq == NULL) {
3795         goto loser;
3796     }
3797 
3798     oids = oidSeq->oids;
3799     while (*oids != NULL) {
3800         oid = *oids;
3801 
3802         oidTag = SECOID_FindOIDTag(oid);
3803 
3804         if (oidTag == SEC_OID_OCSP_RESPONDER) {
3805             goto success;
3806         }
3807 
3808         oids++;
3809     }
3810 
3811 loser:
3812     retval = PR_FALSE;
3813     PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
3814     goto done;
3815 success:
3816     retval = PR_TRUE;
3817 done:
3818     if (extItem.data != NULL) {
3819         PORT_Free(extItem.data);
3820     }
3821     if (oidSeq != NULL) {
3822         CERT_DestroyOidSequence(oidSeq);
3823     }
3824 
3825     return (retval);
3826 }
3827 
3828 #ifdef LATER /*                                                    \
3829               * XXX This function is not currently used, but will  \
3830               * be needed later when we do revocation checking of  \
3831               * the responder certificate.  Of course, it may need \
3832               * revising then, if the cert extension interface has \
3833               * changed.  (Hopefully it will!)                     \
3834               */
3835 
3836 /* Checks a certificate to see if it has the OCSP no check extension. */
3837 static PRBool
ocsp_CertHasNoCheckExtension(CERTCertificate * cert)3838 ocsp_CertHasNoCheckExtension(CERTCertificate *cert)
3839 {
3840     SECStatus rv;
3841 
3842     rv = CERT_FindCertExtension(cert, SEC_OID_PKIX_OCSP_NO_CHECK,
3843                                 NULL);
3844     if (rv == SECSuccess) {
3845         return PR_TRUE;
3846     }
3847     return PR_FALSE;
3848 }
3849 #endif /* LATER */
3850 
3851 static PRBool
ocsp_matchcert(SECItem * certIndex,CERTCertificate * testCert)3852 ocsp_matchcert(SECItem *certIndex, CERTCertificate *testCert)
3853 {
3854     SECItem item;
3855     unsigned char buf[HASH_LENGTH_MAX];
3856 
3857     item.data = buf;
3858     item.len = SHA1_LENGTH;
3859 
3860     if (CERT_GetSubjectPublicKeyDigest(NULL, testCert, SEC_OID_SHA1,
3861                                        &item) == NULL) {
3862         return PR_FALSE;
3863     }
3864     if (SECITEM_ItemsAreEqual(certIndex, &item)) {
3865         return PR_TRUE;
3866     }
3867     if (CERT_GetSubjectPublicKeyDigest(NULL, testCert, SEC_OID_MD5,
3868                                        &item) == NULL) {
3869         return PR_FALSE;
3870     }
3871     if (SECITEM_ItemsAreEqual(certIndex, &item)) {
3872         return PR_TRUE;
3873     }
3874     if (CERT_GetSubjectPublicKeyDigest(NULL, testCert, SEC_OID_MD2,
3875                                        &item) == NULL) {
3876         return PR_FALSE;
3877     }
3878     if (SECITEM_ItemsAreEqual(certIndex, &item)) {
3879         return PR_TRUE;
3880     }
3881 
3882     return PR_FALSE;
3883 }
3884 
3885 static CERTCertificate *
3886 ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle, CERTOCSPCertID *certID);
3887 
3888 CERTCertificate *
ocsp_GetSignerCertificate(CERTCertDBHandle * handle,ocspResponseData * tbsData,ocspSignature * signature,CERTCertificate * issuer)3889 ocsp_GetSignerCertificate(CERTCertDBHandle *handle, ocspResponseData *tbsData,
3890                           ocspSignature *signature, CERTCertificate *issuer)
3891 {
3892     CERTCertificate **certs = NULL;
3893     CERTCertificate *signerCert = NULL;
3894     SECStatus rv = SECFailure;
3895     PRBool lookupByName = PR_TRUE;
3896     void *certIndex = NULL;
3897     int certCount = 0;
3898 
3899     PORT_Assert(tbsData->responderID != NULL);
3900     switch (tbsData->responderID->responderIDType) {
3901         case ocspResponderID_byName:
3902             lookupByName = PR_TRUE;
3903             certIndex = &tbsData->derResponderID;
3904             break;
3905         case ocspResponderID_byKey:
3906             lookupByName = PR_FALSE;
3907             certIndex = &tbsData->responderID->responderIDValue.keyHash;
3908             break;
3909         case ocspResponderID_other:
3910         default:
3911             PORT_Assert(0);
3912             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
3913             return NULL;
3914     }
3915 
3916     /*
3917      * If the signature contains some certificates as well, temporarily
3918      * import them in case they are needed for verification.
3919      *
3920      * Note that the result of this is that each cert in "certs" needs
3921      * to be destroyed.
3922      */
3923     if (signature->derCerts != NULL) {
3924         for (; signature->derCerts[certCount] != NULL; certCount++) {
3925             /* just counting */
3926         }
3927         rv = CERT_ImportCerts(handle, certUsageStatusResponder, certCount,
3928                               signature->derCerts, &certs,
3929                               PR_FALSE, PR_FALSE, NULL);
3930         if (rv != SECSuccess)
3931             goto finish;
3932     }
3933 
3934     /*
3935      * Now look up the certificate that did the signing.
3936      * The signer can be specified either by name or by key hash.
3937      */
3938     if (lookupByName) {
3939         SECItem *crIndex = (SECItem *)certIndex;
3940         SECItem encodedName;
3941         PLArenaPool *arena;
3942 
3943         arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3944         if (arena != NULL) {
3945 
3946             rv = SEC_QuickDERDecodeItem(arena, &encodedName,
3947                                         ocsp_ResponderIDDerNameTemplate,
3948                                         crIndex);
3949             if (rv != SECSuccess) {
3950                 if (PORT_GetError() == SEC_ERROR_BAD_DER)
3951                     PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
3952             } else {
3953                 signerCert = CERT_FindCertByName(handle, &encodedName);
3954             }
3955             PORT_FreeArena(arena, PR_FALSE);
3956         }
3957     } else {
3958         /*
3959     	 * The signer is either 1) a known issuer CA we passed in,
3960     	 * 2) the default OCSP responder, or 3) an intermediate CA
3961     	 * passed in the cert list to use. Figure out which it is.
3962     	 */
3963         int i;
3964         CERTCertificate *responder =
3965             ocsp_CertGetDefaultResponder(handle, NULL);
3966         if (responder && ocsp_matchcert(certIndex, responder)) {
3967             signerCert = CERT_DupCertificate(responder);
3968         } else if (issuer && ocsp_matchcert(certIndex, issuer)) {
3969             signerCert = CERT_DupCertificate(issuer);
3970         }
3971         for (i = 0; (signerCert == NULL) && (i < certCount); i++) {
3972             if (ocsp_matchcert(certIndex, certs[i])) {
3973                 signerCert = CERT_DupCertificate(certs[i]);
3974             }
3975         }
3976         if (signerCert == NULL) {
3977             PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
3978         }
3979     }
3980 
3981 finish:
3982     if (certs != NULL) {
3983         CERT_DestroyCertArray(certs, certCount);
3984     }
3985 
3986     return signerCert;
3987 }
3988 
3989 SECStatus
ocsp_VerifyResponseSignature(CERTCertificate * signerCert,ocspSignature * signature,SECItem * tbsResponseDataDER,void * pwArg)3990 ocsp_VerifyResponseSignature(CERTCertificate *signerCert,
3991                              ocspSignature *signature,
3992                              SECItem *tbsResponseDataDER,
3993                              void *pwArg)
3994 {
3995     SECKEYPublicKey *signerKey = NULL;
3996     SECStatus rv = SECFailure;
3997     CERTSignedData signedData;
3998 
3999     /*
4000      * Now get the public key from the signer's certificate; we need
4001      * it to perform the verification.
4002      */
4003     signerKey = CERT_ExtractPublicKey(signerCert);
4004     if (signerKey == NULL) {
4005         return SECFailure;
4006     }
4007 
4008     /*
4009      * We copy the signature data *pointer* and length, so that we can
4010      * modify the length without damaging the original copy.  This is a
4011      * simple copy, not a dup, so no destroy/free is necessary.
4012      */
4013     signedData.signature = signature->signature;
4014     signedData.signatureAlgorithm = signature->signatureAlgorithm;
4015     signedData.data = *tbsResponseDataDER;
4016 
4017     rv = CERT_VerifySignedDataWithPublicKey(&signedData, signerKey, pwArg);
4018     if (rv != SECSuccess &&
4019         (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE ||
4020          PORT_GetError() == SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED)) {
4021         PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE);
4022     }
4023 
4024     if (signerKey != NULL) {
4025         SECKEY_DestroyPublicKey(signerKey);
4026     }
4027 
4028     return rv;
4029 }
4030 
4031 /*
4032  * FUNCTION: CERT_VerifyOCSPResponseSignature
4033  *   Check the signature on an OCSP Response.  Will also perform a
4034  *   verification of the signer's certificate.  Note, however, that a
4035  *   successful verification does not make any statement about the
4036  *   signer's *authority* to provide status for the certificate(s),
4037  *   that must be checked individually for each certificate.
4038  * INPUTS:
4039  *   CERTOCSPResponse *response
4040  *     Pointer to response structure with signature to be checked.
4041  *   CERTCertDBHandle *handle
4042  *     Pointer to CERTCertDBHandle for certificate DB to use for verification.
4043  *   void *pwArg
4044  *     Pointer to argument for password prompting, if needed.
4045  * OUTPUTS:
4046  *   CERTCertificate **pSignerCert
4047  *     Pointer in which to store signer's certificate; only filled-in if
4048  *     non-null.
4049  * RETURN:
4050  *   Returns SECSuccess when signature is valid, anything else means invalid.
4051  *   Possible errors set:
4052  *	SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID
4053  *	SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time
4054  *	SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found
4055  *	SEC_ERROR_BAD_SIGNATURE - the signature did not verify
4056  *   Other errors are any of the many possible failures in cert verification
4057  *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
4058  *   verifying the signer's cert, or low-level problems (no memory, etc.)
4059  */
4060 SECStatus
CERT_VerifyOCSPResponseSignature(CERTOCSPResponse * response,CERTCertDBHandle * handle,void * pwArg,CERTCertificate ** pSignerCert,CERTCertificate * issuer)4061 CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,
4062                                  CERTCertDBHandle *handle, void *pwArg,
4063                                  CERTCertificate **pSignerCert,
4064                                  CERTCertificate *issuer)
4065 {
4066     SECItem *tbsResponseDataDER;
4067     CERTCertificate *signerCert = NULL;
4068     SECStatus rv = SECFailure;
4069     PRTime producedAt;
4070 
4071     /* ocsp_DecodeBasicOCSPResponse will fail if asn1 decoder is unable
4072      * to properly decode tbsData (see the function and
4073      * ocsp_BasicOCSPResponseTemplate). Thus, tbsData can not be
4074      * equal to null */
4075     ocspResponseData *tbsData = ocsp_GetResponseData(response,
4076                                                      &tbsResponseDataDER);
4077     ocspSignature *signature = ocsp_GetResponseSignature(response);
4078 
4079     if (!signature) {
4080         PORT_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE);
4081         return SECFailure;
4082     }
4083 
4084     /*
4085      * If this signature has already gone through verification, just
4086      * return the cached result.
4087      */
4088     if (signature->wasChecked) {
4089         if (signature->status == SECSuccess) {
4090             if (pSignerCert != NULL)
4091                 *pSignerCert = CERT_DupCertificate(signature->cert);
4092         } else {
4093             PORT_SetError(signature->failureReason);
4094         }
4095         return signature->status;
4096     }
4097 
4098     signerCert = ocsp_GetSignerCertificate(handle, tbsData,
4099                                            signature, issuer);
4100     if (signerCert == NULL) {
4101         rv = SECFailure;
4102         if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
4103             /* Make the error a little more specific. */
4104             PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
4105         }
4106         goto finish;
4107     }
4108 
4109     /*
4110      * We could mark this true at the top of this function, or always
4111      * below at "finish", but if the problem was just that we could not
4112      * find the signer's cert, leave that as if the signature hasn't
4113      * been checked in case a subsequent call might have better luck.
4114      */
4115     signature->wasChecked = PR_TRUE;
4116 
4117     /*
4118      * The function will also verify the signer certificate; we
4119      * need to tell it *when* that certificate must be valid -- for our
4120      * purposes we expect it to be valid when the response was signed.
4121      * The value of "producedAt" is the signing time.
4122      */
4123     rv = DER_GeneralizedTimeToTime(&producedAt, &tbsData->producedAt);
4124     if (rv != SECSuccess)
4125         goto finish;
4126 
4127     /*
4128      * Just because we have a cert does not mean it is any good; check
4129      * it for validity, trust and usage.
4130      */
4131     if (!ocsp_CertIsOCSPDefaultResponder(handle, signerCert)) {
4132         SECCertUsage certUsage;
4133         if (CERT_IsCACert(signerCert, NULL)) {
4134             certUsage = certUsageAnyCA;
4135         } else {
4136             certUsage = certUsageStatusResponder;
4137         }
4138         rv = cert_VerifyCertWithFlags(handle, signerCert, PR_TRUE, certUsage,
4139                                       producedAt, CERT_VERIFYCERT_SKIP_OCSP,
4140                                       pwArg, NULL);
4141         if (rv != SECSuccess) {
4142             PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
4143             goto finish;
4144         }
4145     }
4146 
4147     rv = ocsp_VerifyResponseSignature(signerCert, signature,
4148                                       tbsResponseDataDER,
4149                                       pwArg);
4150 
4151 finish:
4152     if (signature->wasChecked)
4153         signature->status = rv;
4154 
4155     if (rv != SECSuccess) {
4156         signature->failureReason = PORT_GetError();
4157         if (signerCert != NULL)
4158             CERT_DestroyCertificate(signerCert);
4159     } else {
4160         /*
4161     	 * Save signer's certificate in signature.
4162     	 */
4163         signature->cert = signerCert;
4164         if (pSignerCert != NULL) {
4165             /*
4166     	     * Pass pointer to signer's certificate back to our caller,
4167     	     * who is also now responsible for destroying it.
4168     	     */
4169             *pSignerCert = CERT_DupCertificate(signerCert);
4170         }
4171     }
4172 
4173     return rv;
4174 }
4175 
4176 /*
4177  * See if the request's certID and the single response's certID match.
4178  * This can be easy or difficult, depending on whether the same hash
4179  * algorithm was used.
4180  */
4181 static PRBool
ocsp_CertIDsMatch(CERTOCSPCertID * requestCertID,CERTOCSPCertID * responseCertID)4182 ocsp_CertIDsMatch(CERTOCSPCertID *requestCertID,
4183                   CERTOCSPCertID *responseCertID)
4184 {
4185     PRBool match = PR_FALSE;
4186     SECOidTag hashAlg;
4187     SECItem *keyHash = NULL;
4188     SECItem *nameHash = NULL;
4189 
4190     /*
4191      * In order to match, they must have the same issuer and the same
4192      * serial number.
4193      *
4194      * We just compare the easier things first.
4195      */
4196     if (SECITEM_CompareItem(&requestCertID->serialNumber,
4197                             &responseCertID->serialNumber) != SECEqual) {
4198         goto done;
4199     }
4200 
4201     /*
4202      * Make sure the "parameters" are not too bogus.  Since we encoded
4203      * requestCertID->hashAlgorithm, we don't need to check it.
4204      */
4205     if (responseCertID->hashAlgorithm.parameters.len > 2) {
4206         goto done;
4207     }
4208     if (SECITEM_CompareItem(&requestCertID->hashAlgorithm.algorithm,
4209                             &responseCertID->hashAlgorithm.algorithm) ==
4210         SECEqual) {
4211         /*
4212     	 * If the hash algorithms match then we can do a simple compare
4213     	 * of the hash values themselves.
4214     	 */
4215         if ((SECITEM_CompareItem(&requestCertID->issuerNameHash,
4216                                  &responseCertID->issuerNameHash) == SECEqual) &&
4217             (SECITEM_CompareItem(&requestCertID->issuerKeyHash,
4218                                  &responseCertID->issuerKeyHash) == SECEqual)) {
4219             match = PR_TRUE;
4220         }
4221         goto done;
4222     }
4223 
4224     hashAlg = SECOID_FindOIDTag(&responseCertID->hashAlgorithm.algorithm);
4225     switch (hashAlg) {
4226         case SEC_OID_SHA1:
4227             keyHash = &requestCertID->issuerSHA1KeyHash;
4228             nameHash = &requestCertID->issuerSHA1NameHash;
4229             break;
4230         case SEC_OID_MD5:
4231             keyHash = &requestCertID->issuerMD5KeyHash;
4232             nameHash = &requestCertID->issuerMD5NameHash;
4233             break;
4234         case SEC_OID_MD2:
4235             keyHash = &requestCertID->issuerMD2KeyHash;
4236             nameHash = &requestCertID->issuerMD2NameHash;
4237             break;
4238         default:
4239             PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
4240             return PR_FALSE;
4241     }
4242 
4243     if ((keyHash != NULL) &&
4244         (SECITEM_CompareItem(nameHash,
4245                              &responseCertID->issuerNameHash) == SECEqual) &&
4246         (SECITEM_CompareItem(keyHash,
4247                              &responseCertID->issuerKeyHash) == SECEqual)) {
4248         match = PR_TRUE;
4249     }
4250 
4251 done:
4252     return match;
4253 }
4254 
4255 /*
4256  * Find the single response for the cert specified by certID.
4257  * No copying is done; this just returns a pointer to the appropriate
4258  * response within responses, if it is found (and null otherwise).
4259  * This is fine, of course, since this function is internal-use only.
4260  */
4261 static CERTOCSPSingleResponse *
ocsp_GetSingleResponseForCertID(CERTOCSPSingleResponse ** responses,CERTCertDBHandle * handle,CERTOCSPCertID * certID)4262 ocsp_GetSingleResponseForCertID(CERTOCSPSingleResponse **responses,
4263                                 CERTCertDBHandle *handle,
4264                                 CERTOCSPCertID *certID)
4265 {
4266     CERTOCSPSingleResponse *single;
4267     int i;
4268 
4269     if (responses == NULL)
4270         return NULL;
4271 
4272     for (i = 0; responses[i] != NULL; i++) {
4273         single = responses[i];
4274         if (ocsp_CertIDsMatch(certID, single->certID)) {
4275             return single;
4276         }
4277     }
4278 
4279     /*
4280      * The OCSP server should have included a response even if it knew
4281      * nothing about the certificate in question.  Since it did not,
4282      * this will make it look as if it had.
4283      *
4284      * XXX Should we make this a separate error to notice the server's
4285      * bad behavior?
4286      */
4287     PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT);
4288     return NULL;
4289 }
4290 
4291 static ocspCheckingContext *
ocsp_GetCheckingContext(CERTCertDBHandle * handle)4292 ocsp_GetCheckingContext(CERTCertDBHandle *handle)
4293 {
4294     CERTStatusConfig *statusConfig;
4295     ocspCheckingContext *ocspcx = NULL;
4296 
4297     statusConfig = CERT_GetStatusConfig(handle);
4298     if (statusConfig != NULL) {
4299         ocspcx = statusConfig->statusContext;
4300 
4301         /*
4302     	 * This is actually an internal error, because we should never
4303     	 * have a good statusConfig without a good statusContext, too.
4304     	 * For lack of anything better, though, we just assert and use
4305     	 * the same error as if there were no statusConfig (set below).
4306     	 */
4307         PORT_Assert(ocspcx != NULL);
4308     }
4309 
4310     if (ocspcx == NULL)
4311         PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED);
4312 
4313     return ocspcx;
4314 }
4315 
4316 /*
4317  * Return cert reference if the given signerCert is the default responder for
4318  * the given certID.  If not, or if any error, return NULL.
4319  */
4320 static CERTCertificate *
ocsp_CertGetDefaultResponder(CERTCertDBHandle * handle,CERTOCSPCertID * certID)4321 ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle, CERTOCSPCertID *certID)
4322 {
4323     ocspCheckingContext *ocspcx;
4324 
4325     ocspcx = ocsp_GetCheckingContext(handle);
4326     if (ocspcx == NULL)
4327         goto loser;
4328 
4329     /*
4330      * Right now we have only one default responder.  It applies to
4331      * all certs when it is used, so the check is simple and certID
4332      * has no bearing on the answer.  Someday in the future we may
4333      * allow configuration of different responders for different
4334      * issuers, and then we would have to use the issuer specified
4335      * in certID to determine if signerCert is the right one.
4336      */
4337     if (ocspcx->useDefaultResponder) {
4338         PORT_Assert(ocspcx->defaultResponderCert != NULL);
4339         return ocspcx->defaultResponderCert;
4340     }
4341 
4342 loser:
4343     return NULL;
4344 }
4345 
4346 /*
4347  * Return true if the cert is one of the default responders configured for
4348  * ocsp context. If not, or if any error, return false.
4349  */
4350 PRBool
ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle * handle,CERTCertificate * cert)4351 ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert)
4352 {
4353     ocspCheckingContext *ocspcx;
4354 
4355     ocspcx = ocsp_GetCheckingContext(handle);
4356     if (ocspcx == NULL)
4357         return PR_FALSE;
4358 
4359     /*
4360      * Right now we have only one default responder.  It applies to
4361      * all certs when it is used, so the check is simple and certID
4362      * has no bearing on the answer.  Someday in the future we may
4363      * allow configuration of different responders for different
4364      * issuers, and then we would have to use the issuer specified
4365      * in certID to determine if signerCert is the right one.
4366      */
4367     if (ocspcx->useDefaultResponder &&
4368         CERT_CompareCerts(ocspcx->defaultResponderCert, cert)) {
4369         return PR_TRUE;
4370     }
4371 
4372     return PR_FALSE;
4373 }
4374 
4375 /*
4376  * Check that the given signer certificate is authorized to sign status
4377  * information for the given certID.  Return true if it is, false if not
4378  * (or if there is any error along the way).  If false is returned because
4379  * the signer is not authorized, the following error will be set:
4380  *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
4381  * Other errors are low-level problems (no memory, bad database, etc.).
4382  *
4383  * There are three ways to be authorized.  In the order in which we check,
4384  * using the terms used in the OCSP spec, the signer must be one of:
4385  *  1.  A "trusted responder" -- it matches a local configuration
4386  *      of OCSP signing authority for the certificate in question.
4387  *  2.  The CA who issued the certificate in question.
4388  *  3.  A "CA designated responder", aka an "authorized responder" -- it
4389  *      must be represented by a special cert issued by the CA who issued
4390  *      the certificate in question.
4391  */
4392 static PRBool
ocsp_AuthorizedResponderForCertID(CERTCertDBHandle * handle,CERTCertificate * signerCert,CERTOCSPCertID * certID,PRTime thisUpdate)4393 ocsp_AuthorizedResponderForCertID(CERTCertDBHandle *handle,
4394                                   CERTCertificate *signerCert,
4395                                   CERTOCSPCertID *certID,
4396                                   PRTime thisUpdate)
4397 {
4398     CERTCertificate *issuerCert = NULL, *defRespCert;
4399     SECItem *keyHash = NULL;
4400     SECItem *nameHash = NULL;
4401     SECOidTag hashAlg;
4402     PRBool keyHashEQ = PR_FALSE, nameHashEQ = PR_FALSE;
4403 
4404     /*
4405      * Check first for a trusted responder, which overrides everything else.
4406      */
4407     if ((defRespCert = ocsp_CertGetDefaultResponder(handle, certID)) &&
4408         CERT_CompareCerts(defRespCert, signerCert)) {
4409         return PR_TRUE;
4410     }
4411 
4412     /*
4413      * In the other two cases, we need to do an issuer comparison.
4414      * How we do it depends on whether the signer certificate has the
4415      * special extension (for a designated responder) or not.
4416      *
4417      * First, lets check if signer of the response is the actual issuer
4418      * of the cert. For that we will use signer cert key hash and cert subj
4419      * name hash and will compare them with already calculated issuer key
4420      * hash and issuer name hash. The hash algorithm is picked from response
4421      * certID hash to avoid second hash calculation.
4422      */
4423 
4424     hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm);
4425 
4426     keyHash = CERT_GetSubjectPublicKeyDigest(NULL, signerCert, hashAlg, NULL);
4427     if (keyHash != NULL) {
4428 
4429         keyHashEQ =
4430             (SECITEM_CompareItem(keyHash,
4431                                  &certID->issuerKeyHash) == SECEqual);
4432         SECITEM_FreeItem(keyHash, PR_TRUE);
4433     }
4434     if (keyHashEQ &&
4435         (nameHash = CERT_GetSubjectNameDigest(NULL, signerCert,
4436                                               hashAlg, NULL))) {
4437         nameHashEQ =
4438             (SECITEM_CompareItem(nameHash,
4439                                  &certID->issuerNameHash) == SECEqual);
4440 
4441         SECITEM_FreeItem(nameHash, PR_TRUE);
4442         if (nameHashEQ) {
4443             /* The issuer of the cert is the the signer of the response */
4444             return PR_TRUE;
4445         }
4446     }
4447 
4448     keyHashEQ = PR_FALSE;
4449     nameHashEQ = PR_FALSE;
4450 
4451     if (!ocsp_CertIsOCSPDesignatedResponder(signerCert)) {
4452         PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
4453         return PR_FALSE;
4454     }
4455 
4456     /*
4457      * The signer is a designated responder.  Its issuer must match
4458      * the issuer of the cert being checked.
4459      */
4460     issuerCert = CERT_FindCertIssuer(signerCert, thisUpdate,
4461                                      certUsageAnyCA);
4462     if (issuerCert == NULL) {
4463         /*
4464          * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone,
4465          * but the following will give slightly more information.
4466          * Once we have an error stack, things will be much better.
4467          */
4468         PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
4469         return PR_FALSE;
4470     }
4471 
4472     keyHash = CERT_GetSubjectPublicKeyDigest(NULL, issuerCert, hashAlg, NULL);
4473     nameHash = CERT_GetSubjectNameDigest(NULL, issuerCert, hashAlg, NULL);
4474 
4475     CERT_DestroyCertificate(issuerCert);
4476 
4477     if (keyHash != NULL && nameHash != NULL) {
4478         keyHashEQ =
4479             (SECITEM_CompareItem(keyHash,
4480                                  &certID->issuerKeyHash) == SECEqual);
4481 
4482         nameHashEQ =
4483             (SECITEM_CompareItem(nameHash,
4484                                  &certID->issuerNameHash) == SECEqual);
4485     }
4486 
4487     if (keyHash) {
4488         SECITEM_FreeItem(keyHash, PR_TRUE);
4489     }
4490     if (nameHash) {
4491         SECITEM_FreeItem(nameHash, PR_TRUE);
4492     }
4493 
4494     if (keyHashEQ && nameHashEQ) {
4495         return PR_TRUE;
4496     }
4497 
4498     PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE);
4499     return PR_FALSE;
4500 }
4501 
4502 /*
4503  * We need to check that a responder gives us "recent" information.
4504  * Since a responder can pre-package responses, we need to pick an amount
4505  * of time that is acceptable to us, and reject any response that is
4506  * older than that.
4507  *
4508  * XXX This *should* be based on some configuration parameter, so that
4509  * different usages could specify exactly what constitutes "sufficiently
4510  * recent".  But that is not going to happen right away.  For now, we
4511  * want something from within the last 24 hours.  This macro defines that
4512  * number in seconds.
4513  */
4514 #define OCSP_ALLOWABLE_LAPSE_SECONDS (24L * 60L * 60L)
4515 
4516 static PRBool
ocsp_TimeIsRecent(PRTime checkTime)4517 ocsp_TimeIsRecent(PRTime checkTime)
4518 {
4519     PRTime now = PR_Now();
4520     PRTime lapse, tmp;
4521 
4522     LL_I2L(lapse, OCSP_ALLOWABLE_LAPSE_SECONDS);
4523     LL_I2L(tmp, PR_USEC_PER_SEC);
4524     LL_MUL(lapse, lapse, tmp); /* allowable lapse in microseconds */
4525 
4526     LL_ADD(checkTime, checkTime, lapse);
4527     if (LL_CMP(now, >, checkTime))
4528         return PR_FALSE;
4529 
4530     return PR_TRUE;
4531 }
4532 
4533 #define OCSP_SLOP (5L * 60L) /* OCSP responses are allowed to be 5 minutes \
4534                                 in the future by default */
4535 
4536 static PRUint32 ocspsloptime = OCSP_SLOP; /* seconds */
4537 
4538 /*
4539  * If an old response contains the revoked certificate status, we want
4540  * to return SECSuccess so the response will be used.
4541  */
4542 static SECStatus
ocsp_HandleOldSingleResponse(CERTOCSPSingleResponse * single,PRTime time)4543 ocsp_HandleOldSingleResponse(CERTOCSPSingleResponse *single, PRTime time)
4544 {
4545     SECStatus rv;
4546     ocspCertStatus *status = single->certStatus;
4547     if (status->certStatusType == ocspCertStatus_revoked) {
4548         rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time);
4549         if (rv != SECSuccess &&
4550             PORT_GetError() == SEC_ERROR_REVOKED_CERTIFICATE) {
4551             /*
4552              * Return SECSuccess now.  The subsequent ocsp_CertRevokedAfter
4553              * call in ocsp_CertHasGoodStatus will cause
4554              * ocsp_CertHasGoodStatus to fail with
4555              * SEC_ERROR_REVOKED_CERTIFICATE.
4556              */
4557             return SECSuccess;
4558         }
4559     }
4560     PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE);
4561     return SECFailure;
4562 }
4563 
4564 /*
4565  * Check that this single response is okay.  A return of SECSuccess means:
4566  *   1. The signer (represented by "signerCert") is authorized to give status
4567  *	for the cert represented by the individual response in "single".
4568  *   2. The value of thisUpdate is earlier than now.
4569  *   3. The value of producedAt is later than or the same as thisUpdate.
4570  *   4. If nextUpdate is given:
4571  *	- The value of nextUpdate is later than now.
4572  *	- The value of producedAt is earlier than nextUpdate.
4573  *	Else if no nextUpdate:
4574  *	- The value of thisUpdate is fairly recent.
4575  *	- The value of producedAt is fairly recent.
4576  *	However we do not need to perform an explicit check for this last
4577  *	constraint because it is already guaranteed by checking that
4578  *	producedAt is later than thisUpdate and thisUpdate is recent.
4579  * Oh, and any responder is "authorized" to say that a cert is unknown to it.
4580  *
4581  * If any of those checks fail, SECFailure is returned and an error is set:
4582  *	SEC_ERROR_OCSP_FUTURE_RESPONSE
4583  *	SEC_ERROR_OCSP_OLD_RESPONSE
4584  *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
4585  * Other errors are low-level problems (no memory, bad database, etc.).
4586  */
4587 static SECStatus
ocsp_VerifySingleResponse(CERTOCSPSingleResponse * single,CERTCertDBHandle * handle,CERTCertificate * signerCert,PRTime producedAt)4588 ocsp_VerifySingleResponse(CERTOCSPSingleResponse *single,
4589                           CERTCertDBHandle *handle,
4590                           CERTCertificate *signerCert,
4591                           PRTime producedAt)
4592 {
4593     CERTOCSPCertID *certID = single->certID;
4594     PRTime now, thisUpdate, nextUpdate, tmstamp, tmp;
4595     SECStatus rv;
4596 
4597     OCSP_TRACE(("OCSP ocsp_VerifySingleResponse, nextUpdate: %d\n",
4598                 ((single->nextUpdate) != 0)));
4599     /*
4600      * If all the responder said was that the given cert was unknown to it,
4601      * that is a valid response.  Not very interesting to us, of course,
4602      * but all this function is concerned with is validity of the response,
4603      * not the status of the cert.
4604      */
4605     PORT_Assert(single->certStatus != NULL);
4606     if (single->certStatus->certStatusType == ocspCertStatus_unknown)
4607         return SECSuccess;
4608 
4609     /*
4610      * We need to extract "thisUpdate" for use below and to pass along
4611      * to AuthorizedResponderForCertID in case it needs it for doing an
4612      * issuer look-up.
4613      */
4614     rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate);
4615     if (rv != SECSuccess)
4616         return rv;
4617 
4618     /*
4619      * First confirm that signerCert is authorized to give this status.
4620      */
4621     if (ocsp_AuthorizedResponderForCertID(handle, signerCert, certID,
4622                                           thisUpdate) != PR_TRUE)
4623         return SECFailure;
4624 
4625     /*
4626      * Now check the time stuff, as described above.
4627      */
4628     now = PR_Now();
4629     /* allow slop time for future response */
4630     LL_UI2L(tmstamp, ocspsloptime); /* get slop time in seconds */
4631     LL_UI2L(tmp, PR_USEC_PER_SEC);
4632     LL_MUL(tmp, tmstamp, tmp); /* convert the slop time to PRTime */
4633     LL_ADD(tmstamp, tmp, now); /* add current time to it */
4634 
4635     if (LL_CMP(thisUpdate, >, tmstamp) || LL_CMP(producedAt, <, thisUpdate)) {
4636         PORT_SetError(SEC_ERROR_OCSP_FUTURE_RESPONSE);
4637         return SECFailure;
4638     }
4639     if (single->nextUpdate != NULL) {
4640         rv = DER_GeneralizedTimeToTime(&nextUpdate, single->nextUpdate);
4641         if (rv != SECSuccess)
4642             return rv;
4643 
4644         LL_ADD(tmp, tmp, nextUpdate);
4645         if (LL_CMP(tmp, <, now) || LL_CMP(producedAt, >, nextUpdate))
4646             return ocsp_HandleOldSingleResponse(single, now);
4647     } else if (ocsp_TimeIsRecent(thisUpdate) != PR_TRUE) {
4648         return ocsp_HandleOldSingleResponse(single, now);
4649     }
4650 
4651     return SECSuccess;
4652 }
4653 
4654 /*
4655  * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation
4656  *   Get the value of the URI of the OCSP responder for the given cert.
4657  *   This is found in the (optional) Authority Information Access extension
4658  *   in the cert.
4659  * INPUTS:
4660  *   CERTCertificate *cert
4661  *     The certificate being examined.
4662  * RETURN:
4663  *   char *
4664  *     A copy of the URI for the OCSP method, if found.  If either the
4665  *     extension is not present or it does not contain an entry for OCSP,
4666  *     SEC_ERROR_CERT_BAD_ACCESS_LOCATION will be set and a NULL returned.
4667  *     Any other error will also result in a NULL being returned.
4668  *
4669  *     This result should be freed (via PORT_Free) when no longer in use.
4670  */
4671 char *
CERT_GetOCSPAuthorityInfoAccessLocation(const CERTCertificate * cert)4672 CERT_GetOCSPAuthorityInfoAccessLocation(const CERTCertificate *cert)
4673 {
4674     CERTGeneralName *locname = NULL;
4675     SECItem *location = NULL;
4676     SECItem *encodedAuthInfoAccess = NULL;
4677     CERTAuthInfoAccess **authInfoAccess = NULL;
4678     char *locURI = NULL;
4679     PLArenaPool *arena = NULL;
4680     SECStatus rv;
4681     int i;
4682 
4683     /*
4684      * Allocate this one from the heap because it will get filled in
4685      * by CERT_FindCertExtension which will also allocate from the heap,
4686      * and we can free the entire thing on our way out.
4687      */
4688     encodedAuthInfoAccess = SECITEM_AllocItem(NULL, NULL, 0);
4689     if (encodedAuthInfoAccess == NULL)
4690         goto loser;
4691 
4692     rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
4693                                 encodedAuthInfoAccess);
4694     if (rv == SECFailure) {
4695         PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
4696         goto loser;
4697     }
4698 
4699     /*
4700      * The rest of the things allocated in the routine will come out of
4701      * this arena, which is temporary just for us to decode and get at the
4702      * AIA extension.  The whole thing will be destroyed on our way out,
4703      * after we have copied the location string (url) itself (if found).
4704      */
4705     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
4706     if (arena == NULL)
4707         goto loser;
4708 
4709     authInfoAccess = CERT_DecodeAuthInfoAccessExtension(arena,
4710                                                         encodedAuthInfoAccess);
4711     if (authInfoAccess == NULL)
4712         goto loser;
4713 
4714     for (i = 0; authInfoAccess[i] != NULL; i++) {
4715         if (SECOID_FindOIDTag(&authInfoAccess[i]->method) == SEC_OID_PKIX_OCSP)
4716             locname = authInfoAccess[i]->location;
4717     }
4718 
4719     /*
4720      * If we found an AIA extension, but it did not include an OCSP method,
4721      * that should look to our caller as if we did not find the extension
4722      * at all, because it is only an OCSP method that we care about.
4723      * So set the same error that would be set if the AIA extension was
4724      * not there at all.
4725      */
4726     if (locname == NULL) {
4727         PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
4728         goto loser;
4729     }
4730 
4731     /*
4732      * The following is just a pointer back into locname (i.e. not a copy);
4733      * thus it should not be freed.
4734      */
4735     location = CERT_GetGeneralNameByType(locname, certURI, PR_FALSE);
4736     if (location == NULL) {
4737         /*
4738     	 * XXX Appears that CERT_GetGeneralNameByType does not set an
4739     	 * error if there is no name by that type.  For lack of anything
4740     	 * better, act as if the extension was not found.  In the future
4741     	 * this should probably be something more like the extension was
4742     	 * badly formed.
4743     	 */
4744         PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
4745         goto loser;
4746     }
4747 
4748     /*
4749      * That location is really a string, but it has a specified length
4750      * without a null-terminator.  We need a real string that does have
4751      * a null-terminator, and we need a copy of it anyway to return to
4752      * our caller -- so allocate and copy.
4753      */
4754     locURI = PORT_Alloc(location->len + 1);
4755     if (locURI == NULL) {
4756         goto loser;
4757     }
4758     PORT_Memcpy(locURI, location->data, location->len);
4759     locURI[location->len] = '\0';
4760 
4761 loser:
4762     if (arena != NULL)
4763         PORT_FreeArena(arena, PR_FALSE);
4764 
4765     if (encodedAuthInfoAccess != NULL)
4766         SECITEM_FreeItem(encodedAuthInfoAccess, PR_TRUE);
4767 
4768     return locURI;
4769 }
4770 
4771 /*
4772  * Figure out where we should go to find out the status of the given cert
4773  * via OCSP.  If allowed to use a default responder uri and a default
4774  * responder is set up, then that is our answer.
4775  * If not, see if the certificate has an Authority Information Access (AIA)
4776  * extension for OCSP, and return the value of that.  Otherwise return NULL.
4777  * We also let our caller know whether or not the responder chosen was
4778  * a default responder or not through the output variable isDefault;
4779  * its value has no meaning unless a good (non-null) value is returned
4780  * for the location.
4781  *
4782  * The result needs to be freed (PORT_Free) when no longer in use.
4783  */
4784 char *
ocsp_GetResponderLocation(CERTCertDBHandle * handle,CERTCertificate * cert,PRBool canUseDefault,PRBool * isDefault)4785 ocsp_GetResponderLocation(CERTCertDBHandle *handle, CERTCertificate *cert,
4786                           PRBool canUseDefault, PRBool *isDefault)
4787 {
4788     ocspCheckingContext *ocspcx = NULL;
4789     char *ocspUrl = NULL;
4790 
4791     if (canUseDefault) {
4792         ocspcx = ocsp_GetCheckingContext(handle);
4793     }
4794     if (ocspcx != NULL && ocspcx->useDefaultResponder) {
4795         /*
4796     	 * A default responder wins out, if specified.
4797     	 * XXX Someday this may be a more complicated determination based
4798     	 * on the cert's issuer.  (That is, we could have different default
4799     	 * responders configured for different issuers.)
4800     	 */
4801         PORT_Assert(ocspcx->defaultResponderURI != NULL);
4802         *isDefault = PR_TRUE;
4803         return (PORT_Strdup(ocspcx->defaultResponderURI));
4804     }
4805 
4806     /*
4807      * No default responder set up, so go see if we can find an AIA
4808      * extension that has a value for OCSP, and get the url from that.
4809      */
4810     *isDefault = PR_FALSE;
4811     ocspUrl = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
4812     if (!ocspUrl) {
4813         CERT_StringFromCertFcn altFcn;
4814 
4815         PR_EnterMonitor(OCSP_Global.monitor);
4816         altFcn = OCSP_Global.alternateOCSPAIAFcn;
4817         PR_ExitMonitor(OCSP_Global.monitor);
4818         if (altFcn) {
4819             ocspUrl = (*altFcn)(cert);
4820             if (ocspUrl)
4821                 *isDefault = PR_TRUE;
4822         }
4823     }
4824     return ocspUrl;
4825 }
4826 
4827 /*
4828  * Return SECSuccess if the cert was revoked *after* "time",
4829  * SECFailure otherwise.
4830  */
4831 static SECStatus
ocsp_CertRevokedAfter(ocspRevokedInfo * revokedInfo,PRTime time)4832 ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, PRTime time)
4833 {
4834     PRTime revokedTime;
4835     SECStatus rv;
4836 
4837     rv = DER_GeneralizedTimeToTime(&revokedTime, &revokedInfo->revocationTime);
4838     if (rv != SECSuccess)
4839         return rv;
4840 
4841     /*
4842      * Set the error even if we will return success; someone might care.
4843      */
4844     PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
4845 
4846     if (LL_CMP(revokedTime, >, time))
4847         return SECSuccess;
4848 
4849     return SECFailure;
4850 }
4851 
4852 /*
4853  * See if the cert represented in the single response had a good status
4854  * at the specified time.
4855  */
4856 SECStatus
ocsp_CertHasGoodStatus(ocspCertStatus * status,PRTime time)4857 ocsp_CertHasGoodStatus(ocspCertStatus *status, PRTime time)
4858 {
4859     SECStatus rv;
4860     switch (status->certStatusType) {
4861         case ocspCertStatus_good:
4862             rv = SECSuccess;
4863             break;
4864         case ocspCertStatus_revoked:
4865             rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time);
4866             break;
4867         case ocspCertStatus_unknown:
4868             PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT);
4869             rv = SECFailure;
4870             break;
4871         case ocspCertStatus_other:
4872         default:
4873             PORT_Assert(0);
4874             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
4875             rv = SECFailure;
4876             break;
4877     }
4878     return rv;
4879 }
4880 
4881 static SECStatus
ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse * single,PRTime time)4882 ocsp_SingleResponseCertHasGoodStatus(CERTOCSPSingleResponse *single,
4883                                      PRTime time)
4884 {
4885     return ocsp_CertHasGoodStatus(single->certStatus, time);
4886 }
4887 
4888 /* SECFailure means the arguments were invalid.
4889  * On SECSuccess, the out parameters contain the OCSP status.
4890  * rvOcsp contains the overall result of the OCSP operation.
4891  * Depending on input parameter ignoreGlobalOcspFailureSetting,
4892  * a soft failure might be converted into *rvOcsp=SECSuccess.
4893  * If the cached attempt to obtain OCSP information had resulted
4894  * in a failure, missingResponseError shows the error code of
4895  * that failure.
4896  * cacheFreshness is ocspMissing if no entry was found,
4897  *                   ocspFresh if a fresh entry was found, or
4898  *                   ocspStale if a stale entry was found.
4899  */
4900 SECStatus
ocsp_GetCachedOCSPResponseStatus(CERTOCSPCertID * certID,PRTime time,PRBool ignoreGlobalOcspFailureSetting,SECStatus * rvOcsp,SECErrorCodes * missingResponseError,OCSPFreshness * cacheFreshness)4901 ocsp_GetCachedOCSPResponseStatus(CERTOCSPCertID *certID,
4902                                  PRTime time,
4903                                  PRBool ignoreGlobalOcspFailureSetting,
4904                                  SECStatus *rvOcsp,
4905                                  SECErrorCodes *missingResponseError,
4906                                  OCSPFreshness *cacheFreshness)
4907 {
4908     OCSPCacheItem *cacheItem = NULL;
4909 
4910     if (!certID || !missingResponseError || !rvOcsp || !cacheFreshness) {
4911         PORT_SetError(SEC_ERROR_INVALID_ARGS);
4912         return SECFailure;
4913     }
4914     *rvOcsp = SECFailure;
4915     *missingResponseError = 0;
4916     *cacheFreshness = ocspMissing;
4917 
4918     PR_EnterMonitor(OCSP_Global.monitor);
4919     cacheItem = ocsp_FindCacheEntry(&OCSP_Global.cache, certID);
4920     if (cacheItem) {
4921         *cacheFreshness = ocsp_IsCacheItemFresh(cacheItem) ? ocspFresh
4922                                                            : ocspStale;
4923         /* having an arena means, we have a cached certStatus */
4924         if (cacheItem->certStatusArena) {
4925             *rvOcsp = ocsp_CertHasGoodStatus(&cacheItem->certStatus, time);
4926             if (*rvOcsp != SECSuccess) {
4927                 *missingResponseError = PORT_GetError();
4928             }
4929         } else {
4930             /*
4931              * No status cached, the previous attempt failed.
4932              * If OCSP is required, we never decide based on a failed attempt
4933              * However, if OCSP is optional, a recent OCSP failure is
4934              * an allowed good state.
4935              */
4936             if (*cacheFreshness == ocspFresh &&
4937                 !ignoreGlobalOcspFailureSetting &&
4938                 OCSP_Global.ocspFailureMode ==
4939                     ocspMode_FailureIsNotAVerificationFailure) {
4940                 *rvOcsp = SECSuccess;
4941             }
4942             *missingResponseError = cacheItem->missingResponseError;
4943         }
4944     }
4945     PR_ExitMonitor(OCSP_Global.monitor);
4946     return SECSuccess;
4947 }
4948 
4949 PRBool
ocsp_FetchingFailureIsVerificationFailure(void)4950 ocsp_FetchingFailureIsVerificationFailure(void)
4951 {
4952     PRBool isFailure;
4953 
4954     PR_EnterMonitor(OCSP_Global.monitor);
4955     isFailure =
4956         OCSP_Global.ocspFailureMode == ocspMode_FailureIsVerificationFailure;
4957     PR_ExitMonitor(OCSP_Global.monitor);
4958     return isFailure;
4959 }
4960 
4961 /*
4962  * FUNCTION: CERT_CheckOCSPStatus
4963  *   Checks the status of a certificate via OCSP.  Will only check status for
4964  *   a certificate that has an AIA (Authority Information Access) extension
4965  *   for OCSP *or* when a "default responder" is specified and enabled.
4966  *   (If no AIA extension for OCSP and no default responder in place, the
4967  *   cert is considered to have a good status and SECSuccess is returned.)
4968  * INPUTS:
4969  *   CERTCertDBHandle *handle
4970  *     certificate DB of the cert that is being checked
4971  *   CERTCertificate *cert
4972  *     the certificate being checked
4973  *   XXX in the long term also need a boolean parameter that specifies
4974  *	whether to check the cert chain, as well; for now we check only
4975  *	the leaf (the specified certificate)
4976  *   PRTime time
4977  *     time for which status is to be determined
4978  *   void *pwArg
4979  *     argument for password prompting, if needed
4980  * RETURN:
4981  *   Returns SECSuccess if an approved OCSP responder "knows" the cert
4982  *   *and* returns a non-revoked status for it; SECFailure otherwise,
4983  *   with an error set describing the reason:
4984  *
4985  *	SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
4986  *	SEC_ERROR_OCSP_FUTURE_RESPONSE
4987  *	SEC_ERROR_OCSP_MALFORMED_REQUEST
4988  *	SEC_ERROR_OCSP_MALFORMED_RESPONSE
4989  *	SEC_ERROR_OCSP_OLD_RESPONSE
4990  *	SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
4991  *	SEC_ERROR_OCSP_SERVER_ERROR
4992  *	SEC_ERROR_OCSP_TRY_SERVER_LATER
4993  *	SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
4994  *	SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
4995  *	SEC_ERROR_OCSP_UNKNOWN_CERT
4996  *	SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
4997  *	SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE
4998  *
4999  *	SEC_ERROR_BAD_SIGNATURE
5000  *	SEC_ERROR_CERT_BAD_ACCESS_LOCATION
5001  *	SEC_ERROR_INVALID_TIME
5002  *	SEC_ERROR_REVOKED_CERTIFICATE
5003  *	SEC_ERROR_UNKNOWN_ISSUER
5004  *	SEC_ERROR_UNKNOWN_SIGNER
5005  *
5006  *   Other errors are any of the many possible failures in cert verification
5007  *   (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
5008  *   verifying the signer's cert, or low-level problems (error allocating
5009  *   memory, error performing ASN.1 decoding, etc.).
5010  */
5011 SECStatus
CERT_CheckOCSPStatus(CERTCertDBHandle * handle,CERTCertificate * cert,PRTime time,void * pwArg)5012 CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
5013                      PRTime time, void *pwArg)
5014 {
5015     CERTOCSPCertID *certID;
5016     PRBool certIDWasConsumed = PR_FALSE;
5017     SECStatus rv;
5018     SECStatus rvOcsp;
5019     SECErrorCodes cachedErrorCode;
5020     OCSPFreshness cachedResponseFreshness;
5021 
5022     OCSP_TRACE_CERT(cert);
5023     OCSP_TRACE_TIME("## requested validity time:", time);
5024 
5025     certID = CERT_CreateOCSPCertID(cert, time);
5026     if (!certID)
5027         return SECFailure;
5028     rv = ocsp_GetCachedOCSPResponseStatus(
5029         certID, time, PR_FALSE, /* ignoreGlobalOcspFailureSetting */
5030         &rvOcsp, &cachedErrorCode, &cachedResponseFreshness);
5031     if (rv != SECSuccess) {
5032         CERT_DestroyOCSPCertID(certID);
5033         return SECFailure;
5034     }
5035     if (cachedResponseFreshness == ocspFresh) {
5036         CERT_DestroyOCSPCertID(certID);
5037         if (rvOcsp != SECSuccess) {
5038             PORT_SetError(cachedErrorCode);
5039         }
5040         return rvOcsp;
5041     }
5042 
5043     rv = ocsp_GetOCSPStatusFromNetwork(handle, certID, cert, time, pwArg,
5044                                        &certIDWasConsumed,
5045                                        &rvOcsp);
5046     if (rv != SECSuccess) {
5047         PRErrorCode err = PORT_GetError();
5048         if (ocsp_FetchingFailureIsVerificationFailure()) {
5049             PORT_SetError(err);
5050             rvOcsp = SECFailure;
5051         } else if (cachedResponseFreshness == ocspStale &&
5052                    (cachedErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT ||
5053                     cachedErrorCode == SEC_ERROR_REVOKED_CERTIFICATE)) {
5054             /* If we couldn't get a response for a certificate that the OCSP
5055              * responder previously told us was bad, then assume it is still
5056              * bad until we hear otherwise, as it is very unlikely that the
5057              * certificate status has changed from "revoked" to "good" and it
5058              * is also unlikely that the certificate status has changed from
5059              * "unknown" to "good", except for some buggy OCSP responders.
5060              */
5061             PORT_SetError(cachedErrorCode);
5062             rvOcsp = SECFailure;
5063         } else {
5064             rvOcsp = SECSuccess;
5065         }
5066     }
5067     if (!certIDWasConsumed) {
5068         CERT_DestroyOCSPCertID(certID);
5069     }
5070     return rvOcsp;
5071 }
5072 
5073 /*
5074  * FUNCTION: CERT_CacheOCSPResponseFromSideChannel
5075  *   First, this function checks the OCSP cache to see if a good response
5076  *   for the given certificate already exists. If it does, then the function
5077  *   returns successfully.
5078  *
5079  *   If not, then it validates that the given OCSP response is a valid,
5080  *   good response for the given certificate and inserts it into the
5081  *   cache.
5082  *
5083  *   This function is intended for use when OCSP responses are provided via a
5084  *   side-channel, i.e. TLS OCSP stapling (a.k.a. the status_request extension).
5085  *
5086  * INPUTS:
5087  *   CERTCertDBHandle *handle
5088  *     certificate DB of the cert that is being checked
5089  *   CERTCertificate *cert
5090  *     the certificate being checked
5091  *   PRTime time
5092  *     time for which status is to be determined
5093  *   SECItem *encodedResponse
5094  *     the DER encoded bytes of the OCSP response
5095  *   void *pwArg
5096  *     argument for password prompting, if needed
5097  * RETURN:
5098  *   SECSuccess if the cert was found in the cache, or if the OCSP response was
5099  *   found to be valid and inserted into the cache. SECFailure otherwise.
5100  */
5101 SECStatus
CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle * handle,CERTCertificate * cert,PRTime time,const SECItem * encodedResponse,void * pwArg)5102 CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle,
5103                                       CERTCertificate *cert,
5104                                       PRTime time,
5105                                       const SECItem *encodedResponse,
5106                                       void *pwArg)
5107 {
5108     CERTOCSPCertID *certID = NULL;
5109     PRBool certIDWasConsumed = PR_FALSE;
5110     SECStatus rv = SECFailure;
5111     SECStatus rvOcsp = SECFailure;
5112     SECErrorCodes dummy_error_code; /* we ignore this */
5113     CERTOCSPResponse *decodedResponse = NULL;
5114     CERTOCSPSingleResponse *singleResponse = NULL;
5115     OCSPFreshness freshness;
5116 
5117     /* The OCSP cache can be in three states regarding this certificate:
5118      *    + Good (cached, timely, 'good' response, or revoked in the future)
5119      *    + Revoked (cached, timely, but doesn't fit in the last category)
5120      *    + Miss (no knowledge)
5121      *
5122      * Likewise, the side-channel information can be
5123      *    + Good (timely, 'good' response, or revoked in the future)
5124      *    + Revoked (timely, but doesn't fit in the last category)
5125      *    + Invalid (bad syntax, bad signature, not timely etc)
5126      *
5127      * The common case is that the cache result is Good and so is the
5128      * side-channel information. We want to save processing time in this case
5129      * so we say that any time we see a Good result from the cache we return
5130      * early.
5131      *
5132      *                       Cache result
5133      *      | Good             Revoked               Miss
5134      *   ---+--------------------------------------------
5135      *    G |  noop           Cache more           Cache it
5136      * S    |                 recent result
5137      * i    |
5138      * d    |
5139      * e    |
5140      *    R |  noop           Cache more           Cache it
5141      * C    |                 recent result
5142      * h    |
5143      * a    |
5144      * n    |
5145      * n  I |  noop           Noop                  Noop
5146      * e    |
5147      * l    |
5148      *
5149      * When we fetch from the network we might choose to cache a negative
5150      * result when the response is invalid. This saves us hammering, uselessly,
5151      * at a broken responder. However, side channels are commonly attacker
5152      * controlled and so we must not cache a negative result for an Invalid
5153      * side channel.
5154      */
5155 
5156     if (!cert || !encodedResponse) {
5157         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5158         return SECFailure;
5159     }
5160     certID = CERT_CreateOCSPCertID(cert, time);
5161     if (!certID)
5162         return SECFailure;
5163 
5164     /* We pass PR_TRUE for ignoreGlobalOcspFailureSetting so that a cached
5165      * error entry is not interpreted as being a 'Good' entry here.
5166      */
5167     rv = ocsp_GetCachedOCSPResponseStatus(
5168         certID, time, PR_TRUE, /* ignoreGlobalOcspFailureSetting */
5169         &rvOcsp, &dummy_error_code, &freshness);
5170     if (rv == SECSuccess && rvOcsp == SECSuccess && freshness == ocspFresh) {
5171         /* The cached value is good. We don't want to waste time validating
5172          * this OCSP response. This is the first column in the table above. */
5173         CERT_DestroyOCSPCertID(certID);
5174         return rv;
5175     }
5176 
5177     /* The logic for caching the more recent response is handled in
5178      * ocsp_CacheSingleResponse. */
5179 
5180     rv = ocsp_GetDecodedVerifiedSingleResponseForID(handle, certID, cert,
5181                                                     time, pwArg,
5182                                                     encodedResponse,
5183                                                     &decodedResponse,
5184                                                     &singleResponse);
5185     if (rv == SECSuccess) {
5186         rvOcsp = ocsp_SingleResponseCertHasGoodStatus(singleResponse, time);
5187         /* Cache any valid singleResponse, regardless of status. */
5188         ocsp_CacheSingleResponse(certID, singleResponse, &certIDWasConsumed);
5189     }
5190     if (decodedResponse) {
5191         CERT_DestroyOCSPResponse(decodedResponse);
5192     }
5193     if (!certIDWasConsumed) {
5194         CERT_DestroyOCSPCertID(certID);
5195     }
5196     return rv == SECSuccess ? rvOcsp : rv;
5197 }
5198 
5199 /*
5200  * Status in *certIDWasConsumed will always be correct, regardless of
5201  * return value.
5202  */
5203 static SECStatus
ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle * handle,CERTOCSPCertID * certID,CERTCertificate * cert,PRTime time,void * pwArg,PRBool * certIDWasConsumed,SECStatus * rv_ocsp)5204 ocsp_GetOCSPStatusFromNetwork(CERTCertDBHandle *handle,
5205                               CERTOCSPCertID *certID,
5206                               CERTCertificate *cert,
5207                               PRTime time,
5208                               void *pwArg,
5209                               PRBool *certIDWasConsumed,
5210                               SECStatus *rv_ocsp)
5211 {
5212     char *location = NULL;
5213     PRBool locationIsDefault;
5214     SECItem *encodedResponse = NULL;
5215     CERTOCSPRequest *request = NULL;
5216     SECStatus rv = SECFailure;
5217 
5218     CERTOCSPResponse *decodedResponse = NULL;
5219     CERTOCSPSingleResponse *singleResponse = NULL;
5220     enum { stageGET,
5221            stagePOST } currentStage;
5222     PRBool retry = PR_FALSE;
5223 
5224     if (!certIDWasConsumed || !rv_ocsp) {
5225         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5226         return SECFailure;
5227     }
5228     *certIDWasConsumed = PR_FALSE;
5229     *rv_ocsp = SECFailure;
5230 
5231     if (!OCSP_Global.monitor) {
5232         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
5233         return SECFailure;
5234     }
5235     PR_EnterMonitor(OCSP_Global.monitor);
5236     if (OCSP_Global.forcePost) {
5237         currentStage = stagePOST;
5238     } else {
5239         currentStage = stageGET;
5240     }
5241     PR_ExitMonitor(OCSP_Global.monitor);
5242 
5243     /*
5244      * The first thing we need to do is find the location of the responder.
5245      * This will be the value of the default responder (if enabled), else
5246      * it will come out of the AIA extension in the cert (if present).
5247      * If we have no such location, then this cert does not "deserve" to
5248      * be checked -- that is, we consider it a success and just return.
5249      * The way we tell that is by looking at the error number to see if
5250      * the problem was no AIA extension was found; any other error was
5251      * a true failure that we unfortunately have to treat as an overall
5252      * failure here.
5253      */
5254     location = ocsp_GetResponderLocation(handle, cert, PR_TRUE,
5255                                          &locationIsDefault);
5256     if (location == NULL) {
5257         int err = PORT_GetError();
5258         if (err == SEC_ERROR_EXTENSION_NOT_FOUND ||
5259             err == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) {
5260             PORT_SetError(0);
5261             *rv_ocsp = SECSuccess;
5262             return SECSuccess;
5263         }
5264         return SECFailure;
5265     }
5266 
5267     /*
5268      * XXX In the fullness of time, we will want/need to handle a
5269      * certificate chain.  This will be done either when a new parameter
5270      * tells us to, or some configuration variable tells us to.  In any
5271      * case, handling it is complicated because we may need to send as
5272      * many requests (and receive as many responses) as we have certs
5273      * in the chain.  If we are going to talk to a default responder,
5274      * and we only support one default responder, we can put all of the
5275      * certs together into one request.  Otherwise, we must break them up
5276      * into multiple requests.  (Even if all of the requests will go to
5277      * the same location, the signature on each response will be different,
5278      * because each issuer is different.  Carefully read the OCSP spec
5279      * if you do not understand this.)
5280      */
5281 
5282     /*
5283      * XXX If/when signing of requests is supported, that second NULL
5284      * should be changed to be the signer certificate.  Not sure if that
5285      * should be passed into this function or retrieved via some operation
5286      * on the handle/context.
5287      */
5288 
5289     do {
5290         const char *method;
5291         PRBool validResponseWithAccurateInfo = PR_FALSE;
5292         retry = PR_FALSE;
5293         *rv_ocsp = SECFailure;
5294 
5295         if (currentStage == stageGET) {
5296             method = "GET";
5297         } else {
5298             PORT_Assert(currentStage == stagePOST);
5299             method = "POST";
5300         }
5301 
5302         encodedResponse =
5303             ocsp_GetEncodedOCSPResponseForSingleCert(NULL, certID, cert,
5304                                                      location, method,
5305                                                      time, locationIsDefault,
5306                                                      pwArg, &request);
5307 
5308         if (encodedResponse) {
5309             rv = ocsp_GetDecodedVerifiedSingleResponseForID(handle, certID, cert,
5310                                                             time, pwArg,
5311                                                             encodedResponse,
5312                                                             &decodedResponse,
5313                                                             &singleResponse);
5314             if (rv == SECSuccess) {
5315                 switch (singleResponse->certStatus->certStatusType) {
5316                     case ocspCertStatus_good:
5317                     case ocspCertStatus_revoked:
5318                         validResponseWithAccurateInfo = PR_TRUE;
5319                         break;
5320                     default:
5321                         break;
5322                 }
5323                 *rv_ocsp = ocsp_SingleResponseCertHasGoodStatus(singleResponse, time);
5324             }
5325         }
5326 
5327         if (currentStage == stageGET) {
5328             /* only accept GET response if good or revoked */
5329             if (validResponseWithAccurateInfo) {
5330                 ocsp_CacheSingleResponse(certID, singleResponse,
5331                                          certIDWasConsumed);
5332             } else {
5333                 retry = PR_TRUE;
5334                 currentStage = stagePOST;
5335             }
5336         } else {
5337             /* cache the POST respone, regardless of status */
5338             if (!singleResponse) {
5339                 cert_RememberOCSPProcessingFailure(certID, certIDWasConsumed);
5340             } else {
5341                 ocsp_CacheSingleResponse(certID, singleResponse,
5342                                          certIDWasConsumed);
5343             }
5344         }
5345 
5346         if (encodedResponse) {
5347             SECITEM_FreeItem(encodedResponse, PR_TRUE);
5348             encodedResponse = NULL;
5349         }
5350         if (request) {
5351             CERT_DestroyOCSPRequest(request);
5352             request = NULL;
5353         }
5354         if (decodedResponse) {
5355             CERT_DestroyOCSPResponse(decodedResponse);
5356             decodedResponse = NULL;
5357         }
5358         singleResponse = NULL;
5359 
5360     } while (retry);
5361 
5362     PORT_Free(location);
5363     return rv;
5364 }
5365 
5366 /*
5367  * FUNCTION: ocsp_GetDecodedVerifiedSingleResponseForID
5368  *   This function decodes an OCSP response and checks for a valid response
5369  *   concerning the given certificate.
5370  *
5371  *   Note: a 'valid' response is one that parses successfully, is not an OCSP
5372  *   exception (see RFC 2560 Section 2.3), is correctly signed and is current.
5373  *   A 'good' response is a valid response that attests that the certificate
5374  *   is not currently revoked (see RFC 2560 Section 2.2).
5375  *
5376  * INPUTS:
5377  *   CERTCertDBHandle *handle
5378  *     certificate DB of the cert that is being checked
5379  *   CERTOCSPCertID *certID
5380  *     the cert ID corresponding to |cert|
5381  *   CERTCertificate *cert
5382  *     the certificate being checked
5383  *   PRTime time
5384  *     time for which status is to be determined
5385  *   void *pwArg
5386  *     the opaque argument to the password prompting function.
5387  *   SECItem *encodedResponse
5388  *     the DER encoded bytes of the OCSP response
5389  *   CERTOCSPResponse **pDecodedResponse
5390  *     (output) The caller must ALWAYS check for this output parameter,
5391  *     and if it's non-null, must destroy it using CERT_DestroyOCSPResponse.
5392  *   CERTOCSPSingleResponse **pSingle
5393  *     (output) on success, this points to the single response that corresponds
5394  *     to the certID parameter. Points to the inside of pDecodedResponse.
5395  *     It isn't a copy, don't free it.
5396  * RETURN:
5397  *   SECSuccess iff the response is valid.
5398  */
5399 static SECStatus
ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle * handle,CERTOCSPCertID * certID,CERTCertificate * cert,PRTime time,void * pwArg,const SECItem * encodedResponse,CERTOCSPResponse ** pDecodedResponse,CERTOCSPSingleResponse ** pSingle)5400 ocsp_GetDecodedVerifiedSingleResponseForID(CERTCertDBHandle *handle,
5401                                            CERTOCSPCertID *certID,
5402                                            CERTCertificate *cert,
5403                                            PRTime time,
5404                                            void *pwArg,
5405                                            const SECItem *encodedResponse,
5406                                            CERTOCSPResponse **pDecodedResponse,
5407                                            CERTOCSPSingleResponse **pSingle)
5408 {
5409     CERTCertificate *signerCert = NULL;
5410     CERTCertificate *issuerCert = NULL;
5411     SECStatus rv = SECFailure;
5412 
5413     if (!pSingle || !pDecodedResponse) {
5414         return SECFailure;
5415     }
5416     *pSingle = NULL;
5417     *pDecodedResponse = CERT_DecodeOCSPResponse(encodedResponse);
5418     if (!*pDecodedResponse) {
5419         return SECFailure;
5420     }
5421 
5422     /*
5423      * Okay, we at least have a response that *looks* like a response!
5424      * Now see if the overall response status value is good or not.
5425      * If not, we set an error and give up.  (It means that either the
5426      * server had a problem, or it didn't like something about our
5427      * request.  Either way there is nothing to do but give up.)
5428      * Otherwise, we continue to find the actual per-cert status
5429      * in the response.
5430      */
5431     if (CERT_GetOCSPResponseStatus(*pDecodedResponse) != SECSuccess) {
5432         goto loser;
5433     }
5434 
5435     /*
5436      * If we've made it this far, we expect a response with a good signature.
5437      * So, check for that.
5438      */
5439     issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA);
5440     rv = CERT_VerifyOCSPResponseSignature(*pDecodedResponse, handle, pwArg,
5441                                           &signerCert, issuerCert);
5442     if (rv != SECSuccess) {
5443         goto loser;
5444     }
5445 
5446     PORT_Assert(signerCert != NULL); /* internal consistency check */
5447     /* XXX probably should set error, return failure if signerCert is null */
5448 
5449     /*
5450      * Again, we are only doing one request for one cert.
5451      * XXX When we handle cert chains, the following code will obviously
5452      * have to be modified, in coordation with the code above that will
5453      * have to determine how to make multiple requests, etc.
5454      */
5455     rv = ocsp_GetVerifiedSingleResponseForCertID(handle, *pDecodedResponse, certID,
5456                                                  signerCert, time, pSingle);
5457 loser:
5458     if (issuerCert != NULL)
5459         CERT_DestroyCertificate(issuerCert);
5460     if (signerCert != NULL)
5461         CERT_DestroyCertificate(signerCert);
5462     return rv;
5463 }
5464 
5465 /*
5466  * FUNCTION: ocsp_CacheSingleResponse
5467  *   This function requires that the caller has checked that the response
5468  *   is valid and verified.
5469  *   The (positive or negative) valid response will be used to update the cache.
5470  * INPUTS:
5471  *   CERTOCSPCertID *certID
5472  *     the cert ID corresponding to |cert|
5473  *   PRBool *certIDWasConsumed
5474  *     (output) on return, this is true iff |certID| was consumed by this
5475  *     function.
5476  */
5477 void
ocsp_CacheSingleResponse(CERTOCSPCertID * certID,CERTOCSPSingleResponse * single,PRBool * certIDWasConsumed)5478 ocsp_CacheSingleResponse(CERTOCSPCertID *certID,
5479                          CERTOCSPSingleResponse *single,
5480                          PRBool *certIDWasConsumed)
5481 {
5482     if (single != NULL) {
5483         PR_EnterMonitor(OCSP_Global.monitor);
5484         if (OCSP_Global.maxCacheEntries >= 0) {
5485             ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, single,
5486                                           certIDWasConsumed);
5487             /* ignore cache update failures */
5488         }
5489         PR_ExitMonitor(OCSP_Global.monitor);
5490     }
5491 }
5492 
5493 SECStatus
ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle * handle,CERTOCSPResponse * response,CERTOCSPCertID * certID,CERTCertificate * signerCert,PRTime time,CERTOCSPSingleResponse ** pSingleResponse)5494 ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle,
5495                                         CERTOCSPResponse *response,
5496                                         CERTOCSPCertID *certID,
5497                                         CERTCertificate *signerCert,
5498                                         PRTime time,
5499                                         CERTOCSPSingleResponse
5500                                             **pSingleResponse)
5501 {
5502     SECStatus rv;
5503     ocspResponseData *responseData;
5504     PRTime producedAt;
5505     CERTOCSPSingleResponse *single;
5506 
5507     /*
5508      * The ResponseData part is the real guts of the response.
5509      */
5510     responseData = ocsp_GetResponseData(response, NULL);
5511     if (responseData == NULL) {
5512         rv = SECFailure;
5513         goto loser;
5514     }
5515 
5516     /*
5517      * There is one producedAt time for the entire response (and a separate
5518      * thisUpdate time for each individual single response).  We need to
5519      * compare them, so get the overall time to pass into the check of each
5520      * single response.
5521      */
5522     rv = DER_GeneralizedTimeToTime(&producedAt, &responseData->producedAt);
5523     if (rv != SECSuccess)
5524         goto loser;
5525 
5526     single = ocsp_GetSingleResponseForCertID(responseData->responses,
5527                                              handle, certID);
5528     if (single == NULL) {
5529         rv = SECFailure;
5530         goto loser;
5531     }
5532 
5533     rv = ocsp_VerifySingleResponse(single, handle, signerCert, producedAt);
5534     if (rv != SECSuccess)
5535         goto loser;
5536     *pSingleResponse = single;
5537 
5538 loser:
5539     return rv;
5540 }
5541 
5542 SECStatus
CERT_GetOCSPStatusForCertID(CERTCertDBHandle * handle,CERTOCSPResponse * response,CERTOCSPCertID * certID,CERTCertificate * signerCert,PRTime time)5543 CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle,
5544                             CERTOCSPResponse *response,
5545                             CERTOCSPCertID *certID,
5546                             CERTCertificate *signerCert,
5547                             PRTime time)
5548 {
5549     /*
5550      * We do not update the cache, because:
5551      *
5552      * CERT_GetOCSPStatusForCertID is an old exported API that was introduced
5553      * before the OCSP cache got implemented.
5554      *
5555      * The implementation of helper function cert_ProcessOCSPResponse
5556      * requires the ability to transfer ownership of the the given certID to
5557      * the cache. The external API doesn't allow us to prevent the caller from
5558      * destroying the certID. We don't have the original certificate available,
5559      * therefore we are unable to produce another certID object (that could
5560      * be stored in the cache).
5561      *
5562      * Should we ever implement code to produce a deep copy of certID,
5563      * then this could be changed to allow updating the cache.
5564      * The duplication would have to be done in
5565      * cert_ProcessOCSPResponse, if the out parameter to indicate
5566      * a transfer of ownership is NULL.
5567      */
5568     return cert_ProcessOCSPResponse(handle, response, certID,
5569                                     signerCert, time,
5570                                     NULL, NULL);
5571 }
5572 
5573 /*
5574  * The first 5 parameters match the definition of CERT_GetOCSPStatusForCertID.
5575  */
5576 SECStatus
cert_ProcessOCSPResponse(CERTCertDBHandle * handle,CERTOCSPResponse * response,CERTOCSPCertID * certID,CERTCertificate * signerCert,PRTime time,PRBool * certIDWasConsumed,SECStatus * cacheUpdateStatus)5577 cert_ProcessOCSPResponse(CERTCertDBHandle *handle,
5578                          CERTOCSPResponse *response,
5579                          CERTOCSPCertID *certID,
5580                          CERTCertificate *signerCert,
5581                          PRTime time,
5582                          PRBool *certIDWasConsumed,
5583                          SECStatus *cacheUpdateStatus)
5584 {
5585     SECStatus rv;
5586     SECStatus rv_cache = SECSuccess;
5587     CERTOCSPSingleResponse *single = NULL;
5588 
5589     rv = ocsp_GetVerifiedSingleResponseForCertID(handle, response, certID,
5590                                                  signerCert, time, &single);
5591     if (rv == SECSuccess) {
5592         /*
5593          * Check whether the status says revoked, and if so
5594          * how that compares to the time value passed into this routine.
5595          */
5596         rv = ocsp_SingleResponseCertHasGoodStatus(single, time);
5597     }
5598 
5599     if (certIDWasConsumed) {
5600         /*
5601          * We don't have copy-of-certid implemented. In order to update
5602          * the cache, the caller must supply an out variable
5603          * certIDWasConsumed, allowing us to return ownership status.
5604          */
5605 
5606         PR_EnterMonitor(OCSP_Global.monitor);
5607         if (OCSP_Global.maxCacheEntries >= 0) {
5608             /* single == NULL means: remember response failure */
5609             rv_cache =
5610                 ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID,
5611                                               single, certIDWasConsumed);
5612         }
5613         PR_ExitMonitor(OCSP_Global.monitor);
5614         if (cacheUpdateStatus) {
5615             *cacheUpdateStatus = rv_cache;
5616         }
5617     }
5618 
5619     return rv;
5620 }
5621 
5622 SECStatus
cert_RememberOCSPProcessingFailure(CERTOCSPCertID * certID,PRBool * certIDWasConsumed)5623 cert_RememberOCSPProcessingFailure(CERTOCSPCertID *certID,
5624                                    PRBool *certIDWasConsumed)
5625 {
5626     SECStatus rv = SECSuccess;
5627     PR_EnterMonitor(OCSP_Global.monitor);
5628     if (OCSP_Global.maxCacheEntries >= 0) {
5629         rv = ocsp_CreateOrUpdateCacheEntry(&OCSP_Global.cache, certID, NULL,
5630                                            certIDWasConsumed);
5631     }
5632     PR_ExitMonitor(OCSP_Global.monitor);
5633     return rv;
5634 }
5635 
5636 /*
5637  * Disable status checking and destroy related structures/data.
5638  */
5639 static SECStatus
ocsp_DestroyStatusChecking(CERTStatusConfig * statusConfig)5640 ocsp_DestroyStatusChecking(CERTStatusConfig *statusConfig)
5641 {
5642     ocspCheckingContext *statusContext;
5643 
5644     /*
5645      * Disable OCSP checking
5646      */
5647     statusConfig->statusChecker = NULL;
5648 
5649     statusContext = statusConfig->statusContext;
5650     PORT_Assert(statusContext != NULL);
5651     if (statusContext == NULL)
5652         return SECFailure;
5653 
5654     if (statusContext->defaultResponderURI != NULL)
5655         PORT_Free(statusContext->defaultResponderURI);
5656     if (statusContext->defaultResponderNickname != NULL)
5657         PORT_Free(statusContext->defaultResponderNickname);
5658 
5659     PORT_Free(statusContext);
5660     statusConfig->statusContext = NULL;
5661 
5662     PORT_Free(statusConfig);
5663 
5664     return SECSuccess;
5665 }
5666 
5667 /*
5668  * FUNCTION: CERT_DisableOCSPChecking
5669  *   Turns off OCSP checking for the given certificate database.
5670  *   This routine disables OCSP checking.  Though it will return
5671  *   SECFailure if OCSP checking is not enabled, it is "safe" to
5672  *   call it that way and just ignore the return value, if it is
5673  *   easier to just call it than to "remember" whether it is enabled.
5674  * INPUTS:
5675  *   CERTCertDBHandle *handle
5676  *     Certificate database for which OCSP checking will be disabled.
5677  * RETURN:
5678  *   Returns SECFailure if an error occurred (usually means that OCSP
5679  *   checking was not enabled or status contexts were not initialized --
5680  *   error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise.
5681  */
5682 SECStatus
CERT_DisableOCSPChecking(CERTCertDBHandle * handle)5683 CERT_DisableOCSPChecking(CERTCertDBHandle *handle)
5684 {
5685     CERTStatusConfig *statusConfig;
5686     ocspCheckingContext *statusContext;
5687 
5688     if (handle == NULL) {
5689         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5690         return SECFailure;
5691     }
5692 
5693     statusConfig = CERT_GetStatusConfig(handle);
5694     statusContext = ocsp_GetCheckingContext(handle);
5695     if (statusContext == NULL)
5696         return SECFailure;
5697 
5698     if (statusConfig->statusChecker != CERT_CheckOCSPStatus) {
5699         /*
5700     	 * Status configuration is present, but either not currently
5701     	 * enabled or not for OCSP.
5702     	 */
5703         PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED);
5704         return SECFailure;
5705     }
5706 
5707     /* cache no longer necessary */
5708     CERT_ClearOCSPCache();
5709 
5710     /*
5711      * This is how we disable status checking.  Everything else remains
5712      * in place in case we are enabled again.
5713      */
5714     statusConfig->statusChecker = NULL;
5715 
5716     return SECSuccess;
5717 }
5718 
5719 /*
5720  * Allocate and initialize the informational structures for status checking.
5721  * This is done when some configuration of OCSP is being done or when OCSP
5722  * checking is being turned on, whichever comes first.
5723  */
5724 static SECStatus
ocsp_InitStatusChecking(CERTCertDBHandle * handle)5725 ocsp_InitStatusChecking(CERTCertDBHandle *handle)
5726 {
5727     CERTStatusConfig *statusConfig = NULL;
5728     ocspCheckingContext *statusContext = NULL;
5729 
5730     PORT_Assert(CERT_GetStatusConfig(handle) == NULL);
5731     if (CERT_GetStatusConfig(handle) != NULL) {
5732         /* XXX or call statusConfig->statusDestroy and continue? */
5733         return SECFailure;
5734     }
5735 
5736     statusConfig = PORT_ZNew(CERTStatusConfig);
5737     if (statusConfig == NULL)
5738         goto loser;
5739 
5740     statusContext = PORT_ZNew(ocspCheckingContext);
5741     if (statusContext == NULL)
5742         goto loser;
5743 
5744     statusConfig->statusDestroy = ocsp_DestroyStatusChecking;
5745     statusConfig->statusContext = statusContext;
5746 
5747     CERT_SetStatusConfig(handle, statusConfig);
5748 
5749     return SECSuccess;
5750 
5751 loser:
5752     if (statusConfig != NULL)
5753         PORT_Free(statusConfig);
5754     return SECFailure;
5755 }
5756 
5757 /*
5758  * FUNCTION: CERT_EnableOCSPChecking
5759  *   Turns on OCSP checking for the given certificate database.
5760  * INPUTS:
5761  *   CERTCertDBHandle *handle
5762  *     Certificate database for which OCSP checking will be enabled.
5763  * RETURN:
5764  *   Returns SECFailure if an error occurred (likely only problem
5765  *   allocating memory); SECSuccess otherwise.
5766  */
5767 SECStatus
CERT_EnableOCSPChecking(CERTCertDBHandle * handle)5768 CERT_EnableOCSPChecking(CERTCertDBHandle *handle)
5769 {
5770     CERTStatusConfig *statusConfig;
5771 
5772     SECStatus rv;
5773 
5774     if (handle == NULL) {
5775         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5776         return SECFailure;
5777     }
5778 
5779     statusConfig = CERT_GetStatusConfig(handle);
5780     if (statusConfig == NULL) {
5781         rv = ocsp_InitStatusChecking(handle);
5782         if (rv != SECSuccess)
5783             return rv;
5784 
5785         /* Get newly established value */
5786         statusConfig = CERT_GetStatusConfig(handle);
5787         PORT_Assert(statusConfig != NULL);
5788     }
5789 
5790     /*
5791      * Setting the checker function is what really enables the checking
5792      * when each cert verification is done.
5793      */
5794     statusConfig->statusChecker = CERT_CheckOCSPStatus;
5795 
5796     return SECSuccess;
5797 }
5798 
5799 /*
5800  * FUNCTION: CERT_SetOCSPDefaultResponder
5801  *   Specify the location and cert of the default responder.
5802  *   If OCSP checking is already enabled *and* use of a default responder
5803  *   is also already enabled, all OCSP checking from now on will go directly
5804  *   to the specified responder.  If OCSP checking is not enabled, or if
5805  *   it is but use of a default responder is not enabled, the information
5806  *   will be recorded and take effect whenever both are enabled.
5807  * INPUTS:
5808  *   CERTCertDBHandle *handle
5809  *     Cert database on which OCSP checking should use the default responder.
5810  *   char *url
5811  *     The location of the default responder (e.g. "http://foo.com:80/ocsp")
5812  *     Note that the location will not be tested until the first attempt
5813  *     to send a request there.
5814  *   char *name
5815  *     The nickname of the cert to trust (expected) to sign the OCSP responses.
5816  *     If the corresponding cert cannot be found, SECFailure is returned.
5817  * RETURN:
5818  *   Returns SECFailure if an error occurred; SECSuccess otherwise.
5819  *   The most likely error is that the cert for "name" could not be found
5820  *   (probably SEC_ERROR_UNKNOWN_CERT).  Other errors are low-level (no memory,
5821  *   bad database, etc.).
5822  */
5823 SECStatus
CERT_SetOCSPDefaultResponder(CERTCertDBHandle * handle,const char * url,const char * name)5824 CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle,
5825                              const char *url, const char *name)
5826 {
5827     CERTCertificate *cert;
5828     ocspCheckingContext *statusContext;
5829     char *url_copy = NULL;
5830     char *name_copy = NULL;
5831     SECStatus rv;
5832 
5833     if (handle == NULL || url == NULL || name == NULL) {
5834         /*
5835     	 * XXX When interface is exported, probably want better errors;
5836     	 * perhaps different one for each parameter.
5837     	 */
5838         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5839         return SECFailure;
5840     }
5841 
5842     /*
5843      * Find the certificate for the specified nickname.  Do this first
5844      * because it seems the most likely to fail.
5845      *
5846      * XXX Shouldn't need that cast if the FindCertByNickname interface
5847      * used const to convey that it does not modify the name.  Maybe someday.
5848      */
5849     cert = CERT_FindCertByNickname(handle, (char *)name);
5850     if (cert == NULL) {
5851         /*
5852          * look for the cert on an external token.
5853          */
5854         cert = PK11_FindCertFromNickname((char *)name, NULL);
5855     }
5856     if (cert == NULL)
5857         return SECFailure;
5858 
5859     /*
5860      * Make a copy of the url and nickname.
5861      */
5862     url_copy = PORT_Strdup(url);
5863     name_copy = PORT_Strdup(name);
5864     if (url_copy == NULL || name_copy == NULL) {
5865         rv = SECFailure;
5866         goto loser;
5867     }
5868 
5869     statusContext = ocsp_GetCheckingContext(handle);
5870 
5871     /*
5872      * Allocate and init the context if it doesn't already exist.
5873      */
5874     if (statusContext == NULL) {
5875         rv = ocsp_InitStatusChecking(handle);
5876         if (rv != SECSuccess)
5877             goto loser;
5878 
5879         statusContext = ocsp_GetCheckingContext(handle);
5880         PORT_Assert(statusContext != NULL); /* extreme paranoia */
5881     }
5882 
5883     /*
5884      * Note -- we do not touch the status context until after all of
5885      * the steps which could cause errors.  If something goes wrong,
5886      * we want to leave things as they were.
5887      */
5888 
5889     /*
5890      * Get rid of old url and name if there.
5891      */
5892     if (statusContext->defaultResponderNickname != NULL)
5893         PORT_Free(statusContext->defaultResponderNickname);
5894     if (statusContext->defaultResponderURI != NULL)
5895         PORT_Free(statusContext->defaultResponderURI);
5896 
5897     /*
5898      * And replace them with the new ones.
5899      */
5900     statusContext->defaultResponderURI = url_copy;
5901     statusContext->defaultResponderNickname = name_copy;
5902 
5903     /*
5904      * If there was already a cert in place, get rid of it and replace it.
5905      * Otherwise, we are not currently enabled, so we don't want to save it;
5906      * it will get re-found and set whenever use of a default responder is
5907      * enabled.
5908      */
5909     if (statusContext->defaultResponderCert != NULL) {
5910         CERT_DestroyCertificate(statusContext->defaultResponderCert);
5911         statusContext->defaultResponderCert = cert;
5912         /*OCSP enabled, switching responder: clear cache*/
5913         CERT_ClearOCSPCache();
5914     } else {
5915         PORT_Assert(statusContext->useDefaultResponder == PR_FALSE);
5916         CERT_DestroyCertificate(cert);
5917         /*OCSP currently not enabled, no need to clear cache*/
5918     }
5919 
5920     return SECSuccess;
5921 
5922 loser:
5923     CERT_DestroyCertificate(cert);
5924     if (url_copy != NULL)
5925         PORT_Free(url_copy);
5926     if (name_copy != NULL)
5927         PORT_Free(name_copy);
5928     return rv;
5929 }
5930 
5931 /*
5932  * FUNCTION: CERT_EnableOCSPDefaultResponder
5933  *   Turns on use of a default responder when OCSP checking.
5934  *   If OCSP checking is already enabled, this will make subsequent checks
5935  *   go directly to the default responder.  (The location of the responder
5936  *   and the nickname of the responder cert must already be specified.)
5937  *   If OCSP checking is not enabled, this will be recorded and take effect
5938  *   whenever it is enabled.
5939  * INPUTS:
5940  *   CERTCertDBHandle *handle
5941  *     Cert database on which OCSP checking should use the default responder.
5942  * RETURN:
5943  *   Returns SECFailure if an error occurred; SECSuccess otherwise.
5944  *   No errors are especially likely unless the caller did not previously
5945  *   perform a successful call to SetOCSPDefaultResponder (in which case
5946  *   the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER).
5947  */
5948 SECStatus
CERT_EnableOCSPDefaultResponder(CERTCertDBHandle * handle)5949 CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle)
5950 {
5951     ocspCheckingContext *statusContext;
5952     CERTCertificate *cert;
5953     SECStatus rv;
5954     SECCertificateUsage usage;
5955 
5956     if (handle == NULL) {
5957         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5958         return SECFailure;
5959     }
5960 
5961     statusContext = ocsp_GetCheckingContext(handle);
5962 
5963     if (statusContext == NULL) {
5964         /*
5965     	 * Strictly speaking, the error already set is "correct",
5966     	 * but cover over it with one more helpful in this context.
5967     	 */
5968         PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
5969         return SECFailure;
5970     }
5971 
5972     if (statusContext->defaultResponderURI == NULL) {
5973         PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
5974         return SECFailure;
5975     }
5976 
5977     if (statusContext->defaultResponderNickname == NULL) {
5978         PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER);
5979         return SECFailure;
5980     }
5981 
5982     /*
5983      * Find the cert for the nickname.
5984      */
5985     cert = CERT_FindCertByNickname(handle,
5986                                    statusContext->defaultResponderNickname);
5987     if (cert == NULL) {
5988         cert = PK11_FindCertFromNickname(statusContext->defaultResponderNickname,
5989                                          NULL);
5990     }
5991     /*
5992      * We should never have trouble finding the cert, because its
5993      * existence should have been proven by SetOCSPDefaultResponder.
5994      */
5995     PORT_Assert(cert != NULL);
5996     if (cert == NULL)
5997         return SECFailure;
5998 
5999     /*
6000      * Supplied cert should at least have  a signing capability in order for us
6001      * to use it as a trusted responder cert. Ability to sign is guaranteed  if
6002      * cert is validated to have any set of the usages below.
6003      */
6004     rv = CERT_VerifyCertificateNow(handle, cert, PR_TRUE,
6005                                    certificateUsageCheckAllUsages,
6006                                    NULL, &usage);
6007     if (rv != SECSuccess || (usage & (certificateUsageSSLClient | certificateUsageSSLServer | certificateUsageSSLServerWithStepUp | certificateUsageEmailSigner | certificateUsageObjectSigner | certificateUsageStatusResponder | certificateUsageSSLCA)) == 0) {
6008         PORT_SetError(SEC_ERROR_OCSP_RESPONDER_CERT_INVALID);
6009         return SECFailure;
6010     }
6011 
6012     /*
6013      * And hang onto it.
6014      */
6015     statusContext->defaultResponderCert = cert;
6016 
6017     /* we don't allow a mix of cache entries from different responders */
6018     CERT_ClearOCSPCache();
6019 
6020     /*
6021      * Finally, record the fact that we now have a default responder enabled.
6022      */
6023     statusContext->useDefaultResponder = PR_TRUE;
6024     return SECSuccess;
6025 }
6026 
6027 /*
6028  * FUNCTION: CERT_DisableOCSPDefaultResponder
6029  *   Turns off use of a default responder when OCSP checking.
6030  *   (Does nothing if use of a default responder is not enabled.)
6031  * INPUTS:
6032  *   CERTCertDBHandle *handle
6033  *     Cert database on which OCSP checking should stop using a default
6034  *     responder.
6035  * RETURN:
6036  *   Returns SECFailure if an error occurred; SECSuccess otherwise.
6037  *   Errors very unlikely (like random memory corruption...).
6038  */
6039 SECStatus
CERT_DisableOCSPDefaultResponder(CERTCertDBHandle * handle)6040 CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle)
6041 {
6042     CERTStatusConfig *statusConfig;
6043     ocspCheckingContext *statusContext;
6044     CERTCertificate *tmpCert;
6045 
6046     if (handle == NULL) {
6047         PORT_SetError(SEC_ERROR_INVALID_ARGS);
6048         return SECFailure;
6049     }
6050 
6051     statusConfig = CERT_GetStatusConfig(handle);
6052     if (statusConfig == NULL)
6053         return SECSuccess;
6054 
6055     statusContext = ocsp_GetCheckingContext(handle);
6056     PORT_Assert(statusContext != NULL);
6057     if (statusContext == NULL)
6058         return SECFailure;
6059 
6060     tmpCert = statusContext->defaultResponderCert;
6061     if (tmpCert) {
6062         statusContext->defaultResponderCert = NULL;
6063         CERT_DestroyCertificate(tmpCert);
6064         /* we don't allow a mix of cache entries from different responders */
6065         CERT_ClearOCSPCache();
6066     }
6067 
6068     /*
6069      * Finally, record the fact.
6070      */
6071     statusContext->useDefaultResponder = PR_FALSE;
6072     return SECSuccess;
6073 }
6074 
6075 SECStatus
CERT_ForcePostMethodForOCSP(PRBool forcePost)6076 CERT_ForcePostMethodForOCSP(PRBool forcePost)
6077 {
6078     if (!OCSP_Global.monitor) {
6079         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
6080         return SECFailure;
6081     }
6082 
6083     PR_EnterMonitor(OCSP_Global.monitor);
6084     OCSP_Global.forcePost = forcePost;
6085     PR_ExitMonitor(OCSP_Global.monitor);
6086 
6087     return SECSuccess;
6088 }
6089 
6090 SECStatus
CERT_GetOCSPResponseStatus(CERTOCSPResponse * response)6091 CERT_GetOCSPResponseStatus(CERTOCSPResponse *response)
6092 {
6093     PORT_Assert(response);
6094     if (response->statusValue == ocspResponse_successful)
6095         return SECSuccess;
6096 
6097     switch (response->statusValue) {
6098         case ocspResponse_malformedRequest:
6099             PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
6100             break;
6101         case ocspResponse_internalError:
6102             PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
6103             break;
6104         case ocspResponse_tryLater:
6105             PORT_SetError(SEC_ERROR_OCSP_TRY_SERVER_LATER);
6106             break;
6107         case ocspResponse_sigRequired:
6108             /* XXX We *should* retry with a signature, if possible. */
6109             PORT_SetError(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
6110             break;
6111         case ocspResponse_unauthorized:
6112             PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
6113             break;
6114         case ocspResponse_unused:
6115         default:
6116             PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
6117             break;
6118     }
6119     return SECFailure;
6120 }
6121