]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecOCSPResponse.c
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / sec / securityd / SecOCSPResponse.c
1 /*
2 * Copyright (c) 2008-2009,2012-2016 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 CFReleaseSafe(this->scts);
126 free(this);
127 }
128
129 static SecOCSPSingleResponseRef SecOCSPSingleResponseCreate(
130 SecAsn1OCSPSingleResponse *resp, SecAsn1CoderRef coder) {
131 assert(resp != NULL);
132 SecOCSPSingleResponseRef this;
133 require(this = (SecOCSPSingleResponseRef)
134 calloc(1, sizeof(struct __SecOCSPSingleResponse)), errOut);
135 this->certStatus = CS_NotParsed;
136 this->thisUpdate = NULL_TIME;
137 this->nextUpdate = NULL_TIME;
138 this->revokedTime = NULL_TIME;
139 this->crlReason = kSecRevocationReasonUndetermined;
140 this->scts = NULL;
141
142 if ((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
143 ocspdErrorLog("OCSPSingleResponse: bad certStatus");
144 goto errOut;
145 }
146 this->certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
147 if (this->certStatus == CS_Revoked) {
148 /* Decode further to get SecAsn1OCSPRevokedInfo */
149 SecAsn1OCSPCertStatus certStatus;
150 memset(&certStatus, 0, sizeof(certStatus));
151 if (SecAsn1DecodeData(coder, &resp->certStatus,
152 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
153 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus");
154 goto errOut;
155 }
156 SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo;
157 if (revokedInfo != NULL) {
158 /* Treat this as optional even for CS_Revoked */
159 this->revokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime);
160 const SecAsn1Item *revReason = revokedInfo->revocationReason;
161 if((revReason != NULL) &&
162 (revReason->Data != NULL) &&
163 (revReason->Length != 0)) {
164 this->crlReason = revReason->Data[0];
165 }
166 }
167 }
168 this->thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
169 if (this->thisUpdate == NULL_TIME) {
170 ocspdErrorLog("OCSPResponse: bad thisUpdate DER");
171 goto errOut;
172 }
173
174 if (resp->nextUpdate != NULL) {
175 this->nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
176 if (this->nextUpdate == NULL_TIME) {
177 ocspdErrorLog("OCSPResponse: bad nextUpdate DER");
178 goto errOut;
179 }
180 }
181
182 /* Lookup through extensions to find SCTs */
183 if(resp->singleExtensions) {
184 ocspdErrorLog("OCSPResponse: single response has extension(s).");
185 int i = 0;
186 NSS_CertExtension *extn;
187 while ((extn = resp->singleExtensions[i])) {
188 if(SecAsn1OidCompare(&extn->extnId, &OID_GOOGLE_OCSP_SCT )) {
189 ocspdErrorLog("OCSPResponse: single response has an SCT extension.");
190 SecAsn1Item sct_data = {0,};
191
192 // Note: if there are more that one valid SCT extension, we just use the first one that successfully decoded
193 if((this->scts == NULL) && (SecAsn1DecodeData(coder, &extn->value, kSecAsn1OctetStringTemplate, &sct_data) == 0)) {
194 this->scts = SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sct_data.Data, sct_data.Length);
195 ocspdErrorLog("OCSPResponse: single response has an SCT extension, parsed = %p.", this->scts);
196 }
197 }
198 i++;
199 }
200 }
201
202 ocspdDebug("status %d reason %d", (int)this->certStatus,
203 (int)this->crlReason);
204 return this;
205 errOut:
206 if (this)
207 SecOCSPSingleResponseDestroy(this);
208 return NULL;
209 }
210
211 #define LEEWAY (4500.0)
212
213 /* Calculate temporal validity; set latestNextUpdate and expireTime.
214 Returns true if valid, else returns false. */
215 bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this,
216 CFTimeInterval maxAge, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime)
217 {
218 bool ok = false;
219 this->latestNextUpdate = NULL_TIME;
220 CFStringRef hexResp = CFDataCopyHexString(this->data);
221
222 if (this->producedAt > verifyTime + LEEWAY) {
223 ocspdErrorLog("OCSPResponse: producedAt more than 1:15 from now %@", hexResp);
224 goto exit;
225 }
226
227 /* Make this->latestNextUpdate be the date farthest in the future
228 of any of the singleResponses nextUpdate fields. */
229 SecAsn1OCSPSingleResponse **responses;
230 for (responses = this->responseData.responses; *responses; ++responses) {
231 SecAsn1OCSPSingleResponse *resp = *responses;
232
233 /* thisUpdate later than 'now' invalidates the whole response. */
234 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
235 if (thisUpdate > verifyTime + LEEWAY) {
236 ocspdErrorLog("OCSPResponse: thisUpdate more than 1:15 from now %@", hexResp);
237 goto exit;
238 }
239
240 /* Keep track of latest nextUpdate. */
241 if (resp->nextUpdate != NULL) {
242 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
243 if (nextUpdate > this->latestNextUpdate) {
244 this->latestNextUpdate = nextUpdate;
245 }
246 }
247 else {
248 /* RFC 5019 section 2.2.4 states on nextUpdate:
249 Responders MUST always include this value to aid in
250 response caching. See Section 6 for additional
251 information on caching.
252 */
253 ocspdErrorLog("OCSPResponse: nextUpdate not present %@", hexResp);
254 #ifdef STRICT_RFC5019
255 goto exit;
256 #endif
257 }
258 }
259
260 /* Now that we have this->latestNextUpdate, we figure out the latest
261 date at which we will expire this response from our cache. To comply
262 with rfc5019s:
263
264 6.1. Caching at the Client
265
266 To minimize bandwidth usage, clients MUST locally cache authoritative
267 OCSP responses (i.e., a response with a signature that has been
268 successfully validated and that indicate an OCSPResponseStatus of
269 'successful').
270
271 Most OCSP clients will send OCSPRequests at or near the nextUpdate
272 time (when a cached response expires). To avoid large spikes in
273 responder load that might occur when many clients refresh cached
274 responses for a popular certificate, responders MAY indicate when the
275 client should fetch an updated OCSP response by using the cache-
276 control:max-age directive. Clients SHOULD fetch the updated OCSP
277 Response on or after the max-age time. To ensure that clients
278 receive an updated OCSP response, OCSP responders MUST refresh the
279 OCSP response before the max-age time.
280
281 6.2 [...]
282
283 we need to take the cache-control:max-age directive into account.
284
285 The way the code below is written we ignore a max-age=0 in the
286 http header. Since a value of 0 (NULL_TIME) also means there
287 was no max-age in the header. This seems ok since that would imply
288 no-cache so we also ignore negative values for the same reason,
289 instead we'll expire whenever this->latestNextUpdate tells us to,
290 which is the signed value if max-age is too low, since we don't
291 want to refetch multilple times for a single page load in a browser. */
292 if (this->latestNextUpdate == NULL_TIME) {
293 /* See comment above on RFC 5019 section 2.2.4. */
294 /* Absolute expire time = current time plus defaultTTL */
295 this->expireTime = verifyTime + defaultTTL;
296 } else if (this->latestNextUpdate < verifyTime - LEEWAY) {
297 ocspdErrorLog("OCSPResponse: latestNextUpdate more than 1:15 ago %@", hexResp);
298 goto exit;
299 } else if (maxAge > 0) {
300 /* Beware of double overflows such as:
301
302 now + maxAge < this->latestNextUpdate
303
304 in the math below since an attacker could create any positive
305 value for maxAge. */
306 if (maxAge < this->latestNextUpdate - verifyTime) {
307 /* maxAge header wants us to expire the cache entry sooner than
308 nextUpdate would allow, to balance server load. */
309 this->expireTime = verifyTime + maxAge;
310 } else {
311 /* maxAge http header attempting to make us cache the response
312 longer than it's valid for, bad http header! Ignoring you. */
313 ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate,"
314 " using latestNextUpdate %@", hexResp);
315 this->expireTime = this->latestNextUpdate;
316 }
317 } else {
318 /* No maxAge provided, just use latestNextUpdate. */
319 this->expireTime = this->latestNextUpdate;
320 }
321
322 ok = true;
323 exit:
324 CFReleaseSafe(hexResp);
325 return ok;
326 }
327
328 SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID) {
329 CFStringRef hexResp = CFDataCopyHexString(ocspResponse);
330 SecAsn1OCSPResponse topResp = {};
331 SecOCSPResponseRef this;
332
333 require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)),
334 errOut);
335 require_noerr(SecAsn1CoderCreate(&this->coder), errOut);
336
337 this->data = ocspResponse;
338 this->responseID = responseID;
339 CFRetain(ocspResponse);
340
341 SecAsn1Item resp;
342 resp.Length = CFDataGetLength(ocspResponse);
343 resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse);
344 if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate,
345 &topResp)) {
346 ocspdErrorLog("OCSPResponse: decode failure at top level %@", hexResp);
347 }
348 /* remainder is valid only on RS_Success */
349 if ((topResp.responseStatus.Data == NULL) ||
350 (topResp.responseStatus.Length == 0)) {
351 ocspdErrorLog("OCSPResponse: no responseStatus %@", hexResp);
352 goto errOut;
353 }
354 this->responseStatus = topResp.responseStatus.Data[0];
355 if (this->responseStatus != kSecOCSPSuccess) {
356 secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus, hexResp);
357 /* not a failure of our constructor; this object is now useful, but
358 * only for this one byte of status info */
359 goto fini;
360 }
361 if (topResp.responseBytes == NULL) {
362 /* I don't see how this can be legal on RS_Success */
363 ocspdErrorLog("OCSPResponse: empty responseBytes %@", hexResp);
364 goto errOut;
365 }
366 if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
367 &OID_PKIX_OCSP_BASIC)) {
368 ocspdErrorLog("OCSPResponse: unknown responseType %@", hexResp);
369 goto errOut;
370
371 }
372
373 /* decode the SecAsn1OCSPBasicResponse */
374 if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response,
375 kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) {
376 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse %@", hexResp);
377 goto errOut;
378 }
379
380 /* signature and cert evaluation done externally */
381
382 /* decode the SecAsn1OCSPResponseData */
383 if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData,
384 kSecAsn1OCSPResponseDataTemplate, &this->responseData)) {
385 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData %@", hexResp);
386 goto errOut;
387 }
388 this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
389 if (this->producedAt == NULL_TIME) {
390 ocspdErrorLog("OCSPResponse: bad producedAt %@", hexResp);
391 goto errOut;
392 }
393
394 if (this->responseData.responderID.Data == NULL) {
395 ocspdErrorLog("OCSPResponse: bad responderID %@", hexResp);
396 goto errOut;
397 }
398
399 /* Choice processing for ResponderID */
400 this->responderIdTag = (SecAsn1OCSPResponderIDTag)
401 (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
402 const SecAsn1Template *templ;
403 switch(this->responderIdTag) {
404 case RIT_Name:
405 /* @@@ Since we don't use the decoded byName value we could skip
406 decoding it but we do it anyway for validation. */
407 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
408 break;
409 case RIT_Key:
410 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
411 break;
412 default:
413 ocspdErrorLog("OCSPResponse: bad responderID tag %@", hexResp);
414 goto errOut;
415 }
416 if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
417 &this->responderID)) {
418 ocspdErrorLog("OCSPResponse: decode failure at responderID %@", hexResp);
419 goto errOut;
420 }
421
422 fini:
423 CFReleaseSafe(hexResp);
424 return this;
425 errOut:
426 CFReleaseSafe(hexResp);
427 if (this) {
428 SecOCSPResponseFinalize(this);
429 }
430 return NULL;
431 }
432
433 SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef this) {
434 return SecOCSPResponseCreateWithID(this, -1);
435 }
436
437 int64_t SecOCSPResponseGetID(SecOCSPResponseRef this) {
438 return this->responseID;
439 }
440
441 CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
442 return this->data;
443 }
444
445 SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
446 return this->responseStatus;
447 }
448
449 CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
450 return this->expireTime;
451 }
452
453 CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
454 return this->nonce;
455 }
456
457 CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
458 return this->producedAt;
459 }
460
461 CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
462 CFMutableArrayRef result = NULL;
463 result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
464 if (!result) {
465 return NULL;
466 }
467 SecAsn1Item **certs;
468 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
469 SecCertificateRef cert = NULL;
470 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
471 if (cert) {
472 CFArrayAppendValue(result, cert);
473 CFReleaseNull(cert);
474 }
475 }
476
477 return result;
478 }
479
480 void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
481 CFReleaseSafe(this->data);
482 CFReleaseSafe(this->nonce);
483 SecAsn1CoderRelease(this->coder);
484 free(this);
485 }
486
487 static CFAbsoluteTime SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL) {
488 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
489 responder is indicating that newer revocation information
490 is available all the time".
491 Let's ensure that thisUpdate isn't more than defaultTTL in
492 the past then. */
493 return this->nextUpdate == NULL_TIME ? this->thisUpdate + defaultTTL : this->nextUpdate;
494 }
495
496 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) {
497 if (this->thisUpdate > verifyTime + LEEWAY) {
498 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
499 return false;
500 }
501
502 CFAbsoluteTime cnu = SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL);
503 if (verifyTime - LEEWAY > cnu) {
504 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate ? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime - cnu) / 86400);
505 return false;
506 }
507
508 return true;
509 }
510
511 CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this)
512 {
513 return CFRetainSafe(this->scts);
514 }
515
516
517 SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
518 SecOCSPResponseRef this, SecOCSPRequestRef request) {
519 SecOCSPSingleResponseRef sr = NULL;
520
521 CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
522 const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
523 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
524 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate, NULL);
525 #else
526 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
527 #endif
528 CFDataRef issuerNameHash = NULL;
529 CFDataRef issuerPubKeyHash = NULL;
530 SecAsn1Oid *algorithm = NULL;
531 SecAsn1Item *parameters = NULL;
532
533 SecAsn1OCSPSingleResponse **responses;
534 for (responses = this->responseData.responses; *responses; ++responses) {
535 SecAsn1OCSPSingleResponse *resp = *responses;
536 SecAsn1OCSPCertID *certId = &resp->certID;
537 /* First check the easy part, serial number should match. */
538 if (certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
539 memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
540 certId->serialNumber.Length)) {
541 /* Serial # mismatch, skip this singleResponse. */
542 continue;
543 }
544
545 /* Calcluate the issuerKey and issuerName digests using the
546 hashAlgorithm and parameters specified in the certId, if
547 they differ from the ones we already computed. */
548 if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
549 !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
550 algorithm = &certId->algId.algorithm;
551 parameters = &certId->algId.parameters;
552 CFReleaseSafe(issuerNameHash);
553 CFReleaseSafe(issuerPubKeyHash);
554 issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
555 parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
556 issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
557 parameters, publicKey->data, publicKey->length);
558 }
559
560 if (!issuerNameHash || !issuerPubKeyHash) {
561 /* This can happen when the hash algorithm is not supported, should be really rare */
562 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
563 ocspdErrorLog("Unknown hash algorithm in singleResponse");
564 algorithm = NULL;
565 parameters = NULL;
566 continue;
567 }
568
569 if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
570 && !memcmp(CFDataGetBytePtr(issuerNameHash),
571 certId->issuerNameHash.Data, certId->issuerNameHash.Length)
572 && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
573 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
574 certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
575
576 /* resp matches the certificate in request, so let's use it. */
577 sr = SecOCSPSingleResponseCreate(resp, this->coder);
578 if (sr) {
579 ocspdDebug("found matching singleResponse");
580 break;
581 }
582 }
583
584 }
585
586 CFReleaseSafe(issuerPubKeyHash);
587 CFReleaseSafe(issuerNameHash);
588 CFReleaseSafe(serial);
589 CFReleaseSafe(issuer);
590
591 if (!sr) {
592 ocspdDebug("certID not found");
593 }
594
595 return sr;
596 }
597
598 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
599 SecKeyRef key) {
600 /* Beware this->basicResponse.sig: on decode, length is in BITS */
601 return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
602 this->basicResponse.tbsResponseData.Data,
603 this->basicResponse.tbsResponseData.Length,
604 this->basicResponse.sig.Data,
605 this->basicResponse.sig.Length / 8) == errSecSuccess;
606 }
607
608 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
609 SecCertificateRef issuer) {
610 bool shouldBeSigner = false;
611 if (this->responderIdTag == RIT_Name) {
612 /* Name inside response must == signer's SubjectName. */
613 CFDataRef subject = SecCertificateCopySubjectSequence(issuer);
614 if (!subject) {
615 ocspdDebug("error on SecCertificateCopySubjectSequence");
616 return false;
617 }
618 if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
619 !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
620 this->responderID.byName.Length)) {
621 ocspdDebug("good ResponderID.byName");
622 shouldBeSigner = true;
623 } else {
624 ocspdDebug("BAD ResponderID.byName");
625 }
626 CFRelease(subject);
627 } else /* if (this->responderIdTag == RIT_Key) */ {
628 /* ResponderID.byKey must == SHA1(signer's public key) */
629 CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(issuer);
630 if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
631 !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
632 this->responderID.byKey.Length)) {
633 ocspdDebug("good ResponderID.byKey");
634 shouldBeSigner = true;
635 } else {
636 ocspdDebug("BAD ResponderID.byKey");
637 }
638 CFRelease(pubKeyDigest);
639 }
640
641 if (shouldBeSigner) {
642 #if TARGET_OS_IPHONE
643 SecKeyRef key = SecCertificateCopyPublicKey(issuer);
644 #else
645 SecKeyRef key = SecCertificateCopyPublicKey_ios(issuer);
646 #endif
647 if (key) {
648 shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
649 ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
650 CFRelease(key);
651 } else {
652 ocspdDebug("Failed to extract key from leaf certificate");
653 shouldBeSigner = false;
654 }
655 }
656
657 return shouldBeSigner;
658 }
659
660 /* Returns the SecCertificateRef of the cert that signed this ocspResponse if
661 we can find one and NULL if we can't find a valid signer. */
662 SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, SecCertificateRef issuer) {
663 /* Look though any certs that came with the response to find
664 * which one signed the response. */
665 SecAsn1Item **certs;
666 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
667 SecCertificateRef cert = SecCertificateCreateWithBytes(
668 kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
669 if (cert) {
670 if (SecOCSPResponseIsIssuer(this, cert)) {
671 return cert;
672 } else {
673 CFRelease(cert);
674 }
675 } else {
676 ocspdErrorLog("ocsp response cert failed to parse");
677 }
678 }
679 ocspdDebug("ocsp response did not contain a signer cert.");
680
681 /* If none of the returned certs work, try the issuer of the certificate
682 being checked directly. */
683 if (issuer && SecOCSPResponseIsIssuer(this, issuer)) {
684 CFRetain(issuer);
685 return issuer;
686 }
687
688 /* We couldn't find who signed this ocspResponse, give up. */
689 return NULL;
690 }