2 * Copyright (c) 2008-2009,2012-2018 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 "trust/trustd/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
;
221 if (this->producedAt
> verifyTime
+ LEEWAY
) {
222 secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now");
226 /* Make this->latestNextUpdate be the date farthest in the future
227 of any of the singleResponses nextUpdate fields. */
228 SecAsn1OCSPSingleResponse
**responses
;
229 for (responses
= this->responseData
.responses
; *responses
; ++responses
) {
230 SecAsn1OCSPSingleResponse
*resp
= *responses
;
232 /* thisUpdate later than 'now' invalidates the whole response. */
233 CFAbsoluteTime thisUpdate
= genTimeToCFAbsTime(&resp
->thisUpdate
);
234 if (thisUpdate
> verifyTime
+ LEEWAY
) {
235 secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now");
239 /* Keep track of latest nextUpdate. */
240 if (resp
->nextUpdate
!= NULL
) {
241 CFAbsoluteTime nextUpdate
= genTimeToCFAbsTime(resp
->nextUpdate
);
242 if (nextUpdate
> this->latestNextUpdate
) {
243 this->latestNextUpdate
= nextUpdate
;
247 /* RFC 5019 section 2.2.4 states on nextUpdate:
248 Responders MUST always include this value to aid in
249 response caching. See Section 6 for additional
250 information on caching.
252 secnotice("ocsp", "OCSPResponse: nextUpdate not present");
253 #ifdef STRICT_RFC5019
259 /* Now that we have this->latestNextUpdate, we figure out the latest
260 date at which we will expire this response from our cache. To comply
263 6.1. Caching at the Client
265 To minimize bandwidth usage, clients MUST locally cache authoritative
266 OCSP responses (i.e., a response with a signature that has been
267 successfully validated and that indicate an OCSPResponseStatus of
270 Most OCSP clients will send OCSPRequests at or near the nextUpdate
271 time (when a cached response expires). To avoid large spikes in
272 responder load that might occur when many clients refresh cached
273 responses for a popular certificate, responders MAY indicate when the
274 client should fetch an updated OCSP response by using the cache-
275 control:max-age directive. Clients SHOULD fetch the updated OCSP
276 Response on or after the max-age time. To ensure that clients
277 receive an updated OCSP response, OCSP responders MUST refresh the
278 OCSP response before the max-age time.
282 we need to take the cache-control:max-age directive into account.
284 The way the code below is written we ignore a max-age=0 in the
285 http header. Since a value of 0 (NULL_TIME) also means there
286 was no max-age in the header. This seems ok since that would imply
287 no-cache so we also ignore negative values for the same reason,
288 instead we'll expire whenever this->latestNextUpdate tells us to,
289 which is the signed value if max-age is too low, since we don't
290 want to refetch multilple times for a single page load in a browser. */
291 if (this->latestNextUpdate
== NULL_TIME
) {
292 /* See comment above on RFC 5019 section 2.2.4. */
293 /* Absolute expire time = current time plus defaultTTL */
294 this->expireTime
= verifyTime
+ defaultTTL
;
295 } else if (this->latestNextUpdate
< verifyTime
- LEEWAY
) {
296 secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago");
298 } else if (maxAge
> 0) {
299 /* Beware of double overflows such as:
301 now + maxAge < this->latestNextUpdate
303 in the math below since an attacker could create any positive
305 if (maxAge
< this->latestNextUpdate
- verifyTime
) {
306 /* maxAge header wants us to expire the cache entry sooner than
307 nextUpdate would allow, to balance server load. */
308 this->expireTime
= verifyTime
+ maxAge
;
310 /* maxAge http header attempting to make us cache the response
311 longer than it's valid for, bad http header! Ignoring you. */
313 CFStringRef hexResp
= CFDataCopyHexString(this->data
);
314 ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate,"
315 " using latestNextUpdate %@", hexResp
);
316 CFReleaseSafe(hexResp
);
318 this->expireTime
= this->latestNextUpdate
;
321 /* No maxAge provided, just use latestNextUpdate. */
322 this->expireTime
= this->latestNextUpdate
;
330 SecOCSPResponseRef
SecOCSPResponseCreateWithID(CFDataRef ocspResponse
, int64_t responseID
) {
331 SecAsn1OCSPResponse topResp
= {};
332 SecOCSPResponseRef
this = NULL
;
334 require(ocspResponse
, errOut
);
335 require(this = (SecOCSPResponseRef
)calloc(1, sizeof(struct __SecOCSPResponse
)),
337 require_noerr(SecAsn1CoderCreate(&this->coder
), errOut
);
339 this->data
= ocspResponse
;
340 this->responseID
= responseID
;
341 CFRetain(ocspResponse
);
344 resp
.Length
= CFDataGetLength(ocspResponse
);
345 resp
.Data
= (uint8_t *)CFDataGetBytePtr(ocspResponse
);
346 if (SecAsn1DecodeData(this->coder
, &resp
, kSecAsn1OCSPResponseTemplate
,
348 ocspdErrorLog("OCSPResponse: decode failure at top level");
350 /* remainder is valid only on RS_Success */
351 if ((topResp
.responseStatus
.Data
== NULL
) ||
352 (topResp
.responseStatus
.Length
== 0)) {
353 ocspdErrorLog("OCSPResponse: no responseStatus");
356 this->responseStatus
= topResp
.responseStatus
.Data
[0];
357 if (this->responseStatus
!= kSecOCSPSuccess
) {
359 CFStringRef hexResp
= CFDataCopyHexString(this->data
);
360 secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus
, hexResp
);
361 CFReleaseNull(hexResp
);
363 /* not a failure of our constructor; this object is now useful, but
364 * only for this one byte of status info */
367 if (topResp
.responseBytes
== NULL
) {
368 /* I don't see how this can be legal on RS_Success */
369 ocspdErrorLog("OCSPResponse: empty responseBytes");
372 if (!SecAsn1OidCompare(&topResp
.responseBytes
->responseType
,
373 &OID_PKIX_OCSP_BASIC
)) {
374 ocspdErrorLog("OCSPResponse: unknown responseType");
379 /* decode the SecAsn1OCSPBasicResponse */
380 if (SecAsn1DecodeData(this->coder
, &topResp
.responseBytes
->response
,
381 kSecAsn1OCSPBasicResponseTemplate
, &this->basicResponse
)) {
382 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse");
386 /* signature and cert evaluation done externally */
388 /* decode the SecAsn1OCSPResponseData */
389 if (SecAsn1DecodeData(this->coder
, &this->basicResponse
.tbsResponseData
,
390 kSecAsn1OCSPResponseDataTemplate
, &this->responseData
)) {
391 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData");
394 this->producedAt
= genTimeToCFAbsTime(&this->responseData
.producedAt
);
395 if (this->producedAt
== NULL_TIME
) {
396 ocspdErrorLog("OCSPResponse: bad producedAt");
400 if (this->responseData
.responderID
.Data
== NULL
) {
401 ocspdErrorLog("OCSPResponse: bad responderID");
405 /* Choice processing for ResponderID */
406 this->responderIdTag
= (SecAsn1OCSPResponderIDTag
)
407 (this->responseData
.responderID
.Data
[0] & SEC_ASN1_TAGNUM_MASK
);
408 const SecAsn1Template
*templ
;
409 switch(this->responderIdTag
) {
411 /* @@@ Since we don't use the decoded byName value we could skip
412 decoding it but we do it anyway for validation. */
413 templ
= kSecAsn1OCSPResponderIDAsNameTemplate
;
416 templ
= kSecAsn1OCSPResponderIDAsKeyTemplate
;
419 ocspdErrorLog("OCSPResponse: bad responderID tag");
422 if (SecAsn1DecodeData(this->coder
, &this->responseData
.responderID
, templ
,
423 &this->responderID
)) {
424 ocspdErrorLog("OCSPResponse: decode failure at responderID");
433 CFStringRef hexResp
= (this) ? CFDataCopyHexString(this->data
) : NULL
;
434 secdebug("ocsp", "bad ocsp response: %@", hexResp
);
435 CFReleaseSafe(hexResp
);
439 SecOCSPResponseFinalize(this);
444 SecOCSPResponseRef
SecOCSPResponseCreate(CFDataRef
this) {
445 return SecOCSPResponseCreateWithID(this, -1);
448 int64_t SecOCSPResponseGetID(SecOCSPResponseRef
this) {
449 return this->responseID
;
452 CFDataRef
SecOCSPResponseGetData(SecOCSPResponseRef
this) {
456 SecOCSPResponseStatus
SecOCSPGetResponseStatus(SecOCSPResponseRef
this) {
457 return this->responseStatus
;
460 CFAbsoluteTime
SecOCSPResponseGetExpirationTime(SecOCSPResponseRef
this) {
461 return this->expireTime
;
464 CFDataRef
SecOCSPResponseGetNonce(SecOCSPResponseRef
this) {
468 CFAbsoluteTime
SecOCSPResponseProducedAt(SecOCSPResponseRef
this) {
469 return this->producedAt
;
472 CFArrayRef
SecOCSPResponseCopySigners(SecOCSPResponseRef
this) {
473 CFMutableArrayRef result
= NULL
;
474 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
479 for (certs
= this->basicResponse
.certs
; certs
&& *certs
; ++certs
) {
480 SecCertificateRef cert
= NULL
;
481 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, (*certs
)->Data
, (*certs
)->Length
);
483 CFArrayAppendValue(result
, cert
);
491 void SecOCSPResponseFinalize(SecOCSPResponseRef
this) {
492 CFReleaseSafe(this->data
);
493 CFReleaseSafe(this->nonce
);
494 SecAsn1CoderRelease(this->coder
);
498 static CFAbsoluteTime
SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef
this, CFTimeInterval defaultTTL
) {
499 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
500 responder is indicating that newer revocation information
501 is available all the time".
502 Let's ensure that thisUpdate isn't more than defaultTTL in
504 return this->nextUpdate
== NULL_TIME
? this->thisUpdate
+ defaultTTL
: this->nextUpdate
;
507 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef
this, CFTimeInterval defaultTTL
, CFAbsoluteTime verifyTime
) {
508 if (this->thisUpdate
> verifyTime
+ LEEWAY
) {
509 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
513 CFAbsoluteTime cnu
= SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL
);
514 if (verifyTime
- LEEWAY
> cnu
) {
515 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate
? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime
- cnu
) / 86400);
522 CFArrayRef
SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef
this)
524 return CFRetainSafe(this->scts
);
528 SecOCSPSingleResponseRef
SecOCSPResponseCopySingleResponse(
529 SecOCSPResponseRef
this, SecOCSPRequestRef request
) {
530 SecOCSPSingleResponseRef sr
= NULL
;
532 if (!request
) { return sr
; }
533 CFDataRef issuer
= SecCertificateCopyIssuerSequence(request
->certificate
);
534 const DERItem
*publicKey
= SecCertificateGetPublicKeyData(request
->issuer
);
535 CFDataRef serial
= SecCertificateCopySerialNumberData(request
->certificate
, NULL
);
536 CFDataRef issuerNameHash
= NULL
;
537 CFDataRef issuerPubKeyHash
= NULL
;
538 SecAsn1Oid
*algorithm
= NULL
;
539 SecAsn1Item
*parameters
= NULL
;
541 SecAsn1OCSPSingleResponse
**responses
;
542 for (responses
= this->responseData
.responses
; *responses
; ++responses
) {
543 SecAsn1OCSPSingleResponse
*resp
= *responses
;
544 SecAsn1OCSPCertID
*certId
= &resp
->certID
;
545 /* First check the easy part, serial number should match. */
546 if (!serial
|| certId
->serialNumber
.Length
!= (size_t)CFDataGetLength(serial
) ||
547 memcmp(CFDataGetBytePtr(serial
), certId
->serialNumber
.Data
,
548 certId
->serialNumber
.Length
)) {
549 /* Serial # mismatch, skip this singleResponse. */
553 /* Calcluate the issuerKey and issuerName digests using the
554 hashAlgorithm and parameters specified in the certId, if
555 they differ from the ones we already computed. */
556 if (!SecAsn1OidCompare(algorithm
, &certId
->algId
.algorithm
) ||
557 !SecAsn1OidCompare(parameters
, &certId
->algId
.parameters
)) {
558 algorithm
= &certId
->algId
.algorithm
;
559 parameters
= &certId
->algId
.parameters
;
560 CFReleaseSafe(issuerNameHash
);
561 CFReleaseSafe(issuerPubKeyHash
);
562 issuerNameHash
= SecDigestCreate(kCFAllocatorDefault
, algorithm
,
563 parameters
, CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
564 issuerPubKeyHash
= SecDigestCreate(kCFAllocatorDefault
, algorithm
,
565 parameters
, publicKey
->data
, publicKey
->length
);
568 if (!issuerNameHash
|| !issuerPubKeyHash
) {
569 /* This can happen when the hash algorithm is not supported, should be really rare */
570 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
571 ocspdErrorLog("Unknown hash algorithm in singleResponse");
577 if (certId
->issuerNameHash
.Length
== (size_t)CFDataGetLength(issuerNameHash
)
578 && !memcmp(CFDataGetBytePtr(issuerNameHash
),
579 certId
->issuerNameHash
.Data
, certId
->issuerNameHash
.Length
)
580 && certId
->issuerPubKeyHash
.Length
== (size_t)CFDataGetLength(issuerPubKeyHash
)
581 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash
),
582 certId
->issuerPubKeyHash
.Data
, certId
->issuerPubKeyHash
.Length
)) {
584 /* resp matches the certificate in request, so let's use it. */
585 sr
= SecOCSPSingleResponseCreate(resp
, this->coder
);
587 ocspdDebug("found matching singleResponse");
594 CFReleaseSafe(issuerPubKeyHash
);
595 CFReleaseSafe(issuerNameHash
);
596 CFReleaseSafe(serial
);
597 CFReleaseSafe(issuer
);
600 ocspdDebug("certID not found");
606 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef
this,
608 /* Beware this->basicResponse.sig: on decode, length is in BITS */
609 return SecKeyDigestAndVerify(key
, &this->basicResponse
.algId
,
610 this->basicResponse
.tbsResponseData
.Data
,
611 this->basicResponse
.tbsResponseData
.Length
,
612 this->basicResponse
.sig
.Data
,
613 this->basicResponse
.sig
.Length
/ 8) == errSecSuccess
;
616 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef
this,
617 SecCertificateRef issuer
) {
618 bool shouldBeSigner
= false;
619 if (this->responderIdTag
== RIT_Name
) {
620 /* Name inside response must == signer's SubjectName. */
621 CFDataRef subject
= SecCertificateCopySubjectSequence(issuer
);
623 ocspdDebug("error on SecCertificateCopySubjectSequence");
626 if ((size_t)CFDataGetLength(subject
) == this->responderID
.byName
.Length
&&
627 !memcmp(this->responderID
.byName
.Data
, CFDataGetBytePtr(subject
),
628 this->responderID
.byName
.Length
)) {
629 ocspdDebug("good ResponderID.byName");
630 shouldBeSigner
= true;
632 ocspdDebug("BAD ResponderID.byName");
635 } else /* if (this->responderIdTag == RIT_Key) */ {
636 /* ResponderID.byKey must == SHA1(signer's public key) */
637 CFDataRef pubKeyDigest
= SecCertificateCopyPublicKeySHA1Digest(issuer
);
638 if ((size_t)CFDataGetLength(pubKeyDigest
) == this->responderID
.byKey
.Length
&&
639 !memcmp(this->responderID
.byKey
.Data
, CFDataGetBytePtr(pubKeyDigest
),
640 this->responderID
.byKey
.Length
)) {
641 ocspdDebug("good ResponderID.byKey");
642 shouldBeSigner
= true;
644 ocspdDebug("BAD ResponderID.byKey");
646 CFRelease(pubKeyDigest
);
649 if (shouldBeSigner
) {
650 SecKeyRef key
= SecCertificateCopyKey(issuer
);
652 shouldBeSigner
= SecOCSPResponseVerifySignature(this, key
);
653 ocspdDebug("ocsp response signature %sok", shouldBeSigner
? "" : "not ");
656 ocspdDebug("Failed to extract key from leaf certificate");
657 shouldBeSigner
= false;
661 return shouldBeSigner
;
664 /* Returns the SecCertificateRef of the cert that signed this ocspResponse if
665 we can find one and NULL if we can't find a valid signer. */
666 SecCertificateRef
SecOCSPResponseCopySigner(SecOCSPResponseRef
this, SecCertificateRef issuer
) {
667 /* Look though any certs that came with the response to find
668 * which one signed the response. */
670 for (certs
= this->basicResponse
.certs
; certs
&& *certs
; ++certs
) {
671 SecCertificateRef cert
= SecCertificateCreateWithBytes(
672 kCFAllocatorDefault
, (*certs
)->Data
, (*certs
)->Length
);
674 if (SecOCSPResponseIsIssuer(this, cert
)) {
680 ocspdErrorLog("ocsp response cert failed to parse");
683 ocspdDebug("ocsp response did not contain a signer cert.");
685 /* If none of the returned certs work, try the issuer of the certificate
686 being checked directly. */
687 if (issuer
&& SecOCSPResponseIsIssuer(this, issuer
)) {
692 /* We couldn't find who signed this ocspResponse, give up. */