2 * Copyright (c) 2004,2011-2012,2014-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * tpOcspVerify.cpp - top-level OCSP verification
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>
43 #pragma mark ---- private routines ----
46 * Get a smart CertID for specified cert and issuer
48 static CSSM_RETURN
tpOcspGetCertId(
51 OCSPClientCertID
*&certID
) /* mallocd by coder and RETURNED */
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
;
60 crtn
= subject
.fetchField(&CSSMOID_X509V1SerialNumber
, &subjectSerial
);
64 crtn
= subject
.fetchField(&CSSMOID_X509V1IssuerNameStd
, &issuerSubject
);
68 crtn
= issuer
.fetchField(&CSSMOID_CSSMKeyStruct
, &issuerPubKeyData
);
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
);
77 subject
.freeField(&CSSMOID_X509V1SerialNumber
, subjectSerial
);
78 issuer
.freeField(&CSSMOID_X509V1IssuerNameStd
, issuerSubject
);
79 issuer
.freeField(&CSSMOID_CSSMKeyStruct
, issuerPubKeyData
);
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.
87 static CSSM_DATA
**tpOcspUrlsFromCert(
91 CSSM_DATA_PTR extField
= NULL
;
94 crtn
= subject
.fetchField(&CSSMOID_AuthorityInfoAccess
, &extField
);
96 tpOcspDebug("tpOcspUrlsFromCert: no AIA extension");
99 if(extField
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
100 tpErrorLog("tpOcspUrlsFromCert: malformed CSSM_FIELD");
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");
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
)) {
118 CE_GeneralName
*genName
= &ad
->accessLocation
;
119 if(genName
->nameType
!= GNT_URI
) {
120 tpErrorLog("tpOcspUrlsFromCert: CSSMOID_AD_OCSP, but not type URI");
126 urls
= coder
.mallocn
<CSSM_DATA_PTR
>(2);
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
];
136 urls
[numUrls
] = coder
.mallocn
<CSSM_DATA
>();
137 coder
.allocCopyItem(genName
->name
, *urls
[numUrls
++]);
138 urls
[numUrls
] = NULL
;
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
);
149 subject
.freeField(&CSSMOID_AuthorityInfoAccess
, extField
);
154 * Create an SecAsn1OCSPDRequest for one cert. This consists of:
156 * -- cooking up an OCSPRequest if net fetch is enabled or a local responder
158 * -- extracting URLs from subject cert if net fetch is enabled;
159 * -- creating an SecAsn1OCSPDRequest, mallocd in coder's space;
161 static SecAsn1OCSPDRequest
*tpGenOcspdReq(
162 TPVerifyContext
&vfyCtx
,
166 OCSPClientCertID
&certId
,
167 const CSSM_DATA
**urls
, // from subject's AuthorityInfoAccess
168 CSSM_DATA
&nonce
) // possibly mallocd in coder's space and RETURNED
170 OCSPRequest
*ocspReq
= NULL
;
171 SecAsn1OCSPDRequest
*ocspdReq
= NULL
; // to return
172 OCSPClientCertID
*certID
= NULL
;
174 bool deleteCertID
= false;
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
;
186 bool genNonce
= optFlags
& CSSM_TP_OCSP_GEN_NONCE
? true : false;
187 bool requireRespNonce
= optFlags
& CSSM_TP_OCSP_REQUIRE_RESP_NONCE
? true : false;
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.
194 if( ( (optFlags
& CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE
) ||
195 !(optFlags
& CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT
)
197 (localResponder
== NULL
) &&
199 tpOcspDebug("tpGenOcspdReq: no route to OCSP; NULL return");
203 /* do we need an OCSP request? */
204 if(!(optFlags
& CSSM_TP_ACTION_OCSP_DISABLE_NET
) || (localResponder
!= NULL
)) {
206 ocspReq
= new OCSPRequest(subject
, issuer
, genNonce
);
207 certID
= ocspReq
->certID();
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
) {
219 /* certID needed one way or the other */
221 crtn
= tpOcspGetCertId(subject
, issuer
, certID
);
229 * Create the SecAsn1OCSPDRequest. All fields optional.
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;
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.
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;
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
);
256 /* nonce not available until encode() called */
257 coder
.allocCopyItem(*ocspReq
->nonce(), nonce
);
260 if(localResponder
!= NULL
) {
261 ocspdReq
->localRespURI
= localResponder
;
263 if(!(optFlags
& CSSM_TP_ACTION_OCSP_DISABLE_NET
)) {
264 ocspdReq
->urls
= const_cast<CSSM_DATA
**>(urls
);
275 static bool revocationTimeAfterVerificationTime(CFAbsoluteTime revokedTime
, CSSM_TIMESTRING verifyTimeStr
)
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
280 CFAbsoluteTime verifyTime
= 0;
284 CFDateRef cfVerifyTime
= NULL
; // made with CFDateCreate
285 int rtn
= timeStringToCfDate((char *)verifyTimeStr
, (unsigned)strlen(verifyTimeStr
), &cfVerifyTime
);
289 verifyTime
= CFDateGetAbsoluteTime(cfVerifyTime
);
290 CFRelease(cfVerifyTime
);
295 verifyTime
= CFAbsoluteTimeGetCurrent();
297 return verifyTime
< revokedTime
;
301 * Apply a verified OCSPSingleResponse to a TPCertInfo.
303 static CSSM_RETURN
tpApplySingleResp(
304 OCSPSingleResponse
&singleResp
,
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
311 SecAsn1OCSPCertStatusTag certStatus
= singleResp
.certStatus();
312 CSSM_RETURN crtn
= CSSM_OK
;
313 if ((certStatus
== CS_Revoked
) &&
314 revocationTimeAfterVerificationTime(singleResp
.revokedTime(), verifyTime
))
316 tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u, but revoked after verification time", dex
);
317 certStatus
= 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);
331 tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u", dex
);
332 switch(singleResp
.crlReason()) {
333 case CE_CR_CertificateHold
:
334 crtn
= CSSMERR_TP_CERT_SUSPENDED
;
337 /* FIXME - may want more detailed CRLReason-specific errors */
338 crtn
= CSSMERR_TP_CERT_REVOKED
;
339 cert
.crlReason((sint32
)singleResp
.crlReason());
342 if(!cert
.addStatusCode(crtn
)) {
348 /* not an error, no per-cert status, nothing here */
349 tpOcspDebug("tpApplySingleResp: CS_Unknown for cert %u", dex
);
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
;
363 * An exceptional case: synchronously flush the OCSPD cache and send a new
364 * resquest for just this one cert.
366 static OCSPResponse
*tpOcspFlushAndReFetch(
367 TPVerifyContext
&vfyCtx
,
371 OCSPClientCertID
&certID
)
373 const CSSM_DATA
*derCertID
= certID
.encode();
376 crtn
= ocspdCacheFlush(*derCertID
);
379 cssmPerror("ocspdCacheFlush", crtn
);
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");
397 OCSPClientCertID
&cid
,
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
409 unsigned dex
; // in inputCerts, for debug
413 PendingRequest::PendingRequest(
416 OCSPClientCertID
&cid
,
419 : subject(subj
), issuer(iss
), certID(cid
),
420 urls(u
), dex(dx
), processed(false)
426 #pragma mark ---- public API ----
428 CSSM_RETURN
tpVerifyCertGroupWithOCSP(
429 TPVerifyContext
&vfyCtx
,
430 TPCertGroup
&certGroup
) // to be verified
432 assert(vfyCtx
.clHand
!= 0);
433 assert(vfyCtx
.policy
== kRevokeOcsp
);
435 CSSM_RETURN ourRtn
= CSSM_OK
;
436 OcspRespStatus respStat
;
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
;
446 unsigned numCerts
= certGroup
.numCerts();
448 /* Can't verify without an issuer; we're done */
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
464 if(ocspOpts
!= NULL
) {
465 optFlags
= vfyCtx
.ocspOpts
->Flags
;
466 localResponder
= ocspOpts
->LocalResponder
;
467 localResponderCert
= ocspOpts
->LocalResponderCert
;
469 if(optFlags
& CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE
) {
470 cacheReadDisable
= true;
472 if(optFlags
& CSSM_TP_ACTION_OCSP_CACHE_WRITE_DISABLE
) {
473 cacheWriteDisable
= true;
475 if(optFlags
& CSSM_TP_OCSP_GEN_NONCE
) {
478 if(optFlags
& CSSM_TP_OCSP_REQUIRE_RESP_NONCE
) {
479 requireRespNonce
= true;
481 if(requireRespNonce
& !genNonce
) {
483 tpErrorLog("tpVerifyCertGroupWithOCSP: requireRespNonce, !genNonce\n");
484 return CSSMERR_TP_INVALID_REQUEST_INPUTS
;
487 tpOcspDebug("tpVerifyCertGroupWithOCSP numCerts %u optFlags 0x%lx",
488 numCerts
, (unsigned long)optFlags
);
491 * create list of pendingRequests parallel to certGroup
493 PendingRequest
**pending
= coder
.mallocn
<PendingRequest
*>(numCerts
);
494 memset(pending
, 0, (numCerts
* sizeof(PendingRequest
*)));
496 for(unsigned dex
=0; dex
<numCerts
; dex
++) {
497 OCSPClientCertID
*certID
= NULL
;
498 TPCertInfo
*subject
= certGroup
.certAtIndex(dex
);
500 if(subject
->trustSettingsFound()) {
501 /* functionally equivalent to root - we're done */
502 tpOcspDebug("...tpVerifyCertGroupWithOCSP: terminate per user trust at %u",
506 TPCertInfo
*issuer
= certGroup
.certAtIndex(dex
+ 1);
507 crtn
= tpOcspGetCertId(*subject
, *issuer
, certID
);
509 tpErrorLog("tpVerifyCertGroupWithOCSP: error extracting cert fields; "
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.
521 CSSM_DATA
**urls
= tpOcspUrlsFromCert(*subject
, coder
);
522 pending
[dex
] = new PendingRequest(*subject
, *issuer
, *certID
, urls
, dex
);
524 /* subsequent errors to errOut: */
527 * Create empty SecAsn1OCSPDRequests big enough for all certs
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;
535 * For each cert, either obtain a cached OCSPResponse, or create
536 * a request to get one.
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.
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
);
550 tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache hit (1) dex %u",
552 crtn
= tpApplySingleResp(*singleResp
, pendReq
->subject
, dex
, optFlags
,
553 vfyCtx
.verifyTime
, pendReq
->processed
);
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 */
565 * This indicates a bad cached response. Well that's kinda weird, let's
566 * just flush this out and try a normal transaction.
568 tpOcspCacheFlush(pendReq
->certID
);
573 * Prepare a request for ocspd
575 SecAsn1OCSPDRequest
*ocspdReq
= tpGenOcspdReq(vfyCtx
, coder
,
576 pendReq
->subject
, pendReq
->issuer
, pendReq
->certID
,
577 const_cast<const CSSM_DATA
**>(pendReq
->urls
),
579 if(ocspdReq
== NULL
) {
580 /* tpGenOcspdReq determined there was no route to OCSP responder */
581 tpOcspDebug("tpVerifyCertGroupWithOCSP: no OCSP possible for cert %u", dex
);
584 ocspdReqs
.requests
[numRequests
++] = ocspdReq
;
586 if(numRequests
== 0) {
587 /* no candidates for OCSP: almost done */
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
;
597 crtn
= ocspdFetch(vfyCtx
.alloc
, derOcspdRequests
, derOcspdReplies
);
599 tpErrorLog("tpVerifyCertGroupWithOCSP: error during ocspd RPC\n");
601 cssmPerror("ocspdFetch", crtn
);
603 /* But this is not necessarily fatal...update per-cert status and check
604 * caller requirements below */
607 memset(&ocspdReplies
, 0, sizeof(ocspdReplies
));
608 prtn
= coder
.decodeItem(derOcspdReplies
, kSecAsn1OCSPDRepliesTemplate
,
610 /* we're done with this, mallocd in ocspdFetch() */
611 vfyCtx
.alloc
.free(derOcspdReplies
.Data
);
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.
619 tpErrorLog("tpVerifyCertGroupWithOCSP: error decoding ocspd reply\n");
620 pending
[0]->subject
.addStatusCode(CSSMERR_APPLETP_OCSP_BAD_RESPONSE
);
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?
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
];
637 /* Cook up our version of an OCSPResponse from the encoded data */
638 OCSPResponse
*ocspResp
= NULL
;
640 ocspResp
= new OCSPResponse(reply
->ocspResp
, TP_OCSP_CACHE_TTL
);
643 tpErrorLog("tpVerifyCertGroupWithOCSP: error decoding ocsp response\n");
644 /* what the heck, keep going */
649 * Find matching subject cert if possible (it's technically optional for
650 * verification of the response in some cases, e.g., local responder).
652 PendingRequest
*pendReq
= NULL
; // fully qualified
653 PendingRequest
*reqWithIdMatch
= NULL
; // CertID match only, not nonce
654 for(unsigned pdex
=0; pdex
<numCerts
; pdex
++) {
656 /* first check ID match; that is required no matter what */
657 if((pending
[pdex
])->certID
.compareToExist(reply
->certID
)) {
658 reqWithIdMatch
= pending
[pdex
];
660 if(reqWithIdMatch
== NULL
) {
664 /* that's good enough */
665 pendReq
= reqWithIdMatch
;
666 tpOcspDebug("OCSP process reply: CertID match, no nonce");
669 if(tpCompareCssmData(&reqWithIdMatch
->nonce
, ocspResp
->nonce())) {
670 tpOcspDebug("OCSP process reply: nonce MATCH");
671 pendReq
= reqWithIdMatch
;
676 * In this case we keep going; if we never find a match, then we can
677 * use reqWithIdMatch if !requireRespNonce.
679 tpOcspDebug("OCSP process reply: certID match, nonce MISMATCH");
681 if(pendReq
== NULL
) {
682 if(requireRespNonce
) {
683 tpOcspDebug("OCSP process reply: tossing out response due to "
686 if(ourRtn
== CSSM_OK
) {
687 ourRtn
= CSSMERR_APPLETP_OCSP_NONCE_MISMATCH
;
691 if(reqWithIdMatch
!= NULL
) {
693 * Nonce mismatch but caller thinks that's OK. Log it and proceed.
696 tpOcspDebug("OCSP process reply: using bad nonce due to !requireRespNonce");
697 pendReq
= reqWithIdMatch
;
698 pendReq
->subject
.addStatusCode(CSSMERR_APPLETP_OCSP_NONCE_MISMATCH
);
701 TPCertInfo
*issuer
= NULL
;
702 if(pendReq
!= NULL
) {
703 issuer
= &pendReq
->issuer
;
706 /* verify response and either throw out or add to local cache */
707 respStat
= tpVerifyOcspResp(vfyCtx
, coder
, issuer
, *ocspResp
, crtn
);
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
);
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.
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
;
736 respStat
= tpVerifyOcspResp(vfyCtx
, coder
, issuer
, *ocspResp
, crtn
);
737 if(respStat
!= ORS_Good
) {
738 tpErrorLog("tpVerifyCertGroupWithOCSP: verify error after "
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
;
747 ourRtn
= CSSMERR_APPLETP_OCSP_BAD_RESPONSE
;
751 /* Voila! Recovery. Proceed. */
752 tpOcspDebug("tpVerifyCertGroupWithOCSP: refetch for cert %u SUCCEEDED",
755 } /* switch response status */
757 if(!cacheWriteDisable
) {
758 tpOcspCacheAdd(reply
->ocspResp
, localResponder
);
761 /* attempt to apply to pendReq */
762 if(pendReq
!= NULL
) {
763 OCSPSingleResponse
*singleResp
=
764 ocspResp
->singleResponseFor(pendReq
->certID
);
766 crtn
= tpApplySingleResp(*singleResp
, pendReq
->subject
, pendReq
->dex
,
767 optFlags
, vfyCtx
.verifyTime
, pendReq
->processed
);
768 if(crtn
&& (ourRtn
== CSSM_OK
)) {
773 } /* a reply which matches a pending request */
776 * Done with this - note local OCSP response cache doesn't store this
777 * object; it stores an encoded copy.
780 } /* for each reply */
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
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",
798 if(pendReq
->processed
) {
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
);
807 tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache (2) hit dex %u",
809 crtn
= tpApplySingleResp(*singleResp
, pendReq
->subject
, dex
, optFlags
,
810 vfyCtx
.verifyTime
, pendReq
->processed
);
812 if(ourRtn
== CSSM_OK
) {
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) {
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)
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
;
837 if(responseStatus
== CSSM_OK
) {
838 /* no response available (as opposed to getting an invalid response) */
839 pendReq
->subject
.addStatusCode(CSSMERR_APPLETP_OCSP_UNAVAILABLE
);
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
);
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 */
849 tpOcspDebug("tpVerifyCertGroupWithOCSP: OCSP URI present but no valid response for cert %u", dex
);
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
;
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 */
869 delete &pendReq
->certID
;