1/*
2 * Copyright (c) 2004 Apple Computer, 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#include <string.h>
25#include "CommonCode.h"
26#include "DSX509Relation.h"
27#include <security_utilities/debugging.h>
28#include "CommonCrypto/CommonDigest.h"
29
30/*
31	int mNumberOfValues;
32	Value* mValues;
33	BlobValue *mData;
34*/
35
36DSX509Tuple::DSX509Tuple (int numberOfValues) : mNumberOfValues (numberOfValues), mValues (NULL), mData (NULL)
37{
38	mValues = new Value*[numberOfValues];
39	for (int i = 0; i < numberOfValues; ++i)
40		mValues[i] = NULL;
41}
42
43
44
45DSX509Tuple::~DSX509Tuple ()
46{
47	// walk the value array and delete each value
48	for (int i = 0; i < mNumberOfValues; ++i)
49		if (mValues[i] != NULL) delete mValues[i];
50	delete [] mValues;
51
52	if (mData != NULL) delete mData;
53}
54
55
56
57void DSX509Tuple::SetValue (int i, Value* v)
58{
59	mValues[i] = v;
60}
61
62
63
64Value* DSX509Tuple::GetValue (int i)
65{
66	return mValues[i];
67}
68
69
70
71int DSX509Tuple::GetNumberOfValues ()
72{
73	return mNumberOfValues;
74}
75
76
77
78void DSX509Tuple::GetData (CSSM_DATA &data)
79{
80	size_t t;
81	const uint8* d = mData->GetRawValue (t);
82	data.Data = (uint8*) d;
83	data.Length = t;
84}
85
86
87
88void DSX509Tuple::SetData (BlobValue *value)
89{
90	mData = value;
91}
92
93
94
95DSX509UniqueIdentifier::DSX509UniqueIdentifier (DSX509Tuple *t) :
96	UniqueIdentifier (CSSM_DL_DB_RECORD_X509_CERTIFICATE), mTuple (t)
97{
98}
99
100
101
102DSX509UniqueIdentifier::~DSX509UniqueIdentifier ()
103{
104	delete mTuple;
105}
106
107
108
109void DSX509UniqueIdentifier::Export (CSSM_DB_UNIQUE_RECORD &record)
110{
111	// memset the whole thing to 0, we don't care
112	memset (&record, 0, sizeof (CSSM_DB_UNIQUE_RECORD));
113}
114
115
116
117DSX509Tuple* DSX509UniqueIdentifier::GetTuple ()
118{
119	return mTuple;
120}
121
122
123
124static void * appMalloc (CSSM_SIZE size, void *allocRef) {
125	return (malloc (size));
126}
127
128
129
130static void appFree (void *mem_ptr, void *allocRef) {
131	free (mem_ptr);
132 	return;
133}
134
135
136
137static void * appRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
138	return (realloc (ptr, size));
139}
140
141
142
143static void * appCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
144	return (calloc (num, size));
145}
146
147
148
149static CSSM_API_MEMORY_FUNCS memFuncs = {
150	appMalloc,
151	appFree,
152	appRealloc,
153 	appCalloc,
154 	NULL
155 };
156
157
158
159static void CheckResult (CSSM_RETURN result)
160{
161	if (result != 0) throw CSSMError (result);
162}
163
164
165
166void DSX509Relation::InitializeCertLibrary ()
167{
168	if (mCertificateLibrary != 0) return;
169
170	// figure out which GUID to attach to
171	const CSSM_GUID* attachGuid = &gGuidAppleX509CL;
172
173	// Initialize CDSA
174	CSSM_VERSION version = {2, 0};
175
176	// load the CL
177	CSSM_RETURN result = CSSM_ModuleLoad (attachGuid, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
178	CheckResult (result);
179
180	result = CSSM_ModuleAttach (attachGuid, &version, &memFuncs, 0,	 CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &mCertificateLibrary);
181	CheckResult (result);
182}
183
184
185
186DSX509Relation::DSX509Relation (CSSM_DB_RECORDTYPE recordType, int numberOfColumns, columnInfoLoader *theColumnInfo) : PartialRelation (CSSM_DL_DB_RECORD_X509_CERTIFICATE, kNumberOfX509Attributes,theColumnInfo), mCertificateLibrary (0)
187{
188	mDirectoryService = new DirectoryService();
189}
190
191
192
193DSX509Relation::~DSX509Relation ()
194{
195	if (mCertificateLibrary != 0)
196		CSSM_ModuleDetach (mCertificateLibrary);
197}
198
199
200
201Query* DSX509Relation::MakeQuery (const CSSM_QUERY* query)
202{
203	return new DSX509Query (this, query);
204}
205
206
207
208Tuple* DSX509Relation::GetTupleFromUniqueIdentifier (UniqueIdentifier* uniqueID)
209{
210	DSX509UniqueIdentifier *id = (DSX509UniqueIdentifier*) uniqueID;
211	return id->GetTuple ();
212}
213
214
215
216UniqueIdentifier* DSX509Relation::ImportUniqueIdentifier (CSSM_DB_UNIQUE_RECORD *uniqueRecord)
217{
218	throw CSSMERR_DL_UNSUPPORTED_QUERY;
219}
220
221
222
223CSSM_CL_HANDLE DSX509Relation::GetCLHandle ()
224{
225	InitializeCertLibrary ();
226	return mCertificateLibrary;
227}
228
229
230
231
232DSX509Query::DSX509Query (DSX509Relation* relation, const CSSM_QUERY *queryBase) :
233	Query (relation, queryBase), mRecordCount (0), mCurrentItem (1),
234	mRecordList (NULL), mNumberOfTuples (0), mNextTuple (0)
235{
236	CSSM_RETURN error;
237	// attach to open directory
238	mRecordList = relation->mDirectoryService->translate_cssm_query_to_OD_query(queryBase, &error);
239	if(!mRecordList) throw CSSMERR_DL_ENDOFDATA;
240}
241
242
243
244DSX509Query::~DSX509Query ()
245{
246	// delete mRecordList;	need to release the results handle
247}
248
249
250
251
252
253
254
255static bool CompareOIDs (const CSSM_OID &a, const CSSM_OID &b)
256{
257	if (a.Length != b.Length) return false;
258	return memcmp (a.Data, b.Data, a.Length) == 0;
259}
260
261
262
263static CSSM_DATA GetValueFromFields (CSSM_FIELD *fields, uint32 numFields, const CSSM_OID& oid)
264{
265	uint32 i;
266	for (i = 0; i < numFields; ++i)
267		if (CompareOIDs (fields[i].FieldOid, oid)) return fields[i].FieldValue;
268
269	throw CSSMERR_CSSM_INVALID_ATTRIBUTE;
270}
271
272
273
274static CSSM_DATA* GetAttributeFromX509Name (CSSM_X509_NAME *name, const CSSM_OID& oid)
275{
276	uint32 i;
277	for (i = 0; i < name->numberOfRDNs; ++i) {
278		CSSM_X509_RDN &rdn = name->RelativeDistinguishedName[i];
279		uint32 j;
280		for (j = 0; j < rdn.numberOfPairs; ++j) {
281			CSSM_X509_TYPE_VALUE_PAIR &pair = rdn.AttributeTypeAndValue[j];
282			if (CompareOIDs (pair.type, oid))
283				return &pair.value;
284		}
285	}
286	return NULL;
287}
288
289
290
291Tuple* DSX509Query::GetNextTuple (UniqueIdentifier *&id)
292{
293	DSX509Tuple* t;
294	CFStringRef original_search;
295
296	original_search = this->mRecordList->searchString;
297
298	// get the current item from the list
299	CFDataRef	certData = this->mDirectoryService->getNextCertFromResults(this->mRecordList);
300	if(!certData) return NULL;
301	DSX509Record record ((DSX509Relation*) mRelation);
302
303	t = record.GetTuple (certData, original_search, mTupleList, kMaxTuples);
304	mNextTuple++;
305
306	if (EvaluateTuple (t)) {
307		id = new DSX509UniqueIdentifier (t);
308		return t;
309	}
310	return NULL;
311}
312
313
314
315
316DSX509Tuple* DSX509Record::GetTuple (CFDataRef certData, CFStringRef original_search, DSX509Tuple *tupleList[], int maxTuples)
317{
318	DSX509Tuple** tupleFinger = tupleList;
319	CSSM_CL_HANDLE clHandle = mRelation->GetCLHandle ();
320	// we now need to parse the cert
321	CSSM_DATA cert;
322	cert.Data = (uint8 *) CFDataGetBytePtr(certData);
323	cert.Length = CFDataGetLength(certData);
324
325	CSSM_FIELD *fields;
326	uint32 numberOfFields;
327
328	CSSM_RETURN result = CSSM_CL_CertGetAllFields (clHandle, &cert, &numberOfFields, &fields);
329	CheckResult (result);
330
331	CSSM_DATA data;
332
333	// get the version
334	data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1Version);
335	// make a tuple
336	DSX509Tuple* t = new DSX509Tuple (kNumberOfX509Attributes);
337
338	// set the data types
339	t->SetValue (kCertTypeID, new UInt32Value (*(uint32*) data.Data));
340	t->SetValue (kCertEncodingID, new UInt32Value (CSSM_CERT_ENCODING_DER));
341
342	// we need the print name, so start with the subject name
343	data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SubjectNameCStruct);
344
345	// from there, get the attribute
346	CSSM_X509_NAME* namePtr = (CSSM_X509_NAME*) data.Data;
347	CSSM_DATA *dp;
348	dp = GetAttributeFromX509Name (namePtr, CSSMOID_CommonName);
349	t->SetValue (kCertPrintName, dp == NULL ? new BlobValue (original_search)  : new BlobValue (*dp));
350
351	//  set the email address to the original search string
352	t->SetValue (kCertAlias, new BlobValue (original_search));
353
354	// get the subject
355	data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SubjectName);
356	t->SetValue (kCertSubject, new BlobValue (data));
357
358	// get the issuer
359	data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1IssuerName);
360	t->SetValue (kCertIssuer, new BlobValue (data));
361
362	// get the serial number
363	data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SerialNumber);
364	t->SetValue (kCertSerialNumber, new BlobValue (data));
365
366	// handle the subject key identifier
367	t->SetValue (kCertSubjectKeyIdentifier, NULL);
368
369	// make hash of the public key.
370	data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SubjectPublicKeyCStruct);
371	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *publicKeyInfo = (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *) data.Data;
372
373	CC_SHA1_CTX context;
374	CC_SHA1_Init (&context);
375	CC_SHA1_Update (&context, publicKeyInfo->subjectPublicKey.Data, publicKeyInfo->subjectPublicKey.Length);
376
377	uint8 sha1Digest [20];
378	CC_SHA1_Final (sha1Digest, &context);
379
380	t->SetValue (kCertPublicKeyHash, new BlobValue (sha1Digest, 20));
381
382	// release the cert data
383	CSSM_CL_FreeFields (clHandle, numberOfFields, &fields);
384
385	// get the data that we will ultimately return
386	t->SetData (new BlobValue (cert));
387
388	// save off the tuple
389	*tupleFinger++ = t;
390	--maxTuples;
391	return t;
392}
393