]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/certGroupUtils.cpp
Security-54.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) // to be deleted
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 TP_CERT_CURRENT_CHECK_INLINE
230 if(checkIssuerCurrent) {
231 /* also verify validity of issuer */
232 crtn = issuerCert->isCurrent(allowExpired);
233 }
234 #endif
235 }
236 else {
237 /* general cert verify failure */
238 crtn = CSSMERR_TP_VERIFICATION_FAILURE;
239 }
240 return crtn;
241 }
242
243 /*
244 * Determine if two certs - passed in encoded form - are equivalent.
245 */
246 CSSM_BOOL tp_CompareCerts(
247 const CSSM_DATA *cert1,
248 const CSSM_DATA *cert2)
249 {
250 return tpCompareCssmData(cert1, cert2);
251 }
252
253 #if TP_DL_ENABLE
254 /*
255 * Given a DL/DB, look up cert by subject name. Subsequent
256 * certs can be found using the returned result handle.
257 */
258 static CSSM_DB_UNIQUE_RECORD_PTR tpCertLookup(
259 CSSM_DL_DB_HANDLE dlDb,
260 const CSSM_DATA *subjectName, // DER-encoded
261 CSSM_HANDLE_PTR resultHand,
262 CSSM_DATA_PTR cert) // RETURNED
263 {
264 CSSM_QUERY query;
265 CSSM_SELECTION_PREDICATE predicate;
266 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
267
268 cert->Data = NULL;
269 cert->Length = 0;
270
271 /* SWAG until cert schema nailed down */
272 predicate.DbOperator = CSSM_DB_EQUAL;
273 predicate.Attribute.Info.AttributeNameFormat =
274 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
275 predicate.Attribute.Info.Label.AttributeName = "Subject";
276 predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
277 predicate.Attribute.Value = const_cast<CSSM_DATA_PTR>(subjectName);
278 predicate.Attribute.NumberOfValues = 1;
279
280 query.RecordType = CSSM_DL_DB_RECORD_X509_CERTIFICATE;
281 query.Conjunctive = CSSM_DB_NONE;
282 query.NumSelectionPredicates = 1;
283 query.SelectionPredicate = &predicate;
284 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
285 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
286 query.QueryFlags = 0; // FIXME - used?
287
288 CSSM_DL_DataGetFirst(dlDb,
289 &query,
290 resultHand,
291 NULL, // don't fetch attributes
292 cert,
293 &record);
294 return record;
295 }
296
297 /*
298 * Search a list of DBs for a cert which verifies specified subject cert.
299 * Just a boolean return - we found it, or not. If we did, we return
300 * TPCertInfo associated with the raw cert.
301 *
302 * Special case of subject cert expired indicated by *subjectExpired
303 * returned as something other than CSSM_OK.
304 */
305 TPCertInfo *tpFindIssuer(
306 CssmAllocator &alloc,
307 CSSM_CL_HANDLE clHand,
308 CSSM_CSP_HANDLE cspHand,
309 TPCertInfo *subjectCert,
310 const CSSM_DATA *issuerName, // TBD - passed for convenience
311 const CSSM_DL_DB_LIST *dbList,
312 const char *cssmTimeStr, // may be NULL
313 CSSM_RETURN *issuerExpired) // RETURNED
314 {
315 uint32 dbDex;
316 CSSM_HANDLE resultHand;
317 CSSM_DATA_PTR cert; // we malloc
318 CSSM_DL_DB_HANDLE dlDb;
319 CSSM_DB_UNIQUE_RECORD_PTR record;
320 TPCertInfo *issuerCert = NULL;
321
322 *issuerExpired = CSSM_OK;
323 if(dbList == NULL) {
324 return NULL;
325 }
326 cert = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA));
327 cert->Data = NULL;
328 cert->Length = 0;
329
330 for(dbDex=0; dbDex<dbList->NumHandles; dbDex++) {
331 dlDb = dbList->DLDBHandle[dbDex];
332 record = tpCertLookup(dlDb,
333 issuerName,
334 &resultHand,
335 cert);
336 /* remember we have to abort this query regardless...*/
337 if(record != NULL) {
338 /* Found one. Does it verify the subject cert? */
339 issuerCert = new TPCertInfo(cert, clHand, cssmTimeStr, CSSM_TRUE);
340 if(tp_VerifyCert(clHand,
341 cspHand,
342 subjectCert,
343 issuerCert,
344 CSSM_FALSE, // check current, ignored
345 CSSM_FALSE)) { // allowExpired, ignored
346
347 delete issuerCert;
348 issuerCert = NULL;
349
350 /* special case - abort immediately if issuerExpired has expired */
351 if((*issuerExpired) != CSSM_OK) {
352 CSSM_DL_DataAbortQuery(dlDb, resultHand);
353 goto abort;
354 }
355
356 /*
357 * Verify fail. Continue searching this DB. Break on
358 * finding the holy grail or no more records found.
359 */
360 for(;;) {
361 tpFreeCssmData(alloc, cert, CSSM_FALSE);
362 CSSM_RETURN crtn = CSSM_DL_DataGetNext(dlDb,
363 resultHand,
364 NULL, // no attrs
365 cert,
366 &record);
367 if(crtn) {
368 /* no more, done with this DB */
369 break;
370 }
371
372 /* found one - does it verify subject? */
373 issuerCert = new TPCertInfo(cert, clHand, cssmTimeStr,
374 CSSM_TRUE);
375 if(tp_VerifyCert(clHand,
376 cspHand,
377 subjectCert,
378 issuerCert,
379 CSSM_FALSE,
380 CSSM_FALSE)) {
381 /* yes! */
382 break;
383 }
384 delete issuerCert;
385 issuerCert = NULL;
386 } /* searching subsequent records */
387 } /* verify fail */
388 /* else success! */
389
390 if(issuerCert != NULL) {
391 /* successful return */
392 CSSM_DL_DataAbortQuery(dlDb, resultHand);
393 issuerCert->dlDbHandle(dlDb);
394 issuerCert->uniqueRecord(record);
395 return issuerCert;
396 }
397 } /* tpCertLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
398
399 /* in any case, abort the query for this db */
400 CSSM_DL_DataAbortQuery(dlDb, resultHand);
401
402 } /* main loop searching dbList */
403
404 abort:
405 /* issuer not found */
406 tpFreeCssmData(alloc, cert, CSSM_TRUE);
407 return NULL;
408 }
409
410 #endif /* TP_DL_ENABLE */
411
412 /*
413 * Given a aignature OID, return the corresponding CSSM_ALGID for the
414 * signature the required key.
415 */
416 CSSM_ALGORITHMS tpOidToAldId(
417 const CSSM_OID *oid,
418 CSSM_ALGORITHMS *keyAlg) // RETURNED
419 {
420 *keyAlg = CSSM_ALGID_RSA; // default
421 if(tpCompareOids(oid, &CSSMOID_MD2WithRSA)) {
422 return CSSM_ALGID_MD2WithRSA;
423 }
424 else if(tpCompareOids(oid, &CSSMOID_MD5WithRSA)) {
425 return CSSM_ALGID_MD5WithRSA;
426 }
427 else if(tpCompareOids(oid, &CSSMOID_SHA1WithRSA)) {
428 return CSSM_ALGID_SHA1WithRSA;
429 }
430 else if(tpCompareOids(oid, &CSSMOID_SHA1WithDSA)) {
431 *keyAlg = CSSM_ALGID_DSA;
432 return CSSM_ALGID_SHA1WithDSA;
433 }
434 else if(tpCompareOids(oid, &CSSMOID_APPLE_FEE_MD5)) {
435 *keyAlg = CSSM_ALGID_FEE;
436 return CSSM_ALGID_FEE_MD5;
437 }
438 else if(tpCompareOids(oid, &CSSMOID_APPLE_FEE_SHA1)) {
439 *keyAlg = CSSM_ALGID_FEE;
440 return CSSM_ALGID_FEE_SHA1;
441 }
442 else if(tpCompareOids(oid, &CSSMOID_APPLE_ECDSA)) {
443 *keyAlg = CSSM_ALGID_FEE;
444 return CSSM_ALGID_SHA1WithECDSA;
445 }
446 else {
447 *keyAlg = CSSM_ALGID_NONE;
448 return CSSM_ALGID_NONE;
449 }
450 }