2 * Copyright (c) 2001-2003 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
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
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
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
22 Description: common CDSA access utilities
27 #include "cuCdsaUtils.h"
30 #include <Security/SecCertificate.h>
31 #include <Security/cssmapple.h> /* for cssmPerror() */
32 #include <Security/oidsalg.h> /* for cssmPerror() */
35 static CSSM_VERSION vers
= {2, 0};
36 static const CSSM_GUID testGuid
= { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
39 * Standard app-level memory functions required by CDSA.
41 void * cuAppMalloc (uint32 size
, void *allocRef
) {
42 return( malloc(size
) );
45 void cuAppFree (void *mem_ptr
, void *allocRef
) {
50 void * cuAppRealloc (void *ptr
, uint32 size
, void *allocRef
) {
51 return( realloc( ptr
, size
) );
54 void * cuAppCalloc (uint32 num
, uint32 size
, void *allocRef
) {
55 return( calloc( num
, size
) );
58 static CSSM_API_MEMORY_FUNCS memFuncs
= {
66 CSSM_BOOL
cuCompareCssmData(const CSSM_DATA
*d1
,
69 if(d1
->Length
!= d2
->Length
) {
72 if(memcmp(d1
->Data
, d2
->Data
, d1
->Length
)) {
79 * Init CSSM; returns CSSM_FALSE on error. Reusable.
81 static CSSM_BOOL cssmInitd
= CSSM_FALSE
;
83 CSSM_BOOL
cuCssmStartup()
86 CSSM_PVC_MODE pvcPolicy
= CSSM_PVC_NONE
;
91 crtn
= CSSM_Init (&vers
,
92 CSSM_PRIVILEGE_SCOPE_NONE
,
94 CSSM_KEY_HIERARCHY_NONE
,
99 cuPrintError("CSSM_Init", crtn
);
103 cssmInitd
= CSSM_TRUE
;
109 * Attach to CSP. Returns zero on error.
111 CSSM_CSP_HANDLE
cuCspStartup(
112 CSSM_BOOL bareCsp
) // true ==> CSP, false ==> CSP/DL
114 CSSM_CSP_HANDLE cspHand
;
116 const CSSM_GUID
*guid
;
118 /* common CSSM init */
119 if(cuCssmStartup() == CSSM_FALSE
) {
123 guid
= &gGuidAppleCSP
;
126 guid
= &gGuidAppleCSPDL
;
128 crtn
= CSSM_ModuleLoad(guid
,
129 CSSM_KEY_HIERARCHY_NONE
,
130 NULL
, // eventHandler
131 NULL
); // AppNotifyCallbackCtx
133 cuPrintError("CSSM_ModuleLoad()", crtn
);
136 crtn
= CSSM_ModuleAttach (guid
,
138 &memFuncs
, // memFuncs
142 CSSM_KEY_HIERARCHY_NONE
,
143 NULL
, // FunctionTable
148 cuPrintError("CSSM_ModuleAttach()", crtn
);
154 /* Attach to DL side of CSPDL */
155 CSSM_DL_HANDLE
cuDlStartup()
157 CSSM_DL_HANDLE dlHand
= 0;
160 if(cuCssmStartup() == CSSM_FALSE
) {
163 crtn
= CSSM_ModuleLoad(&gGuidAppleCSPDL
,
164 CSSM_KEY_HIERARCHY_NONE
,
165 NULL
, // eventHandler
166 NULL
); // AppNotifyCallbackCtx
168 cuPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn
);
171 crtn
= CSSM_ModuleAttach (&gGuidAppleCSPDL
,
173 &memFuncs
, // memFuncs
177 CSSM_KEY_HIERARCHY_NONE
,
178 NULL
, // FunctionTable
183 cuPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn
);
189 CSSM_CL_HANDLE
cuClStartup()
191 CSSM_CL_HANDLE clHand
;
194 if(cuCssmStartup() == CSSM_FALSE
) {
197 crtn
= CSSM_ModuleLoad(&gGuidAppleX509CL
,
198 CSSM_KEY_HIERARCHY_NONE
,
199 NULL
, // eventHandler
200 NULL
); // AppNotifyCallbackCtx
202 cuPrintError("CSSM_ModuleLoad(AppleCL)", crtn
);
205 crtn
= CSSM_ModuleAttach (&gGuidAppleX509CL
,
207 &memFuncs
, // memFuncs
209 CSSM_SERVICE_CL
, // SubserviceFlags - Where is this used?
211 CSSM_KEY_HIERARCHY_NONE
,
212 NULL
, // FunctionTable
217 cuPrintError("CSSM_ModuleAttach(AppleCL)", crtn
);
225 CSSM_TP_HANDLE
cuTpStartup()
227 CSSM_TP_HANDLE tpHand
;
230 if(cuCssmStartup() == CSSM_FALSE
) {
233 crtn
= CSSM_ModuleLoad(&gGuidAppleX509TP
,
234 CSSM_KEY_HIERARCHY_NONE
,
235 NULL
, // eventHandler
236 NULL
); // AppNotifyCallbackCtx
238 cuPrintError("CSSM_ModuleLoad(AppleTP)", crtn
);
241 crtn
= CSSM_ModuleAttach (&gGuidAppleX509TP
,
243 &memFuncs
, // memFuncs
245 CSSM_SERVICE_TP
, // SubserviceFlags
247 CSSM_KEY_HIERARCHY_NONE
,
248 NULL
, // FunctionTable
253 cuPrintError("CSSM_ModuleAttach(AppleTP)", crtn
);
262 * open a DB, ensure it's empty.
264 CSSM_DB_HANDLE
cuDbStartup(
265 CSSM_DL_HANDLE dlHand
, // from dlStartup()
268 CSSM_DB_HANDLE dbHand
= 0;
272 /* first delete possible existing DB, ignore error */
273 crtn
= CSSM_DL_DbDelete(dlHand
, dbName
, NULL
, NULL
);
275 /* only allowed error is "no such file" */
277 case CSSMERR_DL_DATASTORE_DOESNOT_EXIST
:
280 cuPrintError("CSSM_DL_DbDelete", crtn
);
284 memset(&dbInfo
, 0, sizeof(CSSM_DBINFO
));
287 crtn
= CSSM_DL_DbCreate(dlHand
,
291 // &Security::KeychainCore::Schema::DBInfo,
292 CSSM_DB_ACCESS_PRIVILEGED
,
293 NULL
, // CredAndAclEntry
294 NULL
, // OpenParameters
297 cuPrintError("CSSM_DL_DbCreate", crtn
);
303 * Attach to existing DB or create an empty new one.
305 CSSM_DB_HANDLE
cuDbStartupByName(CSSM_DL_HANDLE dlHand
,
311 CSSM_DB_HANDLE dbHand
;
313 /* try open existing DB in either case */
315 crtn
= CSSM_DL_DbOpen(dlHand
,
318 CSSM_DB_ACCESS_READ
| CSSM_DB_ACCESS_WRITE
,
319 NULL
, // CSSM_ACCESS_CREDENTIALS *AccessCred
320 NULL
, // void *OpenParameters
322 if(crtn
== CSSM_OK
) {
327 printf("***no such data base (%s)\n", dbName
);
328 cuPrintError("CSSM_DL_DbOpen", crtn
);
332 /* have to create one */
333 return cuDbStartup(dlHand
, dbName
);
337 * Given a context specified via a CSSM_CC_HANDLE, add a new
338 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
339 * AttributeLength, and an untyped pointer.
341 CSSM_RETURN
cuAddContextAttribute(CSSM_CC_HANDLE CCHandle
,
342 uint32 AttributeType
,
343 uint32 AttributeLength
,
344 const void *AttributePtr
)
346 CSSM_CONTEXT_ATTRIBUTE newAttr
;
349 newAttr
.AttributeType
= AttributeType
;
350 newAttr
.AttributeLength
= AttributeLength
;
351 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)AttributePtr
;
352 crtn
= CSSM_UpdateContextAttributes(CCHandle
, 1, &newAttr
);
354 cuPrintError("CSSM_UpdateContextAttributes", crtn
);
361 * Derive symmetric key.
362 * Note in the X CSP, we never return an IV.
364 CSSM_RETURN
cuCspDeriveKey(CSSM_CSP_HANDLE cspHand
,
365 uint32 keyAlg
, // CSSM_ALGID_RC5, etc.
366 const char *keyLabel
,
367 unsigned keyLabelLen
,
368 uint32 keyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
369 uint32 keySizeInBits
,
370 CSSM_DATA_PTR password
, // in PKCS-5 lingo
371 CSSM_DATA_PTR salt
, // ditto
372 uint32 iterationCnt
, // ditto
376 CSSM_CC_HANDLE ccHand
;
378 CSSM_DATA dummyLabel
;
379 CSSM_PKCS5_PBKDF2_PARAMS pbeParams
;
381 CSSM_ACCESS_CREDENTIALS creds
;
383 memset(key
, 0, sizeof(CSSM_KEY
));
384 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
385 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
386 CSSM_ALGID_PKCS5_PBKDF2
,
396 cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
399 keyAttr
= CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
|
400 CSSM_KEYATTR_SENSITIVE
;
401 dummyLabel
.Length
= keyLabelLen
;
402 dummyLabel
.Data
= (uint8
*)keyLabel
;
404 /* passing in password is pretty strange....*/
405 pbeParams
.Passphrase
= *password
;
406 pbeParams
.PseudoRandomFunction
= CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1
;
407 pbeData
.Data
= (uint8
*)&pbeParams
;
408 pbeData
.Length
= sizeof(pbeParams
);
409 crtn
= CSSM_DeriveKey(ccHand
,
414 NULL
, // cred and acl
417 cuPrintError("CSSM_DeriveKey", crtn
);
420 crtn
= CSSM_DeleteContext(ccHand
);
422 cuPrintError("CSSM_DeleteContext", crtn
);
428 * Generate key pair of arbitrary algorithm.
431 /* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
432 #define DO_DSA_GEN_PARAMS 0
434 CSSM_RETURN
cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand
,
435 CSSM_DL_DB_HANDLE
*dlDbHand
, // optional
437 const char *keyLabel
,
438 unsigned keyLabelLen
,
439 uint32 keySize
, // in bits
440 CSSM_KEY_PTR pubKey
, // mallocd by caller
441 CSSM_KEYUSE pubKeyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
442 CSSM_KEYATTR_FLAGS pubAttrs
, // CSSM_KEYATTR_EXTRACTABLE, etc.
443 CSSM_KEY_PTR privKey
, // mallocd by caller
444 CSSM_KEYUSE privKeyUsage
, // CSSM_KEYUSE_DECRYPT, etc.
445 CSSM_KEYATTR_FLAGS privAttrs
) // CSSM_KEYATTR_EXTRACTABLE, etc.
449 CSSM_CC_HANDLE ccHand
;
450 CSSM_DATA keyLabelData
;
452 keyLabelData
.Data
= (uint8
*)keyLabel
,
453 keyLabelData
.Length
= keyLabelLen
;
454 memset(pubKey
, 0, sizeof(CSSM_KEY
));
455 memset(privKey
, 0, sizeof(CSSM_KEY
));
457 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
467 cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn
);
471 /* post-context-create algorithm-specific stuff */
473 #if DO_DSA_GEN_PARAMS
476 * extra step - generate params - this just adds some
477 * info to the context
480 CSSM_DATA dummy
= {0, NULL
};
481 crtn
= CSSM_GenerateAlgorithmParams(ccHand
,
484 cuPrintError("CSSM_GenerateAlgorithmParams", crtn
);
485 CSSM_DeleteContext(ccHand
);
488 cuAppFree(dummy
.Data
, NULL
);
491 #endif /* DO_DSA_GEN_PARAMS */
496 /* optionally specify DL/DB storage location */
498 crtn
= cuAddContextAttribute(ccHand
,
499 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
500 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
503 CSSM_DeleteContext(ccHand
);
507 ocrtn
= CSSM_GenerateKeyPair(ccHand
,
514 &keyLabelData
, // same labels
515 NULL
, // CredAndAclEntry
518 cuPrintError("CSSM_GenerateKeyPair", ocrtn
);
520 crtn
= CSSM_DeleteContext(ccHand
);
522 cuPrintError("CSSM_DeleteContext", crtn
);
523 if(ocrtn
== CSSM_OK
) {
524 /* error on CSSM_GenerateKeyPair takes precedence */
533 * Add a certificate to an open Keychain.
535 CSSM_RETURN
cuAddCertToKC(
536 SecKeychainRef keychain
,
537 const CSSM_DATA
*cert
,
538 CSSM_CERT_TYPE certType
,
539 CSSM_CERT_ENCODING certEncoding
,
540 const char *printName
, // C string
541 const CSSM_DATA
*keyLabel
) // ??
543 SecCertificateRef certificate
;
545 OSStatus rslt
= SecCertificateCreateFromData(cert
, certType
, certEncoding
, &certificate
);
548 rslt
= SecCertificateAddToKeychain(certificate
, keychain
);
549 CFRelease(certificate
);
556 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
559 unsigned cuDER_ToInt(const CSSM_DATA
*DER_Data
)
564 while(i
< DER_Data
->Length
) {
565 rtn
|= DER_Data
->Data
[i
];
566 if(++i
== DER_Data
->Length
) {
577 void cuPrintError(const char *op
, CSSM_RETURN err
)
583 * Verify a CRL against system anchors and intermediate certs.
585 CSSM_RETURN
cuCrlVerify(
586 CSSM_TP_HANDLE tpHand
,
587 CSSM_CL_HANDLE clHand
,
588 CSSM_CSP_HANDLE cspHand
,
589 const CSSM_DATA
*crlData
,
590 CSSM_DL_DB_HANDLE_PTR certKeychain
, // intermediate certs
591 const CSSM_DATA
*anchors
,
594 /* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
595 CSSM_TP_VERIFY_CONTEXT vfyCtx
;
596 CSSM_TP_CALLERAUTH_CONTEXT authCtx
;
598 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
599 memset(&authCtx
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
601 /* CSSM_TP_CALLERAUTH_CONTEXT components */
603 typedef struct cssm_tp_callerauth_context {
604 CSSM_TP_POLICYINFO Policy;
605 CSSM_TIMESTRING VerifyTime;
606 CSSM_TP_STOP_ON VerificationAbortOn;
607 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
608 uint32 NumberOfAnchorCerts;
609 CSSM_DATA_PTR AnchorCerts;
610 CSSM_DL_DB_LIST_PTR DBList;
611 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
612 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
615 CSSM_APPLE_TP_CRL_OPTIONS crlOpts
;
616 policyId
.FieldOid
= CSSMOID_APPLE_TP_REVOCATION_CRL
;
617 policyId
.FieldValue
.Data
= (uint8
*)&crlOpts
;
618 policyId
.FieldValue
.Length
= sizeof(crlOpts
);
619 crlOpts
.Version
= CSSM_APPLE_TP_CRL_OPTS_VERSION
;
620 /* perhaps this should be user-specifiable */
621 crlOpts
.CrlFlags
= CSSM_TP_ACTION_FETCH_CRL_FROM_NET
;
622 crlOpts
.crlStore
= NULL
;
624 authCtx
.Policy
.NumberOfPolicyIds
= 1;
625 authCtx
.Policy
.PolicyIds
= &policyId
;
626 authCtx
.Policy
.PolicyControl
= NULL
;
628 authCtx
.VerifyTime
= NULL
;
629 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
630 authCtx
.CallbackWithVerifiedCert
= NULL
;
633 authCtx
.NumberOfAnchorCerts
= anchorCount
;
634 authCtx
.AnchorCerts
= const_cast<CSSM_DATA_PTR
>(anchors
);
636 /* DBList of intermediate certs */
637 CSSM_DL_DB_HANDLE handles
[1];
639 if(certKeychain
!= NULL
) {
640 handles
[0] = *certKeychain
;
643 CSSM_DL_DB_LIST dlDbList
;
644 dlDbList
.DLDBHandle
= certKeychain
;
645 dlDbList
.NumHandles
= (certKeychain
? 1 : 0);
647 authCtx
.DBList
= &dlDbList
;
648 authCtx
.CallerCredentials
= NULL
;
650 /* CSSM_TP_VERIFY_CONTEXT */
651 vfyCtx
.ActionData
.Data
= NULL
;
652 vfyCtx
.ActionData
.Length
= 0;
653 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
654 vfyCtx
.Cred
= &authCtx
;
656 /* cook up CSSM_ENCODED_CRL */
657 CSSM_ENCODED_CRL encCrl
;
658 encCrl
.CrlType
= CSSM_CRL_TYPE_X_509v2
;
659 encCrl
.CrlEncoding
= CSSM_CRL_ENCODING_DER
;
660 encCrl
.CrlBlob
= *crlData
;
662 /* CDSA API requires a SignerCertGroup; for us, all the certs are in
664 CSSM_CERTGROUP certGroup
;
665 certGroup
.CertType
= CSSM_CERT_X_509v1
;
666 certGroup
.CertEncoding
= CSSM_CERT_ENCODING_DER
;
667 certGroup
.NumCerts
= 0;
668 certGroup
.GroupList
.CertList
= NULL
;
669 certGroup
.CertGroupType
= CSSM_CERTGROUP_DATA
;
671 CSSM_RETURN crtn
= CSSM_TP_CrlVerify(tpHand
,
677 NULL
); // RevokerVerifyResult
679 cuPrintError("CSSM_TP_CrlVerify", crtn
);