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 ocspdErrorLog("OCSPResponse: producedAt more than 1:15 from now %@", hexResp
);
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 ocspdErrorLog("OCSPResponse: thisUpdate more than 1:15 from now %@", hexResp
);
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 ocspdErrorLog("OCSPResponse: nextUpdate not present %@", hexResp
);
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 ocspdErrorLog("OCSPResponse: latestNextUpdate more than 1:15 ago %@", hexResp
);
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 %@", hexResp
);
348 /* remainder is valid only on RS_Success */
349 if ((topResp
.responseStatus
.Data
== NULL
) ||
350 (topResp
.responseStatus
.Length
== 0)) {
351 ocspdErrorLog("OCSPResponse: no responseStatus %@", hexResp
);
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 %@", hexResp
);
366 if (!SecAsn1OidCompare(&topResp
.responseBytes
->responseType
,
367 &OID_PKIX_OCSP_BASIC
)) {
368 ocspdErrorLog("OCSPResponse: unknown responseType %@", hexResp
);
373 /* decode the SecAsn1OCSPBasicResponse */
374 if (SecAsn1DecodeData(this->coder
, &topResp
.responseBytes
->response
,
375 kSecAsn1OCSPBasicResponseTemplate
, &this->basicResponse
)) {
376 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse %@", hexResp
);
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 %@", hexResp
);
388 this->producedAt
= genTimeToCFAbsTime(&this->responseData
.producedAt
);
389 if (this->producedAt
== NULL_TIME
) {
390 ocspdErrorLog("OCSPResponse: bad producedAt %@", hexResp
);
394 if (this->responseData
.responderID
.Data
== NULL
) {
395 ocspdErrorLog("OCSPResponse: bad responderID %@", hexResp
);
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 %@", hexResp
);
416 if (SecAsn1DecodeData(this->coder
, &this->responseData
.responderID
, templ
,
417 &this->responderID
)) {
418 ocspdErrorLog("OCSPResponse: decode failure at responderID %@", hexResp
);
423 CFReleaseSafe(hexResp
);
426 CFReleaseSafe(hexResp
);
428 SecOCSPResponseFinalize(this);
433 SecOCSPResponseRef
SecOCSPResponseCreate(CFDataRef
this) {
434 return SecOCSPResponseCreateWithID(this, -1);
437 int64_t SecOCSPResponseGetID(SecOCSPResponseRef
this) {
438 return this->responseID
;
441 CFDataRef
SecOCSPResponseGetData(SecOCSPResponseRef
this) {
445 SecOCSPResponseStatus
SecOCSPGetResponseStatus(SecOCSPResponseRef
this) {
446 return this->responseStatus
;
449 CFAbsoluteTime
SecOCSPResponseGetExpirationTime(SecOCSPResponseRef
this) {
450 return this->expireTime
;
453 CFDataRef
SecOCSPResponseGetNonce(SecOCSPResponseRef
this) {
457 CFAbsoluteTime
SecOCSPResponseProducedAt(SecOCSPResponseRef
this) {
458 return this->producedAt
;
461 CFArrayRef
SecOCSPResponseCopySigners(SecOCSPResponseRef
this) {
462 CFMutableArrayRef result
= NULL
;
463 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
468 for (certs
= this->basicResponse
.certs
; certs
&& *certs
; ++certs
) {
469 SecCertificateRef cert
= NULL
;
470 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, (*certs
)->Data
, (*certs
)->Length
);
472 CFArrayAppendValue(result
, cert
);
480 void SecOCSPResponseFinalize(SecOCSPResponseRef
this) {
481 CFReleaseSafe(this->data
);
482 CFReleaseSafe(this->nonce
);
483 SecAsn1CoderRelease(this->coder
);
487 static CFAbsoluteTime
SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef
this, CFTimeInterval defaultTTL
) {
488 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
489 responder is indicating that newer revocation information
490 is available all the time".
491 Let's ensure that thisUpdate isn't more than defaultTTL in
493 return this->nextUpdate
== NULL_TIME
? this->thisUpdate
+ defaultTTL
: this->nextUpdate
;
496 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef
this, CFTimeInterval defaultTTL
, CFAbsoluteTime verifyTime
) {
497 if (this->thisUpdate
> verifyTime
+ LEEWAY
) {
498 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
502 CFAbsoluteTime cnu
= SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL
);
503 if (verifyTime
- LEEWAY
> cnu
) {
504 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate
? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime
- cnu
) / 86400);
511 CFArrayRef
SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef
this)
513 return CFRetainSafe(this->scts
);
517 SecOCSPSingleResponseRef
SecOCSPResponseCopySingleResponse(
518 SecOCSPResponseRef
this, SecOCSPRequestRef request
) {
519 SecOCSPSingleResponseRef sr
= NULL
;
521 CFDataRef issuer
= SecCertificateCopyIssuerSequence(request
->certificate
);
522 const DERItem
*publicKey
= SecCertificateGetPublicKeyData(request
->issuer
);
523 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
524 CFDataRef serial
= SecCertificateCopySerialNumber(request
->certificate
, NULL
);
526 CFDataRef serial
= SecCertificateCopySerialNumber(request
->certificate
);
528 CFDataRef issuerNameHash
= NULL
;
529 CFDataRef issuerPubKeyHash
= NULL
;
530 SecAsn1Oid
*algorithm
= NULL
;
531 SecAsn1Item
*parameters
= NULL
;
533 SecAsn1OCSPSingleResponse
**responses
;
534 for (responses
= this->responseData
.responses
; *responses
; ++responses
) {
535 SecAsn1OCSPSingleResponse
*resp
= *responses
;
536 SecAsn1OCSPCertID
*certId
= &resp
->certID
;
537 /* First check the easy part, serial number should match. */
538 if (certId
->serialNumber
.Length
!= (size_t)CFDataGetLength(serial
) ||
539 memcmp(CFDataGetBytePtr(serial
), certId
->serialNumber
.Data
,
540 certId
->serialNumber
.Length
)) {
541 /* Serial # mismatch, skip this singleResponse. */
545 /* Calcluate the issuerKey and issuerName digests using the
546 hashAlgorithm and parameters specified in the certId, if
547 they differ from the ones we already computed. */
548 if (!SecAsn1OidCompare(algorithm
, &certId
->algId
.algorithm
) ||
549 !SecAsn1OidCompare(parameters
, &certId
->algId
.parameters
)) {
550 algorithm
= &certId
->algId
.algorithm
;
551 parameters
= &certId
->algId
.parameters
;
552 CFReleaseSafe(issuerNameHash
);
553 CFReleaseSafe(issuerPubKeyHash
);
554 issuerNameHash
= SecDigestCreate(kCFAllocatorDefault
, algorithm
,
555 parameters
, CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
556 issuerPubKeyHash
= SecDigestCreate(kCFAllocatorDefault
, algorithm
,
557 parameters
, publicKey
->data
, publicKey
->length
);
560 if (!issuerNameHash
|| !issuerPubKeyHash
) {
561 /* This can happen when the hash algorithm is not supported, should be really rare */
562 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
563 ocspdErrorLog("Unknown hash algorithm in singleResponse");
569 if (certId
->issuerNameHash
.Length
== (size_t)CFDataGetLength(issuerNameHash
)
570 && !memcmp(CFDataGetBytePtr(issuerNameHash
),
571 certId
->issuerNameHash
.Data
, certId
->issuerNameHash
.Length
)
572 && certId
->issuerPubKeyHash
.Length
== (size_t)CFDataGetLength(issuerPubKeyHash
)
573 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash
),
574 certId
->issuerPubKeyHash
.Data
, certId
->issuerPubKeyHash
.Length
)) {
576 /* resp matches the certificate in request, so let's use it. */
577 sr
= SecOCSPSingleResponseCreate(resp
, this->coder
);
579 ocspdDebug("found matching singleResponse");
586 CFReleaseSafe(issuerPubKeyHash
);
587 CFReleaseSafe(issuerNameHash
);
588 CFReleaseSafe(serial
);
589 CFReleaseSafe(issuer
);
592 ocspdDebug("certID not found");
598 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef
this,
600 /* Beware this->basicResponse.sig: on decode, length is in BITS */
601 return SecKeyDigestAndVerify(key
, &this->basicResponse
.algId
,
602 this->basicResponse
.tbsResponseData
.Data
,
603 this->basicResponse
.tbsResponseData
.Length
,
604 this->basicResponse
.sig
.Data
,
605 this->basicResponse
.sig
.Length
/ 8) == errSecSuccess
;
608 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef
this,
609 SecCertificateRef issuer
) {
610 bool shouldBeSigner
= false;
611 if (this->responderIdTag
== RIT_Name
) {
612 /* Name inside response must == signer's SubjectName. */
613 CFDataRef subject
= SecCertificateCopySubjectSequence(issuer
);
615 ocspdDebug("error on SecCertificateCopySubjectSequence");
618 if ((size_t)CFDataGetLength(subject
) == this->responderID
.byName
.Length
&&
619 !memcmp(this->responderID
.byName
.Data
, CFDataGetBytePtr(subject
),
620 this->responderID
.byName
.Length
)) {
621 ocspdDebug("good ResponderID.byName");
622 shouldBeSigner
= true;
624 ocspdDebug("BAD ResponderID.byName");
627 } else /* if (this->responderIdTag == RIT_Key) */ {
628 /* ResponderID.byKey must == SHA1(signer's public key) */
629 CFDataRef pubKeyDigest
= SecCertificateCopyPublicKeySHA1Digest(issuer
);
630 if ((size_t)CFDataGetLength(pubKeyDigest
) == this->responderID
.byKey
.Length
&&
631 !memcmp(this->responderID
.byKey
.Data
, CFDataGetBytePtr(pubKeyDigest
),
632 this->responderID
.byKey
.Length
)) {
633 ocspdDebug("good ResponderID.byKey");
634 shouldBeSigner
= true;
636 ocspdDebug("BAD ResponderID.byKey");
638 CFRelease(pubKeyDigest
);
641 if (shouldBeSigner
) {
643 SecKeyRef key
= SecCertificateCopyPublicKey(issuer
);
645 SecKeyRef key
= SecCertificateCopyPublicKey_ios(issuer
);
648 shouldBeSigner
= SecOCSPResponseVerifySignature(this, key
);
649 ocspdDebug("ocsp response signature %sok", shouldBeSigner
? "" : "not ");
652 ocspdDebug("Failed to extract key from leaf certificate");
653 shouldBeSigner
= false;
657 return shouldBeSigner
;
660 /* Returns the SecCertificateRef of the cert that signed this ocspResponse if
661 we can find one and NULL if we can't find a valid signer. */
662 SecCertificateRef
SecOCSPResponseCopySigner(SecOCSPResponseRef
this, SecCertificateRef issuer
) {
663 /* Look though any certs that came with the response to find
664 * which one signed the response. */
666 for (certs
= this->basicResponse
.certs
; certs
&& *certs
; ++certs
) {
667 SecCertificateRef cert
= SecCertificateCreateWithBytes(
668 kCFAllocatorDefault
, (*certs
)->Data
, (*certs
)->Length
);
670 if (SecOCSPResponseIsIssuer(this, cert
)) {
676 ocspdErrorLog("ocsp response cert failed to parse");
679 ocspdDebug("ocsp response did not contain a signer cert.");
681 /* If none of the returned certs work, try the issuer of the certificate
682 being checked directly. */
683 if (issuer
&& SecOCSPResponseIsIssuer(this, issuer
)) {
688 /* We couldn't find who signed this ocspResponse, give up. */