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