]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecOCSPResponse.c
ba5634d99dc559c17164e4913022f81ccf5b6d2c
[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
221 if (this->producedAt > verifyTime + LEEWAY) {
222 secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now");
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 secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now");
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 secnotice("ocsp", "OCSPResponse: nextUpdate not present");
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 secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago");
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 #ifdef DEBUG
313 CFStringRef hexResp = CFDataCopyHexString(this->data);
314 ocspdDebug("OCSPResponse: now + maxAge > latestNextUpdate,"
315 " using latestNextUpdate %@", hexResp);
316 CFReleaseSafe(hexResp);
317 #endif
318 this->expireTime = this->latestNextUpdate;
319 }
320 } else {
321 /* No maxAge provided, just use latestNextUpdate. */
322 this->expireTime = this->latestNextUpdate;
323 }
324
325 ok = true;
326 exit:
327 return ok;
328 }
329
330 SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t responseID) {
331 SecAsn1OCSPResponse topResp = {};
332 SecOCSPResponseRef this;
333
334 require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)),
335 errOut);
336 require_noerr(SecAsn1CoderCreate(&this->coder), errOut);
337
338 this->data = ocspResponse;
339 this->responseID = responseID;
340 CFRetain(ocspResponse);
341
342 SecAsn1Item resp;
343 resp.Length = CFDataGetLength(ocspResponse);
344 resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse);
345 if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate,
346 &topResp)) {
347 ocspdErrorLog("OCSPResponse: decode failure at top level");
348 }
349 /* remainder is valid only on RS_Success */
350 if ((topResp.responseStatus.Data == NULL) ||
351 (topResp.responseStatus.Length == 0)) {
352 ocspdErrorLog("OCSPResponse: no responseStatus");
353 goto errOut;
354 }
355 this->responseStatus = topResp.responseStatus.Data[0];
356 if (this->responseStatus != kSecOCSPSuccess) {
357 #ifdef DEBUG
358 CFStringRef hexResp = CFDataCopyHexString(this->data);
359 secdebug("ocsp", "OCSPResponse: status: %d %@", this->responseStatus, hexResp);
360 CFReleaseNull(hexResp);
361 #endif
362 /* not a failure of our constructor; this object is now useful, but
363 * only for this one byte of status info */
364 goto fini;
365 }
366 if (topResp.responseBytes == NULL) {
367 /* I don't see how this can be legal on RS_Success */
368 ocspdErrorLog("OCSPResponse: empty responseBytes");
369 goto errOut;
370 }
371 if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
372 &OID_PKIX_OCSP_BASIC)) {
373 ocspdErrorLog("OCSPResponse: unknown responseType");
374 goto errOut;
375
376 }
377
378 /* decode the SecAsn1OCSPBasicResponse */
379 if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response,
380 kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) {
381 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse");
382 goto errOut;
383 }
384
385 /* signature and cert evaluation done externally */
386
387 /* decode the SecAsn1OCSPResponseData */
388 if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData,
389 kSecAsn1OCSPResponseDataTemplate, &this->responseData)) {
390 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData");
391 goto errOut;
392 }
393 this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
394 if (this->producedAt == NULL_TIME) {
395 ocspdErrorLog("OCSPResponse: bad producedAt");
396 goto errOut;
397 }
398
399 if (this->responseData.responderID.Data == NULL) {
400 ocspdErrorLog("OCSPResponse: bad responderID");
401 goto errOut;
402 }
403
404 /* Choice processing for ResponderID */
405 this->responderIdTag = (SecAsn1OCSPResponderIDTag)
406 (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
407 const SecAsn1Template *templ;
408 switch(this->responderIdTag) {
409 case RIT_Name:
410 /* @@@ Since we don't use the decoded byName value we could skip
411 decoding it but we do it anyway for validation. */
412 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
413 break;
414 case RIT_Key:
415 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
416 break;
417 default:
418 ocspdErrorLog("OCSPResponse: bad responderID tag");
419 goto errOut;
420 }
421 if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
422 &this->responderID)) {
423 ocspdErrorLog("OCSPResponse: decode failure at responderID");
424 goto errOut;
425 }
426
427 fini:
428 return this;
429 errOut:
430 #ifdef DEBUG
431 {
432 CFStringRef hexResp = CFDataCopyHexString(this->data);
433 secdebug("ocsp", "bad ocsp response: %@", hexResp);
434 CFReleaseSafe(hexResp);
435 }
436 #endif
437 if (this) {
438 SecOCSPResponseFinalize(this);
439 }
440 return NULL;
441 }
442
443 SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef this) {
444 return SecOCSPResponseCreateWithID(this, -1);
445 }
446
447 int64_t SecOCSPResponseGetID(SecOCSPResponseRef this) {
448 return this->responseID;
449 }
450
451 CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
452 return this->data;
453 }
454
455 SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
456 return this->responseStatus;
457 }
458
459 CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
460 return this->expireTime;
461 }
462
463 CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
464 return this->nonce;
465 }
466
467 CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
468 return this->producedAt;
469 }
470
471 CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
472 CFMutableArrayRef result = NULL;
473 result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
474 if (!result) {
475 return NULL;
476 }
477 SecAsn1Item **certs;
478 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
479 SecCertificateRef cert = NULL;
480 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
481 if (cert) {
482 CFArrayAppendValue(result, cert);
483 CFReleaseNull(cert);
484 }
485 }
486
487 return result;
488 }
489
490 void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
491 CFReleaseSafe(this->data);
492 CFReleaseSafe(this->nonce);
493 SecAsn1CoderRelease(this->coder);
494 free(this);
495 }
496
497 static CFAbsoluteTime SecOCSPSingleResponseComputedNextUpdate(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL) {
498 /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
499 responder is indicating that newer revocation information
500 is available all the time".
501 Let's ensure that thisUpdate isn't more than defaultTTL in
502 the past then. */
503 return this->nextUpdate == NULL_TIME ? this->thisUpdate + defaultTTL : this->nextUpdate;
504 }
505
506 bool SecOCSPSingleResponseCalculateValidity(SecOCSPSingleResponseRef this, CFTimeInterval defaultTTL, CFAbsoluteTime verifyTime) {
507 if (this->thisUpdate > verifyTime + LEEWAY) {
508 ocspdErrorLog("OCSPSingleResponse: thisUpdate more than 1:15 from now");
509 return false;
510 }
511
512 CFAbsoluteTime cnu = SecOCSPSingleResponseComputedNextUpdate(this, defaultTTL);
513 if (verifyTime - LEEWAY > cnu) {
514 ocspdErrorLog("OCSPSingleResponse: %s %.2f days ago", this->nextUpdate ? "nextUpdate" : "thisUpdate + defaultTTL", (verifyTime - cnu) / 86400);
515 return false;
516 }
517
518 return true;
519 }
520
521 CFArrayRef SecOCSPSingleResponseCopySCTs(SecOCSPSingleResponseRef this)
522 {
523 return CFRetainSafe(this->scts);
524 }
525
526
527 SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
528 SecOCSPResponseRef this, SecOCSPRequestRef request) {
529 SecOCSPSingleResponseRef sr = NULL;
530
531 if (!request) { return sr; }
532 CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
533 const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
534 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
535 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate, NULL);
536 #else
537 CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
538 #endif
539 CFDataRef issuerNameHash = NULL;
540 CFDataRef issuerPubKeyHash = NULL;
541 SecAsn1Oid *algorithm = NULL;
542 SecAsn1Item *parameters = NULL;
543
544 SecAsn1OCSPSingleResponse **responses;
545 for (responses = this->responseData.responses; *responses; ++responses) {
546 SecAsn1OCSPSingleResponse *resp = *responses;
547 SecAsn1OCSPCertID *certId = &resp->certID;
548 /* First check the easy part, serial number should match. */
549 if (!serial || certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
550 memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
551 certId->serialNumber.Length)) {
552 /* Serial # mismatch, skip this singleResponse. */
553 continue;
554 }
555
556 /* Calcluate the issuerKey and issuerName digests using the
557 hashAlgorithm and parameters specified in the certId, if
558 they differ from the ones we already computed. */
559 if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
560 !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
561 algorithm = &certId->algId.algorithm;
562 parameters = &certId->algId.parameters;
563 CFReleaseSafe(issuerNameHash);
564 CFReleaseSafe(issuerPubKeyHash);
565 issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
566 parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
567 issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
568 parameters, publicKey->data, publicKey->length);
569 }
570
571 if (!issuerNameHash || !issuerPubKeyHash) {
572 /* This can happen when the hash algorithm is not supported, should be really rare */
573 /* See also: <rdar://problem/21908655> CrashTracer: securityd at securityd: SecOCSPResponseCopySingleResponse */
574 ocspdErrorLog("Unknown hash algorithm in singleResponse");
575 algorithm = NULL;
576 parameters = NULL;
577 continue;
578 }
579
580 if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
581 && !memcmp(CFDataGetBytePtr(issuerNameHash),
582 certId->issuerNameHash.Data, certId->issuerNameHash.Length)
583 && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
584 && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
585 certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
586
587 /* resp matches the certificate in request, so let's use it. */
588 sr = SecOCSPSingleResponseCreate(resp, this->coder);
589 if (sr) {
590 ocspdDebug("found matching singleResponse");
591 break;
592 }
593 }
594
595 }
596
597 CFReleaseSafe(issuerPubKeyHash);
598 CFReleaseSafe(issuerNameHash);
599 CFReleaseSafe(serial);
600 CFReleaseSafe(issuer);
601
602 if (!sr) {
603 ocspdDebug("certID not found");
604 }
605
606 return sr;
607 }
608
609 static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
610 SecKeyRef key) {
611 /* Beware this->basicResponse.sig: on decode, length is in BITS */
612 return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
613 this->basicResponse.tbsResponseData.Data,
614 this->basicResponse.tbsResponseData.Length,
615 this->basicResponse.sig.Data,
616 this->basicResponse.sig.Length / 8) == errSecSuccess;
617 }
618
619 static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
620 SecCertificateRef issuer) {
621 bool shouldBeSigner = false;
622 if (this->responderIdTag == RIT_Name) {
623 /* Name inside response must == signer's SubjectName. */
624 CFDataRef subject = SecCertificateCopySubjectSequence(issuer);
625 if (!subject) {
626 ocspdDebug("error on SecCertificateCopySubjectSequence");
627 return false;
628 }
629 if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
630 !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
631 this->responderID.byName.Length)) {
632 ocspdDebug("good ResponderID.byName");
633 shouldBeSigner = true;
634 } else {
635 ocspdDebug("BAD ResponderID.byName");
636 }
637 CFRelease(subject);
638 } else /* if (this->responderIdTag == RIT_Key) */ {
639 /* ResponderID.byKey must == SHA1(signer's public key) */
640 CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(issuer);
641 if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
642 !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
643 this->responderID.byKey.Length)) {
644 ocspdDebug("good ResponderID.byKey");
645 shouldBeSigner = true;
646 } else {
647 ocspdDebug("BAD ResponderID.byKey");
648 }
649 CFRelease(pubKeyDigest);
650 }
651
652 if (shouldBeSigner) {
653 #if TARGET_OS_IPHONE
654 SecKeyRef key = SecCertificateCopyPublicKey(issuer);
655 #else
656 SecKeyRef key = SecCertificateCopyPublicKey_ios(issuer);
657 #endif
658 if (key) {
659 shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
660 ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
661 CFRelease(key);
662 } else {
663 ocspdDebug("Failed to extract key from leaf certificate");
664 shouldBeSigner = false;
665 }
666 }
667
668 return shouldBeSigner;
669 }
670
671 /* Returns the SecCertificateRef of the cert that signed this ocspResponse if
672 we can find one and NULL if we can't find a valid signer. */
673 SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, SecCertificateRef issuer) {
674 /* Look though any certs that came with the response to find
675 * which one signed the response. */
676 SecAsn1Item **certs;
677 for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
678 SecCertificateRef cert = SecCertificateCreateWithBytes(
679 kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
680 if (cert) {
681 if (SecOCSPResponseIsIssuer(this, cert)) {
682 return cert;
683 } else {
684 CFRelease(cert);
685 }
686 } else {
687 ocspdErrorLog("ocsp response cert failed to parse");
688 }
689 }
690 ocspdDebug("ocsp response did not contain a signer cert.");
691
692 /* If none of the returned certs work, try the issuer of the certificate
693 being checked directly. */
694 if (issuer && SecOCSPResponseIsIssuer(this, issuer)) {
695 CFRetain(issuer);
696 return issuer;
697 }
698
699 /* We couldn't find who signed this ocspResponse, give up. */
700 return NULL;
701 }