--- /dev/null
+/*
+ * Copyright (c) 2004-2005 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 <clAppUtils/CertParser.h>
+#include <security_cdsa_utils/cuCdsaUtils.h>
+#include <security_ocspd/ocspResponse.h>
+#include <security_ocspd/ocspExtensions.h>
+#include <security_ocspd/ocspdUtils.h>
+#include <assert.h>
+#include <string.h>
+#include <Security/oidsalg.h>
+#include <Security/oidscert.h>
+#include <Security/ocspTemplates.h>
+#include <security_utilities/devrandom.h>
+#include <CommonCrypto/CommonDigest.h>
+#include <security_cdsa_utilities/cssmerrors.h>
+
+/* preencoded DER NULL */
+static uint8 nullParam[2] = {5, 0};
+
+/* size of nonce we generate, in bytes */
+#define OCSP_NONCE_SIZE 8
+
+/*
+ * The only constructor.
+ */
+OCSPRequest::OCSPRequest(
+ CertParser &subject,
+ CertParser &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 issuerName;
+ CSSM_DATA issuerKey;
+ CSSM_KEY_PTR issuerPubKey;
+ /* from subject */
+ CSSM_DATA subjectSerial;
+
+ CSSM_RETURN crtn = CSSM_OK;
+ 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 */
+ issuerName.Length = 0; // don't check
+ issuerName.Data = (uint8 *)mSubject.fieldForOid(CSSMOID_X509V1IssuerNameStd,
+ issuerName.Length);
+ issuerKey.Length = sizeof(CSSM_KEY);
+ issuerKey.Data = (uint8 *)mIssuer.fieldForOid(CSSMOID_CSSMKeyStruct,
+ issuerKey.Length);
+ subjectSerial.Length = 0;
+ subjectSerial.Data = (uint8 *)mSubject.fieldForOid(CSSMOID_X509V1SerialNumber,
+ subjectSerial.Length);
+
+ /* SHA1(issuerName) */
+ ocspdSha1(issuerName.Data, issuerName.Length, issuerNameHash);
+
+ /* SHA1(issuer public key) */
+ 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)) {
+ printf("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(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;
+}
+