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// Apple X.509 CRL-related session functions.
21//
22
23#include "AppleX509CLSession.h"
24#include "clNssUtils.h"
25#include "clNameUtils.h"
26
27void
28AppleX509CLSession::CrlDescribeFormat(
29	uint32 &NumberOfFields,
30	CSSM_OID_PTR &OidList)
31{
32	DecodedCrl::describeFormat(*this, NumberOfFields, OidList);
33}
34
35
36void
37AppleX509CLSession::CrlGetAllFields(
38	const CssmData &Crl,
39	uint32 &NumberOfCrlFields,
40	CSSM_FIELD_PTR &CrlFields)
41{
42	class DecodedCrl decodedCrl(*this, Crl);
43	decodedCrl.getAllParsedCrlFields(NumberOfCrlFields, CrlFields);
44}
45
46
47CSSM_HANDLE
48AppleX509CLSession::CrlGetFirstFieldValue(
49	const CssmData &Crl,
50	const CssmData &CrlField,
51	uint32 &NumberOfMatchedFields,
52	CSSM_DATA_PTR &Value)
53{
54	NumberOfMatchedFields = 0;
55	Value = NULL;
56	CssmAutoData aData(*this);
57
58	DecodedCrl *decodedCrl = new DecodedCrl(*this, Crl);
59	uint32 numMatches;
60
61	/* this returns false if field not there, throws on bad OID */
62	bool brtn;
63	try {
64		brtn = decodedCrl->getCrlFieldData(CrlField,
65			0, 				// index
66			numMatches,
67			aData);
68	}
69	catch (...) {
70		delete decodedCrl;
71		throw;
72	}
73	if(!brtn) {
74		delete decodedCrl;
75		return CSSM_INVALID_HANDLE;
76	}
77
78	/* cook up a CLCachedCRL, stash it in cache */
79	CLCachedCRL *cachedCrl = new CLCachedCRL(*decodedCrl);
80	cacheMap.addEntry(*cachedCrl, cachedCrl->handle());
81
82	/* cook up a CLQuery, stash it */
83	CLQuery *query = new CLQuery(
84		CLQ_CRL,
85		CrlField,
86		numMatches,
87		false,				// isFromCache
88		cachedCrl->handle());
89	queryMap.addEntry(*query, query->handle());
90
91	/* success - copy field data to outgoing Value */
92	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
93	*Value = aData.release();
94	NumberOfMatchedFields = numMatches;
95	return query->handle();
96}
97
98
99bool
100AppleX509CLSession::CrlGetNextFieldValue(
101	CSSM_HANDLE ResultsHandle,
102	CSSM_DATA_PTR &Value)
103{
104	/* fetch & validate the query */
105	CLQuery *query = queryMap.lookupEntry(ResultsHandle);
106	if(query == NULL) {
107		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
108	}
109	if(query->queryType() != CLQ_CRL) {
110		clErrorLog("CrlGetNextFieldValue: bad queryType (%d)",
111			(int)query->queryType());
112		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
113	}
114	if(query->nextIndex() >= query->numFields()) {
115		return false;
116	}
117
118	/* fetch the associated cached CRL */
119	CLCachedCRL *cachedCrl = lookupCachedCRL(query->cachedObject());
120	uint32 dummy;
121	CssmAutoData aData(*this);
122	if(!cachedCrl->crl().getCrlFieldData(query->fieldId(),
123		query->nextIndex(),
124		dummy,
125		aData))  {
126		return false;
127	}
128
129	/* success - copy field data to outgoing Value */
130	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
131	*Value = aData.release();
132	query->incrementIndex();
133	return true;
134}
135
136
137void
138AppleX509CLSession::IsCertInCrl(
139	const CssmData &Cert,
140	const CssmData &Crl,
141	CSSM_BOOL &CertFound)
142{
143	/*
144	 * Decode the two entities. Note that doing it this way incurs
145	 * the unnecessary (for our purposes) overhead of decoding
146	 * extensions, but doing it this way is so spiffy that I can't
147	 * resist.
148	 */
149	DecodedCert decodedCert(*this, Cert);
150	DecodedCrl  decodedCrl(*this, Crl);
151
152	NSS_TBSCertificate &tbsCert = decodedCert.mCert.tbs;
153	NSS_TBSCrl &tbsCrl = decodedCrl.mCrl.tbs;
154
155	/* trivial case - empty CRL */
156	unsigned numCrlEntries =
157		clNssArraySize((const void **)tbsCrl.revokedCerts);
158	if(numCrlEntries == 0) {
159		clFieldLog("IsCertInCrl: empty CRL");
160		CertFound = CSSM_FALSE;
161		return;
162	}
163
164	/*
165	 * Get normalized and encoded versions of issuer names.
166	 * Since the decoded entities are local, we can normalize in place.
167	 */
168	CssmAutoData encCertIssuer(*this);
169	CssmAutoData encCrlIssuer(*this);
170	try {
171		/* snag a handy temp allocator */
172		SecNssCoder &coder = decodedCert.coder();
173		CL_normalizeX509NameNSS(tbsCert.issuer, coder);
174		PRErrorCode prtn = SecNssEncodeItemOdata(&tbsCert.issuer,
175			kSecAsn1NameTemplate, encCertIssuer);
176		if(prtn) {
177			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
178		}
179
180		CL_normalizeX509NameNSS(tbsCrl.issuer, coder);
181		prtn = SecNssEncodeItemOdata(&tbsCrl.issuer,
182			kSecAsn1NameTemplate, encCrlIssuer);
183		if(prtn) {
184			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
185		}
186	}
187	catch(...) {
188		clFieldLog("IsCertInCrl: normalize failure");
189		throw;
190	}
191
192	/* issuer names match? */
193	CertFound = CSSM_FALSE;
194	if(encCertIssuer.get() != encCrlIssuer.get()) {
195		clFieldLog("IsCertInCrl: issuer name mismatch");
196		return;
197	}
198
199	/* is this cert's serial number in the CRL? */
200	CSSM_DATA &certSerial = tbsCert.serialNumber;
201	for(unsigned dex=0; dex<numCrlEntries; dex++) {
202		NSS_RevokedCert *revokedCert = tbsCrl.revokedCerts[dex];
203		assert(revokedCert != NULL);
204		CSSM_DATA &revokedSerial = revokedCert->userCertificate;
205		if(clCompareCssmData(&certSerial, &revokedSerial)) {
206			/* success */
207			CertFound = CSSM_TRUE;
208			break;
209		}
210	}
211}
212
213#pragma mark --- Cached ---
214
215void
216AppleX509CLSession::CrlCache(
217	const CssmData &Crl,
218	CSSM_HANDLE &CrlHandle)
219{
220	DecodedCrl *decodedCrl = new DecodedCrl(*this, Crl);
221
222	/* cook up a CLCachedCRL, stash it in cache */
223	CLCachedCRL *cachedCrl = new CLCachedCRL(*decodedCrl);
224	cacheMap.addEntry(*cachedCrl, cachedCrl->handle());
225	CrlHandle = cachedCrl->handle();
226}
227
228/*
229 * FIXME - CrlRecordIndex not supported, it'll require mods to
230 * the DecodedCrl::getCrlFieldData mechanism
231 */
232CSSM_HANDLE
233AppleX509CLSession::CrlGetFirstCachedFieldValue(
234	CSSM_HANDLE CrlHandle,
235	const CssmData *CrlRecordIndex,
236	const CssmData &CrlField,
237	uint32 &NumberOfMatchedFields,
238	CSSM_DATA_PTR &Value)
239{
240	if(CrlRecordIndex != NULL) {
241		/* not yet */
242		CssmError::throwMe(CSSMERR_CL_INVALID_CRL_INDEX);
243	}
244
245	/* fetch the associated cached CRL */
246	CLCachedCRL *cachedCrl = lookupCachedCRL(CrlHandle);
247	if(cachedCrl == NULL) {
248		CssmError::throwMe(CSSMERR_CL_INVALID_CACHE_HANDLE);
249	}
250
251	CssmAutoData aData(*this);
252	uint32 numMatches;
253
254	/* this returns false if field not there, throws on bad OID */
255	if(!cachedCrl->crl().getCrlFieldData(CrlField,
256			0, 				// index
257			numMatches,
258			aData)) {
259		return CSSM_INVALID_HANDLE;
260	}
261
262	/* cook up a CLQuery, stash it */
263	CLQuery *query = new CLQuery(
264		CLQ_CRL,
265		CrlField,
266		numMatches,
267		true,				// isFromCache
268		cachedCrl->handle());
269	queryMap.addEntry(*query, query->handle());
270
271	/* success - copy field data to outgoing Value */
272	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
273	*Value = aData.release();
274	NumberOfMatchedFields = numMatches;
275	return query->handle();
276}
277
278
279bool
280AppleX509CLSession::CrlGetNextCachedFieldValue(
281	CSSM_HANDLE ResultsHandle,
282	CSSM_DATA_PTR &Value)
283{
284	/* Identical to, so just call... */
285	return CrlGetNextFieldValue(ResultsHandle, Value);
286}
287
288
289void
290AppleX509CLSession::IsCertInCachedCrl(
291	const CssmData &Cert,
292	CSSM_HANDLE CrlHandle,
293	CSSM_BOOL &CertFound,
294	CssmData &CrlRecordIndex)
295{
296	unimplemented();
297}
298
299
300void
301AppleX509CLSession::CrlAbortCache(
302	CSSM_HANDLE CrlHandle)
303{
304	/* fetch the associated cached CRL, remove from map, delete it */
305	CLCachedCRL *cachedCrl = lookupCachedCRL(CrlHandle);
306	if(cachedCrl == NULL) {
307		CssmError::throwMe(CSSMERR_CL_INVALID_CACHE_HANDLE);
308	}
309	cacheMap.removeEntry(cachedCrl->handle());
310	delete cachedCrl;
311}
312
313
314void
315AppleX509CLSession::CrlAbortQuery(
316	CSSM_HANDLE ResultsHandle)
317{
318	/* fetch & validate the query */
319	CLQuery *query = queryMap.lookupEntry(ResultsHandle);
320	if(query == NULL) {
321		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
322	}
323	if(query->queryType() != CLQ_CRL) {
324		clErrorLog("CrlAbortQuery: bad queryType (%d)", (int)query->queryType());
325		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
326	}
327
328	if(!query->fromCache()) {
329		/* the associated cached CRL was created just for this query; dispose */
330		CLCachedCRL *cachedCrl = lookupCachedCRL(query->cachedObject());
331		if(cachedCrl == NULL) {
332			/* should never happen */
333			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
334		}
335		cacheMap.removeEntry(cachedCrl->handle());
336		delete cachedCrl;
337	}
338	queryMap.removeEntry(query->handle());
339	delete query;
340}
341
342#pragma mark --- Template ---
343
344void
345AppleX509CLSession::CrlCreateTemplate(
346	uint32 NumberOfFields,
347	const CSSM_FIELD *CrlTemplate,
348	CssmData &NewCrl)
349{
350	unimplemented();
351}
352
353
354void
355AppleX509CLSession::CrlSetFields(
356	uint32 NumberOfFields,
357	const CSSM_FIELD *CrlTemplate,
358	const CssmData &OldCrl,
359	CssmData &ModifiedCrl)
360{
361	unimplemented();
362}
363
364
365void
366AppleX509CLSession::CrlAddCert(
367	CSSM_CC_HANDLE CCHandle,
368	const CssmData &Cert,
369	uint32 NumberOfFields,
370	const CSSM_FIELD CrlEntryFields[],
371	const CssmData &OldCrl,
372	CssmData &NewCrl)
373{
374	unimplemented();
375}
376
377
378void
379AppleX509CLSession::CrlRemoveCert(
380	const CssmData &Cert,
381	const CssmData &OldCrl,
382	CssmData &NewCrl)
383{
384	unimplemented();
385}
386
387
388void
389AppleX509CLSession::CrlGetAllCachedRecordFields(
390	CSSM_HANDLE CrlHandle,
391	const CssmData &CrlRecordIndex,
392	uint32 &NumberOfFields,
393	CSSM_FIELD_PTR &CrlFields)
394{
395	unimplemented();
396}
397
398/*
399 * These are functionally identical to the corresponding
400 * Cert functions.
401 */
402void
403AppleX509CLSession::CrlVerifyWithKey(
404	CSSM_CC_HANDLE CCHandle,
405	const CssmData &CrlToBeVerified)
406{
407	CertVerifyWithKey(CCHandle, CrlToBeVerified);
408}
409
410
411void
412AppleX509CLSession::CrlVerify(
413	CSSM_CC_HANDLE CCHandle,
414	const CssmData &CrlToBeVerified,
415	const CssmData *SignerCert,
416	const CSSM_FIELD *VerifyScope,
417	uint32 ScopeSize)
418{
419	CertVerify(CCHandle, CrlToBeVerified, SignerCert, VerifyScope,
420		ScopeSize);
421}
422
423void
424AppleX509CLSession::CrlSign(
425	CSSM_CC_HANDLE CCHandle,
426	const CssmData &UnsignedCrl,
427	const CSSM_FIELD *SignScope,
428	uint32 ScopeSize,
429	CssmData &SignedCrl)
430{
431	unimplemented();
432}
433
434
435
436
437