]> git.saurik.com Git - apple/security.git/blob - sec/securityd/SecOCSPResponse.c
Security-55179.1.tar.gz
[apple/security.git] / sec / securityd / SecOCSPResponse.c
1 /*
2 * Copyright (c) 2008-2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecOCSPResponse.c - Wrapper to decode ocsp responses.
26 */
27
28 #include <securityd/SecOCSPResponse.h>
29 #include <Security/SecCertificateInternal.h>
30 #include <Security/SecFramework.h>
31 #include <Security/SecKeyPriv.h>
32 #include <AssertMacros.h>
33 #include <security_utilities/debugging.h>
34 #include <security_asn1/SecAsn1Coder.h>
35 #include <security_asn1/ocspTemplates.h>
36 #include <security_asn1/oidsalg.h>
37 #include <security_asn1/oidsocsp.h>
38 #include <CommonCrypto/CommonDigest.h>
39 #include <asl.h>
40 #include <stdlib.h>
41 #include "SecInternal.h"
42
43 #define ocspdErrorLog(args...) asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
44 #define ocspdHttpDebug(args...) secdebug("ocspdHttp", ## args)
45 #define ocspdDebug(args...) secdebug("ocsp", ## args)
46
47
48 /*
49 OCSPResponse ::= SEQUENCE {
50 responseStatus OCSPResponseStatus,
51 responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
52
53 OCSPResponseStatus ::= ENUMERATED {
54 successful (0), --Response has valid confirmations
55 malformedRequest (1), --Illegal confirmation request
56 internalError (2), --Internal error in issuer
57 tryLater (3), --Try again later
58 --(4) is not used
59 sigRequired (5), --Must sign the request
60 unauthorized (6) --Request unauthorized
61 }
62
63 ResponseBytes ::= SEQUENCE {
64 responseType OBJECT IDENTIFIER,
65 response OCTET STRING }
66
67 id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
68 id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
69
70 The value for response SHALL be the DER encoding of
71 BasicOCSPResponse.
72
73 BasicOCSPResponse ::= SEQUENCE {
74 tbsResponseData ResponseData,
75 signatureAlgorithm AlgorithmIdentifier,
76 signature BIT STRING,
77 certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
78
79 The value for signature SHALL be computed on the hash of the DER
80 encoding ResponseData.
81
82 ResponseData ::= SEQUENCE {
83 version [0] EXPLICIT Version DEFAULT v1,
84 responderID ResponderID,
85 producedAt GeneralizedTime,
86 responses SEQUENCE OF SingleResponse,
87 responseExtensions [1] EXPLICIT Extensions OPTIONAL }
88
89 ResponderID ::= CHOICE {
90 byName [1] Name,
91 byKey [2] KeyHash }
92
93 KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
94 (excluding the tag and length fields)
95
96 SingleResponse ::= SEQUENCE {
97 certID CertID,
98 certStatus CertStatus,
99 thisUpdate GeneralizedTime,
100 nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
101 singleExtensions [1] EXPLICIT Extensions OPTIONAL }
102
103 CertStatus ::= CHOICE {
104 good [0] IMPLICIT NULL,
105 revoked [1] IMPLICIT RevokedInfo,
106 unknown [2] IMPLICIT UnknownInfo }
107
108 RevokedInfo ::= SEQUENCE {
109 revocationTime GeneralizedTime,
110 revocationReason [0] EXPLICIT CRLReason OPTIONAL }
111
112 UnknownInfo ::= NULL -- this can be replaced with an enumeration
113 */
114
115 static CFAbsoluteTime genTimeToCFAbsTime(const SecAsn1Item *datetime)
116 {
117 return SecAbsoluteTimeFromDateContent(SEC_ASN1_GENERALIZED_TIME,
118 datetime->Data, datetime->Length);
119 }
120
121 void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this) {
122 free(this);
123 }
124
125 static SecOCSPSingleResponseRef SecOCSPSingleResponseCreate(
126 SecAsn1OCSPSingleResponse *resp, SecAsn1CoderRef coder) {
127 assert(resp != NULL);
128 SecOCSPSingleResponseRef this;
129 require(this = (SecOCSPSingleResponseRef)
130 malloc(sizeof(struct __SecOCSPSingleResponse)), errOut);
131 this->certStatus = CS_NotParsed;
132 this->thisUpdate = NULL_TIME;
133 this->nextUpdate = NULL_TIME;
134 this->revokedTime = NULL_TIME;
135 this->crlReason = kSecRevocationReasonUndetermined;
136 //this->extensions = NULL;
137
138 if ((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
139 ocspdErrorLog("OCSPSingleResponse: bad certStatus");
140 goto errOut;
141 }
142 this->certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
143 if (this->certStatus == CS_Revoked) {
144 /* Decode further to get SecAsn1OCSPRevokedInfo */
145 SecAsn1OCSPCertStatus certStatus;
146 memset(&certStatus, 0, sizeof(certStatus));
147 if (SecAsn1DecodeData(coder, &resp->certStatus,
148 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
149 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus");
150 goto errOut;
151 }
152 SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo;
153 if (revokedInfo != NULL) {
154 /* Treat this as optional even for CS_Revoked */
155 this->revokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime);
156 const SecAsn1Item *revReason = revokedInfo->revocationReason;
157 if((revReason != NULL) &&
158 (revReason->Data != NULL) &&
159 (revReason->Length != 0)) {
160 this->crlReason = revReason->Data[0];
161 }
162 }
163 }
164 this->thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
165 if (resp->nextUpdate != NULL) {
166 this->nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
167 }
168 //mExtensions = new OCSPExtensions(resp->singleExtensions);
169 ocspdDebug("status %d reason %d", (int)this->certStatus,
170 (int)this->crlReason);
171 return this;
172 errOut:
173 if (this)
174 SecOCSPSingleResponseDestroy(this);
175 return NULL;
176 }
177
178 /* Calculate temporal validity; set latestNextUpdate and expireTime. Only
179 called from SecOCSPResponseCreate. Returns true if valid, else returns
180 false. */
181 static bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this,
182 CFTimeInterval maxAge, CFTimeInterval defaultTTL)
183 {
184 this->latestNextUpdate = NULL_TIME;
185 CFAbsoluteTime now = this->verifyTime = CFAbsoluteTimeGetCurrent();
186
187 if (this->producedAt > now) {
188 ocspdErrorLog("OCSPResponse: producedAt later than current time");
189 return false;
190 }
191
192 /* Make this->latestNextUpdate be the date farthest in the future
193 of any of the singleResponses nextUpdate fields. */
194 SecAsn1OCSPSingleResponse **responses;
195 for (responses = this->responseData.responses; *responses; ++responses) {
196 SecAsn1OCSPSingleResponse *resp = *responses;
197
198 /* thisUpdate later than 'now' invalidates the whole response. */
199 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
200 if (thisUpdate > now) {
201 ocspdErrorLog("OCSPResponse: thisUpdate later than current time");
202 return false;
203 }
204
205 /* Keep track of latest nextUpdate. */
206 if (resp->nextUpdate != NULL) {
207 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
208 if (nextUpdate > this->latestNextUpdate) {
209 this->latestNextUpdate = nextUpdate;
210 }
211 }
212 #ifdef STRICT_RFC5019
213 else {
214 /* RFC 5019 section 2.2.4 states on nextUpdate:
215 Responders MUST always include this value to aid in
216 response caching. See Section 6 for additional
217 information on caching.
218 */
219 ocspdErrorLog("OCSPResponse: nextUpdate not present");
220 return false;
221 }
222 #endif
223 }
224
225 /* Now that we have this->latestNextUpdate, we figure out the latest
226 date at which we will expire this response from our cache. To comply
227 with rfc5019s:
228
229 6.1. Caching at the Client
230
231 To minimize bandwidth usage, clients MUST locally cache authoritative
232 OCSP responses (i.e., a response with a signature that has been
233 successfully validated and that indicate an OCSPResponseStatus of
234 'successful').
235
236 Most OCSP clients will send OCSPRequests at or near the nextUpdate
237 time (when a cached response expires). To avoid large spikes in
238 responder load that might occur when many clients refresh cached
239 responses for a popular certificate, responders MAY indicate when the
240 client should fetch an updated OCSP response by using the cache-
241 control:max-age directive. Clients SHOULD fetch the updated OCSP
242 Response on or after the max-age time. To ensure that clients
243 receive an updated OCSP response, OCSP responders MUST refresh the
244 OCSP response before the max-age time.
245
246 6.2 [...]
247
248 we need to take the cache-control:max-age directive into account.
249
250 The way the code below is written we ignore a max-age=0 in the
251 http header. Since a value of 0 (NULL_TIME) also means there
252 was no max-age in the header. This seems ok since that would imply
253 no-cache so we also ignore negative values for the same reason,
254 instead we'll expire whenever this->latestNextUpdate tells us to,
255 which is the signed value if max-age is too low, since we don't
256 want to refetch multilple times for a single page load in a browser. */
257 if (this->latestNextUpdate == NULL_TIME) {
258 /* See comment above on RFC 5019 section 2.2.4. */
259 /* Absolute expire time = current time plus defaultTTL */
260 this->expireTime = now + defaultTTL;
261 } else if (this->latestNextUpdate < now) {
262 ocspdErrorLog("OCSPResponse: now > latestNextUpdate");
263 return false;
264 } else if (maxAge > 0) {
265 /* Beware of double overflows such as:
266
267 now + maxAge < this->latestNextUpdate
268
269 in the math below since an attacker could create any positive
270 value for maxAge. */
271 if (maxAge < this->latestNextUpdate - now) {
272 /* maxAge header wants us to expire the cache entry sooner than
273 nextUpdate would allow, to balance server load. */
274 this->expireTime = now + maxAge;
275 } else {
276 /* maxAge http header attempting to make us cache the response
277 longer than it's valid for, bad http header! Ignoring you. */
278 ocspdErrorLog("OCSPResponse: now + maxAge > latestNextUpdate,"
279 " using latestNextUpdate");
280 this->expireTime = this->latestNextUpdate;
281 }
282 } else {
283 /* No maxAge provided, just use latestNextUpdate. */
284 this->expireTime = this->latestNextUpdate;
285 }
286
287 return true;
288 }
289
290 SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef ocspResponse,
291 CFTimeInterval maxAge) {
292 SecAsn1OCSPResponse topResp = {};
293 SecOCSPResponseRef this;
294
295 require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)),
296 errOut);
297 require_noerr(SecAsn1CoderCreate(&this->coder), errOut);
298
299 this->data = ocspResponse;
300 CFRetain(ocspResponse);
301
302 SecAsn1Item resp;
303 resp.Length = CFDataGetLength(ocspResponse);
304 resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse);
305 if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate,
306 &topResp)) {
307 ocspdErrorLog("OCSPResponse: decode failure at top level");
308 }
309 /* remainder is valid only on RS_Success */
310 if ((topResp.responseStatus.Data == NULL) ||
311 (topResp.responseStatus.Length == 0)) {
312 ocspdErrorLog("OCSPResponse: no responseStatus");
313 goto errOut;
314 }
315 this->responseStatus = topResp.responseStatus.Data[0];
316 if (this->responseStatus != kSecOCSPSuccess) {
317 secdebug("ocsp", "OCSPResponse: status: %d", this->responseStatus);
318 /* not a failure of our constructor; this object is now useful, but
319 * only for this one byte of status info */
320 return this;
321 }
322 if (topResp.responseBytes == NULL) {
323 /* I don't see how this can be legal on RS_Success */
324 ocspdErrorLog("OCSPResponse: empty responseBytes");
325 goto errOut;
326 }
327 if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
328 &OID_PKIX_OCSP_BASIC)) {
329 ocspdErrorLog("OCSPResponse: unknown responseType");
330 goto errOut;
331
332 }
333
334 /* decode the SecAsn1OCSPBasicResponse */
335 if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response,
336 kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) {
337 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse");
338 goto errOut;
339 }
340
341 /* signature and cert evaluation done externally */
342
343 /* decode the SecAsn1OCSPResponseData */
344 if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData,
345 kSecAsn1OCSPResponseDataTemplate, &this->responseData)) {
346 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData");
347 goto errOut;
348 }
349 this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
350 if (this->producedAt == NULL_TIME) {
351 ocspdErrorLog("OCSPResponse: bad producedAt");
352 goto errOut;
353 }
354
355 if (this->responseData.responderID.Data == NULL) {
356 ocspdErrorLog("OCSPResponse: bad responderID");
357 goto errOut;
358 }
359
360 /* Choice processing for ResponderID */
361 this->responderIdTag = (SecAsn1OCSPResponderIDTag)
362 (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
363 const SecAsn1Template *templ;
364 switch(this->responderIdTag) {
365 case RIT_Name:
366 /* @@@ Since we don't use the decoded byName value we could skip
367 decoding it but we do it anyway for validation. */
368 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
369 break;
370 case RIT_Key:
371 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
372 break;
373 default:
374 ocspdErrorLog("OCSPResponse: bad responderID tag");
375 goto errOut;
376 }
377 if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
378 &this->responderID)) {
379 ocspdErrorLog("OCSPResponse: decode failure at responderID");
380 goto errOut;
381 }
382
383 /* We should probably get the defaultTTL from the policy.
384 For now defaultTTL is hardcoded to 24 hours. */
385 CFTimeInterval defaultTTL = 24 * 60 * 60;
386 /* Check temporal validity, default TTL 24 hours. */
387 require_quiet(SecOCSPResponseCalculateValidity(this, maxAge, defaultTTL), errOut);
388
389 #if 0
390 /* Individual responses looked into when we're asked for a specific one
391 via SecOCSPResponseCopySingleResponse(). */
392 mExtensions = new OCSPExtensions(mResponseData.responseExtensions);
393 #endif
394
395 return this;
396 errOut:
397 if (this) {
398 SecOCSPResponseFinalize(this);
399 }
400 return NULL;
401 }
402
403 CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
404 return this->data;
405 }
406
407 SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
408 return this->responseStatus;
409 }
410
411 CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
412 return this->expireTime;
413 }
414
415 CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
416 return this->nonce;
417 }
418
419 CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
420 return this->producedAt;
421 }
422
423 CFAbsoluteTime SecOCSPResponseVerifyTime(SecOCSPResponseRef this) {
424 return this->verifyTime;
425 }
426
427 CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
428 return NULL;
429 }
430
431 void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
432 CFReleaseSafe(this->data);
433 SecAsn1CoderRelease(this->coder);
434 free(this);
435 }
436
437 SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
438 SecOCSPResponseRef this, SecOCSPRequestRef request) {
439 SecOCSPSingleResponseRef sr = NULL;
440
441 CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
442 const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
443 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
444 CFDataRef issuerNameHash = NULL;
445 CFDataRef issuerPubKeyHash = NULL;
446 SecAsn1Oid *algorithm = NULL;
447 SecAsn1Item *parameters = NULL;
448
449 /* We should probably get the defaultTTL from the policy.
450 For now defaultTTL is hardcoded to 24 hours. This is how long we trust
451 a response without a nextUpdate field. */
452 CFTimeInterval defaultTTL = 24 * 60 * 60;
453
454 SecAsn1OCSPSingleResponse **responses;
455 for (responses = this->responseData.responses; *responses; ++responses) {
456 SecAsn1OCSPSingleResponse *resp = *responses;
457 SecAsn1OCSPCertID *certId = &resp->certID;
458 /* First check the easy part, serial number should match. */
459 if (certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
460 memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
461 certId->serialNumber.Length)) {
462 /* Serial # mismatch, skip this singleResponse. */
463 continue;
464 }
465
466 /* Calcluate the issuerKey and issuerName digests using the
467 hashAlgorithm and parameters specified in the certId, if
468 they differ from the ones we already computed. */
469 if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
470 !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
471 algorithm = &certId->algId.algorithm;
472 parameters = &certId->algId.parameters;
473 CFReleaseSafe(issuerNameHash);
474 CFReleaseSafe(issuerPubKeyHash);
475 issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
476 parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
477 issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
478 parameters, publicKey->data, publicKey->length);
479 }
480
481 if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
482 && !memcmp(CFDataGetBytePtr(issuerNameHash),
483 certId->issuerNameHash.Data, certId->issuerNameHash.Length)
484 && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
485 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
486 certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
487
488 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
489 if (thisUpdate > this->verifyTime) {
490 ocspdErrorLog("OCSPSingleResponse: thisUpdate > now");
491 continue;
492 }
493
494 if (resp->nextUpdate == NULL) {
495 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
496 responder is indicating that newer revocation information
497 is available all the time".
498 Let's ensure that thisUpdate isn't more than defaultTTL in
499 the past then. */
500 if (this->verifyTime > thisUpdate + defaultTTL) {
501 ocspdErrorLog("OCSPSingleResponse: no nextUpdate present "
502 "and now > thisUpdate + defaultTTL");
503 continue;
504 }
505 } else {
506 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
507 if (this->verifyTime > nextUpdate) {
508 ocspdErrorLog("OCSPSingleResponse: now > nextUpdate");
509 continue;
510 }
511 }
512
513 /* resp matches the certificate in request, so let's use it. */
514 sr = SecOCSPSingleResponseCreate(resp, this->coder);
515 if (sr) {
516 ocspdDebug("found matching singleResponse");
517 break;
518 }
519 }
520 }
521
522 CFReleaseSafe(issuerPubKeyHash);
523 CFReleaseSafe(issuerNameHash);
524 CFReleaseSafe(serial);
525 CFReleaseSafe(issuer);
526
527 if (!sr) {
528 ocspdDebug("certID not found");
529 }
530
531 return sr;
532 }
533
534 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
535 SecKeyRef key) {
536 /* Beware this->basicResponse.sig: on decode, length is in BITS */
537 return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
538 this->basicResponse.tbsResponseData.Data,
539 this->basicResponse.tbsResponseData.Length,
540 this->basicResponse.sig.Data,
541 this->basicResponse.sig.Length / 8) == noErr;
542 }
543
544 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
545 SecCertificatePathRef issuer) {
546 bool shouldBeSigner = false;
547 SecCertificateRef signer = SecCertificatePathGetCertificateAtIndex(issuer, 0);
548 if (this->responderIdTag == RIT_Name) {
549 /* Name inside response must == signer's SubjectName. */
550 CFDataRef subject = SecCertificateCopySubjectSequence(signer);
551 if (!subject) {
552 ocspdDebug("error on SecCertificateCopySubjectSequence");
553 return false;
554 }
555 if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
556 !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
557 this->responderID.byName.Length)) {
558 ocspdDebug("good ResponderID.byName");
559 shouldBeSigner = true;
560 } else {
561 ocspdDebug("BAD ResponderID.byName");
562 }
563 CFRelease(subject);
564 } else /* if (this->responderIdTag == RIT_Key) */ {
565 /* ResponderID.byKey must == SHA1(signer's public key) */
566 CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(signer);
567 if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
568 !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
569 this->responderID.byKey.Length)) {
570 ocspdDebug("good ResponderID.byKey");
571 shouldBeSigner = true;
572 } else {
573 ocspdDebug("BAD ResponderID.byKey");
574 }
575 CFRelease(pubKeyDigest);
576 }
577
578 if (shouldBeSigner) {
579 SecKeyRef key = SecCertificatePathCopyPublicKeyAtIndex(issuer, 0);
580 if (key) {
581 shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
582 ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
583 CFRelease(key);
584 } else {
585 ocspdDebug("Failed to extract key from leaf certificate");
586 shouldBeSigner = false;
587 }
588 }
589
590 return shouldBeSigner;
591 }
592
593 /* Returns the SecCertificatePathRef who's leaf signed this ocspResponse if
594 we can find one and NULL if we can't find a valid signer. */
595 SecCertificatePathRef SecOCSPResponseCopySigner(SecOCSPResponseRef this,
596 SecCertificatePathRef issuer) {
597 SecCertificateRef issuerCert = SecCertificatePathGetCertificateAtIndex(issuer, 0);
598 CFDataRef issuerSubject = SecCertificateGetNormalizedSubjectContent(issuerCert);
599 /* Look though any certs that came with the response and see if they were
600 both issued by the issuerPath and signed the response. */
601 SecAsn1Item **certs;
602 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
603 SecCertificateRef cert = SecCertificateCreateWithBytes(
604 kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
605 if (cert) {
606 CFDataRef certIssuer = SecCertificateGetNormalizedIssuerContent(cert);
607 if (CFEqual(issuerSubject, certIssuer)) {
608 SecCertificatePathRef signer = SecCertificatePathCopyAddingLeaf(issuer, cert);
609 CFRelease(cert);
610 if (signer) {
611 if (SecOCSPResponseIsIssuer(this, signer)) {
612 return signer;
613 } else {
614 ocspdErrorLog("ocsp response cert not signed by issuer.");
615 CFRelease(signer);
616 }
617 }
618 } else {
619 ocspdErrorLog("ocsp response cert issuer doesn't match issuer subject.");
620 }
621 } else {
622 ocspdErrorLog("ocsp response cert failed to parse");
623 }
624 }
625
626 /* If none of the returned certs work, try the issuer of the certificate
627 being checked directly. */
628 if (SecOCSPResponseIsIssuer(this, issuer)) {
629 CFRetain(issuer);
630 return issuer;
631 }
632
633 /* We couldn't find who signed this ocspResponse, give up. */
634 return NULL;
635 }