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>
37 #include <Security/SecCertificate.h>
41 * Is signerCert authorized to sign OCSP responses by issuerCert? IssuerCert is
42 * assumed to be (i.e., must, but we don't check that here) the signer of the
43 * cert being verified, which is not in the loop for this op. Just a bool returned;
44 * it's authorized or it's not.
46 static bool tpIsAuthorizedOcspSigner(
47 TPCertInfo
&issuerCert
, // issuer of cert being verified
48 TPCertInfo
&signerCert
) // potential signer of OCSP response
50 CSSM_DATA_PTR fieldValue
= NULL
; // mallocd by CL
53 CE_ExtendedKeyUsage
*eku
= NULL
;
54 bool foundEku
= false;
57 * First see if issuerCert issued signerCert (No signature vfy yet, just
58 * subject/issuer check).
60 if(!issuerCert
.isIssuerOf(signerCert
)) {
62 SecCertificateRef issuerRef
= NULL
;
63 SecCertificateRef signerRef
= NULL
;
64 const CSSM_DATA
*issuerData
= issuerCert
.itemData();
65 const CSSM_DATA
*signerData
= signerCert
.itemData();
66 crtn
= SecCertificateCreateFromData(issuerData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, &issuerRef
);
67 crtn
= SecCertificateCreateFromData(signerData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, &signerRef
);
68 CFStringRef issuerName
= SecCertificateCopySubjectSummary(issuerRef
);
69 CFStringRef signerName
= SecCertificateCopySubjectSummary(signerRef
);
71 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(issuerName
), kCFStringEncodingUTF8
) + 1;
72 char* buf
= (char*) malloc(maxLength
);
74 if (CFStringGetCString(issuerName
, buf
, (CFIndex
)maxLength
, kCFStringEncodingUTF8
)) {
75 tpOcspDebug("tpIsAuthorizedOcspSigner: issuerCert \"%s\"", buf
);
79 CFRelease(issuerName
);
82 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(signerName
), kCFStringEncodingUTF8
) + 1;
83 char* buf
= (char*) malloc(maxLength
);
85 if (CFStringGetCString(signerName
, buf
, (CFIndex
)maxLength
, kCFStringEncodingUTF8
)) {
86 tpOcspDebug("tpIsAuthorizedOcspSigner: signerCert \"%s\"", buf
);
90 CFRelease(signerName
);
99 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is not issued by issuerCert");
103 /* Fetch ExtendedKeyUse field from signerCert */
104 crtn
= signerCert
.fetchField(&CSSMOID_ExtendedKeyUsage
, &fieldValue
);
106 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU");
109 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
110 if(cssmExt
->format
!= CSSM_X509_DATAFORMAT_PARSED
) {
111 tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format");
114 eku
= (CE_ExtendedKeyUsage
*)cssmExt
->value
.parsedValue
;
116 /* Look for OID_KP_OCSPSigning */
117 for(unsigned dex
=0; dex
<eku
->numPurposes
; dex
++) {
118 if(tpCompareCssmData(&eku
->purposes
[dex
], &CSSMOID_OCSPSigning
)) {
124 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no OCSP "
130 * OK, signerCert is authorized by *someone* to sign OCSP requests, and
131 * it claims to be issued by issuer. Sig verify to be sure.
132 * FIXME this is not handling partial public keys, which would be a colossal
133 * mess to handle in this module...so we don't.
135 crtn
= signerCert
.verifyWithIssuer(&issuerCert
, NULL
);
136 if(crtn
== CSSM_OK
) {
137 tpOcspDebug("tpIsAuthorizedOcspSigner: FOUND authorized signer");
141 /* This is a highly irregular situation... */
142 tpOcspDebug("tpIsAuthorizedOcspSigner: signer sig verify FAIL");
145 if(fieldValue
!= NULL
) {
146 signerCert
.freeField(&CSSMOID_ExtendedKeyUsage
, fieldValue
);
152 * Check ResponderID linkage between an OCSPResponse and a cert we believe to
153 * be the issuer of both that response and the cert being verified. Returns
157 bool tpOcspResponderIDCheck(
158 OCSPResponse
&ocspResp
,
161 bool shouldBeSigner
= false;
162 if(ocspResp
.responderIDTag() == RIT_Name
) {
164 * Name inside response must == signer's SubjectName.
165 * Note we can't use signer.subjectName(); that's normalized.
168 const CSSM_DATA
*respIdName
= ocspResp
.encResponderName();
169 CSSM_DATA
*subjectName
= NULL
;
170 CSSM_RETURN crtn
= signer
.fetchField(&CSSMOID_X509V1SubjectNameStd
,
174 tpOcspDebug("tpOcspResponderIDCheck: error on fetchField(subjectName");
177 if(tpCompareCssmData(respIdName
, subjectName
)) {
178 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byName");
179 shouldBeSigner
= true;
182 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byName");
184 signer
.freeField(&CSSMOID_X509V1SubjectNameStd
, subjectName
);
187 /* ResponderID.byKey must == SHA1(signer's public key) */
188 const CSSM_KEY_PTR pubKey
= signer
.pubKey();
189 assert(pubKey
!= NULL
);
190 uint8 digest
[CC_SHA1_DIGEST_LENGTH
];
191 CSSM_DATA keyHash
= {CC_SHA1_DIGEST_LENGTH
, digest
};
192 CSSM_DATA pubKeyBytes
= {0, NULL
};
193 ocspdGetPublicKeyBytes(NULL
, pubKey
, pubKeyBytes
);
194 ocspdSha1(pubKeyBytes
.Data
, (CC_LONG
)pubKeyBytes
.Length
, digest
);
195 const CSSM_DATA
*respKeyHash
= &ocspResp
.responderID().byKey
;
196 if(tpCompareCssmData(&keyHash
, respKeyHash
)) {
197 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byKey");
198 shouldBeSigner
= true;
201 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byKey");
204 return shouldBeSigner
;
208 * Verify the signature of an OCSP response. Caller is responsible for all other
209 * verification of the response, this is just the crypto.
210 * Returns true on success.
212 static bool tpOcspResponseSigVerify(
213 TPVerifyContext
&vfyCtx
,
214 OCSPResponse
&ocspResp
, // parsed response
217 /* get signature algorithm in CSSM form from the response */
218 const SecAsn1OCSPBasicResponse
&basicResp
= ocspResp
.basicResponse();
219 const CSSM_OID
*algOid
= &basicResp
.algId
.algorithm
;
220 CSSM_ALGORITHMS sigAlg
;
222 if(!cssmOidToAlg(algOid
, &sigAlg
)) {
223 tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm");
226 /* signer's public key from the cert */
227 const CSSM_KEY
*pubKey
= signer
.pubKey();
229 /* signature: on decode, length is in BITS */
230 CSSM_DATA sig
= basicResp
.sig
;
234 CSSM_CC_HANDLE sigHand
;
236 crtn
= CSSM_CSP_CreateSignatureContext(vfyCtx
.cspHand
, sigAlg
, NULL
,
240 cssmPerror("tpOcspResponseSigVerify, CSSM_CSP_CreateSignatureContext", crtn
);
244 crtn
= CSSM_VerifyData(sigHand
, &basicResp
.tbsResponseData
, 1,
245 CSSM_ALGID_NONE
, &sig
);
248 cssmPerror("tpOcspResponseSigVerify, CSSM_VerifyData", crtn
);
254 CSSM_DeleteContext(sigHand
);
258 /* possible return from tpIsOcspIssuer() */
260 OIS_No
, // not the issuer
261 OIS_Good
, // is the issuer and signature matches
262 OIS_BadSig
, // appears to be issuer, but signature doesn't match
265 /* type of rawCert passed to tpIsOcspIssuer */
267 OCT_Local
, // LocalResponder - no checking other than signature
268 OCT_Issuer
, // it's the issuer of the cert being verified
269 OCT_Provided
, // came with response, provenance unknown
273 * Did specified cert issue the OCSP response?
275 * This implements the algorithm described in RFC2560, section 4.2.2.2,
276 * "Authorized Responders". It sees if the cert could be the issuer of the
277 * OCSP response per that algorithm; then if it could, it performs signature
280 static OcspIssuerStatus
tpIsOcspIssuer(
281 TPVerifyContext
&vfyCtx
,
282 OCSPResponse
&ocspResp
, // parsed response
283 /* on input specify at least one of the following two */
284 const CSSM_DATA
*signerData
,
286 OcspCertType certType
, // where rawCert came from
287 TPCertInfo
*issuer
, // OPTIONAL, if known
288 TPCertInfo
**signerRtn
) // optionally RETURNED if at all possible
290 assert((signerData
!= NULL
) || (signer
!= NULL
));
292 /* get signer as TPCertInfo if caller hasn't provided */
293 TPCertInfo
*tmpSigner
= NULL
;
296 tmpSigner
= new TPCertInfo(vfyCtx
.clHand
, vfyCtx
.cspHand
, signerData
,
297 TIC_CopyData
, vfyCtx
.verifyTime
);
300 tpOcspDebug("tpIsOcspIssuer: bad cert");
308 if(signerRtn
!= NULL
) {
313 * Qualification of "this can be the signer" depends on where the
316 bool shouldBeSigner
= false;
317 OcspIssuerStatus ourRtn
= OIS_No
;
320 case OCT_Local
: // caller trusts this and thinks it's the signer
321 shouldBeSigner
= true;
323 case OCT_Issuer
: // last resort, the actual issuer
324 /* check ResponderID linkage */
325 shouldBeSigner
= tpOcspResponderIDCheck(ocspResp
, *signer
);
330 * This cert came with the response.
334 * careful, might not know the issuer...how would this path ever
335 * work then? I don't think it needs to because you can NOT
336 * do OCSP on a cert without its issuer in hand.
341 /* check EKU linkage */
342 shouldBeSigner
= tpIsAuthorizedOcspSigner(*issuer
, *signer
);
346 if(!shouldBeSigner
) {
350 /* verify the signature */
351 if(tpOcspResponseSigVerify(vfyCtx
, ocspResp
, *signer
)) {
356 if((signerRtn
== NULL
) && (tmpSigner
!= NULL
)) {
363 OcspRespStatus
tpVerifyOcspResp(
364 TPVerifyContext
&vfyCtx
,
366 TPCertInfo
*issuer
, // issuer of the related cert, may be issuer of
367 // reply, may not be known
368 OCSPResponse
&ocspResp
,
369 CSSM_RETURN
&cssmErr
) // possible per-cert error
371 OcspRespStatus ourRtn
= ORS_Unknown
;
373 char *ocspResp_genTime
= NULL
;
374 char *ocspResp_cssmTime
= NULL
;
375 CSSM_TIMESTRING cssmTimeStr
= NULL
;
377 tpOcspDebug("tpVerifyOcspResp top");
379 switch(ocspResp
.responseStatus()) {
383 case RS_MalformedRequest
:
384 crtn
= CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ
;
386 case RS_InternalError
:
387 crtn
= CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR
;
390 crtn
= CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
;
393 crtn
= CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED
;
395 case RS_Unauthorized
:
396 crtn
= CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED
;
399 crtn
= CSSMERR_APPLETP_OCSP_BAD_RESPONSE
;
403 tpOcspDebug("tpVerifyOcspResp aborting due to response status %d",
404 (int)(ocspResp
.responseStatus()));
410 /* one of our main jobs is to locate the signer of the response, here */
411 TPCertInfo
*signerInfo
= NULL
;
412 TPCertInfo
*signerInfoTBD
= NULL
; // if non NULL at end, we delete
413 /* we'll be verifying into this cert group */
414 TPCertGroup
ocspCerts(vfyCtx
.alloc
, TGO_Caller
);
415 CSSM_BOOL verifiedToRoot
;
416 CSSM_BOOL verifiedToAnchor
;
417 CSSM_BOOL verifiedViaTrustSetting
;
419 const CSSM_APPLE_TP_OCSP_OPTIONS
*ocspOpts
= vfyCtx
.ocspOpts
;
420 OcspIssuerStatus issuerStat
;
422 /* determine verification time for signer */
423 ocspResp_cssmTime
= (char *)malloc(CSSM_TIME_STRLEN
+ 1);
424 ocspResp_genTime
= (char *)malloc(GENERAL_TIME_STRLEN
+ 1);
425 if (ocspResp_cssmTime
&& ocspResp_genTime
) {
426 cssmTimeStr
= vfyCtx
.verifyTime
; // store old verify time for other ctx users
427 cfAbsTimeToGgenTime(ocspResp
.producedAt(), ocspResp_genTime
);
428 tpTimeToCssmTimestring(ocspResp_genTime
,GENERAL_TIME_STRLEN
,ocspResp_cssmTime
);
429 vfyCtx
.verifyTime
= ocspResp_cssmTime
;
433 * Set true if we ever find an apparent issuer which does not correctly
434 * pass signature verify. If true and we never success, that's a XXX error.
436 bool foundBadIssuer
= false;
437 bool foundLocalResponder
= false;
438 uint32 numSignerCerts
= ocspResp
.numSignerCerts();
441 * This cert group, allocated by AppleTPSession::CertGroupVerify(),
442 * serves two functions here:
444 * -- it accumulates certs we get from the net (as parts of OCSP responses)
445 * for user in verifying OCSPResponse-related certs.
446 * TPCertGroup::buildCertGroup() uses this group as one of the many
447 * sources of certs when building a cert chain.
449 * -- it provides a container into which to stash TPCertInfos which
450 * persist at least as long as the TPVerifyContext; it's of type TGO_Group,
451 * so all of the certs added to it get freed when the group does.
453 assert(vfyCtx
.signerCerts
!= NULL
);
455 TPCertGroup
&gatheredCerts
= vfyCtx
.gatheredCerts
;
457 /* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */
458 TPCertGroup
certsToBeFreed(vfyCtx
.alloc
, TGO_Group
);
461 * First job is to find the cert which signed this response.
462 * Give priority to caller's LocalResponderCert.
464 if((ocspOpts
!= NULL
) && (ocspOpts
->LocalResponderCert
!= NULL
)) {
465 TPCertInfo
*responderInfo
= NULL
;
466 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
467 ocspOpts
->LocalResponderCert
, NULL
,
468 OCT_Local
, issuer
, &responderInfo
);
471 foundBadIssuer
= true;
474 if(responderInfo
!= NULL
) {
475 /* can't use it - should this be an immediate error? */
476 delete responderInfo
;
480 assert(responderInfo
!= NULL
);
481 signerInfo
= signerInfoTBD
= responderInfo
;
482 foundLocalResponder
= true;
483 tpOcspDebug("tpVerifyOcspResp: signer := LocalResponderCert");
488 if((signerInfo
== NULL
) && (numSignerCerts
!= 0)) {
490 * App did not specify a local responder (or provided a bad one)
491 * and the response came with some certs. Try those.
493 TPCertInfo
*respCert
= NULL
;
494 for(unsigned dex
=0; dex
<numSignerCerts
; dex
++) {
495 const CSSM_DATA
*certData
= ocspResp
.signerCert(dex
);
496 if(signerInfo
== NULL
) {
497 /* stop trying this after we succeed... */
498 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
500 OCT_Provided
, issuer
, &respCert
);
505 assert(respCert
!= NULL
);
506 signerInfo
= signerInfoTBD
= respCert
;
507 tpOcspDebug("tpVerifyOcspResp: signer := signerCert[%u]", dex
);
510 foundBadIssuer
= true;
516 * At least add this cert to certGroup for verification.
517 * OcspCert will own the TPCertInfo.
520 respCert
= new TPCertInfo(vfyCtx
.clHand
, vfyCtx
.cspHand
, certData
,
521 TIC_CopyData
, vfyCtx
.verifyTime
);
524 tpOcspDebug("tpVerifyOcspResp: BAD signerCert[%u]", dex
);
527 /* if we got a TPCertInfo, and it's not the signer, add it to certGroup */
528 if((respCert
!= NULL
) && (respCert
!= signerInfo
)) {
529 gatheredCerts
.appendCert(respCert
);
534 if((signerInfo
== NULL
) && (issuer
!= NULL
)) {
536 * Haven't found it yet, try the actual issuer
538 issuerStat
= tpIsOcspIssuer(vfyCtx
, ocspResp
,
540 OCT_Issuer
, issuer
, NULL
);
543 ourRtn
= ORS_Unknown
;
544 cssmErr
= CSSMERR_APPLETP_OCSP_SIG_ERROR
;
550 tpOcspDebug("tpVerifyOcspResp: signer := issuer");
555 if(signerInfo
== NULL
) {
556 if((issuer
!= NULL
) && !issuer
->isStatusFatal(CSSMERR_APPLETP_OCSP_NO_SIGNER
)) {
557 /* user wants to proceed without verifying! */
558 tpOcspDebug("tpVerifyOcspResp: no signer found, user allows!");
562 tpOcspDebug("tpVerifyOcspResp: no signer found");
563 ourRtn
= ORS_Unknown
;
564 /* caller adds to per-cert status */
565 cssmErr
= CSSMERR_APPLETP_OCSP_NO_SIGNER
;
570 if(signerInfo
!= NULL
&& !foundLocalResponder
) {
572 * tpIsOcspIssuer has verified that signerInfo is the signer of the
573 * OCSP response, and that it is either the issuer of the cert being
574 * checked or is a valid authorized responder for that issuer based on
575 * key id linkage and EKU. There is no stipulation in RFC2560 to also
576 * build the chain back to a trusted anchor; however, we'll continue to
577 * enforce this for the local responder case. (10742723)
579 /* check that the cert we found is temporally valid */
580 if (signerInfo
->isExpired() || signerInfo
->isNotValidYet()) {
581 tpOcspDebug("tpVerifyOcspResp ocspSigner expired or not yet valid");
582 ourRtn
= ORS_Unknown
;
583 cssmErr
= CSSMERR_APPLETP_OCSP_NO_SIGNER
;
587 tpOcspDebug("tpVerifyOcspResp SUCCESS");
594 * Last remaining task is to verify the signer, and all the certs back to
598 /* start from scratch with both of these groups */
599 gatheredCerts
.setAllUnused();
600 vfyCtx
.signerCerts
->setAllUnused();
601 crtn
= ocspCerts
.buildCertGroup(
602 *signerInfo
, // subject item
603 vfyCtx
.signerCerts
, // inCertGroup the original group-to-be-verified
604 vfyCtx
.dbList
, // optional
608 vfyCtx
.numAnchorCerts
,
610 certsToBeFreed
, // local to-be-freed right now
611 &gatheredCerts
, // accumulate gathered certs here
612 CSSM_FALSE
, // subjectIsInGroup
617 kSecTrustSettingsKeyUseSignRevocation
,
620 verifiedViaTrustSetting
);
622 tpOcspDebug("tpVerifyOcspResp buildCertGroup failure");
624 ourRtn
= ORS_Unknown
;
628 /* Verify temporal validity of local OCSP signer chain */
629 crtn
= ocspCerts
.getReturnCode(crtn
, NULL
, vfyCtx
.actionFlags
);
630 if ((crtn
== CSSMERR_TP_CERT_EXPIRED
) || (crtn
== CSSMERR_TP_CERT_NOT_VALID_YET
)) {
631 tpOcspDebug("tpVerifyOcspResp ocspSigner expired or not yet valid");
632 ourRtn
= ORS_Unknown
;
633 cssmErr
= CSSMERR_APPLETP_OCSP_NO_SIGNER
;
637 if(!verifiedToAnchor
&& !verifiedViaTrustSetting
) {
639 ourRtn
= ORS_Unknown
;
641 /* verified to root which is not an anchor */
642 tpOcspDebug("tpVerifyOcspResp root, no anchor");
643 cssmErr
= CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT
;
646 /* partial chain, no root, not verifiable by anchor */
647 tpOcspDebug("tpVerifyOcspResp no root, no anchor");
648 cssmErr
= CSSMERR_APPLETP_OCSP_NOT_TRUSTED
;
650 if((issuer
!= NULL
) && !issuer
->isStatusFatal(cssmErr
)) {
651 tpOcspDebug("...ignoring last error per trust setting");
655 ourRtn
= ORS_Unknown
;
659 tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified");
663 /* FIXME policy verify? */
666 delete signerInfoTBD
;
667 if (ocspResp_genTime
&& ocspResp_cssmTime
) vfyCtx
.verifyTime
= cssmTimeStr
;
668 if (ocspResp_genTime
) free(ocspResp_genTime
);
669 if (ocspResp_cssmTime
) free(ocspResp_cssmTime
);
670 /* any other cleanup? */