]> git.saurik.com Git - apple/security.git/blame - libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp
Security-55471.14.18.tar.gz
[apple/security.git] / libsecurity_apple_x509_tp / lib / tpOcspCertVfy.cpp
CommitLineData
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 */
41static 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 }
100errOut:
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 112static
b1ab9ed8
A
113bool 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 */
166static 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() */
213typedef 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 */
220typedef 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 */
234static 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
309errOut:
310 if((signerRtn == NULL) && (tmpSigner != NULL)) {
311 delete tmpSigner;
312 }
313 return ourRtn;
314
315}
316
317OcspRespStatus 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
588errOut:
589 delete signerInfoTBD;
590 /* any other cleanup? */
591 return ourRtn;
592}