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