X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_ocspd/common/ocspResponse.cpp diff --git a/libsecurity_ocspd/common/ocspResponse.cpp b/libsecurity_ocspd/common/ocspResponse.cpp deleted file mode 100644 index 05ffc186..00000000 --- a/libsecurity_ocspd/common/ocspResponse.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright (c) 2004 Apple Computer, 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@ - */ - -/* - * ocspResponse.cpp - OCSP Response class - */ -#include "ocspResponse.h" -#include "ocspdUtils.h" -#include -#include -#include -#include "ocspdDebug.h" -#include -#include -#include - -/* malloc & copy CSSM_DATA using std malloc */ -static void allocCopyData( - const CSSM_DATA &src, - CSSM_DATA &dst) -{ - if(src.Length == 0) { - dst.Data = NULL; - dst.Length = 0; - return; - } - dst.Data = (uint8 *)malloc(src.Length); - memmove(dst.Data, src.Data, src.Length); - dst.Length = src.Length; -} - -/* std free() of a CSSM_DATA */ -static void freeData( - CSSM_DATA &d) -{ - if(d.Data) { - free(d.Data); - d.Data = NULL; - } - d.Length = 0; -} - -#pragma mark ---- OCSPClientCertID ---- - -/* - * Basic constructor given issuer's public key and name, and subject's - * serial number. - */ -OCSPClientCertID::OCSPClientCertID( - const CSSM_DATA &issuerName, - const CSSM_DATA &issuerPubKey, - const CSSM_DATA &subjectSerial) -{ - mEncoded.Data = NULL; - mEncoded.Length = 0; - allocCopyData(issuerName, mIssuerName); - allocCopyData(issuerPubKey, mIssuerPubKey); - allocCopyData(subjectSerial, mSubjectSerial); -} - -OCSPClientCertID::~OCSPClientCertID() -{ - freeData(mIssuerName); - freeData(mIssuerPubKey); - freeData(mSubjectSerial); - freeData(mEncoded); -} - -/* preencoded DER NULL */ -static uint8 nullParam[2] = {5, 0}; - -/* - * DER encode in specified coder's memory. - */ -const CSSM_DATA *OCSPClientCertID::encode() -{ - if(mEncoded.Data != NULL) { - return &mEncoded; - } - - SecAsn1OCSPCertID certID; - uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH]; - uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH]; - - /* algId refers to the hash we'll perform in issuer name and key */ - certID.algId.algorithm = CSSMOID_SHA1; - certID.algId.parameters.Data = nullParam; - certID.algId.parameters.Length = sizeof(nullParam); - - /* SHA1(issuerName) */ - ocspdSha1(mIssuerName.Data, (CC_LONG)mIssuerName.Length, issuerNameHash); - /* SHA1(issuer public key) */ - ocspdSha1(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, pubKeyHash); - - /* build the CertID from those components */ - certID.issuerNameHash.Data = issuerNameHash; - certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH; - certID.issuerPubKeyHash.Data = pubKeyHash; - certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH; - certID.serialNumber = mSubjectSerial; - - /* encode */ - SecAsn1CoderRef coder; - SecAsn1CoderCreate(&coder); - - CSSM_DATA tmp = {0, NULL}; - SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp); - allocCopyData(tmp, mEncoded); - SecAsn1CoderRelease(coder); - return &mEncoded; -} - -/* - * Does this object refer to the same cert as specified SecAsn1OCSPCertID? - * This is the main purpose of this class's existence; this function works - * even if specified SecAsn1OCSPCertID uses a different hash algorithm - * than we do, since we keep copies of our basic components. - * - * Returns true if compare successful. - */ -typedef void (*hashFcn)(const void *data, CC_LONG len, unsigned char *md); - -bool OCSPClientCertID::compareToExist( - const SecAsn1OCSPCertID &exist) -{ - /* easy part */ - if(!ocspdCompareCssmData(&mSubjectSerial, &exist.serialNumber)) { - return false; - } - - hashFcn hf = NULL; - const CSSM_OID *alg = &exist.algId.algorithm; - uint8 digest[OCSPD_MAX_DIGEST_LEN]; - CSSM_DATA digestData = {0, digest}; - - if(ocspdCompareCssmData(alg, &CSSMOID_SHA1)) { - hf = ocspdSha1; - digestData.Length = CC_SHA1_DIGEST_LENGTH; - } - else if(ocspdCompareCssmData(alg, &CSSMOID_MD5)) { - hf = ocspdMD5; - digestData.Length = CC_MD5_DIGEST_LENGTH; - } - else if(ocspdCompareCssmData(alg, &CSSMOID_MD4)) { - hf = ocspdMD4; - digestData.Length = CC_MD4_DIGEST_LENGTH; - } - /* an OID for SHA256? */ - else { - return false; - } - - /* generate digests using exist's hash algorithm */ - hf(mIssuerName.Data, (CC_LONG)mIssuerName.Length, digest); - if(!ocspdCompareCssmData(&digestData, &exist.issuerNameHash)) { - return false; - } - hf(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, digest); - if(!ocspdCompareCssmData(&digestData, &exist.issuerPubKeyHash)) { - return false; - } - - return true; -} - -bool OCSPClientCertID::compareToExist( - const CSSM_DATA &exist) -{ - SecAsn1CoderRef coder; - SecAsn1OCSPCertID certID; - bool brtn = false; - - SecAsn1CoderCreate(&coder); - memset(&certID, 0, sizeof(certID)); - if(SecAsn1DecodeData(coder, &exist, kSecAsn1OCSPCertIDTemplate, &certID)) { - goto errOut; - } - brtn = compareToExist(certID); -errOut: - SecAsn1CoderRelease(coder); - return brtn; -} - -#pragma mark ---- OCSPSingleResponse ---- - -/* - * Constructor, called by OCSPResponse. - */ -OCSPSingleResponse::OCSPSingleResponse( - SecAsn1OCSPSingleResponse *resp) - : mCertStatus(CS_NotParsed), - mThisUpdate(NULL_TIME), - mNextUpdate(NULL_TIME), - mRevokedTime(NULL_TIME), - mCrlReason(CrlReason_NONE), - mExtensions(NULL) -{ - assert(resp != NULL); - - SecAsn1CoderCreate(&mCoder); - if((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) { - ocspdErrorLog("OCSPSingleResponse: bad certStatus\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - mCertStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK); - if(mCertStatus == CS_Revoked) { - /* decode further to get SecAsn1OCSPRevokedInfo */ - SecAsn1OCSPCertStatus certStatus; - memset(&certStatus, 0, sizeof(certStatus)); - if(SecAsn1DecodeData(mCoder, &resp->certStatus, - kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) { - ocspdErrorLog("OCSPSingleResponse: err decoding certStatus\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo; - if(revokedInfo != NULL) { - /* Treat this as optional even for CS_Revoked */ - mRevokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime); - const CSSM_DATA *revReason = revokedInfo->revocationReason; - if((revReason != NULL) && - (revReason->Data != NULL) && - (revReason->Length != 0)) { - mCrlReason = revReason->Data[0]; - } - } - } - mThisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); - if(resp->nextUpdate != NULL) { - mNextUpdate = genTimeToCFAbsTime(resp->nextUpdate); - } - mExtensions = new OCSPExtensions(resp->singleExtensions); - ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus, - (int)mCrlReason); -} - -OCSPSingleResponse::~OCSPSingleResponse() -{ - delete mExtensions; - SecAsn1CoderRelease(mCoder); -} - -/*** Extensions-specific accessors ***/ -#if 0 /* unused ? */ -const CSSM_DATA *OCSPSingleResponse::*crlUrl() -{ - /* TBD */ - return NULL; -} -#endif - -const CSSM_DATA *OCSPSingleResponse::crlNum() -{ - /* TBD */ - return NULL; - -} - -CFAbsoluteTime OCSPSingleResponse::crlTime() /* may be NULL_TIME */ -{ - /* TBD */ - return NULL_TIME; -} - -/* archive cutoff */ -CFAbsoluteTime OCSPSingleResponse::archiveCutoff() -{ - /* TBD */ - return NULL_TIME; -} - -#pragma mark ---- OCSPResponse ---- - -OCSPResponse::OCSPResponse( - const CSSM_DATA &resp, - CFTimeInterval defaultTTL) // default time-to-live in seconds - : mLatestNextUpdate(NULL_TIME), - mExpireTime(NULL_TIME), - mExtensions(NULL) -{ - SecAsn1CoderCreate(&mCoder); - memset(&mTopResp, 0, sizeof(mTopResp)); - memset(&mBasicResponse, 0, sizeof(mBasicResponse)); - memset(&mResponseData, 0, sizeof(mResponseData)); - memset(&mResponderId, 0, sizeof(mResponderId)); - mResponderIdTag = (SecAsn1OCSPResponderIDTag)0; // invalid - mEncResponderName.Data = NULL; - mEncResponderName.Length = 0; - - if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) { - ocspdErrorLog("OCSPResponse: decode failure at top level\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - - /* remainder is valid only on RS_Success */ - if((mTopResp.responseStatus.Data == NULL) || - (mTopResp.responseStatus.Length == 0)) { - ocspdErrorLog("OCSPResponse: no responseStatus\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - if(mTopResp.responseStatus.Data[0] != RS_Success) { - /* not a failure of our constructor; this object is now useful, but - * only for this one byte of status info */ - return; - } - if(mTopResp.responseBytes == NULL) { - /* I don't see how this can be legal on RS_Success */ - ocspdErrorLog("OCSPResponse: empty responseBytes\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - if(!ocspdCompareCssmData(&mTopResp.responseBytes->responseType, - &CSSMOID_PKIX_OCSP_BASIC)) { - ocspdErrorLog("OCSPResponse: unknown responseType\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - - /* decode the SecAsn1OCSPBasicResponse */ - if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response, - kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) { - ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - - /* signature and cert evaluation done externally */ - - /* decode the SecAsn1OCSPResponseData */ - if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData, - kSecAsn1OCSPResponseDataTemplate, &mResponseData)) { - ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - if(mResponseData.responderID.Data == NULL) { - ocspdErrorLog("OCSPResponse: bad responderID\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - - /* choice processing for ResponderID */ - mResponderIdTag = (SecAsn1OCSPResponderIDTag) - (mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK); - const SecAsn1Template *templ; - switch(mResponderIdTag) { - case RIT_Name: - templ = kSecAsn1OCSPResponderIDAsNameTemplate; - break; - case RIT_Key: - templ = kSecAsn1OCSPResponderIDAsKeyTemplate; - break; - default: - ocspdErrorLog("OCSPResponse: bad responderID tag\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - if(SecAsn1DecodeData(mCoder, &mResponseData.responderID, templ, &mResponderId)) { - ocspdErrorLog("OCSPResponse: decode failure at responderID\n"); - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - - /* check temporal validity */ - if(!calculateValidity(defaultTTL)) { - /* Whoops, abort */ - CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); - } - - /* - * Individual responses looked into when we're asked for a specific one - * via singleResponse() - */ - mExtensions = new OCSPExtensions(mResponseData.responseExtensions); -} - -OCSPResponse::~OCSPResponse() -{ - delete mExtensions; - SecAsn1CoderRelease(mCoder); -} - -SecAsn1OCSPResponseStatus OCSPResponse::responseStatus() -{ - assert(mTopResp.responseStatus.Data != NULL); /* else constructor should have failed */ - return (SecAsn1OCSPResponseStatus)(mTopResp.responseStatus.Data[0]); -} - -const CSSM_DATA *OCSPResponse::nonce() /* NULL means not present */ -{ - OCSPExtension *ext = mExtensions->findExtension(CSSMOID_PKIX_OCSP_NONCE); - if(ext == NULL) { - return NULL; - } - OCSPNonce *nonceExt = dynamic_cast(ext); - return &(nonceExt->nonce()); -} - -CFAbsoluteTime OCSPResponse::producedAt() -{ - return genTimeToCFAbsTime(&mResponseData.producedAt); -} - -uint32 OCSPResponse::numSignerCerts() -{ - return ocspdArraySize((const void **)mBasicResponse.certs); -} - -const CSSM_DATA *OCSPResponse::signerCert(uint32 dex) -{ - uint32 numCerts = numSignerCerts(); - if(dex >= numCerts) { - ocspdErrorLog("OCSPResponse::signerCert: numCerts overflow\n"); - CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); - } - return mBasicResponse.certs[dex]; -} - -/* - * Obtain a OCSPSingleResponse for a given "smart" CertID. - */ -OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertID) -{ - unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses); - for(unsigned dex=0; dexcertID; - if(matchCertID.compareToExist(certID)) { - try { - OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp); - return singleResp; - } - catch(...) { - /* try to find another... */ - continue; - } - } - } - ocspdDebug("OCSPResponse::singleResponse: certID not found"); - return NULL; -} - -/* - * If responderID is of form RIT_Name, return the encoded version of the - * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily, - * once, in mCoder space. - */ -const CSSM_DATA *OCSPResponse::encResponderName() -{ - if(mResponderIdTag != RIT_Name) { - assert(0); - return NULL; - } - if(mEncResponderName.Data != NULL) { - return &mEncResponderName; - } - if(SecAsn1EncodeItem(mCoder, &mResponderId.byName, kSecAsn1AnyTemplate, - &mEncResponderName)) { - ocspdDebug("OCSPResponse::encResponderName: error encoding ResponderId!"); - return NULL; - } - return &mEncResponderName; -} - -/* - * Obtain a OCSPSingleResponse for a given raw encoded CertID. - */ -OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID) -{ - unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses); - for(unsigned dex=0; dexcertID, kSecAsn1OCSPCertIDTemplate, - &certID)) { - ocspdDebug("OCSPResponse::singleResponse: error encoding certID!"); - return NULL; - } - if(!ocspdCompareCssmData(&matchCertID, &certID)) { - /* try to find another */ - continue; - } - try { - OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp); - return singleResp; - } - catch(...) { - /* try to find another... */ - continue; - } - } - ocspdDebug("OCSPResponse::singleResponse: certID not found"); - return NULL; - -} - -/* - * Calculate temporal validity; set mLatestNextUpdate and mExpireTime. Only - * called from constructor. Returns true if valid, else returns false. - */ -bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL) -{ - mLatestNextUpdate = NULL_TIME; - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - - unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses); - for(unsigned dex=0; dexthisUpdate); - if(thisUpdate > now) { - ocspdErrorLog("OCSPResponse::calculateValidity: thisUpdate not passed\n"); - return false; - } - - /* - * Accumulate latest nextUpdate - */ - if(resp->nextUpdate != NULL) { - CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate); - if(nextUpdate > mLatestNextUpdate) { - mLatestNextUpdate = nextUpdate; - } - } - } - - CFAbsoluteTime defaultExpire = now + defaultTTL; - if(mLatestNextUpdate == NULL_TIME) { - /* absolute expire time = current time plus default TTL */ - mExpireTime = defaultExpire; - } - else if(defaultExpire < mLatestNextUpdate) { - /* caller more stringent than response */ - mExpireTime = defaultExpire; - } - else { - /* response more stringent than caller */ - if(mLatestNextUpdate < now) { - ocspdErrorLog("OCSPResponse::calculateValidity: now > mLatestNextUpdate\n"); - return false; - } - mExpireTime = mLatestNextUpdate; - } - return true; -} -