1/*
2 * Copyright (c) 2004,2011-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 * ocspRequest.cpp - OCSP Request class
26 */
27
28#include "ocspRequest.h"
29#include "certGroupUtils.h"
30#include "tpdebugging.h"
31#include <security_ocspd/ocspResponse.h>
32#include <security_ocspd/ocspExtensions.h>
33#include <security_ocspd/ocspdUtils.h>
34#include <assert.h>
35#include <string.h>
36#include <Security/oidsalg.h>
37#include <Security/oidscert.h>
38#include <Security/ocspTemplates.h>
39#include <security_utilities/devrandom.h>
40#include <CommonCrypto/CommonDigest.h>
41#include <security_cdsa_utilities/cssmerrors.h>
42
43/* preencoded DER NULL */
44static uint8 nullParam[2] = {5, 0};
45
46/* size of nonce we generate, in bytes */
47#define OCSP_NONCE_SIZE		8
48
49/*
50 * The only constructor. Subject and issuer must remain valid for the
51 * lifetime of this object (they are not refcounted).
52 */
53OCSPRequest::OCSPRequest(
54	TPCertInfo		&subject,
55	TPCertInfo		&issuer,
56	bool			genNonce)
57		: mCoder(NULL),
58		  mSubject(subject),
59		  mIssuer(issuer),
60		  mGenNonce(genNonce),
61		  mCertID(NULL)
62{
63	SecAsn1CoderCreate(&mCoder);
64	mNonce.Data = NULL;
65	mNonce.Length = 0;
66	mEncoded.Data = NULL;
67	mEncoded.Length = 0;
68}
69
70OCSPRequest::~OCSPRequest()
71{
72	delete mCertID;
73	if(mCoder) {
74		SecAsn1CoderRelease(mCoder);
75	}
76}
77
78const CSSM_DATA *OCSPRequest::encode()
79{
80	/* fields obtained from issuer */
81	CSSM_DATA_PTR	issuerName;
82	CSSM_DATA_PTR	issuerKey;
83	CSSM_KEY_PTR	issuerPubKey;
84	/* from subject */
85	CSSM_DATA_PTR	subjectSerial=NULL;
86
87	CSSM_RETURN					crtn;
88	uint8						issuerNameHash[CC_SHA1_DIGEST_LENGTH];
89	uint8						pubKeyHash[CC_SHA1_DIGEST_LENGTH];
90	SecAsn1OCSPRequest			singleReq;
91	SecAsn1OCSPCertID			&certId = singleReq.reqCert;
92	SecAsn1OCSPSignedRequest	signedReq;
93	SecAsn1OCSPRequest			*reqArray[2] = { &singleReq, NULL };
94	SecAsn1OCSPTbsRequest		&tbs = signedReq.tbsRequest;
95	uint8						version = 0;
96	CSSM_DATA					vers = {1, &version};
97	uint8						nonceBytes[OCSP_NONCE_SIZE];
98	CSSM_DATA					nonceData = {OCSP_NONCE_SIZE, nonceBytes};
99	OCSPNonce					*nonce = NULL;
100	NSS_CertExtension			*extenArray[2] = {NULL, NULL};
101
102	if(mEncoded.Data) {
103		/* already done */
104		return &mEncoded;
105	}
106
107	/*
108	 * One single request, no extensions
109	 */
110	memset(&singleReq, 0, sizeof(singleReq));
111
112	/* algId refers to the hash we'll perform in issuer name and key */
113	certId.algId.algorithm = CSSMOID_SHA1;
114	certId.algId.parameters.Data = nullParam;
115	certId.algId.parameters.Length = sizeof(nullParam);
116
117	/* gather fields from two certs */
118	crtn = mSubject.fetchField(&CSSMOID_X509V1IssuerNameStd, &issuerName);
119	if(crtn) {
120		CssmError::throwMe(crtn);
121	}
122	crtn = mIssuer.fetchField(&CSSMOID_CSSMKeyStruct, &issuerKey);
123	if(crtn) {
124		goto errOut;
125	}
126	crtn = mSubject.fetchField(&CSSMOID_X509V1SerialNumber, &subjectSerial);
127	if(crtn) {
128		goto errOut;
129	}
130
131	/* SHA1(issuerName) */
132	ocspdSha1(issuerName->Data, (CC_LONG)issuerName->Length, issuerNameHash);
133
134	/* SHA1(issuer public key) */
135	if(issuerKey->Length != sizeof(CSSM_KEY)) {
136		tpErrorLog("OCSPRequest::encode: malformed issuer key\n");
137		crtn = CSSMERR_TP_INTERNAL_ERROR;
138		goto errOut;
139	}
140	issuerPubKey = (CSSM_KEY_PTR)issuerKey->Data;
141	ocspdSha1(issuerPubKey->KeyData.Data, (CC_LONG)issuerPubKey->KeyData.Length, pubKeyHash);
142
143	/* build the CertID from those components */
144	certId.issuerNameHash.Data = issuerNameHash;
145	certId.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
146	certId.issuerPubKeyHash.Data = pubKeyHash;
147	certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
148	certId.serialNumber = *subjectSerial;
149
150	/*
151	 * Build top level request with one entry in requestList, no signature,
152	 * one optional extension (a nonce)
153	 */
154	memset(&signedReq, 0, sizeof(signedReq));
155	tbs.version = &vers;
156	tbs.requestList = reqArray;
157
158	/* one extension - the nonce */
159	if(mGenNonce) {
160		DevRandomGenerator drg;
161		drg.random(nonceBytes, OCSP_NONCE_SIZE);
162		nonce = new OCSPNonce(mCoder, false, nonceData);
163		extenArray[0] = nonce->nssExt();
164		tbs.requestExtensions = extenArray;
165		SecAsn1AllocCopyItem(mCoder, &nonceData, &mNonce);
166	}
167
168	/* Encode */
169	if(SecAsn1EncodeItem(mCoder, &signedReq, kSecAsn1OCSPSignedRequestTemplate,
170			&mEncoded)) {
171		tpErrorLog("OCSPRequest::encode: error encoding OCSP req\n");
172		crtn = CSSMERR_TP_INTERNAL_ERROR;
173		goto errOut;
174	}
175	/* save a copy of the CertID */
176	mCertID = new OCSPClientCertID(*issuerName, issuerPubKey->KeyData, *subjectSerial);
177
178errOut:
179	if(issuerName) {
180		mIssuer.freeField(&CSSMOID_X509V1IssuerNameStd, issuerName);
181	}
182	if(issuerKey) {
183		mIssuer.freeField(&CSSMOID_CSSMKeyStruct, issuerKey);
184	}
185	if(subjectSerial) {
186		mSubject.freeField(&CSSMOID_X509V1SerialNumber, subjectSerial);
187	}
188	if(nonce) {
189		delete nonce;
190	}
191	if(crtn) {
192		CssmError::throwMe(crtn);
193	}
194	return &mEncoded;
195}
196
197const CSSM_DATA *OCSPRequest::nonce()
198{
199	/* not legal before encode() called */
200	assert(mEncoded.Data != NULL);
201	if(mNonce.Data) {
202		return &mNonce;
203	}
204	else {
205		return NULL;
206	}
207}
208
209OCSPClientCertID *OCSPRequest::certID()
210{
211	encode();
212	return mCertID;
213}
214
215