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