2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Created 10/9/2000 by Doug Mitchell.
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>
32 #include "certGroupUtils.h"
33 #include "cldebugging.h"
36 #include <string.h> /* for memcmp */
39 void *tpCalloc(CssmAllocator
&alloc
, uint32 num
, uint32 size
)
41 void *p
= alloc
.malloc(num
* size
);
42 memset(p
, 0, num
* size
);
48 * Copy one CSSM_DATA to another, mallocing destination.
55 dst
->Data
= (uint8
*)alloc
.malloc(src
->Length
);
56 dst
->Length
= src
->Length
;
57 memmove(dst
->Data
, src
->Data
, src
->Length
);
61 * Malloc a CSSM_DATA, copy another one to it.
63 CSSM_DATA_PTR
tpMallocCopyCssmData(
67 CSSM_DATA_PTR dst
= (CSSM_DATA_PTR
)alloc
.malloc(sizeof(CSSM_DATA
));
68 tpCopyCssmData(alloc
, src
, dst
);
73 * Free the data referenced by a CSSM data, and optionally, the struct itself.
83 if(data
->Length
!= 0) {
84 tpFree(alloc
, data
->Data
);
96 * Compare two CSSM_DATAs, return CSSM_TRUE if identical.
98 CSSM_BOOL
tpCompareCssmData(
99 const CSSM_DATA
*data1
,
100 const CSSM_DATA
*data2
)
102 if((data1
== NULL
) || (data1
->Data
== NULL
) ||
103 (data2
== NULL
) || (data2
->Data
== NULL
) ||
104 (data1
->Length
!= data2
->Length
)) {
107 if(data1
->Length
!= data2
->Length
) {
110 if(memcmp(data1
->Data
, data2
->Data
, data1
->Length
) == 0) {
119 * Compare two OIDs, return CSSM_TRUE if identical.
121 CSSM_BOOL
tpCompareOids(
122 const CSSM_OID
*oid1
,
123 const CSSM_OID
*oid2
)
126 * This should break if/when CSSM_OID is not the same as
127 * CSSM_DATA, which is exactly what we want.
129 return tpCompareCssmData(oid1
, oid2
);
133 * Obtain the public key blob from a cert.
135 CSSM_DATA_PTR
tp_CertGetPublicKey(
137 CSSM_DATA_PTR
*valueToFree
) // used in tp_CertFreePublicKey
141 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*keyInfo
;
144 crtn
= cert
->fetchField(&CSSMOID_X509V1SubjectPublicKeyCStruct
, &val
);
146 errorLog0("Error on CSSM_CL_CertGetFirstFieldValue(PublicKeyCStruct)\n");
150 keyInfo
= (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)val
->Data
;
151 return &keyInfo
->subjectPublicKey
;
154 void tp_CertFreePublicKey(
155 CSSM_CL_HANDLE clHand
,
158 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_X509V1SubjectPublicKeyCStruct
, value
);
162 * Obtain signature algorithm info from a cert.
164 CSSM_X509_ALGORITHM_IDENTIFIER_PTR
tp_CertGetAlgId(
166 CSSM_DATA_PTR
*valueToFree
) // used in tp_CertFreeAlgId
172 crtn
= cert
->fetchField(&CSSMOID_X509V1SignatureAlgorithm
, &val
);
174 errorLog0("Error on fetchField(CSSMOID_X509V1SignatureAlgorithm)\n");
178 return (CSSM_X509_ALGORITHM_IDENTIFIER_PTR
)val
->Data
;
181 void tp_CertFreeAlgId(
182 CSSM_CL_HANDLE clHand
,
185 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_X509V1SignatureAlgorithm
, value
);
189 * Compare two DER-encoded normalized names.
191 CSSM_BOOL
tpIsSameName(
192 const CSSM_DATA
*name1
,
193 const CSSM_DATA
*name2
)
195 return tpCompareCssmData(name1
, name2
);
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.
208 * CSSMERR_TP_VERIFICATION_FAILURE -- sig verify failure
209 * CSSMERR_TP_CERT_EXPIRED
210 * CSSMERR_TP_CERT_NOT_VALID_YET
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
)
222 crtn
= CSSM_CL_CertVerify(clHand
,
224 subjectCert
->certData(),
225 issuerCert
->certData(),
228 if(crtn
== CSSM_OK
) {
229 if(checkIssuerCurrent
) {
230 /* also verify validity of issuer */
231 crtn
= issuerCert
->isCurrent(allowExpired
);
235 /* general cert verify failure */
236 crtn
= CSSMERR_TP_VERIFICATION_FAILURE
;
242 * Determine if two certs - passed in encoded form - are equivalent.
244 CSSM_BOOL
tp_CompareCerts(
245 const CSSM_DATA
*cert1
,
246 const CSSM_DATA
*cert2
)
248 return tpCompareCssmData(cert1
, cert2
);
253 * Given a DL/DB, look up cert by subject name. Subsequent
254 * certs can be found using the returned result handle.
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
264 CSSM_SELECTION_PREDICATE predicate
;
265 CSSM_BOOL EndOfDataStore
;
266 CSSM_DB_UNIQUE_RECORD_PTR record
;
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
;
277 query
.RecordType
= CSSM_DL_DB_RECORD_CERT
;
278 query
.NumSelectionPredicates
= 1;
279 query
.Conjunctive
= CSSM_DB_NONE
;
281 query
.SelectionPredicate
= &predicate
;
283 record
= CSSM_DL_DataGetFirst(dlDb
,
287 NULL
, // don't fetch attributes
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.
297 * Special case of subject cert expired indicated by *subjectExpired
298 * returned as something other than CSSM_OK.
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
310 CSSM_HANDLE resultHand
;
311 CSSM_DATA_PTR cert
; // we malloc
312 CSSM_DL_DB_HANDLE dlDb
;
313 CSSM_DB_UNIQUE_RECORD_PTR record
;
315 *subjectExpired
= CSSM_OK
;
319 cert
= (CSSM_DATA_PTR
)tpMalloc(tpHand
, sizeof(CSSM_DATA
));
323 for(dbDex
=0; dbDex
<dbList
->NumHandles
; dbDex
++) {
324 dlDb
= dbList
->DLDBHandle
[dbDex
];
325 record
= tpCertLookup(tpHand
,
330 /* remember we have to abort this query regardless...*/
332 /* Found one. Does it verify the subject cert? */
333 if(!tp_VerifyCert(tpHand
,
340 /* special case - abort immediately if issuerExpired has expired */
341 if((*issuerExpired
) != CSSM_OK
) {
342 CSSM_DL_AbortQuery(dlDb
, resultHand
);
347 * Verify fail. Continue searching this DB. Break on
348 * finding the holy grail or no more records found.
353 tpFreeCssmData(tpHand
, cert
, CSSM_FALSE
);
354 record
= CSSM_DL_DataGetNext(dlDb
,
360 /* no more, done with this DB */
364 /* found one - does it verify subject? */
365 if(tp_VerifyCert(tpHand
,
374 else if((*issuerExpired
) != CSSM_OK
) {
375 /* abort immediately */
376 CSSM_DL_AbortQuery(dlDb
, resultHand
);
379 } /* searching subsequent records */
384 /* successful return */
385 CSSM_DL_AbortQuery(dlDb
, resultHand
);
388 } /* tpCertLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
390 /* in any case, abort the query for this db */
391 CSSM_DL_AbortQuery(dlDb
, resultHand
);
393 } /* main loop searching dbList */
396 /* issuer not found */
397 tpFreeCssmData(tpHand
, cert
, CSSM_TRUE
);
401 #endif /* TP_DL_ENABLE */
404 * Given a aignature OID, return the corresponding CSSM_ALGID for the
405 * signature the required key.
407 CSSM_ALGORITHMS
tpOidToAldId(
409 CSSM_ALGORITHMS
*keyAlg
) // RETURNED
411 *keyAlg
= CSSM_ALGID_RSA
; // default
412 if(tpCompareOids(oid
, &CSSMOID_MD2WithRSA
)) {
413 return CSSM_ALGID_MD2WithRSA
;
415 else if(tpCompareOids(oid
, &CSSMOID_MD5WithRSA
)) {
416 return CSSM_ALGID_MD5WithRSA
;
418 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithRSA
)) {
419 return CSSM_ALGID_SHA1WithRSA
;
421 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithDSA
)) {
422 *keyAlg
= CSSM_ALGID_DSA
;
423 return CSSM_ALGID_SHA1WithDSA
;
425 else if(tpCompareOids(oid
, &CSSMOID_APPLE_FEE_MD5
)) {
426 *keyAlg
= CSSM_ALGID_FEE
;
427 return CSSM_ALGID_FEE_MD5
;
429 else if(tpCompareOids(oid
, &CSSMOID_APPLE_FEE_SHA1
)) {
430 *keyAlg
= CSSM_ALGID_FEE
;
431 return CSSM_ALGID_FEE_SHA1
;
433 else if(tpCompareOids(oid
, &CSSMOID_APPLE_ECDSA
)) {
434 *keyAlg
= CSSM_ALGID_FEE
;
435 return CSSM_ALGID_SHA1WithECDSA
;
438 *keyAlg
= CSSM_ALGID_NONE
;
439 return CSSM_ALGID_NONE
;