]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/certGroupUtils.cpp
Security-29.tar.gz
[apple/security.git] / AppleX509TP / certGroupUtils.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 certGroupUtils.cpp
21
22 Created 10/9/2000 by Doug Mitchell.
23 */
24
25 #include <Security/cssmtype.h>
26 #include <Security/cssmapi.h>
27 #include <Security/x509defs.h>
28 #include <Security/oidscert.h>
29 #include <Security/oidsalg.h>
30 #include <Security/cssmapple.h>
31
32 #include "certGroupUtils.h"
33 #include "cldebugging.h"
34 #include "tpTime.h"
35
36 #include <string.h> /* for memcmp */
37
38 #if 0
39 void *tpCalloc(CssmAllocator &alloc, uint32 num, uint32 size)
40 {
41 void *p = alloc.malloc(num * size);
42 memset(p, 0, num* size);
43 return p;
44 }
45 #endif
46
47 /*
48 * Copy one CSSM_DATA to another, mallocing destination.
49 */
50 void tpCopyCssmData(
51 CssmAllocator &alloc,
52 const CSSM_DATA *src,
53 CSSM_DATA_PTR dst)
54 {
55 dst->Data = (uint8 *)alloc.malloc(src->Length);
56 dst->Length = src->Length;
57 memmove(dst->Data, src->Data, src->Length);
58 }
59
60 /*
61 * Malloc a CSSM_DATA, copy another one to it.
62 */
63 CSSM_DATA_PTR tpMallocCopyCssmData(
64 CssmAllocator &alloc,
65 const CSSM_DATA *src)
66 {
67 CSSM_DATA_PTR dst = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA));
68 tpCopyCssmData(alloc, src, dst);
69 return dst;
70 }
71
72 /*
73 * Free the data referenced by a CSSM data, and optionally, the struct itself.
74 */
75 void tpFreeCssmData(
76 CssmAllocator &alloc,
77 CSSM_DATA_PTR data,
78 CSSM_BOOL freeStruct)
79 {
80 if(data == NULL) {
81 return;
82 }
83 if(data->Length != 0) {
84 tpFree(alloc, data->Data);
85 }
86 if(freeStruct) {
87 tpFree(alloc, data);
88 }
89 else {
90 data->Length = 0;
91 data->Data = NULL;
92 }
93 }
94
95 /*
96 * Compare two CSSM_DATAs, return CSSM_TRUE if identical.
97 */
98 CSSM_BOOL tpCompareCssmData(
99 const CSSM_DATA *data1,
100 const CSSM_DATA *data2)
101 {
102 if((data1 == NULL) || (data1->Data == NULL) ||
103 (data2 == NULL) || (data2->Data == NULL) ||
104 (data1->Length != data2->Length)) {
105 return CSSM_FALSE;
106 }
107 if(data1->Length != data2->Length) {
108 return CSSM_FALSE;
109 }
110 if(memcmp(data1->Data, data2->Data, data1->Length) == 0) {
111 return CSSM_TRUE;
112 }
113 else {
114 return CSSM_FALSE;
115 }
116 }
117
118 /*
119 * Compare two OIDs, return CSSM_TRUE if identical.
120 */
121 CSSM_BOOL tpCompareOids(
122 const CSSM_OID *oid1,
123 const CSSM_OID *oid2)
124 {
125 /*
126 * This should break if/when CSSM_OID is not the same as
127 * CSSM_DATA, which is exactly what we want.
128 */
129 return tpCompareCssmData(oid1, oid2);
130 }
131
132 /*
133 * Obtain the public key blob from a cert.
134 */
135 CSSM_DATA_PTR tp_CertGetPublicKey(
136 TPCertInfo *cert,
137 CSSM_DATA_PTR *valueToFree) // used in tp_CertFreePublicKey
138 {
139 CSSM_RETURN crtn;
140 CSSM_DATA_PTR val;
141 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *keyInfo;
142
143 *valueToFree = NULL;
144 crtn = cert->fetchField(&CSSMOID_X509V1SubjectPublicKeyCStruct, &val);
145 if(crtn) {
146 errorLog0("Error on CSSM_CL_CertGetFirstFieldValue(PublicKeyCStruct)\n");
147 return NULL;
148 }
149 *valueToFree = val;
150 keyInfo = (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)val->Data;
151 return &keyInfo->subjectPublicKey;
152 }
153
154 void tp_CertFreePublicKey(
155 CSSM_CL_HANDLE clHand,
156 CSSM_DATA_PTR value)
157 {
158 CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SubjectPublicKeyCStruct, value);
159 }
160
161 /*
162 * Obtain signature algorithm info from a cert.
163 */
164 CSSM_X509_ALGORITHM_IDENTIFIER_PTR tp_CertGetAlgId(
165 TPCertInfo *cert,
166 CSSM_DATA_PTR *valueToFree) // used in tp_CertFreeAlgId
167 {
168 CSSM_RETURN crtn;
169 CSSM_DATA_PTR val;
170
171 *valueToFree = NULL;
172 crtn = cert->fetchField(&CSSMOID_X509V1SignatureAlgorithm, &val);
173 if(crtn) {
174 errorLog0("Error on fetchField(CSSMOID_X509V1SignatureAlgorithm)\n");
175 return NULL;
176 }
177 *valueToFree = val;
178 return (CSSM_X509_ALGORITHM_IDENTIFIER_PTR)val->Data;
179 }
180
181 void tp_CertFreeAlgId(
182 CSSM_CL_HANDLE clHand,
183 CSSM_DATA_PTR value)
184 {
185 CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SignatureAlgorithm, value);
186 }
187
188 /*
189 * Compare two DER-encoded normalized names.
190 */
191 CSSM_BOOL tpIsSameName(
192 const CSSM_DATA *name1,
193 const CSSM_DATA *name2)
194 {
195 return tpCompareCssmData(name1, name2);
196 }
197
198
199 /*
200 * Given a TP handle, a CSP handle, a CL handle, and two certs, verify
201 * subjectCert with issuerCert. If checkIssuerExpired is CSSM_TRUE,
202 * we'll do a not before/after check of the issuer only if the
203 * signature verify passes. The rationale is that we're not interested
204 * in this condition for potential issuers which fail the sig verify.
205 *
206 * Returns:
207 * CSSM_OK
208 * CSSMERR_TP_VERIFICATION_FAILURE -- sig verify failure
209 * CSSMERR_TP_CERT_EXPIRED
210 * CSSMERR_TP_CERT_NOT_VALID_YET
211 */
212 CSSM_RETURN tp_VerifyCert(
213 CSSM_CL_HANDLE clHand,
214 CSSM_CSP_HANDLE cspHand,
215 TPCertInfo *subjectCert,
216 TPCertInfo *issuerCert,
217 CSSM_BOOL checkIssuerCurrent,
218 CSSM_BOOL allowExpired)
219 {
220 CSSM_RETURN crtn;
221
222 crtn = CSSM_CL_CertVerify(clHand,
223 CSSM_INVALID_HANDLE,
224 subjectCert->certData(),
225 issuerCert->certData(),
226 NULL, // VerifyScope
227 0); // ScopeSize
228 if(crtn == CSSM_OK) {
229 if(checkIssuerCurrent) {
230 /* also verify validity of issuer */
231 crtn = issuerCert->isCurrent(allowExpired);
232 }
233 }
234 else {
235 /* general cert verify failure */
236 crtn = CSSMERR_TP_VERIFICATION_FAILURE;
237 }
238 return crtn;
239 }
240
241 /*
242 * Determine if two certs - passed in encoded form - are equivalent.
243 */
244 CSSM_BOOL tp_CompareCerts(
245 const CSSM_DATA *cert1,
246 const CSSM_DATA *cert2)
247 {
248 return tpCompareCssmData(cert1, cert2);
249 }
250
251 #if TP_DL_ENABLE
252 /*
253 * Given a DL/DB, look up cert by subject name. Subsequent
254 * certs can be found using the returned result handle.
255 */
256 static CSSM_DB_UNIQUE_RECORD_PTR tpCertLookup(
257 CSSM_TP_HANDLE tpHand,
258 CSSM_DL_DB_HANDLE dlDb,
259 const CSSM_DATA_PTR subjectName, // DER-encoded
260 CSSM_HANDLE_PTR resultHand,
261 CSSM_DATA_PTR cert) // RETURNED
262 {
263 CSSM_QUERY query;
264 CSSM_SELECTION_PREDICATE predicate;
265 CSSM_BOOL EndOfDataStore;
266 CSSM_DB_UNIQUE_RECORD_PTR record;
267
268 cert->Data = NULL;
269 cert->Length = 0;
270
271 predicate.DbOperator = CSSM_DB_EQUAL;
272 predicate.Attribute.Info.AttributeNameFormat =
273 CSSM_DB_ATTRIBUTE_NAME_AS_NUMBER; // may not be needed
274 predicate.Attribute.Info.Attr.AttributeNumber = kSubjectKCItemAttr;
275 predicate.Attribute.Value = *subjectName;
276
277 query.RecordType = CSSM_DL_DB_RECORD_CERT;
278 query.NumSelectionPredicates = 1;
279 query.Conjunctive = CSSM_DB_NONE;
280
281 query.SelectionPredicate = &predicate;
282
283 record = CSSM_DL_DataGetFirst(dlDb,
284 &query,
285 resultHand,
286 &EndOfDataStore,
287 NULL, // don't fetch attributes
288 cert);
289 return record;
290 }
291
292 /*
293 * Search a list of DBs for a cert which verifies specified subject cert.
294 * Just a boolean return - we found it, or not. If we did, we return
295 * a pointer to the raw cert.
296 *
297 * Special case of subject cert expired indicated by *subjectExpired
298 * returned as something other than CSSM_OK.
299 */
300 CSSM_DATA_PTR tpFindIssuer(
301 CSSM_TP_HANDLE tpHand,
302 CSSM_CL_HANDLE clHand,
303 CSSM_CSP_HANDLE cspHand,
304 const CSSM_DATA_PTR subjectCert,
305 const CSSM_DATA_PTR issuerName, // passed for convenience
306 const CSSM_DB_LIST_PTR dbList,
307 CSSM_RETURN *issuerExpired) // RETURNED
308 {
309 uint32 dbDex;
310 CSSM_HANDLE resultHand;
311 CSSM_DATA_PTR cert; // we malloc
312 CSSM_DL_DB_HANDLE dlDb;
313 CSSM_DB_UNIQUE_RECORD_PTR record;
314
315 *subjectExpired = CSSM_OK;
316 if(dbList == NULL) {
317 return NULL;
318 }
319 cert = (CSSM_DATA_PTR)tpMalloc(tpHand, sizeof(CSSM_DATA));
320 cert->Data = NULL;
321 cert->Length = 0;
322
323 for(dbDex=0; dbDex<dbList->NumHandles; dbDex++) {
324 dlDb = dbList->DLDBHandle[dbDex];
325 record = tpCertLookup(tpHand,
326 dlDb,
327 issuerName,
328 &resultHand,
329 cert);
330 /* remember we have to abort this query regardless...*/
331 if(record != NULL) {
332 /* Found one. Does it verify the subject cert? */
333 if(!tp_VerifyCert(tpHand,
334 clHand,
335 cspHand,
336 subjectCert,
337 cert,
338 issuerExpired)) {
339
340 /* special case - abort immediately if issuerExpired has expired */
341 if((*issuerExpired) != CSSM_OK) {
342 CSSM_DL_AbortQuery(dlDb, resultHand);
343 goto abort;
344 }
345
346 /*
347 * Verify fail. Continue searching this DB. Break on
348 * finding the holy grail or no more records found.
349 */
350 for(;;) {
351 CSSM_BOOL eod;
352
353 tpFreeCssmData(tpHand, cert, CSSM_FALSE);
354 record = CSSM_DL_DataGetNext(dlDb,
355 resultHand,
356 &eod,
357 NULL, // no attrs
358 cert);
359 if(record == NULL) {
360 /* no more, done with this DB */
361 break;
362 }
363
364 /* found one - does it verify subject? */
365 if(tp_VerifyCert(tpHand,
366 clHand,
367 cspHand,
368 subjectCert,
369 cert,
370 issuerExpired)) {
371 /* yes! */
372 break;
373 }
374 else if((*issuerExpired) != CSSM_OK) {
375 /* abort immediately */
376 CSSM_DL_AbortQuery(dlDb, resultHand);
377 goto abort;
378 }
379 } /* searching subsequent records */
380 } /* verify fail */
381 /* else success! */
382
383 if(record != NULL) {
384 /* successful return */
385 CSSM_DL_AbortQuery(dlDb, resultHand);
386 return cert;
387 }
388 } /* tpCertLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
389
390 /* in any case, abort the query for this db */
391 CSSM_DL_AbortQuery(dlDb, resultHand);
392
393 } /* main loop searching dbList */
394
395 abort:
396 /* issuer not found */
397 tpFreeCssmData(tpHand, cert, CSSM_TRUE);
398 return NULL;
399 }
400
401 #endif /* TP_DL_ENABLE */
402
403 /*
404 * Given a aignature OID, return the corresponding CSSM_ALGID for the
405 * signature the required key.
406 */
407 CSSM_ALGORITHMS tpOidToAldId(
408 const CSSM_OID *oid,
409 CSSM_ALGORITHMS *keyAlg) // RETURNED
410 {
411 *keyAlg = CSSM_ALGID_RSA; // default
412 if(tpCompareOids(oid, &CSSMOID_MD2WithRSA)) {
413 return CSSM_ALGID_MD2WithRSA;
414 }
415 else if(tpCompareOids(oid, &CSSMOID_MD5WithRSA)) {
416 return CSSM_ALGID_MD5WithRSA;
417 }
418 else if(tpCompareOids(oid, &CSSMOID_SHA1WithRSA)) {
419 return CSSM_ALGID_SHA1WithRSA;
420 }
421 else if(tpCompareOids(oid, &CSSMOID_SHA1WithDSA)) {
422 *keyAlg = CSSM_ALGID_DSA;
423 return CSSM_ALGID_SHA1WithDSA;
424 }
425 else if(tpCompareOids(oid, &CSSMOID_APPLE_FEE_MD5)) {
426 *keyAlg = CSSM_ALGID_FEE;
427 return CSSM_ALGID_FEE_MD5;
428 }
429 else if(tpCompareOids(oid, &CSSMOID_APPLE_FEE_SHA1)) {
430 *keyAlg = CSSM_ALGID_FEE;
431 return CSSM_ALGID_FEE_SHA1;
432 }
433 else if(tpCompareOids(oid, &CSSMOID_APPLE_ECDSA)) {
434 *keyAlg = CSSM_ALGID_FEE;
435 return CSSM_ALGID_SHA1WithECDSA;
436 }
437 else {
438 *keyAlg = CSSM_ALGID_NONE;
439 return CSSM_ALGID_NONE;
440 }
441 }