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