2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * tpOcspCertVfy.cpp - OCSP cert verification routines
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>
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.
41 static bool tpIsAuthorizedOcspSigner(
42 TPCertInfo
&issuerCert
, // issuer of cert being verified
43 TPCertInfo
&signerCert
) // potential signer of OCSP response
45 CSSM_DATA_PTR fieldValue
= NULL
; // mallocd by CL
48 CE_ExtendedKeyUsage
*eku
= NULL
;
49 bool foundEku
= false;
52 * First see if issuerCert issued signerCert (No signature vfy yet, just
53 * subject/issuer check).
55 if(!issuerCert
.isIssuerOf(signerCert
)) {
59 /* Fetch ExtendedKeyUse field from signerCert */
60 crtn
= signerCert
.fetchField(&CSSMOID_ExtendedKeyUsage
, &fieldValue
);
62 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU");
65 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
66 if(cssmExt
->format
!= CSSM_X509_DATAFORMAT_PARSED
) {
67 tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format");
70 eku
= (CE_ExtendedKeyUsage
*)cssmExt
->value
.parsedValue
;
72 /* Look for OID_KP_OCSPSigning */
73 for(unsigned dex
=0; dex
<eku
->numPurposes
; dex
++) {
74 if(tpCompareCssmData(&eku
->purposes
[dex
], &CSSMOID_OCSPSigning
)) {
80 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no OCSP "
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.
91 crtn
= signerCert
.verifyWithIssuer(&issuerCert
, NULL
);
93 tpOcspDebug("tpIsAuthorizedOcspSigner: FOUND authorized signer");
97 /* This is a highly irregular situation... */
98 tpOcspDebug("tpIsAuthorizedOcspSigner: signer sig verify FAIL");
101 if(fieldValue
!= NULL
) {
102 signerCert
.freeField(&CSSMOID_ExtendedKeyUsage
, fieldValue
);
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
112 bool tpOcspResponderIDCheck(
113 OCSPResponse
&ocspResp
,
116 bool shouldBeSigner
= false;
117 if(ocspResp
.responderIDTag() == RIT_Name
) {
119 * Name inside response must == signer's SubjectName.
120 * Note we can't use signer.subjectName(); that's normalized.
123 const CSSM_DATA
*respIdName
= ocspResp
.encResponderName();
124 CSSM_DATA
*subjectName
= NULL
;
125 CSSM_RETURN crtn
= signer
.fetchField(&CSSMOID_X509V1SubjectNameStd
,
129 tpOcspDebug("tpOcspResponderIDCheck: error on fetchField(subjectName");
132 if(tpCompareCssmData(respIdName
, subjectName
)) {
133 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byName");
134 shouldBeSigner
= true;
137 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byName");
139 signer
.freeField(&CSSMOID_X509V1SubjectNameStd
, subjectName
);
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;
154 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byKey");
157 return shouldBeSigner
;
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.
165 static bool tpOcspResponseSigVerify(
166 TPVerifyContext
&vfyCtx
,
167 OCSPResponse
&ocspResp
, // parsed response
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
;
175 if(!cssmOidToAlg(algOid
, &sigAlg
)) {
176 tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm");
179 /* signer's public key from the cert */
180 const CSSM_KEY
*pubKey
= signer
.pubKey();
182 /* signature: on decode, length is in BITS */
183 CSSM_DATA sig
= basicResp
.sig
;
187 CSSM_CC_HANDLE sigHand
;
189 crtn
= CSSM_CSP_CreateSignatureContext(vfyCtx
.cspHand
, sigAlg
, NULL
,
193 cssmPerror("tpOcspResponseSigVerify, CSSM_CSP_CreateSignatureContext", crtn
);
197 crtn
= CSSM_VerifyData(sigHand
, &basicResp
.tbsResponseData
, 1,
198 CSSM_ALGID_NONE
, &sig
);
201 cssmPerror("tpOcspResponseSigVerify, CSSM_VerifyData", crtn
);
207 CSSM_DeleteContext(sigHand
);
211 /* possible return from tpIsOcspIssuer() */
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
218 /* type of rawCert passed to tpIsOcspIssuer */
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
226 * Did specified cert issue the OCSP response?
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
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
,
239 OcspCertType certType
, // where rawCert came from
240 TPCertInfo
*issuer
, // OPTIONAL, if known
241 TPCertInfo
**signerRtn
) // optionally RETURNED if at all possible
243 assert((signerData
!= NULL
) || (signer
!= NULL
));
245 /* get signer as TPCertInfo if caller hasn't provided */
246 TPCertInfo
*tmpSigner
= NULL
;
249 tmpSigner
= new TPCertInfo(vfyCtx
.clHand
, vfyCtx
.cspHand
, signerData
,
250 TIC_CopyData
, vfyCtx
.verifyTime
);
253 tpOcspDebug("tpIsOcspIssuer: bad cert");
261 if(signerRtn
!= NULL
) {
266 * Qualification of "this can be the signer" depends on where the
269 bool shouldBeSigner
= false;
270 OcspIssuerStatus ourRtn
= OIS_No
;
273 case OCT_Local
: // caller trusts this and thinks it's the signer
274 shouldBeSigner
= true;
276 case OCT_Issuer
: // last resort, the actual issuer
277 /* check ResponderID linkage */
278 shouldBeSigner
= tpOcspResponderIDCheck(ocspResp
, *signer
);
283 * This cert came with the response.
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.
294 /* check EKU linkage */
295 shouldBeSigner
= tpIsAuthorizedOcspSigner(*issuer
, *signer
);
299 if(!shouldBeSigner
) {
303 /* verify the signature */
304 if(tpOcspResponseSigVerify(vfyCtx
, ocspResp
, *signer
)) {
309 if((signerRtn
== NULL
) && (tmpSigner
!= NULL
)) {
316 OcspRespStatus
tpVerifyOcspResp(
317 TPVerifyContext
&vfyCtx
,
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
324 OcspRespStatus ourRtn
= ORS_Unknown
;
327 tpOcspDebug("tpVerifyOcspResp top");
329 switch(ocspResp
.responseStatus()) {
333 case RS_MalformedRequest
:
334 crtn
= CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ
;
336 case RS_InternalError
:
337 crtn
= CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR
;
340 crtn
= CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
;
343 crtn
= CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED
;
345 case RS_Unauthorized
:
346 crtn
= CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED
;
349 crtn
= CSSMERR_APPLETP_OCSP_BAD_RESPONSE
;
353 tpOcspDebug("tpVerifyOcspResp aborting due to response status %d",
354 (int)(ocspResp
.responseStatus()));
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
;
369 const CSSM_APPLE_TP_OCSP_OPTIONS
*ocspOpts
= vfyCtx
.ocspOpts
;
370 OcspIssuerStatus issuerStat
;
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.
376 bool foundBadIssuer
= false;
377 bool foundLocalResponder
= false;
378 uint32 numSignerCerts
= ocspResp
.numSignerCerts();
381 * This cert group, allocated by AppleTPSession::CertGroupVerify(),
382 * serves two functions here:
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.
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.
393 assert(vfyCtx
.signerCerts
!= NULL
);
395 TPCertGroup
&gatheredCerts
= vfyCtx
.gatheredCerts
;
397 /* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */
398 TPCertGroup
certsToBeFreed(vfyCtx
.alloc
, TGO_Group
);
401 * First job is to find the cert which signed this response.
402 * Give priority to caller's LocalResponderCert.
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
);
411 foundBadIssuer
= true;
414 if(responderInfo
!= NULL
) {
415 /* can't use it - should this be an immediate error? */
416 delete responderInfo
;
420 assert(responderInfo
!= NULL
);
421 signerInfo
= signerInfoTBD
= responderInfo
;
422 foundLocalResponder
= true;
423 tpOcspDebug("tpVerifyOcspResp: signer := LocalResponderCert");
428 if((signerInfo
== NULL
) && (numSignerCerts
!= 0)) {
430 * App did not specify a local responder (or provided a bad one)
431 * and the response came with some certs. Try those.
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
,
440 OCT_Provided
, issuer
, &respCert
);
445 assert(respCert
!= NULL
);
446 signerInfo
= signerInfoTBD
= respCert
;
447 tpOcspDebug("tpVerifyOcspResp: signer := signerCert[%u]", dex
);
450 foundBadIssuer
= true;
456 * At least add this cert to certGroup for verification.
457 * OcspCert will own the TPCertInfo.
460 respCert
= new TPCertInfo(vfyCtx
.clHand
, vfyCtx
.cspHand
, certData
,
461 TIC_CopyData
, vfyCtx
.verifyTime
);
464 tpOcspDebug("tpVerifyOcspResp: BAD signerCert[%u]", dex
);
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
);
474 if((signerInfo
== NULL
) && (issuer
!= NULL
)) {
476 * Haven't found it yet, try the actual issuer
478 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
480 OCT_Issuer
, issuer
, NULL
);
483 ourRtn
= ORS_Unknown
;
484 cssmErr
= CSSMERR_APPLETP_OCSP_SIG_ERROR
;
490 tpOcspDebug("tpVerifyOcspResp: signer := issuer");
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!");
502 tpOcspDebug("tpVerifyOcspResp: no signer found");
503 ourRtn
= ORS_Unknown
;
504 /* caller adds to per-cert status */
505 cssmErr
= CSSMERR_APPLETP_OCSP_NO_SIGNER
;
510 if(signerInfo
!= NULL
&& !foundLocalResponder
) {
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)
519 tpOcspDebug("tpVerifyOcspResp SUCCESS");
525 * Last remaining task is to verify the signer, and all the certs back to
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
539 vfyCtx
.numAnchorCerts
,
541 certsToBeFreed
, // local to-be-freed right now
542 &gatheredCerts
, // accumulate gathered certs here
543 CSSM_FALSE
, // subjectIsInGroup
548 kSecTrustSettingsKeyUseSignRevocation
,
551 verifiedViaTrustSetting
);
553 tpOcspDebug("tpVerifyOcspResp buildCertGroup failure");
555 ourRtn
= ORS_Unknown
;
559 if(!verifiedToAnchor
&& !verifiedViaTrustSetting
) {
561 ourRtn
= ORS_Unknown
;
563 /* verified to root which is not an anchor */
564 tpOcspDebug("tpVerifyOcspResp root, no anchor");
565 cssmErr
= CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT
;
568 /* partial chain, no root, not verifiable by anchor */
569 tpOcspDebug("tpVerifyOcspResp no root, no anchor");
570 cssmErr
= CSSMERR_APPLETP_OCSP_NOT_TRUSTED
;
572 if((issuer
!= NULL
) && !issuer
->isStatusFatal(cssmErr
)) {
573 tpOcspDebug("...ignoring last error per trust setting");
577 ourRtn
= ORS_Unknown
;
581 tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified");
585 /* FIXME policy verify? */
588 delete signerInfoTBD
;
589 /* any other cleanup? */