]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp
Security-57031.30.12.tar.gz
[apple/security.git] / Security / libsecurity_apple_x509_tp / lib / tpOcspCertVfy.cpp
1 /*
2 * Copyright (c) 2004,2011-2012,2014 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 * tpOcspCertVfy.cpp - OCSP cert verification routines
26 */
27
28 #include "tpOcspCertVfy.h"
29 #include "tpdebugging.h"
30 #include "certGroupUtils.h"
31 #include <Security/oidscert.h>
32 #include <CommonCrypto/CommonDigest.h>
33 #include <security_ocspd/ocspdUtils.h>
34
35 #ifndef NDEBUG
36 #include <Security/SecCertificate.h>
37 #endif
38
39 /*
40 * Is signerCert authorized to sign OCSP responses by issuerCert? IssuerCert is
41 * assumed to be (i.e., must, but we don't check that here) the signer of the
42 * cert being verified, which is not in the loop for this op. Just a bool returned;
43 * it's authorized or it's not.
44 */
45 static bool tpIsAuthorizedOcspSigner(
46 TPCertInfo &issuerCert, // issuer of cert being verified
47 TPCertInfo &signerCert) // potential signer of OCSP response
48 {
49 CSSM_DATA_PTR fieldValue = NULL; // mallocd by CL
50 CSSM_RETURN crtn;
51 bool ourRtn = false;
52 CE_ExtendedKeyUsage *eku = NULL;
53 bool foundEku = false;
54
55 /*
56 * First see if issuerCert issued signerCert (No signature vfy yet, just
57 * subject/issuer check).
58 */
59 if(!issuerCert.isIssuerOf(signerCert)) {
60 #ifndef NDEBUG
61 SecCertificateRef issuerRef = NULL;
62 SecCertificateRef signerRef = NULL;
63 const CSSM_DATA *issuerData = issuerCert.itemData();
64 const CSSM_DATA *signerData = signerCert.itemData();
65 crtn = SecCertificateCreateFromData(issuerData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, &issuerRef);
66 crtn = SecCertificateCreateFromData(signerData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, &signerRef);
67 CFStringRef issuerName = SecCertificateCopySubjectSummary(issuerRef);
68 CFStringRef signerName = SecCertificateCopySubjectSummary(signerRef);
69 if(issuerName) {
70 CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(issuerName), kCFStringEncodingUTF8) + 1;
71 char* buf = (char*) malloc(maxLength);
72 if (buf) {
73 if (CFStringGetCString(issuerName, buf, (CFIndex)maxLength, kCFStringEncodingUTF8)) {
74 tpOcspDebug("tpIsAuthorizedOcspSigner: issuerCert \"%s\"", buf);
75 }
76 free(buf);
77 }
78 CFRelease(issuerName);
79 }
80 if(signerName) {
81 CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(signerName), kCFStringEncodingUTF8) + 1;
82 char* buf = (char*) malloc(maxLength);
83 if (buf) {
84 if (CFStringGetCString(signerName, buf, (CFIndex)maxLength, kCFStringEncodingUTF8)) {
85 tpOcspDebug("tpIsAuthorizedOcspSigner: signerCert \"%s\"", buf);
86 }
87 free(buf);
88 }
89 CFRelease(signerName);
90 }
91 if(issuerRef) {
92 CFRelease(issuerRef);
93 }
94 if(signerRef) {
95 CFRelease(signerRef);
96 }
97 #endif
98 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is not issued by issuerCert");
99 return false;
100 }
101
102 /* Fetch ExtendedKeyUse field from signerCert */
103 crtn = signerCert.fetchField(&CSSMOID_ExtendedKeyUsage, &fieldValue);
104 if(crtn) {
105 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU");
106 return false;
107 }
108 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
109 if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
110 tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format");
111 goto errOut;
112 }
113 eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue;
114
115 /* Look for OID_KP_OCSPSigning */
116 for(unsigned dex=0; dex<eku->numPurposes; dex++) {
117 if(tpCompareCssmData(&eku->purposes[dex], &CSSMOID_OCSPSigning)) {
118 foundEku = true;
119 break;
120 }
121 }
122 if(!foundEku) {
123 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no OCSP "
124 "signing EKU");
125 goto errOut;
126 }
127
128 /*
129 * OK, signerCert is authorized by *someone* to sign OCSP requests, and
130 * it claims to be issued by issuer. Sig verify to be sure.
131 * FIXME this is not handling partial public keys, which would be a colossal
132 * mess to handle in this module...so we don't.
133 */
134 crtn = signerCert.verifyWithIssuer(&issuerCert, NULL);
135 if(crtn == CSSM_OK) {
136 tpOcspDebug("tpIsAuthorizedOcspSigner: FOUND authorized signer");
137 ourRtn = true;
138 }
139 else {
140 /* This is a highly irregular situation... */
141 tpOcspDebug("tpIsAuthorizedOcspSigner: signer sig verify FAIL");
142 }
143 errOut:
144 if(fieldValue != NULL) {
145 signerCert.freeField(&CSSMOID_ExtendedKeyUsage, fieldValue);
146 }
147 return ourRtn;
148 }
149
150 /*
151 * Check ResponderID linkage between an OCSPResponse and a cert we believe to
152 * be the issuer of both that response and the cert being verified. Returns
153 * true if OK.
154 */
155 static
156 bool tpOcspResponderIDCheck(
157 OCSPResponse &ocspResp,
158 TPCertInfo &signer)
159 {
160 bool shouldBeSigner = false;
161 if(ocspResp.responderIDTag() == RIT_Name) {
162 /*
163 * Name inside response must == signer's SubjectName.
164 * Note we can't use signer.subjectName(); that's normalized.
165 */
166
167 const CSSM_DATA *respIdName = ocspResp.encResponderName();
168 CSSM_DATA *subjectName = NULL;
169 CSSM_RETURN crtn = signer.fetchField(&CSSMOID_X509V1SubjectNameStd,
170 &subjectName);
171 if(crtn) {
172 /* bad cert */
173 tpOcspDebug("tpOcspResponderIDCheck: error on fetchField(subjectName");
174 return false;
175 }
176 if(tpCompareCssmData(respIdName, subjectName)) {
177 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byName");
178 shouldBeSigner = true;
179 }
180 else {
181 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byName");
182 }
183 signer.freeField(&CSSMOID_X509V1SubjectNameStd, subjectName);
184 }
185 else {
186 /* ResponderID.byKey must == SHA1(signer's public key) */
187 const CSSM_KEY_PTR pubKey = signer.pubKey();
188 assert(pubKey != NULL);
189 uint8 digest[CC_SHA1_DIGEST_LENGTH];
190 CSSM_DATA keyHash = {CC_SHA1_DIGEST_LENGTH, digest};
191 CSSM_DATA pubKeyBytes = {0, NULL};
192 ocspdGetPublicKeyBytes(NULL, pubKey, pubKeyBytes);
193 ocspdSha1(pubKeyBytes.Data, (CC_LONG)pubKeyBytes.Length, digest);
194 const CSSM_DATA *respKeyHash = &ocspResp.responderID().byKey;
195 if(tpCompareCssmData(&keyHash, respKeyHash)) {
196 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byKey");
197 shouldBeSigner = true;
198 }
199 else {
200 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byKey");
201 }
202 }
203 return shouldBeSigner;
204 }
205
206 /*
207 * Verify the signature of an OCSP response. Caller is responsible for all other
208 * verification of the response, this is just the crypto.
209 * Returns true on success.
210 */
211 static bool tpOcspResponseSigVerify(
212 TPVerifyContext &vfyCtx,
213 OCSPResponse &ocspResp, // parsed response
214 TPCertInfo &signer)
215 {
216 /* get signature algorithm in CSSM form from the response */
217 const SecAsn1OCSPBasicResponse &basicResp = ocspResp.basicResponse();
218 const CSSM_OID *algOid = &basicResp.algId.algorithm;
219 CSSM_ALGORITHMS sigAlg;
220
221 if(!cssmOidToAlg(algOid, &sigAlg)) {
222 tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm");
223 }
224
225 /* signer's public key from the cert */
226 const CSSM_KEY *pubKey = signer.pubKey();
227
228 /* signature: on decode, length is in BITS */
229 CSSM_DATA sig = basicResp.sig;
230 sig.Length /= 8;
231
232 CSSM_RETURN crtn;
233 CSSM_CC_HANDLE sigHand;
234 bool ourRtn = false;
235 crtn = CSSM_CSP_CreateSignatureContext(vfyCtx.cspHand, sigAlg, NULL,
236 pubKey, &sigHand);
237 if(crtn) {
238 #ifndef NDEBUG
239 cssmPerror("tpOcspResponseSigVerify, CSSM_CSP_CreateSignatureContext", crtn);
240 #endif
241 return false;
242 }
243 crtn = CSSM_VerifyData(sigHand, &basicResp.tbsResponseData, 1,
244 CSSM_ALGID_NONE, &sig);
245 if(crtn) {
246 #ifndef NDEBUG
247 cssmPerror("tpOcspResponseSigVerify, CSSM_VerifyData", crtn);
248 #endif
249 }
250 else {
251 ourRtn = true;
252 }
253 CSSM_DeleteContext(sigHand);
254 return ourRtn;
255 }
256
257 /* possible return from tpIsOcspIssuer() */
258 typedef enum {
259 OIS_No, // not the issuer
260 OIS_Good, // is the issuer and signature matches
261 OIS_BadSig, // appears to be issuer, but signature doesn't match
262 } OcspIssuerStatus;
263
264 /* type of rawCert passed to tpIsOcspIssuer */
265 typedef enum {
266 OCT_Local, // LocalResponder - no checking other than signature
267 OCT_Issuer, // it's the issuer of the cert being verified
268 OCT_Provided, // came with response, provenance unknown
269 } OcspCertType;
270
271 /*
272 * Did specified cert issue the OCSP response?
273 *
274 * This implements the algorithm described in RFC2560, section 4.2.2.2,
275 * "Authorized Responders". It sees if the cert could be the issuer of the
276 * OCSP response per that algorithm; then if it could, it performs signature
277 * verification.
278 */
279 static OcspIssuerStatus tpIsOcspIssuer(
280 TPVerifyContext &vfyCtx,
281 OCSPResponse &ocspResp, // parsed response
282 /* on input specify at least one of the following two */
283 const CSSM_DATA *signerData,
284 TPCertInfo *signer,
285 OcspCertType certType, // where rawCert came from
286 TPCertInfo *issuer, // OPTIONAL, if known
287 TPCertInfo **signerRtn) // optionally RETURNED if at all possible
288 {
289 assert((signerData != NULL) || (signer != NULL));
290
291 /* get signer as TPCertInfo if caller hasn't provided */
292 TPCertInfo *tmpSigner = NULL;
293 if(signer == NULL) {
294 try {
295 tmpSigner = new TPCertInfo(vfyCtx.clHand, vfyCtx.cspHand, signerData,
296 TIC_CopyData, vfyCtx.verifyTime);
297 }
298 catch(...) {
299 tpOcspDebug("tpIsOcspIssuer: bad cert");
300 return OIS_No;
301 }
302 signer = tmpSigner;
303 }
304 if(signer == NULL) {
305 return OIS_No;
306 }
307 if(signerRtn != NULL) {
308 *signerRtn = signer;
309 }
310
311 /*
312 * Qualification of "this can be the signer" depends on where the
313 * signer came from.
314 */
315 bool shouldBeSigner = false;
316 OcspIssuerStatus ourRtn = OIS_No;
317
318 switch(certType) {
319 case OCT_Local: // caller trusts this and thinks it's the signer
320 shouldBeSigner = true;
321 break;
322 case OCT_Issuer: // last resort, the actual issuer
323 /* check ResponderID linkage */
324 shouldBeSigner = tpOcspResponderIDCheck(ocspResp, *signer);
325 break;
326 case OCT_Provided:
327 {
328 /*
329 * This cert came with the response.
330 */
331 if(issuer == NULL) {
332 /*
333 * careful, might not know the issuer...how would this path ever
334 * work then? I don't think it needs to because you can NOT
335 * do OCSP on a cert without its issuer in hand.
336 */
337 break;
338 }
339
340 /* check EKU linkage */
341 shouldBeSigner = tpIsAuthorizedOcspSigner(*issuer, *signer);
342 break;
343 }
344 }
345 if(!shouldBeSigner) {
346 goto errOut;
347 }
348
349 /* verify the signature */
350 if(tpOcspResponseSigVerify(vfyCtx, ocspResp, *signer)) {
351 ourRtn = OIS_Good;
352 }
353
354 errOut:
355 if((signerRtn == NULL) && (tmpSigner != NULL)) {
356 delete tmpSigner;
357 }
358 return ourRtn;
359
360 }
361
362 OcspRespStatus tpVerifyOcspResp(
363 TPVerifyContext &vfyCtx,
364 SecNssCoder &coder,
365 TPCertInfo *issuer, // issuer of the related cert, may be issuer of
366 // reply, may not be known
367 OCSPResponse &ocspResp,
368 CSSM_RETURN &cssmErr) // possible per-cert error
369 {
370 OcspRespStatus ourRtn = ORS_Unknown;
371 CSSM_RETURN crtn;
372
373 tpOcspDebug("tpVerifyOcspResp top");
374
375 switch(ocspResp.responseStatus()) {
376 case RS_Success:
377 crtn = CSSM_OK;
378 break;
379 case RS_MalformedRequest:
380 crtn = CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ;
381 break;
382 case RS_InternalError:
383 crtn = CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR;
384 break;
385 case RS_TryLater:
386 crtn = CSSMERR_APPLETP_OCSP_RESP_TRY_LATER;
387 break;
388 case RS_SigRequired:
389 crtn = CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED;
390 break;
391 case RS_Unauthorized:
392 crtn = CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED;
393 break;
394 default:
395 crtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
396 break;
397 }
398 if(crtn) {
399 tpOcspDebug("tpVerifyOcspResp aborting due to response status %d",
400 (int)(ocspResp.responseStatus()));
401 cssmErr = crtn;
402 return ORS_Unknown;
403 }
404 cssmErr = CSSM_OK;
405
406 /* one of our main jobs is to locate the signer of the response, here */
407 TPCertInfo *signerInfo = NULL;
408 TPCertInfo *signerInfoTBD = NULL; // if non NULL at end, we delete
409 /* we'll be verifying into this cert group */
410 TPCertGroup ocspCerts(vfyCtx.alloc, TGO_Caller);
411 CSSM_BOOL verifiedToRoot;
412 CSSM_BOOL verifiedToAnchor;
413 CSSM_BOOL verifiedViaTrustSetting;
414
415 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
416 OcspIssuerStatus issuerStat;
417
418 /*
419 * Set true if we ever find an apparent issuer which does not correctly
420 * pass signature verify. If true and we never success, that's a XXX error.
421 */
422 bool foundBadIssuer = false;
423 bool foundLocalResponder = false;
424 uint32 numSignerCerts = ocspResp.numSignerCerts();
425
426 /*
427 * This cert group, allocated by AppleTPSession::CertGroupVerify(),
428 * serves two functions here:
429 *
430 * -- it accumulates certs we get from the net (as parts of OCSP responses)
431 * for user in verifying OCSPResponse-related certs.
432 * TPCertGroup::buildCertGroup() uses this group as one of the many
433 * sources of certs when building a cert chain.
434 *
435 * -- it provides a container into which to stash TPCertInfos which
436 * persist at least as long as the TPVerifyContext; it's of type TGO_Group,
437 * so all of the certs added to it get freed when the group does.
438 */
439 assert(vfyCtx.signerCerts != NULL);
440
441 TPCertGroup &gatheredCerts = vfyCtx.gatheredCerts;
442
443 /* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */
444 TPCertGroup certsToBeFreed(vfyCtx.alloc, TGO_Group);
445
446 /*
447 * First job is to find the cert which signed this response.
448 * Give priority to caller's LocalResponderCert.
449 */
450 if((ocspOpts != NULL) && (ocspOpts->LocalResponderCert != NULL)) {
451 TPCertInfo *responderInfo = NULL;
452 issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
453 ocspOpts->LocalResponderCert, NULL,
454 OCT_Local, issuer, &responderInfo);
455 switch(issuerStat) {
456 case OIS_BadSig:
457 foundBadIssuer = true;
458 /* drop thru */
459 case OIS_No:
460 if(responderInfo != NULL) {
461 /* can't use it - should this be an immediate error? */
462 delete responderInfo;
463 }
464 break;
465 case OIS_Good:
466 assert(responderInfo != NULL);
467 signerInfo = signerInfoTBD = responderInfo;
468 foundLocalResponder = true;
469 tpOcspDebug("tpVerifyOcspResp: signer := LocalResponderCert");
470 break;
471 }
472 }
473
474 if((signerInfo == NULL) && (numSignerCerts != 0)) {
475 /*
476 * App did not specify a local responder (or provided a bad one)
477 * and the response came with some certs. Try those.
478 */
479 TPCertInfo *respCert = NULL;
480 for(unsigned dex=0; dex<numSignerCerts; dex++) {
481 const CSSM_DATA *certData = ocspResp.signerCert(dex);
482 if(signerInfo == NULL) {
483 /* stop trying this after we succeed... */
484 issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
485 certData, NULL,
486 OCT_Provided, issuer, &respCert);
487 switch(issuerStat) {
488 case OIS_No:
489 break;
490 case OIS_Good:
491 assert(respCert != NULL);
492 signerInfo = signerInfoTBD = respCert;
493 tpOcspDebug("tpVerifyOcspResp: signer := signerCert[%u]", dex);
494 break;
495 case OIS_BadSig:
496 foundBadIssuer = true;
497 break;
498 }
499 }
500 else {
501 /*
502 * At least add this cert to certGroup for verification.
503 * OcspCert will own the TPCertInfo.
504 */
505 try {
506 respCert = new TPCertInfo(vfyCtx.clHand, vfyCtx.cspHand, certData,
507 TIC_CopyData, vfyCtx.verifyTime);
508 }
509 catch(...) {
510 tpOcspDebug("tpVerifyOcspResp: BAD signerCert[%u]", dex);
511 }
512 }
513 /* if we got a TPCertInfo, and it's not the signer, add it to certGroup */
514 if((respCert != NULL) && (respCert != signerInfo)) {
515 gatheredCerts.appendCert(respCert);
516 }
517 }
518 }
519
520 if((signerInfo == NULL) && (issuer != NULL)) {
521 /*
522 * Haven't found it yet, try the actual issuer
523 */
524 issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
525 NULL, issuer,
526 OCT_Issuer, issuer, NULL);
527 switch(issuerStat) {
528 case OIS_BadSig:
529 ourRtn = ORS_Unknown;
530 cssmErr = CSSMERR_APPLETP_OCSP_SIG_ERROR;
531 goto errOut;
532 case OIS_No:
533 break;
534 case OIS_Good:
535 signerInfo = issuer;
536 tpOcspDebug("tpVerifyOcspResp: signer := issuer");
537 break;
538 }
539 }
540
541 if(signerInfo == NULL) {
542 if((issuer != NULL) && !issuer->isStatusFatal(CSSMERR_APPLETP_OCSP_NO_SIGNER)) {
543 /* user wants to proceed without verifying! */
544 tpOcspDebug("tpVerifyOcspResp: no signer found, user allows!");
545 ourRtn = ORS_Good;
546 }
547 else {
548 tpOcspDebug("tpVerifyOcspResp: no signer found");
549 ourRtn = ORS_Unknown;
550 /* caller adds to per-cert status */
551 cssmErr = CSSMERR_APPLETP_OCSP_NO_SIGNER;
552 }
553 goto errOut;
554 }
555
556 if(signerInfo != NULL && !foundLocalResponder) {
557 /*
558 * tpIsOcspIssuer has verified that signerInfo is the signer of the
559 * OCSP response, and that it is either the issuer of the cert being
560 * checked or is a valid authorized responder for that issuer based on
561 * key id linkage and EKU. There is no stipulation in RFC2560 to also
562 * build the chain back to a trusted anchor; however, we'll continue to
563 * enforce this for the local responder case. (10742723)
564 */
565 tpOcspDebug("tpVerifyOcspResp SUCCESS");
566 ourRtn = ORS_Good;
567 goto errOut;
568 }
569
570 /*
571 * Last remaining task is to verify the signer, and all the certs back to
572 * an anchor
573 */
574
575 /* start from scratch with both of these groups */
576 gatheredCerts.setAllUnused();
577 vfyCtx.signerCerts->setAllUnused();
578 crtn = ocspCerts.buildCertGroup(
579 *signerInfo, // subject item
580 vfyCtx.signerCerts, // inCertGroup the original group-to-be-verified
581 vfyCtx.dbList, // optional
582 vfyCtx.clHand,
583 vfyCtx.cspHand,
584 vfyCtx.verifyTime,
585 vfyCtx.numAnchorCerts,
586 vfyCtx.anchorCerts,
587 certsToBeFreed, // local to-be-freed right now
588 &gatheredCerts, // accumulate gathered certs here
589 CSSM_FALSE, // subjectIsInGroup
590 vfyCtx.actionFlags,
591 vfyCtx.policyOid,
592 vfyCtx.policyStr,
593 vfyCtx.policyStrLen,
594 kSecTrustSettingsKeyUseSignRevocation,
595 verifiedToRoot,
596 verifiedToAnchor,
597 verifiedViaTrustSetting);
598 if(crtn) {
599 tpOcspDebug("tpVerifyOcspResp buildCertGroup failure");
600 cssmErr = crtn;
601 ourRtn = ORS_Unknown;
602 goto errOut;
603 }
604
605 if(!verifiedToAnchor && !verifiedViaTrustSetting) {
606 /* required */
607 ourRtn = ORS_Unknown;
608 if(verifiedToRoot) {
609 /* verified to root which is not an anchor */
610 tpOcspDebug("tpVerifyOcspResp root, no anchor");
611 cssmErr = CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT;
612 }
613 else {
614 /* partial chain, no root, not verifiable by anchor */
615 tpOcspDebug("tpVerifyOcspResp no root, no anchor");
616 cssmErr = CSSMERR_APPLETP_OCSP_NOT_TRUSTED;
617 }
618 if((issuer != NULL) && !issuer->isStatusFatal(cssmErr)) {
619 tpOcspDebug("...ignoring last error per trust setting");
620 ourRtn = ORS_Good;
621 }
622 else {
623 ourRtn = ORS_Unknown;
624 }
625 }
626 else {
627 tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified");
628 ourRtn = ORS_Good;
629 }
630
631 /* FIXME policy verify? */
632
633 errOut:
634 delete signerInfoTBD;
635 /* any other cleanup? */
636 return ourRtn;
637 }