]> git.saurik.com Git - apple/security.git/blobdiff - sec/securityd/SecOCSPResponse.c
Security-57031.1.35.tar.gz
[apple/security.git] / sec / securityd / SecOCSPResponse.c
diff --git a/sec/securityd/SecOCSPResponse.c b/sec/securityd/SecOCSPResponse.c
deleted file mode 100644 (file)
index 0bbf7c5..0000000
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * SecOCSPResponse.c - Wrapper to decode ocsp responses.
- */
-
-#include <securityd/SecOCSPResponse.h>
-#include <Security/SecCertificateInternal.h>
-#include <Security/SecFramework.h>
-#include <Security/SecKeyPriv.h>
-#include <AssertMacros.h>
-#include <utilities/debugging.h>
-#include <security_asn1/SecAsn1Coder.h>
-#include <security_asn1/ocspTemplates.h>
-#include <security_asn1/oidsalg.h>
-#include <security_asn1/oidsocsp.h>
-#include <CommonCrypto/CommonDigest.h>
-#include <asl.h>
-#include <stdlib.h>
-#include "SecInternal.h"
-
-#define ocspdErrorLog(args...)     asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args)
-#define ocspdHttpDebug(args...)     secdebug("ocspdHttp", ## args)
-#define ocspdDebug(args...)     secdebug("ocsp", ## args)
-
-
-/*
-   OCSPResponse ::= SEQUENCE {
-      responseStatus         OCSPResponseStatus,
-      responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
-
-   OCSPResponseStatus ::= ENUMERATED {
-       successful            (0),  --Response has valid confirmations
-       malformedRequest      (1),  --Illegal confirmation request
-       internalError         (2),  --Internal error in issuer
-       tryLater              (3),  --Try again later
-                                   --(4) is not used
-       sigRequired           (5),  --Must sign the request
-       unauthorized          (6)   --Request unauthorized
-   }
-
-   ResponseBytes ::=       SEQUENCE {
-       responseType   OBJECT IDENTIFIER,
-       response       OCTET STRING }
-
-   id-pkix-ocsp           OBJECT IDENTIFIER ::= { id-ad-ocsp }
-   id-pkix-ocsp-basic     OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
-
-   The value for response SHALL be the DER encoding of
-   BasicOCSPResponse.
-
-   BasicOCSPResponse       ::= SEQUENCE {
-      tbsResponseData      ResponseData,
-      signatureAlgorithm   AlgorithmIdentifier,
-      signature            BIT STRING,
-      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
-
-   The value for signature SHALL be computed on the hash of the DER
-   encoding ResponseData.
-
-   ResponseData ::= SEQUENCE {
-      version              [0] EXPLICIT Version DEFAULT v1,
-      responderID              ResponderID,
-      producedAt               GeneralizedTime,
-      responses                SEQUENCE OF SingleResponse,
-      responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
-
-   ResponderID ::= CHOICE {
-      byName               [1] Name,
-      byKey                [2] KeyHash }
-
-   KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
-   (excluding the tag and length fields)
-
-   SingleResponse ::= SEQUENCE {
-      certID                       CertID,
-      certStatus                   CertStatus,
-      thisUpdate                   GeneralizedTime,
-      nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
-      singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
-
-   CertStatus ::= CHOICE {
-       good        [0]     IMPLICIT NULL,
-       revoked     [1]     IMPLICIT RevokedInfo,
-       unknown     [2]     IMPLICIT UnknownInfo }
-
-   RevokedInfo ::= SEQUENCE {
-       revocationTime              GeneralizedTime,
-       revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
-
-   UnknownInfo ::= NULL -- this can be replaced with an enumeration
-*/
-
-static CFAbsoluteTime genTimeToCFAbsTime(const SecAsn1Item *datetime)
-{
-    return SecAbsoluteTimeFromDateContent(SEC_ASN1_GENERALIZED_TIME,
-        datetime->Data, datetime->Length);
-}
-
-void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this) {
-    free(this);
-}
-
-static SecOCSPSingleResponseRef SecOCSPSingleResponseCreate(
-    SecAsn1OCSPSingleResponse *resp, SecAsn1CoderRef coder) {
-       assert(resp != NULL);
-    SecOCSPSingleResponseRef this;
-    require(this = (SecOCSPSingleResponseRef)
-        malloc(sizeof(struct __SecOCSPSingleResponse)), errOut);
-    this->certStatus = CS_NotParsed;
-       this->thisUpdate = NULL_TIME;
-       this->nextUpdate = NULL_TIME;
-       this->revokedTime = NULL_TIME;
-       this->crlReason = kSecRevocationReasonUndetermined;
-       //this->extensions = NULL;
-
-       if ((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
-               ocspdErrorLog("OCSPSingleResponse: bad certStatus");
-        goto errOut;
-       }
-       this->certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
-       if (this->certStatus == CS_Revoked) {
-               /* Decode further to get SecAsn1OCSPRevokedInfo */
-               SecAsn1OCSPCertStatus certStatus;
-               memset(&certStatus, 0, sizeof(certStatus));
-               if (SecAsn1DecodeData(coder, &resp->certStatus,
-                               kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
-                       ocspdErrorLog("OCSPSingleResponse: err decoding certStatus");
-            goto errOut;
-               }
-               SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo;
-               if (revokedInfo != NULL) {
-                       /* Treat this as optional even for CS_Revoked */
-                       this->revokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime);
-                       const SecAsn1Item *revReason = revokedInfo->revocationReason;
-                       if((revReason != NULL) &&
-                          (revReason->Data != NULL) &&
-                          (revReason->Length != 0)) {
-                          this->crlReason = revReason->Data[0];
-                       }
-               }
-       }
-       this->thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
-       if (resp->nextUpdate != NULL) {
-               this->nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
-       }
-       //mExtensions = new OCSPExtensions(resp->singleExtensions);
-       ocspdDebug("status %d reason %d", (int)this->certStatus,
-               (int)this->crlReason);
-    return this;
-errOut:
-    if (this)
-        SecOCSPSingleResponseDestroy(this);
-    return NULL;
-}
-
-#define LEEWAY (4500.0)
-
-/* Calculate temporal validity; set latestNextUpdate and expireTime. Only
-   called from SecOCSPResponseCreate. Returns true if valid, else returns
-   false. */
-static bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this,
-    CFTimeInterval maxAge, CFTimeInterval defaultTTL)
-{
-       this->latestNextUpdate = NULL_TIME;
-       CFAbsoluteTime now = this->verifyTime = CFAbsoluteTimeGetCurrent();
-
-    if (this->producedAt > now + LEEWAY) {
-        ocspdErrorLog("OCSPResponse: producedAt more than 1:15 from now");
-        return false;
-    }
-
-    /* Make this->latestNextUpdate be the date farthest in the future
-       of any of the singleResponses nextUpdate fields. */
-    SecAsn1OCSPSingleResponse **responses;
-    for (responses = this->responseData.responses; *responses; ++responses) {
-               SecAsn1OCSPSingleResponse *resp = *responses;
-               
-               /* thisUpdate later than 'now' invalidates the whole response. */
-               CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
-               if (thisUpdate > now + LEEWAY) {
-                       ocspdErrorLog("OCSPResponse: thisUpdate more than 1:15 from now");
-                       return false;
-               }
-
-               /* Keep track of latest nextUpdate. */
-               if (resp->nextUpdate != NULL) {
-                       CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
-                       if (nextUpdate > this->latestNextUpdate) {
-                               this->latestNextUpdate = nextUpdate;
-                       }
-               }
-#ifdef STRICT_RFC5019
-        else {
-            /* RFC 5019 section 2.2.4 states on nextUpdate:
-                 Responders MUST always include this value to aid in
-                 response caching.  See Section 6 for additional
-                 information on caching.
-            */
-                       ocspdErrorLog("OCSPResponse: nextUpdate not present");
-                       return false;
-        }
-#endif
-       }
-
-    /* Now that we have this->latestNextUpdate, we figure out the latest
-       date at which we will expire this response from our cache.  To comply
-       with rfc5019s:
-
-6.1.  Caching at the Client
-
-   To minimize bandwidth usage, clients MUST locally cache authoritative
-   OCSP responses (i.e., a response with a signature that has been
-   successfully validated and that indicate an OCSPResponseStatus of
-   'successful').
-
-   Most OCSP clients will send OCSPRequests at or near the nextUpdate
-   time (when a cached response expires).  To avoid large spikes in
-   responder load that might occur when many clients refresh cached
-   responses for a popular certificate, responders MAY indicate when the
-   client should fetch an updated OCSP response by using the cache-
-   control:max-age directive.  Clients SHOULD fetch the updated OCSP
-   Response on or after the max-age time.  To ensure that clients
-   receive an updated OCSP response, OCSP responders MUST refresh the
-   OCSP response before the max-age time.
-
-6.2 [...]
-
-       we need to take the cache-control:max-age directive into account.
-
-       The way the code below is written we ignore a max-age=0 in the
-       http header.  Since a value of 0 (NULL_TIME) also means there
-       was no max-age in the header. This seems ok since that would imply
-       no-cache so we also ignore negative values for the same reason,
-       instead we'll expire whenever this->latestNextUpdate tells us to,
-       which is the signed value if max-age is too low, since we don't
-       want to refetch multilple times for a single page load in a browser. */
-       if (this->latestNextUpdate == NULL_TIME) {
-        /* See comment above on RFC 5019 section 2.2.4. */
-               /* Absolute expire time = current time plus defaultTTL */
-               this->expireTime = now + defaultTTL;
-       } else if (this->latestNextUpdate < now - LEEWAY) {
-                       ocspdErrorLog("OCSPResponse: latestNextUpdate more than 1:15 ago");
-                       return false;
-    } else if (maxAge > 0) {
-        /* Beware of double overflows such as:
-
-               now + maxAge < this->latestNextUpdate
-
-           in the math below since an attacker could create any positive
-           value for maxAge. */
-        if (maxAge < this->latestNextUpdate - now) {
-            /* maxAge header wants us to expire the cache entry sooner than
-               nextUpdate would allow, to balance server load. */
-            this->expireTime = now + maxAge;
-        } else {
-            /* maxAge http header attempting to make us cache the response
-               longer than it's valid for, bad http header! Ignoring you. */
-            ocspdErrorLog("OCSPResponse: now + maxAge > latestNextUpdate,"
-                " using latestNextUpdate");
-            this->expireTime = this->latestNextUpdate;
-        }
-       } else {
-        /* No maxAge provided, just use latestNextUpdate. */
-               this->expireTime = this->latestNextUpdate;
-    }
-
-       return true;
-}
-
-SecOCSPResponseRef SecOCSPResponseCreate(CFDataRef ocspResponse,
-    CFTimeInterval maxAge) {
-       SecAsn1OCSPResponse topResp = {};
-    SecOCSPResponseRef this;
-
-    require(this = (SecOCSPResponseRef)calloc(1, sizeof(struct __SecOCSPResponse)),
-        errOut);
-    require_noerr(SecAsn1CoderCreate(&this->coder), errOut);
-
-    this->data = ocspResponse;
-    CFRetain(ocspResponse);
-
-    SecAsn1Item resp;
-    resp.Length = CFDataGetLength(ocspResponse);
-    resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse);
-       if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate,
-        &topResp)) {
-               ocspdErrorLog("OCSPResponse: decode failure at top level");
-       }
-       /* remainder is valid only on RS_Success */
-       if ((topResp.responseStatus.Data == NULL) ||
-          (topResp.responseStatus.Length == 0)) {
-               ocspdErrorLog("OCSPResponse: no responseStatus");
-        goto errOut;
-       }
-    this->responseStatus = topResp.responseStatus.Data[0];
-       if (this->responseStatus != kSecOCSPSuccess) {
-               secdebug("ocsp", "OCSPResponse: status: %d", this->responseStatus);
-               /* not a failure of our constructor; this object is now useful, but
-                * only for this one byte of status info */
-               return this;
-       }
-       if (topResp.responseBytes == NULL) {
-               /* I don't see how this can be legal on RS_Success */
-               ocspdErrorLog("OCSPResponse: empty responseBytes");
-        goto errOut;
-       }
-    if (!SecAsn1OidCompare(&topResp.responseBytes->responseType,
-                       &OID_PKIX_OCSP_BASIC)) {
-               ocspdErrorLog("OCSPResponse: unknown responseType");
-        goto errOut;
-
-       }
-
-       /* decode the SecAsn1OCSPBasicResponse */
-       if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response,
-                       kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) {
-               ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse");
-        goto errOut;
-       }
-
-       /* signature and cert evaluation done externally */
-
-       /* decode the SecAsn1OCSPResponseData */
-       if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData,
-                       kSecAsn1OCSPResponseDataTemplate, &this->responseData)) {
-               ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData");
-        goto errOut;
-       }
-    this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt);
-    if (this->producedAt == NULL_TIME) {
-               ocspdErrorLog("OCSPResponse: bad producedAt");
-        goto errOut;
-    }
-
-       if (this->responseData.responderID.Data == NULL) {
-               ocspdErrorLog("OCSPResponse: bad responderID");
-        goto errOut;
-       }
-
-       /* Choice processing for ResponderID */
-    this->responderIdTag = (SecAsn1OCSPResponderIDTag)
-               (this->responseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
-       const SecAsn1Template *templ;
-       switch(this->responderIdTag) {
-               case RIT_Name:
-            /* @@@ Since we don't use the decoded byName value we could skip
-               decoding it but we do it anyway for validation. */
-                       templ = kSecAsn1OCSPResponderIDAsNameTemplate;
-                       break;
-               case RIT_Key:
-                       templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
-                       break;
-               default:
-                       ocspdErrorLog("OCSPResponse: bad responderID tag");
-            goto errOut;
-       }
-       if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ,
-        &this->responderID)) {
-               ocspdErrorLog("OCSPResponse: decode failure at responderID");
-        goto errOut;
-       }
-
-    /* We should probably get the defaultTTL from the policy.
-       For now defaultTTL is hardcoded to 24 hours. */
-    CFTimeInterval defaultTTL = 24 * 60 * 60;
-       /* Check temporal validity, default TTL 24 hours. */
-    require_quiet(SecOCSPResponseCalculateValidity(this, maxAge, defaultTTL), errOut);
-
-#if 0
-       /* Individual responses looked into when we're asked for a specific one
-          via SecOCSPResponseCopySingleResponse(). */
-       mExtensions = new OCSPExtensions(mResponseData.responseExtensions);
-#endif
-
-    return this;
-errOut:
-    if (this) {
-        SecOCSPResponseFinalize(this);
-    }
-    return NULL;
-}
-
-CFDataRef SecOCSPResponseGetData(SecOCSPResponseRef this) {
-    return this->data;
-}
-
-SecOCSPResponseStatus SecOCSPGetResponseStatus(SecOCSPResponseRef this) {
-    return this->responseStatus;
-}
-
-CFAbsoluteTime SecOCSPResponseGetExpirationTime(SecOCSPResponseRef this) {
-    return this->expireTime;
-}
-
-CFDataRef SecOCSPResponseGetNonce(SecOCSPResponseRef this) {
-    return this->nonce;
-}
-
-CFAbsoluteTime SecOCSPResponseProducedAt(SecOCSPResponseRef this) {
-    return this->producedAt;
-}
-
-CFAbsoluteTime SecOCSPResponseVerifyTime(SecOCSPResponseRef this) {
-    return this->verifyTime;
-}
-
-CFArrayRef SecOCSPResponseCopySigners(SecOCSPResponseRef this) {
-    return NULL;
-}
-
-void SecOCSPResponseFinalize(SecOCSPResponseRef this) {
-    CFReleaseSafe(this->data);
-    CFReleaseSafe(this->nonce);
-    SecAsn1CoderRelease(this->coder);
-    free(this);
-}
-
-SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse(
-    SecOCSPResponseRef this, SecOCSPRequestRef request) {
-    SecOCSPSingleResponseRef sr = NULL;
-
-    CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate);
-    const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer);
-    CFDataRef serial = SecCertificateCopySerialNumber(request->certificate);
-    CFDataRef issuerNameHash = NULL;
-    CFDataRef issuerPubKeyHash = NULL;
-    SecAsn1Oid *algorithm = NULL;
-    SecAsn1Item *parameters = NULL;
-
-    /* We should probably get the defaultTTL from the policy.
-       For now defaultTTL is hardcoded to 24 hours. This is how long we trust
-       a response without a nextUpdate field.  */
-    CFTimeInterval defaultTTL = 24 * 60 * 60;
-
-    SecAsn1OCSPSingleResponse **responses;
-    for (responses = this->responseData.responses; *responses; ++responses) {
-               SecAsn1OCSPSingleResponse *resp = *responses;
-        SecAsn1OCSPCertID *certId = &resp->certID;
-        /* First check the easy part, serial number should match. */
-        if (certId->serialNumber.Length != (size_t)CFDataGetLength(serial) ||
-            memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data,
-                certId->serialNumber.Length)) {
-            /* Serial # mismatch, skip this singleResponse. */
-            continue;
-        }
-
-        /* Calcluate the issuerKey and issuerName digests using the
-           hashAlgorithm and parameters specified in the certId, if
-           they differ from the ones we already computed. */
-        if (!SecAsn1OidCompare(algorithm, &certId->algId.algorithm) ||
-            !SecAsn1OidCompare(parameters, &certId->algId.parameters)) {
-            algorithm = &certId->algId.algorithm;
-            parameters = &certId->algId.parameters;
-            CFReleaseSafe(issuerNameHash);
-            CFReleaseSafe(issuerPubKeyHash);
-            issuerNameHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
-                parameters, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
-            issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault, algorithm,
-                parameters, publicKey->data, publicKey->length);
-        }
-
-        if (certId->issuerNameHash.Length == (size_t)CFDataGetLength(issuerNameHash)
-            && !memcmp(CFDataGetBytePtr(issuerNameHash),
-                certId->issuerNameHash.Data, certId->issuerNameHash.Length)
-            && certId->issuerPubKeyHash.Length == (size_t)CFDataGetLength(issuerPubKeyHash)
-            && !memcmp(CFDataGetBytePtr(issuerPubKeyHash),
-                certId->issuerPubKeyHash.Data, certId->issuerPubKeyHash.Length)) {
-
-            CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
-            if (thisUpdate > this->verifyTime) {
-                ocspdErrorLog("OCSPSingleResponse: thisUpdate > now");
-                continue;
-            }
-
-            if (resp->nextUpdate == NULL) {
-                /* rfc2560 section 2.4 states: "If nextUpdate is not set, the
-                   responder is indicating that newer revocation information
-                   is available all the time".
-                   Let's ensure that thisUpdate isn't more than defaultTTL in
-                   the past then. */
-                if (this->verifyTime > thisUpdate + defaultTTL) {
-                    ocspdErrorLog("OCSPSingleResponse: no nextUpdate present "
-                        "and now > thisUpdate + defaultTTL");
-                    continue;
-                }
-            } else {
-                CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
-                if (this->verifyTime > nextUpdate) {
-                    ocspdErrorLog("OCSPSingleResponse: now > nextUpdate");
-                    continue;
-                }
-            }
-
-            /* resp matches the certificate in request, so let's use it. */
-            sr = SecOCSPSingleResponseCreate(resp, this->coder);
-            if (sr) {
-                ocspdDebug("found matching singleResponse");
-                break;
-            }
-        }
-       }
-
-    CFReleaseSafe(issuerPubKeyHash);
-    CFReleaseSafe(issuerNameHash);
-    CFReleaseSafe(serial);
-    CFReleaseSafe(issuer);
-
-    if (!sr) {
-        ocspdDebug("certID not found");
-    }
-
-       return sr;
-}
-
-static bool SecOCSPResponseVerifySignature(SecOCSPResponseRef this,
-    SecKeyRef key) {
-       /* Beware this->basicResponse.sig: on decode, length is in BITS */
-    return SecKeyDigestAndVerify(key, &this->basicResponse.algId,
-        this->basicResponse.tbsResponseData.Data,
-        this->basicResponse.tbsResponseData.Length,
-        this->basicResponse.sig.Data,
-        this->basicResponse.sig.Length / 8) == errSecSuccess;
-}
-
-static bool SecOCSPResponseIsIssuer(SecOCSPResponseRef this,
-    SecCertificatePathRef issuer) {
-    bool shouldBeSigner = false;
-    SecCertificateRef signer = SecCertificatePathGetCertificateAtIndex(issuer, 0);
-       if (this->responderIdTag == RIT_Name) {
-               /* Name inside response must == signer's SubjectName. */
-        CFDataRef subject = SecCertificateCopySubjectSequence(signer);
-        if (!subject) {
-                       ocspdDebug("error on SecCertificateCopySubjectSequence");
-                       return false;
-               }
-        if ((size_t)CFDataGetLength(subject) == this->responderID.byName.Length &&
-            !memcmp(this->responderID.byName.Data, CFDataGetBytePtr(subject),
-                this->responderID.byName.Length)) {
-                       ocspdDebug("good ResponderID.byName");
-                       shouldBeSigner = true;
-        } else {
-                       ocspdDebug("BAD ResponderID.byName");
-               }
-        CFRelease(subject);
-    } else /* if (this->responderIdTag == RIT_Key) */ {
-               /* ResponderID.byKey must == SHA1(signer's public key) */
-        CFDataRef pubKeyDigest = SecCertificateCopyPublicKeySHA1Digest(signer);
-        if ((size_t)CFDataGetLength(pubKeyDigest) == this->responderID.byKey.Length &&
-            !memcmp(this->responderID.byKey.Data, CFDataGetBytePtr(pubKeyDigest),
-                this->responderID.byKey.Length)) {
-                       ocspdDebug("good ResponderID.byKey");
-                       shouldBeSigner = true;
-               } else {
-                       ocspdDebug("BAD ResponderID.byKey");
-               }
-        CFRelease(pubKeyDigest);
-    }
-
-    if (shouldBeSigner) {
-        SecKeyRef key = SecCertificatePathCopyPublicKeyAtIndex(issuer, 0);
-        if (key) {
-            shouldBeSigner = SecOCSPResponseVerifySignature(this, key);
-            ocspdDebug("ocsp response signature %sok", shouldBeSigner ? "" : "not ");
-            CFRelease(key);
-        } else {
-                       ocspdDebug("Failed to extract key from leaf certificate");
-            shouldBeSigner = false;
-        }
-    }
-
-    return shouldBeSigner;
-}
-
-/* Returns the SecCertificatePathRef who's leaf signed this ocspResponse if
-   we can find one and NULL if we can't find a valid signer. */
-SecCertificatePathRef SecOCSPResponseCopySigner(SecOCSPResponseRef this,
-    SecCertificatePathRef issuer) {
-    SecCertificateRef issuerCert = SecCertificatePathGetCertificateAtIndex(issuer, 0);
-    CFDataRef issuerSubject = SecCertificateGetNormalizedSubjectContent(issuerCert);
-    /* Look though any certs that came with the response and see if they were
-       both issued by the issuerPath and signed the response. */
-    SecAsn1Item **certs;
-    for (certs = this->basicResponse.certs; certs && *certs; ++certs) {
-        SecCertificateRef cert = SecCertificateCreateWithBytes(
-            kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
-        if (cert) {
-            CFDataRef certIssuer = SecCertificateGetNormalizedIssuerContent(cert);
-            if (CFEqual(issuerSubject, certIssuer)) {
-                SecCertificatePathRef signer = SecCertificatePathCopyAddingLeaf(issuer, cert);
-                CFRelease(cert);
-                if (signer) {
-                    if (SecOCSPResponseIsIssuer(this, signer)) {
-                        return signer;
-                    } else {
-                        ocspdErrorLog("ocsp response cert not signed by issuer.");
-                        CFRelease(signer);
-                    }
-                }
-            } else {
-                ocspdErrorLog("ocsp response cert issuer doesn't match issuer subject.");
-            }
-        } else {
-                       ocspdErrorLog("ocsp response cert failed to parse");
-        }
-       }
-
-    /* If none of the returned certs work, try the issuer of the certificate
-       being checked directly. */
-    if (SecOCSPResponseIsIssuer(this, issuer)) {
-        CFRetain(issuer);
-        return issuer;
-    }
-
-    /* We couldn't find who signed this ocspResponse, give up. */
-    return NULL;
-}