]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_x509_tp / lib / tpOcspVerify.cpp
1 /*
2 * Copyright (c) 2004,2011-2012,2014-2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * tpOcspVerify.cpp - top-level OCSP verification
26 */
27
28 #include "tpOcspVerify.h"
29 #include "tpdebugging.h"
30 #include "ocspRequest.h"
31 #include "tpOcspCache.h"
32 #include "tpOcspCertVfy.h"
33 #include <security_ocspd/ocspResponse.h>
34 #include "certGroupUtils.h"
35 #include <Security/certextensions.h>
36 #include <Security/oidsattr.h>
37 #include <Security/oidscert.h>
38 #include <security_asn1/SecNssCoder.h>
39 #include <security_ocspd/ocspdClient.h>
40 #include <security_ocspd/ocspdUtils.h>
41 #include "tpTime.h"
42
43 #pragma mark ---- private routines ----
44
45 /*
46 * Get a smart CertID for specified cert and issuer
47 */
48 static CSSM_RETURN tpOcspGetCertId(
49 TPCertInfo &subject,
50 TPCertInfo &issuer,
51 OCSPClientCertID *&certID) /* mallocd by coder and RETURNED */
52 {
53 CSSM_RETURN crtn;
54 CSSM_DATA_PTR issuerSubject = NULL;
55 CSSM_DATA_PTR issuerPubKeyData = NULL;
56 CSSM_KEY_PTR issuerPubKey;
57 CSSM_DATA issuerPubKeyBytes;
58 CSSM_DATA_PTR subjectSerial = NULL;
59
60 crtn = subject.fetchField(&CSSMOID_X509V1SerialNumber, &subjectSerial);
61 if(crtn) {
62 return crtn;
63 }
64 crtn = subject.fetchField(&CSSMOID_X509V1IssuerNameStd, &issuerSubject);
65 if(crtn) {
66 return crtn;
67 }
68 crtn = issuer.fetchField(&CSSMOID_CSSMKeyStruct, &issuerPubKeyData);
69 if(crtn) {
70 return crtn;
71 }
72 assert(issuerPubKeyData->Length == sizeof(CSSM_KEY));
73 issuerPubKey = (CSSM_KEY_PTR)issuerPubKeyData->Data;
74 ocspdGetPublicKeyBytes(NULL, issuerPubKey, issuerPubKeyBytes);
75 certID = new OCSPClientCertID(*issuerSubject, issuerPubKeyBytes, *subjectSerial);
76
77 subject.freeField(&CSSMOID_X509V1SerialNumber, subjectSerial);
78 issuer.freeField(&CSSMOID_X509V1IssuerNameStd, issuerSubject);
79 issuer.freeField(&CSSMOID_CSSMKeyStruct, issuerPubKeyData);
80 return CSSM_OK;
81 }
82
83 /*
84 * Examine cert, looking for AuthorityInfoAccess, with id-ad-ocsp URIs. Create
85 * an NULL_terminated array of CSSM_DATAs containing the URIs if found.
86 */
87 static CSSM_DATA **tpOcspUrlsFromCert(
88 TPCertInfo &subject,
89 SecNssCoder &coder)
90 {
91 CSSM_DATA_PTR extField = NULL;
92 CSSM_RETURN crtn;
93
94 crtn = subject.fetchField(&CSSMOID_AuthorityInfoAccess, &extField);
95 if(crtn) {
96 tpOcspDebug("tpOcspUrlsFromCert: no AIA extension");
97 return NULL;
98 }
99 if(extField->Length != sizeof(CSSM_X509_EXTENSION)) {
100 tpErrorLog("tpOcspUrlsFromCert: malformed CSSM_FIELD");
101 return NULL;
102 }
103 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)extField->Data;
104 if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
105 tpErrorLog("tpOcspUrlsFromCert: malformed CSSM_X509_EXTENSION");
106 return NULL;
107 }
108
109 CE_AuthorityInfoAccess *aia =
110 (CE_AuthorityInfoAccess *)cssmExt->value.parsedValue;
111 CSSM_DATA **urls = NULL;
112 unsigned numUrls = 0;
113 for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) {
114 CE_AccessDescription *ad = &aia->accessDescriptions[dex];
115 if(!tpCompareCssmData(&ad->accessMethod, &CSSMOID_AD_OCSP)) {
116 continue;
117 }
118 CE_GeneralName *genName = &ad->accessLocation;
119 if(genName->nameType != GNT_URI) {
120 tpErrorLog("tpOcspUrlsFromCert: CSSMOID_AD_OCSP, but not type URI");
121 continue;
122 }
123
124 /* got one */
125 if(urls == NULL) {
126 urls = coder.mallocn<CSSM_DATA_PTR>(2);
127 }
128 else {
129 /* realloc */
130 CSSM_DATA **oldUrls = urls;
131 urls = coder.mallocn<CSSM_DATA_PTR>(numUrls + 2);
132 for(unsigned i=0; i<numUrls; i++) {
133 urls[i] = oldUrls[i];
134 }
135 }
136 urls[numUrls] = coder.mallocn<CSSM_DATA>();
137 coder.allocCopyItem(genName->name, *urls[numUrls++]);
138 urls[numUrls] = NULL;
139 #ifndef NDEBUG
140 {
141 CSSM_DATA urlStr;
142 coder.allocItem(urlStr, genName->name.Length + 1);
143 memmove(urlStr.Data, genName->name.Data, genName->name.Length);
144 urlStr.Data[urlStr.Length-1] = '\0';
145 tpOcspDebug("tpOcspUrlsFromCert: found URI %s", urlStr.Data);
146 }
147 #endif
148 }
149 subject.freeField(&CSSMOID_AuthorityInfoAccess, extField);
150 return urls;
151 }
152
153 /*
154 * Create an SecAsn1OCSPDRequest for one cert. This consists of:
155 *
156 * -- cooking up an OCSPRequest if net fetch is enabled or a local responder
157 * is configured;
158 * -- extracting URLs from subject cert if net fetch is enabled;
159 * -- creating an SecAsn1OCSPDRequest, mallocd in coder's space;
160 */
161 static SecAsn1OCSPDRequest *tpGenOcspdReq(
162 TPVerifyContext &vfyCtx,
163 SecNssCoder &coder,
164 TPCertInfo &subject,
165 TPCertInfo &issuer,
166 OCSPClientCertID &certId,
167 const CSSM_DATA **urls, // from subject's AuthorityInfoAccess
168 CSSM_DATA &nonce) // possibly mallocd in coder's space and RETURNED
169 {
170 OCSPRequest *ocspReq = NULL;
171 SecAsn1OCSPDRequest *ocspdReq = NULL; // to return
172 OCSPClientCertID *certID = NULL;
173 CSSM_RETURN crtn;
174 bool deleteCertID = false;
175
176 /* gather options or their defaults */
177 CSSM_APPLE_TP_OCSP_OPT_FLAGS optFlags = 0;
178 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
179 CSSM_DATA_PTR localResponder = NULL;
180 CSSM_DATA_PTR localResponderCert = NULL;
181 if(ocspOpts != NULL) {
182 optFlags = vfyCtx.ocspOpts->Flags;
183 localResponder = ocspOpts->LocalResponder;
184 localResponderCert = ocspOpts->LocalResponderCert;
185 }
186 bool genNonce = optFlags & CSSM_TP_OCSP_GEN_NONCE ? true : false;
187 bool requireRespNonce = optFlags & CSSM_TP_OCSP_REQUIRE_RESP_NONCE ? true : false;
188
189 /*
190 * One degenerate case in case we can't really do anything.
191 * If no URI and no local responder, only proceed if cache is not disabled
192 * and we're requiring full OCSP per cert.
193 */
194 if( ( (optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) ||
195 !(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT)
196 ) &&
197 (localResponder == NULL) &&
198 (urls == NULL)) {
199 tpOcspDebug("tpGenOcspdReq: no route to OCSP; NULL return");
200 return NULL;
201 }
202
203 /* do we need an OCSP request? */
204 if(!(optFlags & CSSM_TP_ACTION_OCSP_DISABLE_NET) || (localResponder != NULL)) {
205 try {
206 ocspReq = new OCSPRequest(subject, issuer, genNonce);
207 certID = ocspReq->certID();
208 }
209 catch(...) {
210 /* not sure how this could even happen but that was a fair amount of code */
211 tpErrorLog("tpGenOcspdReq: error cooking up OCSPRequest\n");
212 if(ocspReq != NULL) {
213 delete ocspReq;
214 return NULL;
215 }
216 }
217 }
218
219 /* certID needed one way or the other */
220 if(certID == NULL) {
221 crtn = tpOcspGetCertId(subject, issuer, certID);
222 if(crtn) {
223 goto errOut;
224 }
225 deleteCertID = true;
226 }
227
228 /*
229 * Create the SecAsn1OCSPDRequest. All fields optional.
230 */
231 ocspdReq = coder.mallocn<SecAsn1OCSPDRequest>();
232 memset(ocspdReq, 0, sizeof(*ocspdReq));
233 if(optFlags & CSSM_TP_ACTION_OCSP_CACHE_WRITE_DISABLE) {
234 ocspdReq->cacheWriteDisable = coder.mallocn<CSSM_DATA>();
235 ocspdReq->cacheWriteDisable->Data = coder.mallocn<uint8>();
236 ocspdReq->cacheWriteDisable->Data[0] = 0xff;
237 ocspdReq->cacheWriteDisable->Length = 1;
238 }
239 /*
240 * Note we're enforcing a not-so-obvious policy here: if nonce match is
241 * required, disk cache reads by ocspd are disabled. In-core cache is
242 * still enabled and hits in that cache do NOT require nonce matches.
243 */
244 if((optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) || requireRespNonce) {
245 ocspdReq->cacheReadDisable = coder.mallocn<CSSM_DATA>();
246 ocspdReq->cacheReadDisable->Data = coder.mallocn<uint8>();
247 ocspdReq->cacheReadDisable->Data[0] = 0xff;
248 ocspdReq->cacheReadDisable->Length = 1;
249 }
250 /* CertID, only required field */
251 coder.allocCopyItem(*certID->encode(), ocspdReq->certID);
252 if(ocspReq != NULL) {
253 ocspdReq->ocspReq = coder.mallocn<CSSM_DATA>();
254 coder.allocCopyItem(*ocspReq->encode(), *ocspdReq->ocspReq);
255 if(genNonce) {
256 /* nonce not available until encode() called */
257 coder.allocCopyItem(*ocspReq->nonce(), nonce);
258 }
259 }
260 if(localResponder != NULL) {
261 ocspdReq->localRespURI = localResponder;
262 }
263 if(!(optFlags & CSSM_TP_ACTION_OCSP_DISABLE_NET)) {
264 ocspdReq->urls = const_cast<CSSM_DATA **>(urls);
265 }
266
267 errOut:
268 delete ocspReq;
269 if(deleteCertID) {
270 delete certID;
271 }
272 return ocspdReq;
273 }
274
275 static bool revocationTimeAfterVerificationTime(CFAbsoluteTime revokedTime, CSSM_TIMESTRING verifyTimeStr)
276 {
277 // Return true if the revocation time is after the specified verification time (i.e. "good")
278 // If verifyTime not specified, use now for the verifyTime
279
280 CFAbsoluteTime verifyTime = 0;
281
282 if (verifyTimeStr)
283 {
284 CFDateRef cfVerifyTime = NULL; // made with CFDateCreate
285 int rtn = timeStringToCfDate((char *)verifyTimeStr, (unsigned)strlen(verifyTimeStr), &cfVerifyTime);
286 if (!rtn)
287 if (cfVerifyTime)
288 {
289 verifyTime = CFDateGetAbsoluteTime(cfVerifyTime);
290 CFRelease(cfVerifyTime);
291 }
292 }
293
294 if (verifyTime == 0)
295 verifyTime = CFAbsoluteTimeGetCurrent();
296
297 return verifyTime < revokedTime;
298 }
299
300 /*
301 * Apply a verified OCSPSingleResponse to a TPCertInfo.
302 */
303 static CSSM_RETURN tpApplySingleResp(
304 OCSPSingleResponse &singleResp,
305 TPCertInfo &cert,
306 unsigned dex, // for debug
307 CSSM_APPLE_TP_OCSP_OPT_FLAGS flags, // for OCSP_SUFFICIENT
308 CSSM_TIMESTRING verifyTime, // Check revocation at specific time
309 bool &processed) // set true iff CS_Good or CS_Revoked found
310 {
311 SecAsn1OCSPCertStatusTag certStatus = singleResp.certStatus();
312 CSSM_RETURN crtn = CSSM_OK;
313 if ((certStatus == CS_Revoked) &&
314 revocationTimeAfterVerificationTime(singleResp.revokedTime(), verifyTime))
315 {
316 tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u, but revoked after verification time", dex);
317 certStatus = CS_Good;
318 }
319
320 switch(certStatus) {
321 case CS_Good:
322 tpOcspDebug("tpApplySingleResp: CS_Good for cert %u", dex);
323 cert.revokeCheckGood(true);
324 if(flags & CSSM_TP_ACTION_OCSP_SUFFICIENT) {
325 /* no more revocation checking necessary for this cert */
326 cert.revokeCheckComplete(true);
327 }
328 processed = true;
329 break;
330 case CS_Revoked:
331 tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u", dex);
332 switch(singleResp.crlReason()) {
333 case CE_CR_CertificateHold:
334 crtn = CSSMERR_TP_CERT_SUSPENDED;
335 break;
336 default:
337 /* FIXME - may want more detailed CRLReason-specific errors */
338 crtn = CSSMERR_TP_CERT_REVOKED;
339 cert.crlReason((sint32)singleResp.crlReason());
340 break;
341 }
342 if(!cert.addStatusCode(crtn)) {
343 crtn = CSSM_OK;
344 }
345 processed = true;
346 break;
347 case CS_Unknown:
348 /* not an error, no per-cert status, nothing here */
349 tpOcspDebug("tpApplySingleResp: CS_Unknown for cert %u", dex);
350 break;
351 default:
352 tpOcspDebug("tpApplySingleResp: BAD certStatus (%d) for cert %u",
353 (int)certStatus, dex);
354 if(cert.addStatusCode(CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED)) {
355 crtn = CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED;
356 }
357 break;
358 }
359 return crtn;
360 }
361
362 /*
363 * An exceptional case: synchronously flush the OCSPD cache and send a new
364 * resquest for just this one cert.
365 */
366 static OCSPResponse *tpOcspFlushAndReFetch(
367 TPVerifyContext &vfyCtx,
368 SecNssCoder &coder,
369 TPCertInfo &subject,
370 TPCertInfo &issuer,
371 OCSPClientCertID &certID)
372 {
373 const CSSM_DATA *derCertID = certID.encode();
374 CSSM_RETURN crtn;
375
376 crtn = ocspdCacheFlush(*derCertID);
377 if(crtn) {
378 #ifndef NDEBUG
379 cssmPerror("ocspdCacheFlush", crtn);
380 #endif
381 return NULL;
382 }
383
384 /* Cook up an OCSPDRequests, one request, just for this */
385 /* send it to ocsdp */
386 /* munge reply into an OCSPRsponse and return it */
387 tpOcspDebug("pOcspFlushAndReFetch: Code on demand");
388 return NULL;
389 }
390
391 class PendingRequest
392 {
393 public:
394 PendingRequest(
395 TPCertInfo &subject,
396 TPCertInfo &issuer,
397 OCSPClientCertID &cid,
398 CSSM_DATA **u,
399 unsigned dex);
400 ~PendingRequest() {}
401
402 TPCertInfo &subject;
403 TPCertInfo &issuer;
404 OCSPClientCertID &certID; // owned by caller
405 CSSM_DATA **urls; // owner-managed array of URLs obtained from subject's
406 // AuthorityInfoAccess.id-ad-ocsp.
407 CSSM_DATA nonce; // owner-managed copy of this requests' nonce, if it
408 // has one
409 unsigned dex; // in inputCerts, for debug
410 bool processed;
411 };
412
413 PendingRequest::PendingRequest(
414 TPCertInfo &subj,
415 TPCertInfo &iss,
416 OCSPClientCertID &cid,
417 CSSM_DATA **u,
418 unsigned dx)
419 : subject(subj), issuer(iss), certID(cid),
420 urls(u), dex(dx), processed(false)
421 {
422 nonce.Data = NULL;
423 nonce.Length = 0;
424 }
425
426 #pragma mark ---- public API ----
427
428 CSSM_RETURN tpVerifyCertGroupWithOCSP(
429 TPVerifyContext &vfyCtx,
430 TPCertGroup &certGroup) // to be verified
431 {
432 assert(vfyCtx.clHand != 0);
433 assert(vfyCtx.policy == kRevokeOcsp);
434
435 CSSM_RETURN ourRtn = CSSM_OK;
436 OcspRespStatus respStat;
437 SecNssCoder coder;
438 CSSM_RETURN crtn;
439 SecAsn1OCSPDRequests ocspdReqs;
440 SecAsn1OCSPReplies ocspdReplies;
441 unsigned numRequests = 0; // in ocspdReqs
442 CSSM_DATA derOcspdRequests = {0, NULL};
443 CSSM_DATA derOcspdReplies = {0, NULL};
444 uint8 version = OCSPD_REQUEST_VERS;
445 unsigned numReplies;
446 unsigned numCerts = certGroup.numCerts();
447 if(numCerts <= 1) {
448 /* Can't verify without an issuer; we're done */
449 return CSSM_OK;
450 }
451 numCerts--;
452
453 /* gather options or their defaults */
454 CSSM_APPLE_TP_OCSP_OPT_FLAGS optFlags = 0;
455 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
456 CSSM_DATA_PTR localResponder = NULL;
457 CSSM_DATA_PTR localResponderCert = NULL;
458 bool cacheReadDisable = false;
459 bool cacheWriteDisable = false;
460 bool genNonce = false; // in outgoing request
461 bool requireRespNonce = false; // in incoming response
462 PRErrorCode prtn;
463
464 if(ocspOpts != NULL) {
465 optFlags = vfyCtx.ocspOpts->Flags;
466 localResponder = ocspOpts->LocalResponder;
467 localResponderCert = ocspOpts->LocalResponderCert;
468 }
469 if(optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) {
470 cacheReadDisable = true;
471 }
472 if(optFlags & CSSM_TP_ACTION_OCSP_CACHE_WRITE_DISABLE) {
473 cacheWriteDisable = true;
474 }
475 if(optFlags & CSSM_TP_OCSP_GEN_NONCE) {
476 genNonce = true;
477 }
478 if(optFlags & CSSM_TP_OCSP_REQUIRE_RESP_NONCE) {
479 requireRespNonce = true;
480 }
481 if(requireRespNonce & !genNonce) {
482 /* no can do */
483 tpErrorLog("tpVerifyCertGroupWithOCSP: requireRespNonce, !genNonce\n");
484 return CSSMERR_TP_INVALID_REQUEST_INPUTS;
485 }
486
487 tpOcspDebug("tpVerifyCertGroupWithOCSP numCerts %u optFlags 0x%lx",
488 numCerts, (unsigned long)optFlags);
489
490 /*
491 * create list of pendingRequests parallel to certGroup
492 */
493 PendingRequest **pending = coder.mallocn<PendingRequest *>(numCerts);
494 memset(pending, 0, (numCerts * sizeof(PendingRequest *)));
495
496 for(unsigned dex=0; dex<numCerts; dex++) {
497 OCSPClientCertID *certID = NULL;
498 TPCertInfo *subject = certGroup.certAtIndex(dex);
499
500 if(subject->trustSettingsFound()) {
501 /* functionally equivalent to root - we're done */
502 tpOcspDebug("...tpVerifyCertGroupWithOCSP: terminate per user trust at %u",
503 (unsigned)dex);
504 goto postOcspd;
505 }
506 TPCertInfo *issuer = certGroup.certAtIndex(dex + 1);
507 crtn = tpOcspGetCertId(*subject, *issuer, certID);
508 if(crtn) {
509 tpErrorLog("tpVerifyCertGroupWithOCSP: error extracting cert fields; "
510 "aborting\n");
511 goto errOut;
512 }
513
514 /*
515 * We use the URLs in the subject cert's AuthorityInfoAccess extension
516 * for two things - mainly to get the URL(s) for actual OCSP transactions,
517 * but also for CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT processing.
518 * So, we do the per-cert processing to get them right now even if we
519 * wind up using a local responder or getting verification from cache.
520 */
521 CSSM_DATA **urls = tpOcspUrlsFromCert(*subject, coder);
522 pending[dex] = new PendingRequest(*subject, *issuer, *certID, urls, dex);
523 }
524 /* subsequent errors to errOut: */
525
526 /*
527 * Create empty SecAsn1OCSPDRequests big enough for all certs
528 */
529 ocspdReqs.requests = coder.mallocn<SecAsn1OCSPDRequest *>(numCerts + 1);
530 memset(ocspdReqs.requests, 0, (numCerts + 1) * sizeof(SecAsn1OCSPDRequest *));
531 ocspdReqs.version.Data = &version;
532 ocspdReqs.version.Length = 1;
533
534 /*
535 * For each cert, either obtain a cached OCSPResponse, or create
536 * a request to get one.
537 *
538 * NOTE: in-core cache reads (via tpOcspCacheLookup() do NOT involve a
539 * nonce check, no matter what the app says. If nonce checking is required by the
540 * app, responses don't get added to cache if the nonce doesn't match, but once
541 * a response is validated and added to cache it's fair game for that task.
542 */
543 for(unsigned dex=0; dex<numCerts; dex++) {
544 PendingRequest *pendReq = pending[dex];
545 OCSPSingleResponse *singleResp = NULL;
546 if(!cacheReadDisable) {
547 singleResp = tpOcspCacheLookup(pendReq->certID, localResponder);
548 }
549 if(singleResp) {
550 tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache hit (1) dex %u",
551 (unsigned)dex);
552 crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags,
553 vfyCtx.verifyTime, pendReq->processed);
554 delete singleResp;
555 if(pendReq->processed) {
556 /* definitely done with this cert one way or the other */
557 if(crtn && (ourRtn == CSSM_OK)) {
558 /* real cert error: first error encountered; we'll keep going */
559 ourRtn = crtn;
560 }
561 continue;
562 }
563 if(crtn) {
564 /*
565 * This indicates a bad cached response. Well that's kinda weird, let's
566 * just flush this out and try a normal transaction.
567 */
568 tpOcspCacheFlush(pendReq->certID);
569 }
570 }
571
572 /*
573 * Prepare a request for ocspd
574 */
575 SecAsn1OCSPDRequest *ocspdReq = tpGenOcspdReq(vfyCtx, coder,
576 pendReq->subject, pendReq->issuer, pendReq->certID,
577 const_cast<const CSSM_DATA **>(pendReq->urls),
578 pendReq->nonce);
579 if(ocspdReq == NULL) {
580 /* tpGenOcspdReq determined there was no route to OCSP responder */
581 tpOcspDebug("tpVerifyCertGroupWithOCSP: no OCSP possible for cert %u", dex);
582 continue;
583 }
584 ocspdReqs.requests[numRequests++] = ocspdReq;
585 }
586 if(numRequests == 0) {
587 /* no candidates for OCSP: almost done */
588 goto postOcspd;
589 }
590
591 /* ship requests off to ocspd, get ocspReplies back */
592 if(coder.encodeItem(&ocspdReqs, kSecAsn1OCSPDRequestsTemplate, derOcspdRequests)) {
593 tpErrorLog("tpVerifyCertGroupWithOCSP: error encoding ocspdReqs\n");
594 ourRtn = CSSMERR_TP_INTERNAL_ERROR;
595 goto errOut;
596 }
597 crtn = ocspdFetch(vfyCtx.alloc, derOcspdRequests, derOcspdReplies);
598 if(crtn) {
599 tpErrorLog("tpVerifyCertGroupWithOCSP: error during ocspd RPC\n");
600 #ifndef NDEBUG
601 cssmPerror("ocspdFetch", crtn);
602 #endif
603 /* But this is not necessarily fatal...update per-cert status and check
604 * caller requirements below */
605 goto postOcspd;
606 }
607 memset(&ocspdReplies, 0, sizeof(ocspdReplies));
608 prtn = coder.decodeItem(derOcspdReplies, kSecAsn1OCSPDRepliesTemplate,
609 &ocspdReplies);
610 /* we're done with this, mallocd in ocspdFetch() */
611 vfyCtx.alloc.free(derOcspdReplies.Data);
612 if(prtn) {
613 /*
614 * This can happen when an OCSP server provides bad data...we cannot
615 * determine which cert is associated with this bad response;
616 * just flag it with the first one and proceed to the loop that
617 * handles CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT.
618 */
619 tpErrorLog("tpVerifyCertGroupWithOCSP: error decoding ocspd reply\n");
620 pending[0]->subject.addStatusCode(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
621 goto postOcspd;
622 }
623 if((ocspdReplies.version.Length != 1) ||
624 (ocspdReplies.version.Data[0] != OCSPD_REPLY_VERS)) {
625 tpErrorLog("tpVerifyCertGroupWithOCSP: ocspd reply version mismatch\n");
626 if(ourRtn == CSSM_OK) {
627 ourRtn = CSSMERR_TP_INTERNAL_ERROR; // maybe something better?
628 }
629 goto errOut;
630 }
631
632 /* process each reply */
633 numReplies = ocspdArraySize((const void **)ocspdReplies.replies);
634 for(unsigned dex=0; dex<numReplies; dex++) {
635 SecAsn1OCSPDReply *reply = ocspdReplies.replies[dex];
636
637 /* Cook up our version of an OCSPResponse from the encoded data */
638 OCSPResponse *ocspResp = NULL;
639 try {
640 ocspResp = new OCSPResponse(reply->ocspResp, TP_OCSP_CACHE_TTL);
641 }
642 catch(...) {
643 tpErrorLog("tpVerifyCertGroupWithOCSP: error decoding ocsp response\n");
644 /* what the heck, keep going */
645 continue;
646 }
647
648 /*
649 * Find matching subject cert if possible (it's technically optional for
650 * verification of the response in some cases, e.g., local responder).
651 */
652 PendingRequest *pendReq = NULL; // fully qualified
653 PendingRequest *reqWithIdMatch = NULL; // CertID match only, not nonce
654 for(unsigned pdex=0; pdex<numCerts; pdex++) {
655
656 /* first check ID match; that is required no matter what */
657 if((pending[pdex])->certID.compareToExist(reply->certID)) {
658 reqWithIdMatch = pending[pdex];
659 }
660 if(reqWithIdMatch == NULL) {
661 continue;
662 }
663 if(!genNonce) {
664 /* that's good enough */
665 pendReq = reqWithIdMatch;
666 tpOcspDebug("OCSP process reply: CertID match, no nonce");
667 break;
668 }
669 if(tpCompareCssmData(&reqWithIdMatch->nonce, ocspResp->nonce())) {
670 tpOcspDebug("OCSP process reply: nonce MATCH");
671 pendReq = reqWithIdMatch;
672 break;
673 }
674
675 /*
676 * In this case we keep going; if we never find a match, then we can
677 * use reqWithIdMatch if !requireRespNonce.
678 */
679 tpOcspDebug("OCSP process reply: certID match, nonce MISMATCH");
680 }
681 if(pendReq == NULL) {
682 if(requireRespNonce) {
683 tpOcspDebug("OCSP process reply: tossing out response due to "
684 "requireRespNonce");
685 delete ocspResp;
686 if(ourRtn == CSSM_OK) {
687 ourRtn = CSSMERR_APPLETP_OCSP_NONCE_MISMATCH;
688 }
689 continue;
690 }
691 if(reqWithIdMatch != NULL) {
692 /*
693 * Nonce mismatch but caller thinks that's OK. Log it and proceed.
694 */
695 assert(genNonce);
696 tpOcspDebug("OCSP process reply: using bad nonce due to !requireRespNonce");
697 pendReq = reqWithIdMatch;
698 pendReq->subject.addStatusCode(CSSMERR_APPLETP_OCSP_NONCE_MISMATCH);
699 }
700 }
701 TPCertInfo *issuer = NULL;
702 if(pendReq != NULL) {
703 issuer = &pendReq->issuer;
704 }
705
706 /* verify response and either throw out or add to local cache */
707 respStat = tpVerifyOcspResp(vfyCtx, coder, issuer, *ocspResp, crtn);
708 switch(respStat) {
709 case ORS_Good:
710 break;
711 case ORS_Unknown:
712 /* not an error but we can't use it */
713 if((crtn != CSSM_OK) && (pendReq != NULL)) {
714 /* pass this info back to caller here... */
715 pendReq->subject.addStatusCode(crtn);
716 }
717 delete ocspResp;
718 continue;
719 case ORS_Bad:
720 delete ocspResp;
721 /*
722 * An exceptional case: synchronously flush the OCSPD cache and send a
723 * new request for just this one cert.
724 * FIXME: does this really buy us anything? A DOS attacker who managed
725 * to get this bogus response into our cache is likely to be able
726 * to do it again and again.
727 */
728 tpOcspDebug("tpVerifyCertGroupWithOCSP: flush/refetch for cert %u", dex);
729 ocspResp = tpOcspFlushAndReFetch(vfyCtx, coder, pendReq->subject,
730 pendReq->issuer, pendReq->certID);
731 if(ocspResp == NULL) {
732 tpErrorLog("tpVerifyCertGroupWithOCSP: error on flush/refetch\n");
733 ourRtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
734 goto errOut;
735 }
736 respStat = tpVerifyOcspResp(vfyCtx, coder, issuer, *ocspResp, crtn);
737 if(respStat != ORS_Good) {
738 tpErrorLog("tpVerifyCertGroupWithOCSP: verify error after "
739 "flush/refetch\n");
740 if((crtn != CSSM_OK) && (pendReq != NULL)) {
741 /* pass this info back to caller here... */
742 if(pendReq->subject.addStatusCode(crtn)) {
743 ourRtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
744 }
745 }
746 else {
747 ourRtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
748 }
749 goto errOut;
750 }
751 /* Voila! Recovery. Proceed. */
752 tpOcspDebug("tpVerifyCertGroupWithOCSP: refetch for cert %u SUCCEEDED",
753 dex);
754 break;
755 } /* switch response status */
756
757 if(!cacheWriteDisable) {
758 tpOcspCacheAdd(reply->ocspResp, localResponder);
759 }
760
761 /* attempt to apply to pendReq */
762 if(pendReq != NULL) {
763 OCSPSingleResponse *singleResp =
764 ocspResp->singleResponseFor(pendReq->certID);
765 if(singleResp) {
766 crtn = tpApplySingleResp(*singleResp, pendReq->subject, pendReq->dex,
767 optFlags, vfyCtx.verifyTime, pendReq->processed);
768 if(crtn && (ourRtn == CSSM_OK)) {
769 ourRtn = crtn;
770 }
771 delete singleResp;
772 }
773 } /* a reply which matches a pending request */
774
775 /*
776 * Done with this - note local OCSP response cache doesn't store this
777 * object; it stores an encoded copy.
778 */
779 delete ocspResp;
780 } /* for each reply */
781
782 postOcspd:
783
784 /*
785 * Now process each cert which hasn't had an OCSP response applied to it.
786 * This can happen if we get back replies which are not strictly in 1-1 sync with
787 * our requests but which nevertheless contain valid info for more than one
788 * cert each.
789 */
790 for(unsigned dex=0; dex<numCerts; dex++) {
791 PendingRequest *pendReq = pending[dex];
792 if(pendReq == NULL) {
793 /* i.e. terminated due to user trust */
794 tpOcspDebug("...tpVerifyCertGroupWithOCSP: NULL pendReq dex %u",
795 (unsigned)dex);
796 break;
797 }
798 if(pendReq->processed) {
799 continue;
800 }
801 OCSPSingleResponse *singleResp = NULL;
802 /* Note this corner case will not work if cache is disabled. */
803 if(!cacheReadDisable) {
804 singleResp = tpOcspCacheLookup(pendReq->certID, localResponder);
805 }
806 if(singleResp) {
807 tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache (2) hit dex %u",
808 (unsigned)dex);
809 crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags,
810 vfyCtx.verifyTime, pendReq->processed);
811 if(crtn) {
812 if(ourRtn == CSSM_OK) {
813 ourRtn = crtn;
814 }
815 }
816 delete singleResp;
817 }
818 if(!pendReq->processed) {
819 /* Couldn't perform OCSP for this cert. */
820 tpOcspDebug("tpVerifyCertGroupWithOCSP: OCSP_UNAVAILABLE for cert %u", dex);
821 bool required = false;
822 CSSM_RETURN responseStatus = CSSM_OK;
823 if(pendReq->subject.numStatusCodes() > 0) {
824 /*
825 * Check whether we got a response for this cert, but it was rejected
826 * due to being improperly signed. That should result in an actual
827 * error, even under Best Attempt processing. (10743149)
828 */
829 if(pendReq->subject.hasStatusCode(CSSMERR_APPLETP_OCSP_BAD_RESPONSE)) {
830 // responseStatus = CSSMERR_APPLETP_OCSP_BAD_RESPONSE; <rdar://problem/10831157>
831 } else if(pendReq->subject.hasStatusCode(CSSMERR_APPLETP_OCSP_SIG_ERROR)) {
832 responseStatus = CSSMERR_APPLETP_OCSP_SIG_ERROR;
833 } else if(pendReq->subject.hasStatusCode(CSSMERR_APPLETP_OCSP_NO_SIGNER)) {
834 responseStatus = CSSMERR_APPLETP_OCSP_NO_SIGNER;
835 }
836 }
837 if(responseStatus == CSSM_OK) {
838 /* no response available (as opposed to getting an invalid response) */
839 pendReq->subject.addStatusCode(CSSMERR_APPLETP_OCSP_UNAVAILABLE);
840 }
841 if(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT) {
842 /* every cert needs OCSP */
843 tpOcspDebug("tpVerifyCertGroupWithOCSP: response required for all certs, missing for cert %u", dex);
844 required = true;
845 }
846 else if(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT) {
847 /* this cert needs OCSP if it had an AIA extension with an OCSP URI */
848 if(pendReq->urls) {
849 tpOcspDebug("tpVerifyCertGroupWithOCSP: OCSP URI present but no valid response for cert %u", dex);
850 required = true;
851 }
852 }
853 if( (required && pendReq->subject.isStatusFatal(CSSMERR_APPLETP_OCSP_UNAVAILABLE)) ||
854 (responseStatus != CSSM_OK && pendReq->subject.isStatusFatal(responseStatus)) ) {
855 /* fatal error, but we keep on processing */
856 if(ourRtn == CSSM_OK) {
857 ourRtn = (responseStatus != CSSM_OK) ? responseStatus : CSSMERR_APPLETP_OCSP_UNAVAILABLE;
858 }
859 }
860 }
861 }
862 errOut:
863 for(unsigned dex=0; dex<numCerts; dex++) {
864 PendingRequest *pendReq = pending[dex];
865 if(pendReq == NULL) {
866 /* i.e. terminated due to user trust */
867 break;
868 }
869 delete &pendReq->certID;
870 delete pendReq;
871 }
872 return ourRtn;
873 }