]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecOCSPResponse.c
Security-57337.60.2.tar.gz
[apple/security.git] / OSX / 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/SecAsn1Templates.h>
38 #include <security_asn1/ocspTemplates.h>
39 #include <security_asn1/oidsocsp.h>
40 #include <stdlib.h>
41 #include "SecInternal.h"
42 #include <utilities/SecCFWrappers.h>
43 #include <utilities/SecSCTUtils.h>
44
45
46 #define ocspdErrorLog(args, ...) secerror(args, ## __VA_ARGS__)
47 #define ocspdHttpDebug(args...) secdebug("ocspdHttp", ## args)
48 #define ocspdDebug(args...) secdebug("ocsp", ## args)
49
50
51 /*
52 OCSPResponse ::= SEQUENCE {
53 responseStatus OCSPResponseStatus,
54 responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
55
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
61 --(4) is not used
62 sigRequired (5), --Must sign the request
63 unauthorized (6) --Request unauthorized
64 }
65
66 ResponseBytes ::= SEQUENCE {
67 responseType OBJECT IDENTIFIER,
68 response OCTET STRING }
69
70 id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
71 id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
72
73 The value for response SHALL be the DER encoding of
74 BasicOCSPResponse.
75
76 BasicOCSPResponse ::= SEQUENCE {
77 tbsResponseData ResponseData,
78 signatureAlgorithm AlgorithmIdentifier,
79 signature BIT STRING,
80 certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
81
82 The value for signature SHALL be computed on the hash of the DER
83 encoding ResponseData.
84
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 }
91
92 ResponderID ::= CHOICE {
93 byName [1] Name,
94 byKey [2] KeyHash }
95
96 KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
97 (excluding the tag and length fields)
98
99 SingleResponse ::= SEQUENCE {
100 certID CertID,
101 certStatus CertStatus,
102 thisUpdate GeneralizedTime,
103 nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
104 singleExtensions [1] EXPLICIT Extensions OPTIONAL }
105
106 CertStatus ::= CHOICE {
107 good [0] IMPLICIT NULL,
108 revoked [1] IMPLICIT RevokedInfo,
109 unknown [2] IMPLICIT UnknownInfo }
110
111 RevokedInfo ::= SEQUENCE {
112 revocationTime GeneralizedTime,
113 revocationReason [0] EXPLICIT CRLReason OPTIONAL }
114
115 UnknownInfo ::= NULL -- this can be replaced with an enumeration
116 */
117
118 static CFAbsoluteTime genTimeToCFAbsTime(const SecAsn1Item *datetime)
119 {
120 return SecAbsoluteTimeFromDateContent(SEC_ASN1_GENERALIZED_TIME,
121 datetime->Data, datetime->Length);
122 }
123
124 void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this) {
125 free(this);
126 }
127
128 static SecOCSPSingleResponseRef SecOCSPSingleResponseCreate(
129 SecAsn1OCSPSingleResponse *resp, SecAsn1CoderRef coder) {
130 assert(resp != NULL);
131 SecOCSPSingleResponseRef this;
132 require(this = (SecOCSPSingleResponseRef)
133 calloc(1, sizeof(struct __SecOCSPSingleResponse)), errOut);
134 this->certStatus = CS_NotParsed;
135 this->thisUpdate = NULL_TIME;
136 this->nextUpdate = NULL_TIME;
137 this->revokedTime = NULL_TIME;
138 this->crlReason = kSecRevocationReasonUndetermined;
139 this->scts = NULL;
140
141 if ((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
142 ocspdErrorLog("OCSPSingleResponse: bad certStatus");
143 goto errOut;
144 }
145 this->certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
146 if (this->certStatus == CS_Revoked) {
147 /* Decode further to get SecAsn1OCSPRevokedInfo */
148 SecAsn1OCSPCertStatus certStatus;
149 memset(&certStatus, 0, sizeof(certStatus));
150 if (SecAsn1DecodeData(coder, &resp->certStatus,
151 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
152 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus");
153 goto errOut;
154 }
155 SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo;
156 if (revokedInfo != NULL) {
157 /* Treat this as optional even for CS_Revoked */
158 this->revokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime);
159 const SecAsn1Item *revReason = revokedInfo->revocationReason;
160 if((revReason != NULL) &&
161 (revReason->Data != NULL) &&
162 (revReason->Length != 0)) {
163 this->crlReason = revReason->Data[0];
164 }
165 }
166 }
167 this->thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
168 if (this->thisUpdate == NULL_TIME) {
169 ocspdErrorLog("OCSPResponse: bad thisUpdate DER");
170 goto errOut;
171 }
172
173 if (resp->nextUpdate != NULL) {
174 this->nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
175 if (this->nextUpdate == NULL_TIME) {
176 ocspdErrorLog("OCSPResponse: bad nextUpdate DER");
177 goto errOut;
178 }
179 }
180
181 /* Lookup through extensions to find SCTs */
182 if(resp->singleExtensions) {
183 ocspdErrorLog("OCSPResponse: single response has extension(s).");
184 int i = 0;
185 NSS_CertExtension *extn;
186 while ((extn = resp->singleExtensions[i])) {
187 if(SecAsn1OidCompare(&extn->extnId, &OID_GOOGLE_OCSP_SCT )) {
188 ocspdErrorLog("OCSPResponse: single response has an SCT extension.");
189 SecAsn1Item sct_data = {0,};
190
191 // Note: if there are more that one valid SCT extension, we just use the first one that successfully decoded
192 if((this->scts == NULL) && (SecAsn1DecodeData(coder, &extn->value, kSecAsn1OctetStringTemplate, &sct_data) == 0)) {
193 this->scts = SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sct_data.Data, sct_data.Length);
194 ocspdErrorLog("OCSPResponse: single response has an SCT extension, parsed = %p.", this->scts);
195 }
196 }
197 i++;
198 }
199 }
200
201 ocspdDebug("status %d reason %d", (int)this->certStatus,
202 (int)this->crlReason);
203 return this;
204 errOut:
205 if (this)
206 SecOCSPSingleResponseDestroy(this);
207 return NULL;
208 }
209
210 #define LEEWAY (4500.0)
211
212 /* Calculate temporal validity; set latestNextUpdate and expireTime.
213 Returns true if valid, else returns false. */
214 bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this,
215 CFTimeInterval maxAge, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime)
216 {
217 bool ok = false;
218 this->latestNextUpdate = NULL_TIME;
219 CFStringRef hexResp = CFDataCopyHexString(this->data);
220
221 if (this->producedAt > verifyTime + LEEWAY) {
222 ocspdErrorLog("OCSPResponse: producedAt more than 1:15 from now %@", hexResp);
223 goto exit;
224 }
225
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;
231
232 /* thisUpdate later than 'now' invalidates the whole response. */
233 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
234 if (thisUpdate > verifyTime + LEEWAY) {
235 ocspdErrorLog("OCSPResponse: thisUpdate more than 1:15 from now %@", hexResp);
236 goto exit;
237 }
238
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;
244 }
245 }
246 else {
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.
251 */
252 ocspdErrorLog("OCSPResponse: nextUpdate not present %@", hexResp);
253 #ifdef STRICT_RFC5019
254 goto exit;
255 #endif
256 }
257 }
258
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
261 with rfc5019s:
262
263 6.1. Caching at the Client
264
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
268 'successful').
269
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.
279
280 6.2 [...]
281
282 we need to take the cache-control:max-age directive into account.
283
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 ocspdErrorLog("OCSPResponse: latestNextUpdate more than 1:15 ago %@", hexResp);
297 goto exit;
298 } else if (maxAge > 0) {
299 /* Beware of double overflows such as:
300
301 now + maxAge < this->latestNextUpdate
302
303 in the math below since an attacker could create any positive
304 value for maxAge. */
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;
309 } else {
310 /* maxAge http header attempting to make us cache the response
311 longer than it's valid for, bad http header! Ignoring you. */
312 ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate,"
313 " using latestNextUpdate %@", hexResp);
314 this->expireTime = this->latestNextUpdate;
315 }
316 } else {
317 /* No maxAge provided, just use latestNextUpdate. */
318 this->expireTime = this->latestNextUpdate;
319 }
320
321 ok = true;
322 exit:
323 CFReleaseSafe(hexResp);
324 return ok;
325 }
326
327 SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID) {
328 CFStringRef hexResp = CFDataCopyHexString(ocspResponse);
329 SecAsn1OCSPResponse topResp = {};
330 SecOCSPResponseRef this;
331
332 require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)),
333 errOut);
334 require_noerr(SecAsn1CoderCreate(&this->coder), errOut);
335
336 this->data = ocspResponse;
337 this->responseID = responseID;
338 CFRetain(ocspResponse);
339
340 SecAsn1Item resp;
341 resp.Length = CFDataGetLength(ocspResponse);
342 resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse);
343 if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate,
344 &topResp)) {
345 ocspdErrorLog("OCSPResponse: decode failure at top level %@", hexResp);
346 }
347 /* remainder is valid only on RS_Success */
348 if ((topResp.responseStatus.Data == NULL) ||
349 (topResp.responseStatus.Length == 0)) {
350 ocspdErrorLog("OCSPResponse: no responseStatus %@", hexResp);
351 goto errOut;
352 }
353 this->responseStatus = topResp.responseStatus.Data[0];
354 if (this->responseStatus != kSecOCSPSuccess) {
355 secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus, hexResp);
356 /* not a failure of our constructor; this object is now useful, but
357 * only for this one byte of status info */
358 goto fini;
359 }
360 if (topResp.responseBytes == NULL) {
361 /* I don't see how this can be legal on RS_Success */
362 ocspdErrorLog("OCSPResponse: empty responseBytes %@", hexResp);
363 goto errOut;
364 }
365 if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
366 &OID_PKIX_OCSP_BASIC)) {
367 ocspdErrorLog("OCSPResponse: unknown responseType %@", hexResp);
368 goto errOut;
369
370 }
371
372 /* decode the SecAsn1OCSPBasicResponse */
373 if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response,
374 kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) {
375 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse %@", hexResp);
376 goto errOut;
377 }
378
379 /* signature and cert evaluation done externally */
380
381 /* decode the SecAsn1OCSPResponseData */
382 if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData,
383 kSecAsn1OCSPResponseDataTemplate, &this->responseData)) {
384 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData %@", hexResp);
385 goto errOut;
386 }
387 this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
388 if (this->producedAt == NULL_TIME) {
389 ocspdErrorLog("OCSPResponse: bad producedAt %@", hexResp);
390 goto errOut;
391 }
392
393 if (this->responseData.responderID.Data == NULL) {
394 ocspdErrorLog("OCSPResponse: bad responderID %@", hexResp);
395 goto errOut;
396 }
397
398 /* Choice processing for ResponderID */
399 this->responderIdTag = (SecAsn1OCSPResponderIDTag)
400 (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
401 const SecAsn1Template *templ;
402 switch(this->responderIdTag) {
403 case RIT_Name:
404 /* @@@ Since we don't use the decoded byName value we could skip
405 decoding it but we do it anyway for validation. */
406 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
407 break;
408 case RIT_Key:
409 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
410 break;
411 default:
412 ocspdErrorLog("OCSPResponse: bad responderID tag %@", hexResp);
413 goto errOut;
414 }
415 if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
416 &this->responderID)) {
417 ocspdErrorLog("OCSPResponse: decode failure at responderID %@", hexResp);
418 goto errOut;
419 }
420
421 fini:
422 CFReleaseSafe(hexResp);
423 return this;
424 errOut:
425 CFReleaseSafe(hexResp);
426 if (this) {
427 SecOCSPResponseFinalize(this);
428 }
429 return NULL;
430 }
431
432 SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef this) {
433 return SecOCSPResponseCreateWithID(this, -1);
434 }
435
436 int64_t SecOCSPResponseGetID(SecOCSPResponseRef this) {
437 return this->responseID;
438 }
439
440 CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
441 return this->data;
442 }
443
444 SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
445 return this->responseStatus;
446 }
447
448 CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
449 return this->expireTime;
450 }
451
452 CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
453 return this->nonce;
454 }
455
456 CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
457 return this->producedAt;
458 }
459
460 CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
461 return NULL;
462 }
463
464 void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
465 CFReleaseSafe(this->data);
466 CFReleaseSafe(this->nonce);
467 SecAsn1CoderRelease(this->coder);
468 free(this);
469 }
470
471 static CFAbsoluteTime SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL) {
472 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
473 responder is indicating that newer revocation information
474 is available all the time".
475 Let's ensure that thisUpdate isn't more than defaultTTL in
476 the past then. */
477 return this->nextUpdate == NULL_TIME ? this->thisUpdate + defaultTTL : this->nextUpdate;
478 }
479
480 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) {
481 if (this->thisUpdate > verifyTime + LEEWAY) {
482 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
483 return false;
484 }
485
486 CFAbsoluteTime cnu = SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL);
487 if (verifyTime - LEEWAY > cnu) {
488 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate ? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime - cnu) / 86400);
489 return false;
490 }
491
492 return true;
493 }
494
495 CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this)
496 {
497 return CFRetainSafe(this->scts);
498 }
499
500
501 SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
502 SecOCSPResponseRef this, SecOCSPRequestRef request) {
503 SecOCSPSingleResponseRef sr = NULL;
504
505 CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
506 const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
507 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
508 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate, NULL);
509 #else
510 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
511 #endif
512 CFDataRef issuerNameHash = NULL;
513 CFDataRef issuerPubKeyHash = NULL;
514 SecAsn1Oid *algorithm = NULL;
515 SecAsn1Item *parameters = NULL;
516
517 SecAsn1OCSPSingleResponse **responses;
518 for (responses = this->responseData.responses; *responses; ++responses) {
519 SecAsn1OCSPSingleResponse *resp = *responses;
520 SecAsn1OCSPCertID *certId = &resp->certID;
521 /* First check the easy part, serial number should match. */
522 if (certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
523 memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
524 certId->serialNumber.Length)) {
525 /* Serial # mismatch, skip this singleResponse. */
526 continue;
527 }
528
529 /* Calcluate the issuerKey and issuerName digests using the
530 hashAlgorithm and parameters specified in the certId, if
531 they differ from the ones we already computed. */
532 if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
533 !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
534 algorithm = &certId->algId.algorithm;
535 parameters = &certId->algId.parameters;
536 CFReleaseSafe(issuerNameHash);
537 CFReleaseSafe(issuerPubKeyHash);
538 issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
539 parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
540 issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
541 parameters, publicKey->data, publicKey->length);
542 }
543
544 if (!issuerNameHash || !issuerPubKeyHash) {
545 /* This can happen when the hash algorithm is not supported, shoudl be really rare */
546 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
547 ocspdErrorLog("Unknown hash algorithm in singleResponse");
548 algorithm = NULL;
549 parameters = NULL;
550 continue;
551 }
552
553 if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
554 && !memcmp(CFDataGetBytePtr(issuerNameHash),
555 certId->issuerNameHash.Data, certId->issuerNameHash.Length)
556 && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
557 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
558 certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
559
560 /* resp matches the certificate in request, so let's use it. */
561 sr = SecOCSPSingleResponseCreate(resp, this->coder);
562 if (sr) {
563 ocspdDebug("found matching singleResponse");
564 break;
565 }
566 }
567
568 }
569
570 CFReleaseSafe(issuerPubKeyHash);
571 CFReleaseSafe(issuerNameHash);
572 CFReleaseSafe(serial);
573 CFReleaseSafe(issuer);
574
575 if (!sr) {
576 ocspdDebug("certID not found");
577 }
578
579 return sr;
580 }
581
582 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
583 SecKeyRef key) {
584 /* Beware this->basicResponse.sig: on decode, length is in BITS */
585 return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
586 this->basicResponse.tbsResponseData.Data,
587 this->basicResponse.tbsResponseData.Length,
588 this->basicResponse.sig.Data,
589 this->basicResponse.sig.Length / 8) == errSecSuccess;
590 }
591
592 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
593 SecCertificatePathRef issuer) {
594 bool shouldBeSigner = false;
595 SecCertificateRef signer = SecCertificatePathGetCertificateAtIndex(issuer, 0);
596 if (this->responderIdTag == RIT_Name) {
597 /* Name inside response must == signer's SubjectName. */
598 CFDataRef subject = SecCertificateCopySubjectSequence(signer);
599 if (!subject) {
600 ocspdDebug("error on SecCertificateCopySubjectSequence");
601 return false;
602 }
603 if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
604 !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
605 this->responderID.byName.Length)) {
606 ocspdDebug("good ResponderID.byName");
607 shouldBeSigner = true;
608 } else {
609 ocspdDebug("BAD ResponderID.byName");
610 }
611 CFRelease(subject);
612 } else /* if (this->responderIdTag == RIT_Key) */ {
613 /* ResponderID.byKey must == SHA1(signer's public key) */
614 CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(signer);
615 if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
616 !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
617 this->responderID.byKey.Length)) {
618 ocspdDebug("good ResponderID.byKey");
619 shouldBeSigner = true;
620 } else {
621 ocspdDebug("BAD ResponderID.byKey");
622 }
623 CFRelease(pubKeyDigest);
624 }
625
626 if (shouldBeSigner) {
627 SecKeyRef key = SecCertificatePathCopyPublicKeyAtIndex(issuer, 0);
628 if (key) {
629 shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
630 ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
631 CFRelease(key);
632 } else {
633 ocspdDebug("Failed to extract key from leaf certificate");
634 shouldBeSigner = false;
635 }
636 }
637
638 return shouldBeSigner;
639 }
640
641 /* Returns the SecCertificatePathRef whose leaf signed this ocspResponse if
642 we can find one and NULL if we can't find a valid signer. */
643 SecCertificatePathRef SecOCSPResponseCopySigner(SecOCSPResponseRef this,
644 SecCertificatePathRef issuer) {
645 SecCertificateRef issuerCert = SecCertificatePathGetCertificateAtIndex(issuer, 0);
646 CFDataRef issuerSubject = SecCertificateGetNormalizedSubjectContent(issuerCert);
647 /* Look though any certs that came with the response and see if they were
648 both issued by the issuerPath and signed the response. */
649 SecAsn1Item **certs;
650 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
651 SecCertificateRef cert = SecCertificateCreateWithBytes(
652 kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
653 if (cert) {
654 CFDataRef certIssuer = SecCertificateGetNormalizedIssuerContent(cert);
655 if (certIssuer && CFEqual(issuerSubject, certIssuer)) {
656 SecCertificatePathRef signer = SecCertificatePathCopyAddingLeaf(issuer, cert);
657 CFRelease(cert);
658 if (signer) {
659 if (SecOCSPResponseIsIssuer(this, signer)) {
660 return signer;
661 } else {
662 ocspdErrorLog("ocsp response cert not signed by issuer.");
663 CFRelease(signer);
664 }
665 }
666 } else {
667 ocspdErrorLog("ocsp response cert issuer doesn't match issuer subject.");
668 }
669 } else {
670 ocspdErrorLog("ocsp response cert failed to parse");
671 }
672 }
673
674 /* If none of the returned certs work, try the issuer of the certificate
675 being checked directly. */
676 if (SecOCSPResponseIsIssuer(this, issuer)) {
677 CFRetain(issuer);
678 return issuer;
679 }
680
681 /* We couldn't find who signed this ocspResponse, give up. */
682 return NULL;
683 }