]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecOCSPResponse.c
Security-58286.41.2.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 secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now");
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 secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now");
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 secnotice("ocsp", "OCSPResponse: nextUpdate not present");
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 secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago");
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");
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");
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");
364 goto errOut;
365 }
366 if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
367 &OID_PKIX_OCSP_BASIC)) {
368 ocspdErrorLog("OCSPResponse: unknown responseType");
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");
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");
386 goto errOut;
387 }
388 this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
389 if (this->producedAt == NULL_TIME) {
390 ocspdErrorLog("OCSPResponse: bad producedAt");
391 goto errOut;
392 }
393
394 if (this->responseData.responderID.Data == NULL) {
395 ocspdErrorLog("OCSPResponse: bad responderID");
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");
414 goto errOut;
415 }
416 if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
417 &this->responderID)) {
418 ocspdErrorLog("OCSPResponse: decode failure at responderID");
419 goto errOut;
420 }
421
422 fini:
423 CFReleaseSafe(hexResp);
424 return this;
425 errOut:
426 secdebug("ocsp", "bad ocsp response: %@", hexResp);
427 CFReleaseSafe(hexResp);
428 if (this) {
429 SecOCSPResponseFinalize(this);
430 }
431 return NULL;
432 }
433
434 SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef this) {
435 return SecOCSPResponseCreateWithID(this, -1);
436 }
437
438 int64_t SecOCSPResponseGetID(SecOCSPResponseRef this) {
439 return this->responseID;
440 }
441
442 CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
443 return this->data;
444 }
445
446 SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
447 return this->responseStatus;
448 }
449
450 CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
451 return this->expireTime;
452 }
453
454 CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
455 return this->nonce;
456 }
457
458 CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
459 return this->producedAt;
460 }
461
462 CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
463 CFMutableArrayRef result = NULL;
464 result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
465 if (!result) {
466 return NULL;
467 }
468 SecAsn1Item **certs;
469 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
470 SecCertificateRef cert = NULL;
471 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
472 if (cert) {
473 CFArrayAppendValue(result, cert);
474 CFReleaseNull(cert);
475 }
476 }
477
478 return result;
479 }
480
481 void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
482 CFReleaseSafe(this->data);
483 CFReleaseSafe(this->nonce);
484 SecAsn1CoderRelease(this->coder);
485 free(this);
486 }
487
488 static CFAbsoluteTime SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL) {
489 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
490 responder is indicating that newer revocation information
491 is available all the time".
492 Let's ensure that thisUpdate isn't more than defaultTTL in
493 the past then. */
494 return this->nextUpdate == NULL_TIME ? this->thisUpdate + defaultTTL : this->nextUpdate;
495 }
496
497 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) {
498 if (this->thisUpdate > verifyTime + LEEWAY) {
499 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
500 return false;
501 }
502
503 CFAbsoluteTime cnu = SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL);
504 if (verifyTime - LEEWAY > cnu) {
505 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate ? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime - cnu) / 86400);
506 return false;
507 }
508
509 return true;
510 }
511
512 CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this)
513 {
514 return CFRetainSafe(this->scts);
515 }
516
517
518 SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
519 SecOCSPResponseRef this, SecOCSPRequestRef request) {
520 SecOCSPSingleResponseRef sr = NULL;
521
522 if (!request) { return sr; }
523 CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
524 const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
525 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
526 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate, NULL);
527 #else
528 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
529 #endif
530 CFDataRef issuerNameHash = NULL;
531 CFDataRef issuerPubKeyHash = NULL;
532 SecAsn1Oid *algorithm = NULL;
533 SecAsn1Item *parameters = NULL;
534
535 SecAsn1OCSPSingleResponse **responses;
536 for (responses = this->responseData.responses; *responses; ++responses) {
537 SecAsn1OCSPSingleResponse *resp = *responses;
538 SecAsn1OCSPCertID *certId = &resp->certID;
539 /* First check the easy part, serial number should match. */
540 if (!serial || certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
541 memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
542 certId->serialNumber.Length)) {
543 /* Serial # mismatch, skip this singleResponse. */
544 continue;
545 }
546
547 /* Calcluate the issuerKey and issuerName digests using the
548 hashAlgorithm and parameters specified in the certId, if
549 they differ from the ones we already computed. */
550 if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
551 !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
552 algorithm = &certId->algId.algorithm;
553 parameters = &certId->algId.parameters;
554 CFReleaseSafe(issuerNameHash);
555 CFReleaseSafe(issuerPubKeyHash);
556 issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
557 parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
558 issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
559 parameters, publicKey->data, publicKey->length);
560 }
561
562 if (!issuerNameHash || !issuerPubKeyHash) {
563 /* This can happen when the hash algorithm is not supported, should be really rare */
564 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
565 ocspdErrorLog("Unknown hash algorithm in singleResponse");
566 algorithm = NULL;
567 parameters = NULL;
568 continue;
569 }
570
571 if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
572 && !memcmp(CFDataGetBytePtr(issuerNameHash),
573 certId->issuerNameHash.Data, certId->issuerNameHash.Length)
574 && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
575 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
576 certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
577
578 /* resp matches the certificate in request, so let's use it. */
579 sr = SecOCSPSingleResponseCreate(resp, this->coder);
580 if (sr) {
581 ocspdDebug("found matching singleResponse");
582 break;
583 }
584 }
585
586 }
587
588 CFReleaseSafe(issuerPubKeyHash);
589 CFReleaseSafe(issuerNameHash);
590 CFReleaseSafe(serial);
591 CFReleaseSafe(issuer);
592
593 if (!sr) {
594 ocspdDebug("certID not found");
595 }
596
597 return sr;
598 }
599
600 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
601 SecKeyRef key) {
602 /* Beware this->basicResponse.sig: on decode, length is in BITS */
603 return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
604 this->basicResponse.tbsResponseData.Data,
605 this->basicResponse.tbsResponseData.Length,
606 this->basicResponse.sig.Data,
607 this->basicResponse.sig.Length / 8) == errSecSuccess;
608 }
609
610 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
611 SecCertificateRef issuer) {
612 bool shouldBeSigner = false;
613 if (this->responderIdTag == RIT_Name) {
614 /* Name inside response must == signer's SubjectName. */
615 CFDataRef subject = SecCertificateCopySubjectSequence(issuer);
616 if (!subject) {
617 ocspdDebug("error on SecCertificateCopySubjectSequence");
618 return false;
619 }
620 if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
621 !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
622 this->responderID.byName.Length)) {
623 ocspdDebug("good ResponderID.byName");
624 shouldBeSigner = true;
625 } else {
626 ocspdDebug("BAD ResponderID.byName");
627 }
628 CFRelease(subject);
629 } else /* if (this->responderIdTag == RIT_Key) */ {
630 /* ResponderID.byKey must == SHA1(signer's public key) */
631 CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(issuer);
632 if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
633 !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
634 this->responderID.byKey.Length)) {
635 ocspdDebug("good ResponderID.byKey");
636 shouldBeSigner = true;
637 } else {
638 ocspdDebug("BAD ResponderID.byKey");
639 }
640 CFRelease(pubKeyDigest);
641 }
642
643 if (shouldBeSigner) {
644 #if TARGET_OS_IPHONE
645 SecKeyRef key = SecCertificateCopyPublicKey(issuer);
646 #else
647 SecKeyRef key = SecCertificateCopyPublicKey_ios(issuer);
648 #endif
649 if (key) {
650 shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
651 ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
652 CFRelease(key);
653 } else {
654 ocspdDebug("Failed to extract key from leaf certificate");
655 shouldBeSigner = false;
656 }
657 }
658
659 return shouldBeSigner;
660 }
661
662 /* Returns the SecCertificateRef of the cert that signed this ocspResponse if
663 we can find one and NULL if we can't find a valid signer. */
664 SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, SecCertificateRef issuer) {
665 /* Look though any certs that came with the response to find
666 * which one signed the response. */
667 SecAsn1Item **certs;
668 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
669 SecCertificateRef cert = SecCertificateCreateWithBytes(
670 kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
671 if (cert) {
672 if (SecOCSPResponseIsIssuer(this, cert)) {
673 return cert;
674 } else {
675 CFRelease(cert);
676 }
677 } else {
678 ocspdErrorLog("ocsp response cert failed to parse");
679 }
680 }
681 ocspdDebug("ocsp response did not contain a signer cert.");
682
683 /* If none of the returned certs work, try the issuer of the certificate
684 being checked directly. */
685 if (issuer && SecOCSPResponseIsIssuer(this, issuer)) {
686 CFRetain(issuer);
687 return issuer;
688 }
689
690 /* We couldn't find who signed this ocspResponse, give up. */
691 return NULL;
692 }