2 * Copyright (c) 2004,2011-2012,2014 Apple 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 #include <Security/SecCertificate.h>
40 * Is signerCert authorized to sign OCSP responses by issuerCert? IssuerCert is
41 * assumed to be (i.e., must, but we don't check that here) the signer of the
42 * cert being verified, which is not in the loop for this op. Just a bool returned;
43 * it's authorized or it's not.
45 static bool tpIsAuthorizedOcspSigner(
46 TPCertInfo
&issuerCert
, // issuer of cert being verified
47 TPCertInfo
&signerCert
) // potential signer of OCSP response
49 CSSM_DATA_PTR fieldValue
= NULL
; // mallocd by CL
52 CE_ExtendedKeyUsage
*eku
= NULL
;
53 bool foundEku
= false;
56 * First see if issuerCert issued signerCert (No signature vfy yet, just
57 * subject/issuer check).
59 if(!issuerCert
.isIssuerOf(signerCert
)) {
61 SecCertificateRef issuerRef
= NULL
;
62 SecCertificateRef signerRef
= NULL
;
63 const CSSM_DATA
*issuerData
= issuerCert
.itemData();
64 const CSSM_DATA
*signerData
= signerCert
.itemData();
65 crtn
= SecCertificateCreateFromData(issuerData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, &issuerRef
);
66 crtn
= SecCertificateCreateFromData(signerData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, &signerRef
);
67 CFStringRef issuerName
= SecCertificateCopySubjectSummary(issuerRef
);
68 CFStringRef signerName
= SecCertificateCopySubjectSummary(signerRef
);
70 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(issuerName
), kCFStringEncodingUTF8
) + 1;
71 char* buf
= (char*) malloc(maxLength
);
73 if (CFStringGetCString(issuerName
, buf
, (CFIndex
)maxLength
, kCFStringEncodingUTF8
)) {
74 tpOcspDebug("tpIsAuthorizedOcspSigner: issuerCert \"%s\"", buf
);
78 CFRelease(issuerName
);
81 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(signerName
), kCFStringEncodingUTF8
) + 1;
82 char* buf
= (char*) malloc(maxLength
);
84 if (CFStringGetCString(signerName
, buf
, (CFIndex
)maxLength
, kCFStringEncodingUTF8
)) {
85 tpOcspDebug("tpIsAuthorizedOcspSigner: signerCert \"%s\"", buf
);
89 CFRelease(signerName
);
98 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is not issued by issuerCert");
102 /* Fetch ExtendedKeyUse field from signerCert */
103 crtn
= signerCert
.fetchField(&CSSMOID_ExtendedKeyUsage
, &fieldValue
);
105 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU");
108 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
109 if(cssmExt
->format
!= CSSM_X509_DATAFORMAT_PARSED
) {
110 tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format");
113 eku
= (CE_ExtendedKeyUsage
*)cssmExt
->value
.parsedValue
;
115 /* Look for OID_KP_OCSPSigning */
116 for(unsigned dex
=0; dex
<eku
->numPurposes
; dex
++) {
117 if(tpCompareCssmData(&eku
->purposes
[dex
], &CSSMOID_OCSPSigning
)) {
123 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no OCSP "
129 * OK, signerCert is authorized by *someone* to sign OCSP requests, and
130 * it claims to be issued by issuer. Sig verify to be sure.
131 * FIXME this is not handling partial public keys, which would be a colossal
132 * mess to handle in this module...so we don't.
134 crtn
= signerCert
.verifyWithIssuer(&issuerCert
, NULL
);
135 if(crtn
== CSSM_OK
) {
136 tpOcspDebug("tpIsAuthorizedOcspSigner: FOUND authorized signer");
140 /* This is a highly irregular situation... */
141 tpOcspDebug("tpIsAuthorizedOcspSigner: signer sig verify FAIL");
144 if(fieldValue
!= NULL
) {
145 signerCert
.freeField(&CSSMOID_ExtendedKeyUsage
, fieldValue
);
151 * Check ResponderID linkage between an OCSPResponse and a cert we believe to
152 * be the issuer of both that response and the cert being verified. Returns
156 bool tpOcspResponderIDCheck(
157 OCSPResponse
&ocspResp
,
160 bool shouldBeSigner
= false;
161 if(ocspResp
.responderIDTag() == RIT_Name
) {
163 * Name inside response must == signer's SubjectName.
164 * Note we can't use signer.subjectName(); that's normalized.
167 const CSSM_DATA
*respIdName
= ocspResp
.encResponderName();
168 CSSM_DATA
*subjectName
= NULL
;
169 CSSM_RETURN crtn
= signer
.fetchField(&CSSMOID_X509V1SubjectNameStd
,
173 tpOcspDebug("tpOcspResponderIDCheck: error on fetchField(subjectName");
176 if(tpCompareCssmData(respIdName
, subjectName
)) {
177 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byName");
178 shouldBeSigner
= true;
181 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byName");
183 signer
.freeField(&CSSMOID_X509V1SubjectNameStd
, subjectName
);
186 /* ResponderID.byKey must == SHA1(signer's public key) */
187 const CSSM_KEY_PTR pubKey
= signer
.pubKey();
188 assert(pubKey
!= NULL
);
189 uint8 digest
[CC_SHA1_DIGEST_LENGTH
];
190 CSSM_DATA keyHash
= {CC_SHA1_DIGEST_LENGTH
, digest
};
191 CSSM_DATA pubKeyBytes
= {0, NULL
};
192 ocspdGetPublicKeyBytes(NULL
, pubKey
, pubKeyBytes
);
193 ocspdSha1(pubKeyBytes
.Data
, (CC_LONG
)pubKeyBytes
.Length
, digest
);
194 const CSSM_DATA
*respKeyHash
= &ocspResp
.responderID().byKey
;
195 if(tpCompareCssmData(&keyHash
, respKeyHash
)) {
196 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byKey");
197 shouldBeSigner
= true;
200 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byKey");
203 return shouldBeSigner
;
207 * Verify the signature of an OCSP response. Caller is responsible for all other
208 * verification of the response, this is just the crypto.
209 * Returns true on success.
211 static bool tpOcspResponseSigVerify(
212 TPVerifyContext
&vfyCtx
,
213 OCSPResponse
&ocspResp
, // parsed response
216 /* get signature algorithm in CSSM form from the response */
217 const SecAsn1OCSPBasicResponse
&basicResp
= ocspResp
.basicResponse();
218 const CSSM_OID
*algOid
= &basicResp
.algId
.algorithm
;
219 CSSM_ALGORITHMS sigAlg
;
221 if(!cssmOidToAlg(algOid
, &sigAlg
)) {
222 tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm");
225 /* signer's public key from the cert */
226 const CSSM_KEY
*pubKey
= signer
.pubKey();
228 /* signature: on decode, length is in BITS */
229 CSSM_DATA sig
= basicResp
.sig
;
233 CSSM_CC_HANDLE sigHand
;
235 crtn
= CSSM_CSP_CreateSignatureContext(vfyCtx
.cspHand
, sigAlg
, NULL
,
239 cssmPerror("tpOcspResponseSigVerify, CSSM_CSP_CreateSignatureContext", crtn
);
243 crtn
= CSSM_VerifyData(sigHand
, &basicResp
.tbsResponseData
, 1,
244 CSSM_ALGID_NONE
, &sig
);
247 cssmPerror("tpOcspResponseSigVerify, CSSM_VerifyData", crtn
);
253 CSSM_DeleteContext(sigHand
);
257 /* possible return from tpIsOcspIssuer() */
259 OIS_No
, // not the issuer
260 OIS_Good
, // is the issuer and signature matches
261 OIS_BadSig
, // appears to be issuer, but signature doesn't match
264 /* type of rawCert passed to tpIsOcspIssuer */
266 OCT_Local
, // LocalResponder - no checking other than signature
267 OCT_Issuer
, // it's the issuer of the cert being verified
268 OCT_Provided
, // came with response, provenance unknown
272 * Did specified cert issue the OCSP response?
274 * This implements the algorithm described in RFC2560, section 4.2.2.2,
275 * "Authorized Responders". It sees if the cert could be the issuer of the
276 * OCSP response per that algorithm; then if it could, it performs signature
279 static OcspIssuerStatus
tpIsOcspIssuer(
280 TPVerifyContext
&vfyCtx
,
281 OCSPResponse
&ocspResp
, // parsed response
282 /* on input specify at least one of the following two */
283 const CSSM_DATA
*signerData
,
285 OcspCertType certType
, // where rawCert came from
286 TPCertInfo
*issuer
, // OPTIONAL, if known
287 TPCertInfo
**signerRtn
) // optionally RETURNED if at all possible
289 assert((signerData
!= NULL
) || (signer
!= NULL
));
291 /* get signer as TPCertInfo if caller hasn't provided */
292 TPCertInfo
*tmpSigner
= NULL
;
295 tmpSigner
= new TPCertInfo(vfyCtx
.clHand
, vfyCtx
.cspHand
, signerData
,
296 TIC_CopyData
, vfyCtx
.verifyTime
);
299 tpOcspDebug("tpIsOcspIssuer: bad cert");
307 if(signerRtn
!= NULL
) {
312 * Qualification of "this can be the signer" depends on where the
315 bool shouldBeSigner
= false;
316 OcspIssuerStatus ourRtn
= OIS_No
;
319 case OCT_Local
: // caller trusts this and thinks it's the signer
320 shouldBeSigner
= true;
322 case OCT_Issuer
: // last resort, the actual issuer
323 /* check ResponderID linkage */
324 shouldBeSigner
= tpOcspResponderIDCheck(ocspResp
, *signer
);
329 * This cert came with the response.
333 * careful, might not know the issuer...how would this path ever
334 * work then? I don't think it needs to because you can NOT
335 * do OCSP on a cert without its issuer in hand.
340 /* check EKU linkage */
341 shouldBeSigner
= tpIsAuthorizedOcspSigner(*issuer
, *signer
);
345 if(!shouldBeSigner
) {
349 /* verify the signature */
350 if(tpOcspResponseSigVerify(vfyCtx
, ocspResp
, *signer
)) {
355 if((signerRtn
== NULL
) && (tmpSigner
!= NULL
)) {
362 OcspRespStatus
tpVerifyOcspResp(
363 TPVerifyContext
&vfyCtx
,
365 TPCertInfo
*issuer
, // issuer of the related cert, may be issuer of
366 // reply, may not be known
367 OCSPResponse
&ocspResp
,
368 CSSM_RETURN
&cssmErr
) // possible per-cert error
370 OcspRespStatus ourRtn
= ORS_Unknown
;
373 tpOcspDebug("tpVerifyOcspResp top");
375 switch(ocspResp
.responseStatus()) {
379 case RS_MalformedRequest
:
380 crtn
= CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ
;
382 case RS_InternalError
:
383 crtn
= CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR
;
386 crtn
= CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
;
389 crtn
= CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED
;
391 case RS_Unauthorized
:
392 crtn
= CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED
;
395 crtn
= CSSMERR_APPLETP_OCSP_BAD_RESPONSE
;
399 tpOcspDebug("tpVerifyOcspResp aborting due to response status %d",
400 (int)(ocspResp
.responseStatus()));
406 /* one of our main jobs is to locate the signer of the response, here */
407 TPCertInfo
*signerInfo
= NULL
;
408 TPCertInfo
*signerInfoTBD
= NULL
; // if non NULL at end, we delete
409 /* we'll be verifying into this cert group */
410 TPCertGroup
ocspCerts(vfyCtx
.alloc
, TGO_Caller
);
411 CSSM_BOOL verifiedToRoot
;
412 CSSM_BOOL verifiedToAnchor
;
413 CSSM_BOOL verifiedViaTrustSetting
;
415 const CSSM_APPLE_TP_OCSP_OPTIONS
*ocspOpts
= vfyCtx
.ocspOpts
;
416 OcspIssuerStatus issuerStat
;
419 * Set true if we ever find an apparent issuer which does not correctly
420 * pass signature verify. If true and we never success, that's a XXX error.
422 bool foundBadIssuer
= false;
423 bool foundLocalResponder
= false;
424 uint32 numSignerCerts
= ocspResp
.numSignerCerts();
427 * This cert group, allocated by AppleTPSession::CertGroupVerify(),
428 * serves two functions here:
430 * -- it accumulates certs we get from the net (as parts of OCSP responses)
431 * for user in verifying OCSPResponse-related certs.
432 * TPCertGroup::buildCertGroup() uses this group as one of the many
433 * sources of certs when building a cert chain.
435 * -- it provides a container into which to stash TPCertInfos which
436 * persist at least as long as the TPVerifyContext; it's of type TGO_Group,
437 * so all of the certs added to it get freed when the group does.
439 assert(vfyCtx
.signerCerts
!= NULL
);
441 TPCertGroup
&gatheredCerts
= vfyCtx
.gatheredCerts
;
443 /* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */
444 TPCertGroup
certsToBeFreed(vfyCtx
.alloc
, TGO_Group
);
447 * First job is to find the cert which signed this response.
448 * Give priority to caller's LocalResponderCert.
450 if((ocspOpts
!= NULL
) && (ocspOpts
->LocalResponderCert
!= NULL
)) {
451 TPCertInfo
*responderInfo
= NULL
;
452 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
453 ocspOpts
->LocalResponderCert
, NULL
,
454 OCT_Local
, issuer
, &responderInfo
);
457 foundBadIssuer
= true;
460 if(responderInfo
!= NULL
) {
461 /* can't use it - should this be an immediate error? */
462 delete responderInfo
;
466 assert(responderInfo
!= NULL
);
467 signerInfo
= signerInfoTBD
= responderInfo
;
468 foundLocalResponder
= true;
469 tpOcspDebug("tpVerifyOcspResp: signer := LocalResponderCert");
474 if((signerInfo
== NULL
) && (numSignerCerts
!= 0)) {
476 * App did not specify a local responder (or provided a bad one)
477 * and the response came with some certs. Try those.
479 TPCertInfo
*respCert
= NULL
;
480 for(unsigned dex
=0; dex
<numSignerCerts
; dex
++) {
481 const CSSM_DATA
*certData
= ocspResp
.signerCert(dex
);
482 if(signerInfo
== NULL
) {
483 /* stop trying this after we succeed... */
484 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
486 OCT_Provided
, issuer
, &respCert
);
491 assert(respCert
!= NULL
);
492 signerInfo
= signerInfoTBD
= respCert
;
493 tpOcspDebug("tpVerifyOcspResp: signer := signerCert[%u]", dex
);
496 foundBadIssuer
= true;
502 * At least add this cert to certGroup for verification.
503 * OcspCert will own the TPCertInfo.
506 respCert
= new TPCertInfo(vfyCtx
.clHand
, vfyCtx
.cspHand
, certData
,
507 TIC_CopyData
, vfyCtx
.verifyTime
);
510 tpOcspDebug("tpVerifyOcspResp: BAD signerCert[%u]", dex
);
513 /* if we got a TPCertInfo, and it's not the signer, add it to certGroup */
514 if((respCert
!= NULL
) && (respCert
!= signerInfo
)) {
515 gatheredCerts
.appendCert(respCert
);
520 if((signerInfo
== NULL
) && (issuer
!= NULL
)) {
522 * Haven't found it yet, try the actual issuer
524 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
526 OCT_Issuer
, issuer
, NULL
);
529 ourRtn
= ORS_Unknown
;
530 cssmErr
= CSSMERR_APPLETP_OCSP_SIG_ERROR
;
536 tpOcspDebug("tpVerifyOcspResp: signer := issuer");
541 if(signerInfo
== NULL
) {
542 if((issuer
!= NULL
) && !issuer
->isStatusFatal(CSSMERR_APPLETP_OCSP_NO_SIGNER
)) {
543 /* user wants to proceed without verifying! */
544 tpOcspDebug("tpVerifyOcspResp: no signer found, user allows!");
548 tpOcspDebug("tpVerifyOcspResp: no signer found");
549 ourRtn
= ORS_Unknown
;
550 /* caller adds to per-cert status */
551 cssmErr
= CSSMERR_APPLETP_OCSP_NO_SIGNER
;
556 if(signerInfo
!= NULL
&& !foundLocalResponder
) {
558 * tpIsOcspIssuer has verified that signerInfo is the signer of the
559 * OCSP response, and that it is either the issuer of the cert being
560 * checked or is a valid authorized responder for that issuer based on
561 * key id linkage and EKU. There is no stipulation in RFC2560 to also
562 * build the chain back to a trusted anchor; however, we'll continue to
563 * enforce this for the local responder case. (10742723)
565 tpOcspDebug("tpVerifyOcspResp SUCCESS");
571 * Last remaining task is to verify the signer, and all the certs back to
575 /* start from scratch with both of these groups */
576 gatheredCerts
.setAllUnused();
577 vfyCtx
.signerCerts
->setAllUnused();
578 crtn
= ocspCerts
.buildCertGroup(
579 *signerInfo
, // subject item
580 vfyCtx
.signerCerts
, // inCertGroup the original group-to-be-verified
581 vfyCtx
.dbList
, // optional
585 vfyCtx
.numAnchorCerts
,
587 certsToBeFreed
, // local to-be-freed right now
588 &gatheredCerts
, // accumulate gathered certs here
589 CSSM_FALSE
, // subjectIsInGroup
594 kSecTrustSettingsKeyUseSignRevocation
,
597 verifiedViaTrustSetting
);
599 tpOcspDebug("tpVerifyOcspResp buildCertGroup failure");
601 ourRtn
= ORS_Unknown
;
605 if(!verifiedToAnchor
&& !verifiedViaTrustSetting
) {
607 ourRtn
= ORS_Unknown
;
609 /* verified to root which is not an anchor */
610 tpOcspDebug("tpVerifyOcspResp root, no anchor");
611 cssmErr
= CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT
;
614 /* partial chain, no root, not verifiable by anchor */
615 tpOcspDebug("tpVerifyOcspResp no root, no anchor");
616 cssmErr
= CSSMERR_APPLETP_OCSP_NOT_TRUSTED
;
618 if((issuer
!= NULL
) && !issuer
->isStatusFatal(cssmErr
)) {
619 tpOcspDebug("...ignoring last error per trust setting");
623 ourRtn
= ORS_Unknown
;
627 tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified");
631 /* FIXME policy verify? */
634 delete signerInfoTBD
;
635 /* any other cleanup? */