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
) // to be deleted
222 crtn
= CSSM_CL_CertVerify(clHand
,
224 subjectCert
->certData(),
225 issuerCert
->certData(),
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
);
237 /* general cert verify failure */
238 crtn
= CSSMERR_TP_VERIFICATION_FAILURE
;
244 * Determine if two certs - passed in encoded form - are equivalent.
246 CSSM_BOOL
tp_CompareCerts(
247 const CSSM_DATA
*cert1
,
248 const CSSM_DATA
*cert2
)
250 return tpCompareCssmData(cert1
, cert2
);
255 * Given a DL/DB, look up cert by subject name. Subsequent
256 * certs can be found using the returned result handle.
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
265 CSSM_SELECTION_PREDICATE predicate
;
266 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
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;
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?
288 CSSM_DL_DataGetFirst(dlDb
,
291 NULL
, // don't fetch attributes
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.
302 * Special case of subject cert expired indicated by *subjectExpired
303 * returned as something other than CSSM_OK.
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
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
;
322 *issuerExpired
= CSSM_OK
;
326 cert
= (CSSM_DATA_PTR
)alloc
.malloc(sizeof(CSSM_DATA
));
330 for(dbDex
=0; dbDex
<dbList
->NumHandles
; dbDex
++) {
331 dlDb
= dbList
->DLDBHandle
[dbDex
];
332 record
= tpCertLookup(dlDb
,
336 /* remember we have to abort this query regardless...*/
338 /* Found one. Does it verify the subject cert? */
339 issuerCert
= new TPCertInfo(cert
, clHand
, cssmTimeStr
, CSSM_TRUE
);
340 if(tp_VerifyCert(clHand
,
344 CSSM_FALSE
, // check current, ignored
345 CSSM_FALSE
)) { // allowExpired, ignored
350 /* special case - abort immediately if issuerExpired has expired */
351 if((*issuerExpired
) != CSSM_OK
) {
352 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
357 * Verify fail. Continue searching this DB. Break on
358 * finding the holy grail or no more records found.
361 tpFreeCssmData(alloc
, cert
, CSSM_FALSE
);
362 CSSM_RETURN crtn
= CSSM_DL_DataGetNext(dlDb
,
368 /* no more, done with this DB */
372 /* found one - does it verify subject? */
373 issuerCert
= new TPCertInfo(cert
, clHand
, cssmTimeStr
,
375 if(tp_VerifyCert(clHand
,
386 } /* searching subsequent records */
390 if(issuerCert
!= NULL
) {
391 /* successful return */
392 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
393 issuerCert
->dlDbHandle(dlDb
);
394 issuerCert
->uniqueRecord(record
);
397 } /* tpCertLookup, i.e., CSSM_DL_DataGetFirst, succeeded */
399 /* in any case, abort the query for this db */
400 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
402 } /* main loop searching dbList */
405 /* issuer not found */
406 tpFreeCssmData(alloc
, cert
, CSSM_TRUE
);
410 #endif /* TP_DL_ENABLE */
413 * Given a aignature OID, return the corresponding CSSM_ALGID for the
414 * signature the required key.
416 CSSM_ALGORITHMS
tpOidToAldId(
418 CSSM_ALGORITHMS
*keyAlg
) // RETURNED
420 *keyAlg
= CSSM_ALGID_RSA
; // default
421 if(tpCompareOids(oid
, &CSSMOID_MD2WithRSA
)) {
422 return CSSM_ALGID_MD2WithRSA
;
424 else if(tpCompareOids(oid
, &CSSMOID_MD5WithRSA
)) {
425 return CSSM_ALGID_MD5WithRSA
;
427 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithRSA
)) {
428 return CSSM_ALGID_SHA1WithRSA
;
430 else if(tpCompareOids(oid
, &CSSMOID_SHA1WithDSA
)) {
431 *keyAlg
= CSSM_ALGID_DSA
;
432 return CSSM_ALGID_SHA1WithDSA
;
434 else if(tpCompareOids(oid
, &CSSMOID_APPLE_FEE_MD5
)) {
435 *keyAlg
= CSSM_ALGID_FEE
;
436 return CSSM_ALGID_FEE_MD5
;
438 else if(tpCompareOids(oid
, &CSSMOID_APPLE_FEE_SHA1
)) {
439 *keyAlg
= CSSM_ALGID_FEE
;
440 return CSSM_ALGID_FEE_SHA1
;
442 else if(tpCompareOids(oid
, &CSSMOID_APPLE_ECDSA
)) {
443 *keyAlg
= CSSM_ALGID_FEE
;
444 return CSSM_ALGID_SHA1WithECDSA
;
447 *keyAlg
= CSSM_ALGID_NONE
;
448 return CSSM_ALGID_NONE
;