/* * 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@ */ /* * ocspRequest.cpp - OCSP Request class */ #include "ocspRequest.h" #include "certGroupUtils.h" #include "tpdebugging.h" #include #include #include #include #include #include #include #include #include #include #include /* preencoded DER NULL */ static uint8 nullParam[2] = {5, 0}; /* size of nonce we generate, in bytes */ #define OCSP_NONCE_SIZE 8 /* * The only constructor. Subject and issuer must remain valid for the * lifetime of this object (they are not refcounted). */ OCSPRequest::OCSPRequest( TPCertInfo &subject, TPCertInfo &issuer, bool genNonce) : mCoder(NULL), mSubject(subject), mIssuer(issuer), mGenNonce(genNonce), mCertID(NULL) { SecAsn1CoderCreate(&mCoder); mNonce.Data = NULL; mNonce.Length = 0; mEncoded.Data = NULL; mEncoded.Length = 0; } OCSPRequest::~OCSPRequest() { delete mCertID; if(mCoder) { SecAsn1CoderRelease(mCoder); } } const CSSM_DATA *OCSPRequest::encode() { /* fields obtained from issuer */ CSSM_DATA_PTR issuerName; CSSM_DATA_PTR issuerKey; CSSM_KEY_PTR issuerPubKey; /* from subject */ CSSM_DATA_PTR subjectSerial; CSSM_RETURN crtn; uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH]; uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH]; SecAsn1OCSPRequest singleReq; SecAsn1OCSPCertID &certId = singleReq.reqCert; SecAsn1OCSPSignedRequest signedReq; SecAsn1OCSPRequest *reqArray[2] = { &singleReq, NULL }; SecAsn1OCSPTbsRequest &tbs = signedReq.tbsRequest; uint8 version = 0; CSSM_DATA vers = {1, &version}; uint8 nonceBytes[OCSP_NONCE_SIZE]; CSSM_DATA nonceData = {OCSP_NONCE_SIZE, nonceBytes}; OCSPNonce *nonce = NULL; NSS_CertExtension *extenArray[2] = {NULL, NULL}; if(mEncoded.Data) { /* already done */ return &mEncoded; } /* * One single request, no extensions */ memset(&singleReq, 0, sizeof(singleReq)); /* 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); /* gather fields from two certs */ crtn = mSubject.fetchField(&CSSMOID_X509V1IssuerNameStd, &issuerName); if(crtn) { CssmError::throwMe(crtn); } crtn = mIssuer.fetchField(&CSSMOID_CSSMKeyStruct, &issuerKey); if(crtn) { goto errOut; } crtn = mSubject.fetchField(&CSSMOID_X509V1SerialNumber, &subjectSerial); if(crtn) { goto errOut; } /* SHA1(issuerName) */ ocspdSha1(issuerName->Data, issuerName->Length, issuerNameHash); /* SHA1(issuer public key) */ if(issuerKey->Length != sizeof(CSSM_KEY)) { tpErrorLog("OCSPRequest::encode: malformed issuer key\n"); crtn = CSSMERR_TP_INTERNAL_ERROR; goto errOut; } issuerPubKey = (CSSM_KEY_PTR)issuerKey->Data; ocspdSha1(issuerPubKey->KeyData.Data, issuerPubKey->KeyData.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 = *subjectSerial; /* * Build top level request with one entry in requestList, no signature, * one optional extension (a nonce) */ memset(&signedReq, 0, sizeof(signedReq)); tbs.version = &vers; tbs.requestList = reqArray; /* one extension - the nonce */ if(mGenNonce) { DevRandomGenerator drg; drg.random(nonceBytes, OCSP_NONCE_SIZE); nonce = new OCSPNonce(mCoder, false, nonceData); extenArray[0] = nonce->nssExt(); tbs.requestExtensions = extenArray; SecAsn1AllocCopyItem(mCoder, &nonceData, &mNonce); } /* Encode */ if(SecAsn1EncodeItem(mCoder, &signedReq, kSecAsn1OCSPSignedRequestTemplate, &mEncoded)) { tpErrorLog("OCSPRequest::encode: error encoding OCSP req\n"); crtn = CSSMERR_TP_INTERNAL_ERROR; goto errOut; } /* save a copy of the CertID */ mCertID = new OCSPClientCertID(*issuerName, issuerPubKey->KeyData, *subjectSerial); errOut: if(issuerName) { mIssuer.freeField(&CSSMOID_X509V1IssuerNameStd, issuerName); } if(issuerKey) { mIssuer.freeField(&CSSMOID_CSSMKeyStruct, issuerKey); } if(subjectSerial) { mSubject.freeField(&CSSMOID_X509V1SerialNumber, subjectSerial); } if(nonce) { delete nonce; } if(crtn) { CssmError::throwMe(crtn); } return &mEncoded; } const CSSM_DATA *OCSPRequest::nonce() { /* not legal before encode() called */ assert(mEncoded.Data != NULL); if(mNonce.Data) { return &mNonce; } else { return NULL; } } OCSPClientCertID *OCSPRequest::certID() { encode(); return mCertID; }