]> git.saurik.com Git - apple/security.git/blob - sec/securityd/SecOCSPResponse.c
Security-55471.14.8.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 <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 #define LEEWAY (4500.0)
179
180 /* Calculate temporal validity; set latestNextUpdate and expireTime. Only
181 called from SecOCSPResponseCreate. Returns true if valid, else returns
182 false. */
183 static bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this,
184 CFTimeInterval maxAge, CFTimeInterval defaultTTL)
185 {
186 this->latestNextUpdate = NULL_TIME;
187 CFAbsoluteTime now = this->verifyTime = CFAbsoluteTimeGetCurrent();
188
189 if (this->producedAt > now + LEEWAY) {
190 ocspdErrorLog("OCSPResponse: producedAt more than 1:15 from now");
191 return false;
192 }
193
194 /* Make this->latestNextUpdate be the date farthest in the future
195 of any of the singleResponses nextUpdate fields. */
196 SecAsn1OCSPSingleResponse **responses;
197 for (responses = this->responseData.responses; *responses; ++responses) {
198 SecAsn1OCSPSingleResponse *resp = *responses;
199
200 /* thisUpdate later than 'now' invalidates the whole response. */
201 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
202 if (thisUpdate > now + LEEWAY) {
203 ocspdErrorLog("OCSPResponse: thisUpdate more than 1:15 from now");
204 return false;
205 }
206
207 /* Keep track of latest nextUpdate. */
208 if (resp->nextUpdate != NULL) {
209 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
210 if (nextUpdate > this->latestNextUpdate) {
211 this->latestNextUpdate = nextUpdate;
212 }
213 }
214 #ifdef STRICT_RFC5019
215 else {
216 /* RFC 5019 section 2.2.4 states on nextUpdate:
217 Responders MUST always include this value to aid in
218 response caching. See Section 6 for additional
219 information on caching.
220 */
221 ocspdErrorLog("OCSPResponse: nextUpdate not present");
222 return false;
223 }
224 #endif
225 }
226
227 /* Now that we have this->latestNextUpdate, we figure out the latest
228 date at which we will expire this response from our cache. To comply
229 with rfc5019s:
230
231 6.1. Caching at the Client
232
233 To minimize bandwidth usage, clients MUST locally cache authoritative
234 OCSP responses (i.e., a response with a signature that has been
235 successfully validated and that indicate an OCSPResponseStatus of
236 'successful').
237
238 Most OCSP clients will send OCSPRequests at or near the nextUpdate
239 time (when a cached response expires). To avoid large spikes in
240 responder load that might occur when many clients refresh cached
241 responses for a popular certificate, responders MAY indicate when the
242 client should fetch an updated OCSP response by using the cache-
243 control:max-age directive. Clients SHOULD fetch the updated OCSP
244 Response on or after the max-age time. To ensure that clients
245 receive an updated OCSP response, OCSP responders MUST refresh the
246 OCSP response before the max-age time.
247
248 6.2 [...]
249
250 we need to take the cache-control:max-age directive into account.
251
252 The way the code below is written we ignore a max-age=0 in the
253 http header. Since a value of 0 (NULL_TIME) also means there
254 was no max-age in the header. This seems ok since that would imply
255 no-cache so we also ignore negative values for the same reason,
256 instead we'll expire whenever this->latestNextUpdate tells us to,
257 which is the signed value if max-age is too low, since we don't
258 want to refetch multilple times for a single page load in a browser. */
259 if (this->latestNextUpdate == NULL_TIME) {
260 /* See comment above on RFC 5019 section 2.2.4. */
261 /* Absolute expire time = current time plus defaultTTL */
262 this->expireTime = now + defaultTTL;
263 } else if (this->latestNextUpdate < now - LEEWAY) {
264 ocspdErrorLog("OCSPResponse: latestNextUpdate more than 1:15 ago");
265 return false;
266 } else if (maxAge > 0) {
267 /* Beware of double overflows such as:
268
269 now + maxAge < this->latestNextUpdate
270
271 in the math below since an attacker could create any positive
272 value for maxAge. */
273 if (maxAge < this->latestNextUpdate - now) {
274 /* maxAge header wants us to expire the cache entry sooner than
275 nextUpdate would allow, to balance server load. */
276 this->expireTime = now + maxAge;
277 } else {
278 /* maxAge http header attempting to make us cache the response
279 longer than it's valid for, bad http header! Ignoring you. */
280 ocspdErrorLog("OCSPResponse: now + maxAge > latestNextUpdate,"
281 " using latestNextUpdate");
282 this->expireTime = this->latestNextUpdate;
283 }
284 } else {
285 /* No maxAge provided, just use latestNextUpdate. */
286 this->expireTime = this->latestNextUpdate;
287 }
288
289 return true;
290 }
291
292 SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef ocspResponse,
293 CFTimeInterval maxAge) {
294 SecAsn1OCSPResponse topResp = {};
295 SecOCSPResponseRef this;
296
297 require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)),
298 errOut);
299 require_noerr(SecAsn1CoderCreate(&this->coder), errOut);
300
301 this->data = ocspResponse;
302 CFRetain(ocspResponse);
303
304 SecAsn1Item resp;
305 resp.Length = CFDataGetLength(ocspResponse);
306 resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse);
307 if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate,
308 &topResp)) {
309 ocspdErrorLog("OCSPResponse: decode failure at top level");
310 }
311 /* remainder is valid only on RS_Success */
312 if ((topResp.responseStatus.Data == NULL) ||
313 (topResp.responseStatus.Length == 0)) {
314 ocspdErrorLog("OCSPResponse: no responseStatus");
315 goto errOut;
316 }
317 this->responseStatus = topResp.responseStatus.Data[0];
318 if (this->responseStatus != kSecOCSPSuccess) {
319 secdebug("ocsp", "OCSPResponse: status: %d", this->responseStatus);
320 /* not a failure of our constructor; this object is now useful, but
321 * only for this one byte of status info */
322 return this;
323 }
324 if (topResp.responseBytes == NULL) {
325 /* I don't see how this can be legal on RS_Success */
326 ocspdErrorLog("OCSPResponse: empty responseBytes");
327 goto errOut;
328 }
329 if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
330 &OID_PKIX_OCSP_BASIC)) {
331 ocspdErrorLog("OCSPResponse: unknown responseType");
332 goto errOut;
333
334 }
335
336 /* decode the SecAsn1OCSPBasicResponse */
337 if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response,
338 kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) {
339 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse");
340 goto errOut;
341 }
342
343 /* signature and cert evaluation done externally */
344
345 /* decode the SecAsn1OCSPResponseData */
346 if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData,
347 kSecAsn1OCSPResponseDataTemplate, &this->responseData)) {
348 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData");
349 goto errOut;
350 }
351 this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
352 if (this->producedAt == NULL_TIME) {
353 ocspdErrorLog("OCSPResponse: bad producedAt");
354 goto errOut;
355 }
356
357 if (this->responseData.responderID.Data == NULL) {
358 ocspdErrorLog("OCSPResponse: bad responderID");
359 goto errOut;
360 }
361
362 /* Choice processing for ResponderID */
363 this->responderIdTag = (SecAsn1OCSPResponderIDTag)
364 (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
365 const SecAsn1Template *templ;
366 switch(this->responderIdTag) {
367 case RIT_Name:
368 /* @@@ Since we don't use the decoded byName value we could skip
369 decoding it but we do it anyway for validation. */
370 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
371 break;
372 case RIT_Key:
373 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
374 break;
375 default:
376 ocspdErrorLog("OCSPResponse: bad responderID tag");
377 goto errOut;
378 }
379 if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
380 &this->responderID)) {
381 ocspdErrorLog("OCSPResponse: decode failure at responderID");
382 goto errOut;
383 }
384
385 /* We should probably get the defaultTTL from the policy.
386 For now defaultTTL is hardcoded to 24 hours. */
387 CFTimeInterval defaultTTL = 24 * 60 * 60;
388 /* Check temporal validity, default TTL 24 hours. */
389 require_quiet(SecOCSPResponseCalculateValidity(this, maxAge, defaultTTL), errOut);
390
391 #if 0
392 /* Individual responses looked into when we're asked for a specific one
393 via SecOCSPResponseCopySingleResponse(). */
394 mExtensions = new OCSPExtensions(mResponseData.responseExtensions);
395 #endif
396
397 return this;
398 errOut:
399 if (this) {
400 SecOCSPResponseFinalize(this);
401 }
402 return NULL;
403 }
404
405 CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
406 return this->data;
407 }
408
409 SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
410 return this->responseStatus;
411 }
412
413 CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
414 return this->expireTime;
415 }
416
417 CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
418 return this->nonce;
419 }
420
421 CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
422 return this->producedAt;
423 }
424
425 CFAbsoluteTime SecOCSPResponseVerifyTime(SecOCSPResponseRef this) {
426 return this->verifyTime;
427 }
428
429 CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
430 return NULL;
431 }
432
433 void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
434 CFReleaseSafe(this->data);
435 CFReleaseSafe(this->nonce);
436 SecAsn1CoderRelease(this->coder);
437 free(this);
438 }
439
440 SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
441 SecOCSPResponseRef this, SecOCSPRequestRef request) {
442 SecOCSPSingleResponseRef sr = NULL;
443
444 CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
445 const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
446 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
447 CFDataRef issuerNameHash = NULL;
448 CFDataRef issuerPubKeyHash = NULL;
449 SecAsn1Oid *algorithm = NULL;
450 SecAsn1Item *parameters = NULL;
451
452 /* We should probably get the defaultTTL from the policy.
453 For now defaultTTL is hardcoded to 24 hours. This is how long we trust
454 a response without a nextUpdate field. */
455 CFTimeInterval defaultTTL = 24 * 60 * 60;
456
457 SecAsn1OCSPSingleResponse **responses;
458 for (responses = this->responseData.responses; *responses; ++responses) {
459 SecAsn1OCSPSingleResponse *resp = *responses;
460 SecAsn1OCSPCertID *certId = &resp->certID;
461 /* First check the easy part, serial number should match. */
462 if (certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
463 memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
464 certId->serialNumber.Length)) {
465 /* Serial # mismatch, skip this singleResponse. */
466 continue;
467 }
468
469 /* Calcluate the issuerKey and issuerName digests using the
470 hashAlgorithm and parameters specified in the certId, if
471 they differ from the ones we already computed. */
472 if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
473 !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
474 algorithm = &certId->algId.algorithm;
475 parameters = &certId->algId.parameters;
476 CFReleaseSafe(issuerNameHash);
477 CFReleaseSafe(issuerPubKeyHash);
478 issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
479 parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
480 issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
481 parameters, publicKey->data, publicKey->length);
482 }
483
484 if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
485 && !memcmp(CFDataGetBytePtr(issuerNameHash),
486 certId->issuerNameHash.Data, certId->issuerNameHash.Length)
487 && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
488 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
489 certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
490
491 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
492 if (thisUpdate > this->verifyTime) {
493 ocspdErrorLog("OCSPSingleResponse: thisUpdate > now");
494 continue;
495 }
496
497 if (resp->nextUpdate == NULL) {
498 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
499 responder is indicating that newer revocation information
500 is available all the time".
501 Let's ensure that thisUpdate isn't more than defaultTTL in
502 the past then. */
503 if (this->verifyTime > thisUpdate + defaultTTL) {
504 ocspdErrorLog("OCSPSingleResponse: no nextUpdate present "
505 "and now > thisUpdate + defaultTTL");
506 continue;
507 }
508 } else {
509 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
510 if (this->verifyTime > nextUpdate) {
511 ocspdErrorLog("OCSPSingleResponse: now > nextUpdate");
512 continue;
513 }
514 }
515
516 /* resp matches the certificate in request, so let's use it. */
517 sr = SecOCSPSingleResponseCreate(resp, this->coder);
518 if (sr) {
519 ocspdDebug("found matching singleResponse");
520 break;
521 }
522 }
523 }
524
525 CFReleaseSafe(issuerPubKeyHash);
526 CFReleaseSafe(issuerNameHash);
527 CFReleaseSafe(serial);
528 CFReleaseSafe(issuer);
529
530 if (!sr) {
531 ocspdDebug("certID not found");
532 }
533
534 return sr;
535 }
536
537 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
538 SecKeyRef key) {
539 /* Beware this->basicResponse.sig: on decode, length is in BITS */
540 return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
541 this->basicResponse.tbsResponseData.Data,
542 this->basicResponse.tbsResponseData.Length,
543 this->basicResponse.sig.Data,
544 this->basicResponse.sig.Length / 8) == errSecSuccess;
545 }
546
547 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
548 SecCertificatePathRef issuer) {
549 bool shouldBeSigner = false;
550 SecCertificateRef signer = SecCertificatePathGetCertificateAtIndex(issuer, 0);
551 if (this->responderIdTag == RIT_Name) {
552 /* Name inside response must == signer's SubjectName. */
553 CFDataRef subject = SecCertificateCopySubjectSequence(signer);
554 if (!subject) {
555 ocspdDebug("error on SecCertificateCopySubjectSequence");
556 return false;
557 }
558 if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
559 !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
560 this->responderID.byName.Length)) {
561 ocspdDebug("good ResponderID.byName");
562 shouldBeSigner = true;
563 } else {
564 ocspdDebug("BAD ResponderID.byName");
565 }
566 CFRelease(subject);
567 } else /* if (this->responderIdTag == RIT_Key) */ {
568 /* ResponderID.byKey must == SHA1(signer's public key) */
569 CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(signer);
570 if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
571 !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
572 this->responderID.byKey.Length)) {
573 ocspdDebug("good ResponderID.byKey");
574 shouldBeSigner = true;
575 } else {
576 ocspdDebug("BAD ResponderID.byKey");
577 }
578 CFRelease(pubKeyDigest);
579 }
580
581 if (shouldBeSigner) {
582 SecKeyRef key = SecCertificatePathCopyPublicKeyAtIndex(issuer, 0);
583 if (key) {
584 shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
585 ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
586 CFRelease(key);
587 } else {
588 ocspdDebug("Failed to extract key from leaf certificate");
589 shouldBeSigner = false;
590 }
591 }
592
593 return shouldBeSigner;
594 }
595
596 /* Returns the SecCertificatePathRef who's leaf signed this ocspResponse if
597 we can find one and NULL if we can't find a valid signer. */
598 SecCertificatePathRef SecOCSPResponseCopySigner(SecOCSPResponseRef this,
599 SecCertificatePathRef issuer) {
600 SecCertificateRef issuerCert = SecCertificatePathGetCertificateAtIndex(issuer, 0);
601 CFDataRef issuerSubject = SecCertificateGetNormalizedSubjectContent(issuerCert);
602 /* Look though any certs that came with the response and see if they were
603 both issued by the issuerPath and signed the response. */
604 SecAsn1Item **certs;
605 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
606 SecCertificateRef cert = SecCertificateCreateWithBytes(
607 kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
608 if (cert) {
609 CFDataRef certIssuer = SecCertificateGetNormalizedIssuerContent(cert);
610 if (CFEqual(issuerSubject, certIssuer)) {
611 SecCertificatePathRef signer = SecCertificatePathCopyAddingLeaf(issuer, cert);
612 CFRelease(cert);
613 if (signer) {
614 if (SecOCSPResponseIsIssuer(this, signer)) {
615 return signer;
616 } else {
617 ocspdErrorLog("ocsp response cert not signed by issuer.");
618 CFRelease(signer);
619 }
620 }
621 } else {
622 ocspdErrorLog("ocsp response cert issuer doesn't match issuer subject.");
623 }
624 } else {
625 ocspdErrorLog("ocsp response cert failed to parse");
626 }
627 }
628
629 /* If none of the returned certs work, try the issuer of the certificate
630 being checked directly. */
631 if (SecOCSPResponseIsIssuer(this, issuer)) {
632 CFRetain(issuer);
633 return issuer;
634 }
635
636 /* We couldn't find who signed this ocspResponse, give up. */
637 return NULL;
638 }