1/*
2 * Copyright (c) 2000-2001,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// Session_Cert.cpp - cert-related session functions.
21//
22
23#include "AppleX509CLSession.h"
24#include "DecodedCert.h"
25#include "DecodedCrl.h"
26#include "CLCachedEntry.h"
27#include "cldebugging.h"
28#include <Security/oidscert.h>
29
30void
31AppleX509CLSession::CertDescribeFormat(
32	uint32 &NumberOfFields,
33	CSSM_OID_PTR &OidList)
34{
35	DecodedCert::describeFormat(*this, NumberOfFields, OidList);
36}
37
38void
39AppleX509CLSession::CertGetAllFields(
40	const CssmData &Cert,
41	uint32 &NumberOfFields,
42	CSSM_FIELD_PTR &CertFields)
43{
44	DecodedCert decodedCert(*this, Cert);
45	decodedCert.getAllParsedCertFields(NumberOfFields, CertFields);
46}
47
48
49CSSM_HANDLE
50AppleX509CLSession::CertGetFirstFieldValue(
51	const CssmData &EncodedCert,
52	const CssmData &CertField,
53	uint32 &NumberOfMatchedFields,
54	CSSM_DATA_PTR &Value)
55{
56	NumberOfMatchedFields = 0;
57	Value = NULL;
58	CssmAutoData aData(*this);
59
60	DecodedCert *decodedCert = new DecodedCert(*this, EncodedCert);
61	uint32 numMatches;
62
63	/* this returns false if field not there, throws on bad OID */
64	bool brtn;
65	try {
66		brtn = decodedCert->getCertFieldData(CertField,
67			0, 				// index
68			numMatches,
69			aData);
70	}
71	catch (...) {
72		delete decodedCert;
73		throw;
74	}
75	if(!brtn) {
76		delete decodedCert;
77		return CSSM_INVALID_HANDLE;
78	}
79
80	/* cook up a CLCachedCert, stash it in cache */
81	CLCachedCert *cachedCert = new CLCachedCert(*decodedCert);
82	cacheMap.addEntry(*cachedCert, cachedCert->handle());
83
84	/* cook up a CLQuery, stash it */
85	CLQuery *query = new CLQuery(
86		CLQ_Cert,
87		CertField,
88		numMatches,
89		false,				// isFromCache
90		cachedCert->handle());
91	queryMap.addEntry(*query, query->handle());
92
93	/* success - copy field data to outgoing Value */
94	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
95	*Value = aData.release();
96	NumberOfMatchedFields = numMatches;
97	return query->handle();
98}
99
100
101bool
102AppleX509CLSession::CertGetNextFieldValue(
103	CSSM_HANDLE ResultsHandle,
104	CSSM_DATA_PTR &Value)
105{
106	/* fetch & validate the query */
107	CLQuery *query = queryMap.lookupEntry(ResultsHandle);
108	if(query == NULL) {
109		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
110	}
111	if(query->queryType() != CLQ_Cert) {
112		clErrorLog("CertGetNextFieldValue: bad queryType (%d)", (int)query->queryType());
113		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
114	}
115	if(query->nextIndex() >= query->numFields()) {
116		return false;
117	}
118
119	/* fetch the associated cached cert */
120	CLCachedCert *cachedCert = lookupCachedCert(query->cachedObject());
121	uint32 dummy;
122	CssmAutoData aData(*this);
123	if(!cachedCert->cert().getCertFieldData(query->fieldId(),
124		query->nextIndex(),
125		dummy,
126		aData))  {
127		return false;
128	}
129
130	/* success - copy field data to outgoing Value */
131	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
132	*Value = aData.release();
133	query->incrementIndex();
134	return true;
135}
136
137void
138AppleX509CLSession::CertCache(
139	const CssmData &EncodedCert,
140	CSSM_HANDLE &CertHandle)
141{
142	DecodedCert *decodedCert = new DecodedCert(*this, EncodedCert);
143
144	/* cook up a CLCachedCert, stash it in cache */
145	CLCachedCert *cachedCert = new CLCachedCert(*decodedCert);
146	cacheMap.addEntry(*cachedCert, cachedCert->handle());
147	CertHandle = cachedCert->handle();
148}
149
150CSSM_HANDLE
151AppleX509CLSession::CertGetFirstCachedFieldValue(
152	CSSM_HANDLE CertHandle,
153	const CssmData &CertField,
154	uint32 &NumberOfMatchedFields,
155	CSSM_DATA_PTR &Value)
156{
157	/* fetch the associated cached cert */
158	CLCachedCert *cachedCert = lookupCachedCert(CertHandle);
159	if(cachedCert == NULL) {
160		CssmError::throwMe(CSSMERR_CL_INVALID_CACHE_HANDLE);
161	}
162
163	CssmAutoData aData(*this);
164	uint32 numMatches;
165
166	/* this returns false if field not there, throws on bad OID */
167	if(!cachedCert->cert().getCertFieldData(CertField,
168			0, 				// index
169			numMatches,
170			aData)) {
171		return CSSM_INVALID_HANDLE;
172	}
173
174	/* cook up a CLQuery, stash it */
175	CLQuery *query = new CLQuery(
176		CLQ_Cert,
177		CertField,
178		numMatches,
179		true,				// isFromCache
180		cachedCert->handle());
181	queryMap.addEntry(*query, query->handle());
182
183	/* success - copy field data to outgoing Value */
184	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
185	*Value = aData.release();
186	NumberOfMatchedFields = numMatches;
187	return query->handle();
188}
189
190
191bool
192AppleX509CLSession::CertGetNextCachedFieldValue(
193	CSSM_HANDLE ResultsHandle,
194	CSSM_DATA_PTR &Value)
195{
196	/* Identical to, so just call... */
197	return CertGetNextFieldValue(ResultsHandle, Value);
198}
199
200void
201AppleX509CLSession::CertAbortCache(
202	CSSM_HANDLE CertHandle)
203{
204	/* fetch the associated cached cert, remove from map, delete it */
205	CLCachedCert *cachedCert = lookupCachedCert(CertHandle);
206	if(cachedCert == NULL) {
207		clErrorLog("CertAbortCache: cachedCert not found");
208		CssmError::throwMe(CSSMERR_CL_INVALID_CACHE_HANDLE);
209	}
210	cacheMap.removeEntry(cachedCert->handle());
211	delete cachedCert;
212}
213
214/*
215 * Abort either type of cert field query (cache based or non-cache based)
216 */
217void
218AppleX509CLSession::CertAbortQuery(
219	CSSM_HANDLE ResultsHandle)
220{
221	/* fetch & validate the query */
222	CLQuery *query = queryMap.lookupEntry(ResultsHandle);
223	if(query == NULL) {
224		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
225	}
226	if(query->queryType() != CLQ_Cert) {
227		clErrorLog("CertAbortQuery: bad queryType (%d)", (int)query->queryType());
228		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
229	}
230
231	if(!query->fromCache()) {
232		/* the associated cached cert was created just for this query; dispose */
233		CLCachedCert *cachedCert = lookupCachedCert(query->cachedObject());
234		if(cachedCert == NULL) {
235			/* should never happen */
236			clErrorLog("CertAbortQuery: cachedCert not found");
237			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
238		}
239		cacheMap.removeEntry(cachedCert->handle());
240		delete cachedCert;
241	}
242	queryMap.removeEntry(query->handle());
243	delete query;
244}
245
246void
247AppleX509CLSession::CertCreateTemplate(
248	uint32 NumberOfFields,
249	const CSSM_FIELD CertFields[],
250	CssmData &CertTemplate)
251{
252	/* cook up an empty Cert */
253	DecodedCert cert(*this);
254
255	/* grind thru specified fields; exceptions are fatal */
256	for(uint32 dex=0; dex<NumberOfFields; dex++) {
257		cert.setCertField(
258			CssmOid::overlay(CertFields[dex].FieldOid),
259			CssmData::overlay(CertFields[dex].FieldValue));
260	}
261
262	/* TBD - ensure all required fields are set? We do this
263	 * when we sign the cert; maybe we should do it here. */
264
265	/*
266	 * We have the CertificateToSign in NSS format. Encode.
267	 */
268	CertTemplate.Data = NULL;
269	CertTemplate.Length = 0;
270	CssmRemoteData rData(*this, CertTemplate);
271	cert.encodeTbs(rData);
272	rData.release();
273}
274
275
276void
277AppleX509CLSession::CertGetAllTemplateFields(
278	const CssmData &CertTemplate,
279	uint32 &NumberOfFields,
280	CSSM_FIELD_PTR &CertFields)
281{
282	DecodedCert	cert(*this);		// empty
283	cert.decodeTbs(CertTemplate);
284	cert.getAllParsedCertFields(NumberOfFields, CertFields);
285}
286
287void
288AppleX509CLSession::FreeFields(
289	uint32 NumberOfFields,
290	CSSM_FIELD_PTR &FieldArray)
291{
292	unsigned 		i;
293	CSSM_FIELD_PTR 	thisField;
294	CSSM_OID_PTR	thisOid;
295
296	for(i=0; i<NumberOfFields; i++) {
297		thisField = &FieldArray[i];
298		thisOid = &thisField->FieldOid;
299
300		/* oid-specific handling of value */
301		/* BUG - the CssmRemoteData constructor clears the referent,
302		 * iff the referent is a CSSSM_DATA (as opposed to a CssmData).
303		 */
304		CssmData &cData = CssmData::overlay(thisField->FieldValue);
305		CssmRemoteData rData(*this, cData);
306		try {
307			DecodedCert::freeCertFieldData(CssmOid::overlay(*thisOid), rData);
308		}
309		catch(...) {
310			/* CRL field? */
311			DecodedCrl::freeCrlFieldData(CssmOid::overlay(*thisOid), rData);
312		}
313		/* and the oid itself */
314		free(thisOid->Data);
315		thisOid->Data = NULL;
316		thisOid->Length = 0;
317	}
318	free(FieldArray);
319}
320
321void
322AppleX509CLSession::FreeFieldValue(
323	const CssmData &CertOrCrlOid,
324	CssmData &Value)
325{
326	CssmRemoteData cd(*this, Value);
327	try {
328		DecodedCert::freeCertFieldData(CertOrCrlOid, cd);
329	}
330	catch(...) {
331		/* CRL field? */
332		DecodedCrl::freeCrlFieldData(CertOrCrlOid, cd);
333	}
334	free(&Value);
335}
336
337void
338AppleX509CLSession::CertGroupFromVerifiedBundle(
339	CSSM_CC_HANDLE CCHandle,
340	const CSSM_CERT_BUNDLE &CertBundle,
341	const CssmData *SignerCert,
342	CSSM_CERTGROUP_PTR &CertGroup)
343{
344	unimplemented();
345}
346
347void
348AppleX509CLSession::CertGroupToSignedBundle(
349	CSSM_CC_HANDLE CCHandle,
350	const CSSM_CERTGROUP &CertGroupToBundle,
351	const CSSM_CERT_BUNDLE_HEADER *BundleInfo,
352	CssmData &SignedBundle)
353{
354	unimplemented();
355}
356
357void
358AppleX509CLSession::PassThrough(
359	CSSM_CC_HANDLE CCHandle,
360	uint32 PassThroughId,
361	const void *InputParams,
362	void **OutputParams)
363{
364	switch(PassThroughId) {
365		case CSSM_APPLEX509CL_OBTAIN_CSR:
366		{
367			/*
368			 * Create a Cert Signing Request (CSR).
369			 * Input is a CSSM_APPLE_CL_CSR_REQUEST.
370			 * Output is a PEM-encoded CertSigningRequest (NSS type
371			 * NSS_SignedCertRequest from pkcs10).
372			 */
373			if(InputParams == NULL) {
374				CssmError::throwMe(CSSMERR_CL_INVALID_INPUT_POINTER);
375			}
376			if(OutputParams == NULL) {
377				CssmError::throwMe(CSSMERR_CL_INVALID_OUTPUT_POINTER);
378			}
379			CSSM_APPLE_CL_CSR_REQUEST *csrReq =
380				(CSSM_APPLE_CL_CSR_REQUEST *)InputParams;
381			if((csrReq->subjectNameX509 == NULL) ||
382			(csrReq->signatureOid.Data == NULL) ||
383			(csrReq->subjectPublicKey == NULL) ||
384			(csrReq->subjectPrivateKey == NULL)) {
385				CssmError::throwMe(CSSMERR_CL_INVALID_INPUT_POINTER);
386			}
387			CSSM_DATA_PTR csrPtr = NULL;
388			generateCsr(CCHandle, csrReq, csrPtr);
389			*OutputParams = csrPtr;
390			break;
391		}
392		case CSSM_APPLEX509CL_VERIFY_CSR:
393		{
394			/*
395			 * Perform signature verify of a CSR.
396			 * Input:  CSSM_DATA referring to a DER-encoded CSR.
397			 * Output: Nothing, throws CSSMERR_CL_VERIFICATION_FAILURE
398			 *         on failure.
399			 */
400			if(InputParams == NULL) {
401				CssmError::throwMe(CSSMERR_CL_INVALID_INPUT_POINTER);
402			}
403			const CSSM_DATA *csrPtr = (const CSSM_DATA *)InputParams;
404			verifyCsr(csrPtr);
405			break;
406		}
407		default:
408			CssmError::throwMe(CSSMERR_CL_INVALID_PASSTHROUGH_ID);
409	}
410}
411
412