2 * Copyright (c) 2008-2009,2012-2016 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 * SecOCSPResponse.c - Wrapper to decode ocsp responses.
28 #include <securityd/SecOCSPResponse.h>
31 #include <AssertMacros.h>
32 #include <CommonCrypto/CommonDigest.h>
33 #include <Security/SecCertificateInternal.h>
34 #include <Security/SecFramework.h>
35 #include <Security/SecKeyPriv.h>
36 #include <security_asn1/SecAsn1Coder.h>
37 #include <security_asn1/SecAsn1Templates.h>
38 #include <security_asn1/ocspTemplates.h>
39 #include <security_asn1/oidsocsp.h>
41 #include "SecInternal.h"
42 #include <utilities/SecCFWrappers.h>
43 #include <utilities/SecSCTUtils.h>
46 #define ocspdErrorLog(args, ...) secerror(args, ## __VA_ARGS__)
47 #define ocspdHttpDebug(args...) secdebug("ocspdHttp", ## args)
48 #define ocspdDebug(args...) secdebug("ocsp", ## args)
52 OCSPResponse ::= SEQUENCE {
53 responseStatus OCSPResponseStatus,
54 responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
56 OCSPResponseStatus ::= ENUMERATED {
57 successful (0), --Response has valid confirmations
58 malformedRequest (1), --Illegal confirmation request
59 internalError (2), --Internal error in issuer
60 tryLater (3), --Try again later
62 sigRequired (5), --Must sign the request
63 unauthorized (6) --Request unauthorized
66 ResponseBytes ::= SEQUENCE {
67 responseType OBJECT IDENTIFIER,
68 response OCTET STRING }
70 id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
71 id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
73 The value for response SHALL be the DER encoding of
76 BasicOCSPResponse ::= SEQUENCE {
77 tbsResponseData ResponseData,
78 signatureAlgorithm AlgorithmIdentifier,
80 certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
82 The value for signature SHALL be computed on the hash of the DER
83 encoding ResponseData.
85 ResponseData ::= SEQUENCE {
86 version [0] EXPLICIT Version DEFAULT v1,
87 responderID ResponderID,
88 producedAt GeneralizedTime,
89 responses SEQUENCE OF SingleResponse,
90 responseExtensions [1] EXPLICIT Extensions OPTIONAL }
92 ResponderID ::= CHOICE {
96 KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
97 (excluding the tag and length fields)
99 SingleResponse ::= SEQUENCE {
101 certStatus CertStatus,
102 thisUpdate GeneralizedTime,
103 nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
104 singleExtensions [1] EXPLICIT Extensions OPTIONAL }
106 CertStatus ::= CHOICE {
107 good [0] IMPLICIT NULL,
108 revoked [1] IMPLICIT RevokedInfo,
109 unknown [2] IMPLICIT UnknownInfo }
111 RevokedInfo ::= SEQUENCE {
112 revocationTime GeneralizedTime,
113 revocationReason [0] EXPLICIT CRLReason OPTIONAL }
115 UnknownInfo ::= NULL -- this can be replaced with an enumeration
118 static CFAbsoluteTime
genTimeToCFAbsTime(const SecAsn1Item
*datetime
)
120 return SecAbsoluteTimeFromDateContent(SEC_ASN1_GENERALIZED_TIME
,
121 datetime
->Data
, datetime
->Length
);
124 void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef
this) {
125 CFReleaseSafe(this->scts
);
129 static SecOCSPSingleResponseRef
SecOCSPSingleResponseCreate(
130 SecAsn1OCSPSingleResponse
*resp
, SecAsn1CoderRef coder
) {
131 assert(resp
!= NULL
);
132 SecOCSPSingleResponseRef
this;
133 require(this = (SecOCSPSingleResponseRef
)
134 calloc(1, sizeof(struct __SecOCSPSingleResponse
)), errOut
);
135 this->certStatus
= CS_NotParsed
;
136 this->thisUpdate
= NULL_TIME
;
137 this->nextUpdate
= NULL_TIME
;
138 this->revokedTime
= NULL_TIME
;
139 this->crlReason
= kSecRevocationReasonUndetermined
;
142 if ((resp
->certStatus
.Data
== NULL
) || (resp
->certStatus
.Length
== 0)) {
143 ocspdErrorLog("OCSPSingleResponse: bad certStatus");
146 this->certStatus
= (SecAsn1OCSPCertStatusTag
)(resp
->certStatus
.Data
[0] & SEC_ASN1_TAGNUM_MASK
);
147 if (this->certStatus
== CS_Revoked
) {
148 /* Decode further to get SecAsn1OCSPRevokedInfo */
149 SecAsn1OCSPCertStatus certStatus
;
150 memset(&certStatus
, 0, sizeof(certStatus
));
151 if (SecAsn1DecodeData(coder
, &resp
->certStatus
,
152 kSecAsn1OCSPCertStatusRevokedTemplate
, &certStatus
)) {
153 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus");
156 SecAsn1OCSPRevokedInfo
*revokedInfo
= certStatus
.revokedInfo
;
157 if (revokedInfo
!= NULL
) {
158 /* Treat this as optional even for CS_Revoked */
159 this->revokedTime
= genTimeToCFAbsTime(&revokedInfo
->revocationTime
);
160 const SecAsn1Item
*revReason
= revokedInfo
->revocationReason
;
161 if((revReason
!= NULL
) &&
162 (revReason
->Data
!= NULL
) &&
163 (revReason
->Length
!= 0)) {
164 this->crlReason
= revReason
->Data
[0];
168 this->thisUpdate
= genTimeToCFAbsTime(&resp
->thisUpdate
);
169 if (this->thisUpdate
== NULL_TIME
) {
170 ocspdErrorLog("OCSPResponse: bad thisUpdate DER");
174 if (resp
->nextUpdate
!= NULL
) {
175 this->nextUpdate
= genTimeToCFAbsTime(resp
->nextUpdate
);
176 if (this->nextUpdate
== NULL_TIME
) {
177 ocspdErrorLog("OCSPResponse: bad nextUpdate DER");
182 /* Lookup through extensions to find SCTs */
183 if(resp
->singleExtensions
) {
184 ocspdErrorLog("OCSPResponse: single response has extension(s).");
186 NSS_CertExtension
*extn
;
187 while ((extn
= resp
->singleExtensions
[i
])) {
188 if(SecAsn1OidCompare(&extn
->extnId
, &OID_GOOGLE_OCSP_SCT
)) {
189 ocspdErrorLog("OCSPResponse: single response has an SCT extension.");
190 SecAsn1Item sct_data
= {0,};
192 // Note: if there are more that one valid SCT extension, we just use the first one that successfully decoded
193 if((this->scts
== NULL
) && (SecAsn1DecodeData(coder
, &extn
->value
, kSecAsn1OctetStringTemplate
, &sct_data
) == 0)) {
194 this->scts
= SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sct_data
.Data
, sct_data
.Length
);
195 ocspdErrorLog("OCSPResponse: single response has an SCT extension, parsed = %p.", this->scts
);
202 ocspdDebug("status %d reason %d", (int)this->certStatus
,
203 (int)this->crlReason
);
207 SecOCSPSingleResponseDestroy(this);
211 #define LEEWAY (4500.0)
213 /* Calculate temporal validity; set latestNextUpdate and expireTime.
214 Returns true if valid, else returns false. */
215 bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef
this,
216 CFTimeInterval maxAge
, CFTimeInterval defaultTTL
, CFAbsoluteTime verifyTime
)
219 this->latestNextUpdate
= NULL_TIME
;
220 CFStringRef hexResp
= CFDataCopyHexString(this->data
);
222 if (this->producedAt
> verifyTime
+ LEEWAY
) {
223 secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now");
227 /* Make this->latestNextUpdate be the date farthest in the future
228 of any of the singleResponses nextUpdate fields. */
229 SecAsn1OCSPSingleResponse
**responses
;
230 for (responses
= this->responseData
.responses
; *responses
; ++responses
) {
231 SecAsn1OCSPSingleResponse
*resp
= *responses
;
233 /* thisUpdate later than 'now' invalidates the whole response. */
234 CFAbsoluteTime thisUpdate
= genTimeToCFAbsTime(&resp
->thisUpdate
);
235 if (thisUpdate
> verifyTime
+ LEEWAY
) {
236 secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now");
240 /* Keep track of latest nextUpdate. */
241 if (resp
->nextUpdate
!= NULL
) {
242 CFAbsoluteTime nextUpdate
= genTimeToCFAbsTime(resp
->nextUpdate
);
243 if (nextUpdate
> this->latestNextUpdate
) {
244 this->latestNextUpdate
= nextUpdate
;
248 /* RFC 5019 section 2.2.4 states on nextUpdate:
249 Responders MUST always include this value to aid in
250 response caching. See Section 6 for additional
251 information on caching.
253 secnotice("ocsp", "OCSPResponse: nextUpdate not present");
254 #ifdef STRICT_RFC5019
260 /* Now that we have this->latestNextUpdate, we figure out the latest
261 date at which we will expire this response from our cache. To comply
264 6.1. Caching at the Client
266 To minimize bandwidth usage, clients MUST locally cache authoritative
267 OCSP responses (i.e., a response with a signature that has been
268 successfully validated and that indicate an OCSPResponseStatus of
271 Most OCSP clients will send OCSPRequests at or near the nextUpdate
272 time (when a cached response expires). To avoid large spikes in
273 responder load that might occur when many clients refresh cached
274 responses for a popular certificate, responders MAY indicate when the
275 client should fetch an updated OCSP response by using the cache-
276 control:max-age directive. Clients SHOULD fetch the updated OCSP
277 Response on or after the max-age time. To ensure that clients
278 receive an updated OCSP response, OCSP responders MUST refresh the
279 OCSP response before the max-age time.
283 we need to take the cache-control:max-age directive into account.
285 The way the code below is written we ignore a max-age=0 in the
286 http header. Since a value of 0 (NULL_TIME) also means there
287 was no max-age in the header. This seems ok since that would imply
288 no-cache so we also ignore negative values for the same reason,
289 instead we'll expire whenever this->latestNextUpdate tells us to,
290 which is the signed value if max-age is too low, since we don't
291 want to refetch multilple times for a single page load in a browser. */
292 if (this->latestNextUpdate
== NULL_TIME
) {
293 /* See comment above on RFC 5019 section 2.2.4. */
294 /* Absolute expire time = current time plus defaultTTL */
295 this->expireTime
= verifyTime
+ defaultTTL
;
296 } else if (this->latestNextUpdate
< verifyTime
- LEEWAY
) {
297 secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago");
299 } else if (maxAge
> 0) {
300 /* Beware of double overflows such as:
302 now + maxAge < this->latestNextUpdate
304 in the math below since an attacker could create any positive
306 if (maxAge
< this->latestNextUpdate
- verifyTime
) {
307 /* maxAge header wants us to expire the cache entry sooner than
308 nextUpdate would allow, to balance server load. */
309 this->expireTime
= verifyTime
+ maxAge
;
311 /* maxAge http header attempting to make us cache the response
312 longer than it's valid for, bad http header! Ignoring you. */
313 ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate,"
314 " using latestNextUpdate %@", hexResp
);
315 this->expireTime
= this->latestNextUpdate
;
318 /* No maxAge provided, just use latestNextUpdate. */
319 this->expireTime
= this->latestNextUpdate
;
324 CFReleaseSafe(hexResp
);
328 SecOCSPResponseRef
SecOCSPResponseCreateWithID(CFDataRef ocspResponse
, int64_t responseID
) {
329 CFStringRef hexResp
= CFDataCopyHexString(ocspResponse
);
330 SecAsn1OCSPResponse topResp
= {};
331 SecOCSPResponseRef
this;
333 require(this = (SecOCSPResponseRef
)calloc(1, sizeof(struct __SecOCSPResponse
)),
335 require_noerr(SecAsn1CoderCreate(&this->coder
), errOut
);
337 this->data
= ocspResponse
;
338 this->responseID
= responseID
;
339 CFRetain(ocspResponse
);
342 resp
.Length
= CFDataGetLength(ocspResponse
);
343 resp
.Data
= (uint8_t *)CFDataGetBytePtr(ocspResponse
);
344 if (SecAsn1DecodeData(this->coder
, &resp
, kSecAsn1OCSPResponseTemplate
,
346 ocspdErrorLog("OCSPResponse: decode failure at top level");
348 /* remainder is valid only on RS_Success */
349 if ((topResp
.responseStatus
.Data
== NULL
) ||
350 (topResp
.responseStatus
.Length
== 0)) {
351 ocspdErrorLog("OCSPResponse: no responseStatus");
354 this->responseStatus
= topResp
.responseStatus
.Data
[0];
355 if (this->responseStatus
!= kSecOCSPSuccess
) {
356 secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus
, hexResp
);
357 /* not a failure of our constructor; this object is now useful, but
358 * only for this one byte of status info */
361 if (topResp
.responseBytes
== NULL
) {
362 /* I don't see how this can be legal on RS_Success */
363 ocspdErrorLog("OCSPResponse: empty responseBytes");
366 if (!SecAsn1OidCompare(&topResp
.responseBytes
->responseType
,
367 &OID_PKIX_OCSP_BASIC
)) {
368 ocspdErrorLog("OCSPResponse: unknown responseType");
373 /* decode the SecAsn1OCSPBasicResponse */
374 if (SecAsn1DecodeData(this->coder
, &topResp
.responseBytes
->response
,
375 kSecAsn1OCSPBasicResponseTemplate
, &this->basicResponse
)) {
376 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse");
380 /* signature and cert evaluation done externally */
382 /* decode the SecAsn1OCSPResponseData */
383 if (SecAsn1DecodeData(this->coder
, &this->basicResponse
.tbsResponseData
,
384 kSecAsn1OCSPResponseDataTemplate
, &this->responseData
)) {
385 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData");
388 this->producedAt
= genTimeToCFAbsTime(&this->responseData
.producedAt
);
389 if (this->producedAt
== NULL_TIME
) {
390 ocspdErrorLog("OCSPResponse: bad producedAt");
394 if (this->responseData
.responderID
.Data
== NULL
) {
395 ocspdErrorLog("OCSPResponse: bad responderID");
399 /* Choice processing for ResponderID */
400 this->responderIdTag
= (SecAsn1OCSPResponderIDTag
)
401 (this->responseData
.responderID
.Data
[0] & SEC_ASN1_TAGNUM_MASK
);
402 const SecAsn1Template
*templ
;
403 switch(this->responderIdTag
) {
405 /* @@@ Since we don't use the decoded byName value we could skip
406 decoding it but we do it anyway for validation. */
407 templ
= kSecAsn1OCSPResponderIDAsNameTemplate
;
410 templ
= kSecAsn1OCSPResponderIDAsKeyTemplate
;
413 ocspdErrorLog("OCSPResponse: bad responderID tag");
416 if (SecAsn1DecodeData(this->coder
, &this->responseData
.responderID
, templ
,
417 &this->responderID
)) {
418 ocspdErrorLog("OCSPResponse: decode failure at responderID");
423 CFReleaseSafe(hexResp
);
426 secdebug("ocsp", "bad ocsp response: %@", hexResp
);
427 CFReleaseSafe(hexResp
);
429 SecOCSPResponseFinalize(this);
434 SecOCSPResponseRef
SecOCSPResponseCreate(CFDataRef
this) {
435 return SecOCSPResponseCreateWithID(this, -1);
438 int64_t SecOCSPResponseGetID(SecOCSPResponseRef
this) {
439 return this->responseID
;
442 CFDataRef
SecOCSPResponseGetData(SecOCSPResponseRef
this) {
446 SecOCSPResponseStatus
SecOCSPGetResponseStatus(SecOCSPResponseRef
this) {
447 return this->responseStatus
;
450 CFAbsoluteTime
SecOCSPResponseGetExpirationTime(SecOCSPResponseRef
this) {
451 return this->expireTime
;
454 CFDataRef
SecOCSPResponseGetNonce(SecOCSPResponseRef
this) {
458 CFAbsoluteTime
SecOCSPResponseProducedAt(SecOCSPResponseRef
this) {
459 return this->producedAt
;
462 CFArrayRef
SecOCSPResponseCopySigners(SecOCSPResponseRef
this) {
463 CFMutableArrayRef result
= NULL
;
464 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
469 for (certs
= this->basicResponse
.certs
; certs
&& *certs
; ++certs
) {
470 SecCertificateRef cert
= NULL
;
471 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, (*certs
)->Data
, (*certs
)->Length
);
473 CFArrayAppendValue(result
, cert
);
481 void SecOCSPResponseFinalize(SecOCSPResponseRef
this) {
482 CFReleaseSafe(this->data
);
483 CFReleaseSafe(this->nonce
);
484 SecAsn1CoderRelease(this->coder
);
488 static CFAbsoluteTime
SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef
this, CFTimeInterval defaultTTL
) {
489 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
490 responder is indicating that newer revocation information
491 is available all the time".
492 Let's ensure that thisUpdate isn't more than defaultTTL in
494 return this->nextUpdate
== NULL_TIME
? this->thisUpdate
+ defaultTTL
: this->nextUpdate
;
497 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef
this, CFTimeInterval defaultTTL
, CFAbsoluteTime verifyTime
) {
498 if (this->thisUpdate
> verifyTime
+ LEEWAY
) {
499 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
503 CFAbsoluteTime cnu
= SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL
);
504 if (verifyTime
- LEEWAY
> cnu
) {
505 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate
? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime
- cnu
) / 86400);
512 CFArrayRef
SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef
this)
514 return CFRetainSafe(this->scts
);
518 SecOCSPSingleResponseRef
SecOCSPResponseCopySingleResponse(
519 SecOCSPResponseRef
this, SecOCSPRequestRef request
) {
520 SecOCSPSingleResponseRef sr
= NULL
;
522 if (!request
) { return sr
; }
523 CFDataRef issuer
= SecCertificateCopyIssuerSequence(request
->certificate
);
524 const DERItem
*publicKey
= SecCertificateGetPublicKeyData(request
->issuer
);
525 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
526 CFDataRef serial
= SecCertificateCopySerialNumber(request
->certificate
, NULL
);
528 CFDataRef serial
= SecCertificateCopySerialNumber(request
->certificate
);
530 CFDataRef issuerNameHash
= NULL
;
531 CFDataRef issuerPubKeyHash
= NULL
;
532 SecAsn1Oid
*algorithm
= NULL
;
533 SecAsn1Item
*parameters
= NULL
;
535 SecAsn1OCSPSingleResponse
**responses
;
536 for (responses
= this->responseData
.responses
; *responses
; ++responses
) {
537 SecAsn1OCSPSingleResponse
*resp
= *responses
;
538 SecAsn1OCSPCertID
*certId
= &resp
->certID
;
539 /* First check the easy part, serial number should match. */
540 if (!serial
|| certId
->serialNumber
.Length
!= (size_t)CFDataGetLength(serial
) ||
541 memcmp(CFDataGetBytePtr(serial
), certId
->serialNumber
.Data
,
542 certId
->serialNumber
.Length
)) {
543 /* Serial # mismatch, skip this singleResponse. */
547 /* Calcluate the issuerKey and issuerName digests using the
548 hashAlgorithm and parameters specified in the certId, if
549 they differ from the ones we already computed. */
550 if (!SecAsn1OidCompare(algorithm
, &certId
->algId
.algorithm
) ||
551 !SecAsn1OidCompare(parameters
, &certId
->algId
.parameters
)) {
552 algorithm
= &certId
->algId
.algorithm
;
553 parameters
= &certId
->algId
.parameters
;
554 CFReleaseSafe(issuerNameHash
);
555 CFReleaseSafe(issuerPubKeyHash
);
556 issuerNameHash
= SecDigestCreate(kCFAllocatorDefault
, algorithm
,
557 parameters
, CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
558 issuerPubKeyHash
= SecDigestCreate(kCFAllocatorDefault
, algorithm
,
559 parameters
, publicKey
->data
, publicKey
->length
);
562 if (!issuerNameHash
|| !issuerPubKeyHash
) {
563 /* This can happen when the hash algorithm is not supported, should be really rare */
564 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
565 ocspdErrorLog("Unknown hash algorithm in singleResponse");
571 if (certId
->issuerNameHash
.Length
== (size_t)CFDataGetLength(issuerNameHash
)
572 && !memcmp(CFDataGetBytePtr(issuerNameHash
),
573 certId
->issuerNameHash
.Data
, certId
->issuerNameHash
.Length
)
574 && certId
->issuerPubKeyHash
.Length
== (size_t)CFDataGetLength(issuerPubKeyHash
)
575 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash
),
576 certId
->issuerPubKeyHash
.Data
, certId
->issuerPubKeyHash
.Length
)) {
578 /* resp matches the certificate in request, so let's use it. */
579 sr
= SecOCSPSingleResponseCreate(resp
, this->coder
);
581 ocspdDebug("found matching singleResponse");
588 CFReleaseSafe(issuerPubKeyHash
);
589 CFReleaseSafe(issuerNameHash
);
590 CFReleaseSafe(serial
);
591 CFReleaseSafe(issuer
);
594 ocspdDebug("certID not found");
600 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef
this,
602 /* Beware this->basicResponse.sig: on decode, length is in BITS */
603 return SecKeyDigestAndVerify(key
, &this->basicResponse
.algId
,
604 this->basicResponse
.tbsResponseData
.Data
,
605 this->basicResponse
.tbsResponseData
.Length
,
606 this->basicResponse
.sig
.Data
,
607 this->basicResponse
.sig
.Length
/ 8) == errSecSuccess
;
610 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef
this,
611 SecCertificateRef issuer
) {
612 bool shouldBeSigner
= false;
613 if (this->responderIdTag
== RIT_Name
) {
614 /* Name inside response must == signer's SubjectName. */
615 CFDataRef subject
= SecCertificateCopySubjectSequence(issuer
);
617 ocspdDebug("error on SecCertificateCopySubjectSequence");
620 if ((size_t)CFDataGetLength(subject
) == this->responderID
.byName
.Length
&&
621 !memcmp(this->responderID
.byName
.Data
, CFDataGetBytePtr(subject
),
622 this->responderID
.byName
.Length
)) {
623 ocspdDebug("good ResponderID.byName");
624 shouldBeSigner
= true;
626 ocspdDebug("BAD ResponderID.byName");
629 } else /* if (this->responderIdTag == RIT_Key) */ {
630 /* ResponderID.byKey must == SHA1(signer's public key) */
631 CFDataRef pubKeyDigest
= SecCertificateCopyPublicKeySHA1Digest(issuer
);
632 if ((size_t)CFDataGetLength(pubKeyDigest
) == this->responderID
.byKey
.Length
&&
633 !memcmp(this->responderID
.byKey
.Data
, CFDataGetBytePtr(pubKeyDigest
),
634 this->responderID
.byKey
.Length
)) {
635 ocspdDebug("good ResponderID.byKey");
636 shouldBeSigner
= true;
638 ocspdDebug("BAD ResponderID.byKey");
640 CFRelease(pubKeyDigest
);
643 if (shouldBeSigner
) {
645 SecKeyRef key
= SecCertificateCopyPublicKey(issuer
);
647 SecKeyRef key
= SecCertificateCopyPublicKey_ios(issuer
);
650 shouldBeSigner
= SecOCSPResponseVerifySignature(this, key
);
651 ocspdDebug("ocsp response signature %sok", shouldBeSigner
? "" : "not ");
654 ocspdDebug("Failed to extract key from leaf certificate");
655 shouldBeSigner
= false;
659 return shouldBeSigner
;
662 /* Returns the SecCertificateRef of the cert that signed this ocspResponse if
663 we can find one and NULL if we can't find a valid signer. */
664 SecCertificateRef
SecOCSPResponseCopySigner(SecOCSPResponseRef
this, SecCertificateRef issuer
) {
665 /* Look though any certs that came with the response to find
666 * which one signed the response. */
668 for (certs
= this->basicResponse
.certs
; certs
&& *certs
; ++certs
) {
669 SecCertificateRef cert
= SecCertificateCreateWithBytes(
670 kCFAllocatorDefault
, (*certs
)->Data
, (*certs
)->Length
);
672 if (SecOCSPResponseIsIssuer(this, cert
)) {
678 ocspdErrorLog("ocsp response cert failed to parse");
681 ocspdDebug("ocsp response did not contain a signer cert.");
683 /* If none of the returned certs work, try the issuer of the certificate
684 being checked directly. */
685 if (issuer
&& SecOCSPResponseIsIssuer(this, issuer
)) {
690 /* We couldn't find who signed this ocspResponse, give up. */