]> git.saurik.com Git - apple/security.git/blob - libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_apple_x509_tp / lib / tpOcspCertVfy.cpp
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 }