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>
33 #include <Security/TrustSettingsSchema.h>
36 static CSSM_VERSION vers
= {2, 0};
37 static const CSSM_GUID testGuid
= { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
40 * Standard app-level memory functions required by CDSA.
42 void * cuAppMalloc (CSSM_SIZE size
, void *allocRef
) {
43 return( malloc(size
) );
46 void cuAppFree (void *mem_ptr
, void *allocRef
) {
51 void * cuAppRealloc (void *ptr
, CSSM_SIZE size
, void *allocRef
) {
52 return( realloc( ptr
, size
) );
55 void * cuAppCalloc (uint32 num
, CSSM_SIZE size
, void *allocRef
) {
56 return( calloc( num
, size
) );
59 static CSSM_API_MEMORY_FUNCS memFuncs
= {
67 CSSM_BOOL
cuCompareCssmData(const CSSM_DATA
*d1
,
70 if(d1
->Length
!= d2
->Length
) {
73 if(memcmp(d1
->Data
, d2
->Data
, d1
->Length
)) {
80 * Init CSSM; returns CSSM_FALSE on error. Reusable.
82 static CSSM_BOOL cssmInitd
= CSSM_FALSE
;
84 CSSM_BOOL
cuCssmStartup()
87 CSSM_PVC_MODE pvcPolicy
= CSSM_PVC_NONE
;
92 crtn
= CSSM_Init (&vers
,
93 CSSM_PRIVILEGE_SCOPE_NONE
,
95 CSSM_KEY_HIERARCHY_NONE
,
100 cuPrintError("CSSM_Init", crtn
);
104 cssmInitd
= CSSM_TRUE
;
110 * Attach to CSP. Returns zero on error.
112 CSSM_CSP_HANDLE
cuCspStartup(
113 CSSM_BOOL bareCsp
) // true ==> CSP, false ==> CSP/DL
115 CSSM_CSP_HANDLE cspHand
;
117 const CSSM_GUID
*guid
;
119 /* common CSSM init */
120 if(cuCssmStartup() == CSSM_FALSE
) {
124 guid
= &gGuidAppleCSP
;
127 guid
= &gGuidAppleCSPDL
;
129 crtn
= CSSM_ModuleLoad(guid
,
130 CSSM_KEY_HIERARCHY_NONE
,
131 NULL
, // eventHandler
132 NULL
); // AppNotifyCallbackCtx
134 cuPrintError("CSSM_ModuleLoad()", crtn
);
137 crtn
= CSSM_ModuleAttach (guid
,
139 &memFuncs
, // memFuncs
143 CSSM_KEY_HIERARCHY_NONE
,
144 NULL
, // FunctionTable
149 cuPrintError("CSSM_ModuleAttach()", crtn
);
155 /* Attach to DL side of CSPDL */
156 CSSM_DL_HANDLE
cuDlStartup()
158 CSSM_DL_HANDLE dlHand
= 0;
161 if(cuCssmStartup() == CSSM_FALSE
) {
164 crtn
= CSSM_ModuleLoad(&gGuidAppleCSPDL
,
165 CSSM_KEY_HIERARCHY_NONE
,
166 NULL
, // eventHandler
167 NULL
); // AppNotifyCallbackCtx
169 cuPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn
);
172 crtn
= CSSM_ModuleAttach (&gGuidAppleCSPDL
,
174 &memFuncs
, // memFuncs
178 CSSM_KEY_HIERARCHY_NONE
,
179 NULL
, // FunctionTable
184 cuPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn
);
190 CSSM_CL_HANDLE
cuClStartup()
192 CSSM_CL_HANDLE clHand
;
195 if(cuCssmStartup() == CSSM_FALSE
) {
198 crtn
= CSSM_ModuleLoad(&gGuidAppleX509CL
,
199 CSSM_KEY_HIERARCHY_NONE
,
200 NULL
, // eventHandler
201 NULL
); // AppNotifyCallbackCtx
203 cuPrintError("CSSM_ModuleLoad(AppleCL)", crtn
);
206 crtn
= CSSM_ModuleAttach (&gGuidAppleX509CL
,
208 &memFuncs
, // memFuncs
210 CSSM_SERVICE_CL
, // SubserviceFlags - Where is this used?
212 CSSM_KEY_HIERARCHY_NONE
,
213 NULL
, // FunctionTable
218 cuPrintError("CSSM_ModuleAttach(AppleCL)", crtn
);
226 CSSM_TP_HANDLE
cuTpStartup()
228 CSSM_TP_HANDLE tpHand
;
231 if(cuCssmStartup() == CSSM_FALSE
) {
234 crtn
= CSSM_ModuleLoad(&gGuidAppleX509TP
,
235 CSSM_KEY_HIERARCHY_NONE
,
236 NULL
, // eventHandler
237 NULL
); // AppNotifyCallbackCtx
239 cuPrintError("CSSM_ModuleLoad(AppleTP)", crtn
);
242 crtn
= CSSM_ModuleAttach (&gGuidAppleX509TP
,
244 &memFuncs
, // memFuncs
246 CSSM_SERVICE_TP
, // SubserviceFlags
248 CSSM_KEY_HIERARCHY_NONE
,
249 NULL
, // FunctionTable
254 cuPrintError("CSSM_ModuleAttach(AppleTP)", crtn
);
262 /* detach and unload */
263 CSSM_RETURN
cuCspDetachUnload(
264 CSSM_CSP_HANDLE cspHand
,
265 CSSM_BOOL bareCsp
) // true ==> CSP, false ==> CSP/DL
267 CSSM_RETURN crtn
= CSSM_ModuleDetach(cspHand
);
271 const CSSM_GUID
*guid
;
273 guid
= &gGuidAppleCSP
;
276 guid
= &gGuidAppleCSPDL
;
278 return CSSM_ModuleUnload(guid
, NULL
, NULL
);
281 CSSM_RETURN
cuClDetachUnload(
282 CSSM_CL_HANDLE clHand
)
284 CSSM_RETURN crtn
= CSSM_ModuleDetach(clHand
);
288 return CSSM_ModuleUnload(&gGuidAppleX509CL
, NULL
, NULL
);
292 CSSM_RETURN
cuDlDetachUnload(
293 CSSM_DL_HANDLE dlHand
)
295 CSSM_RETURN crtn
= CSSM_ModuleDetach(dlHand
);
299 return CSSM_ModuleUnload(&gGuidAppleCSPDL
, NULL
, NULL
);
302 CSSM_RETURN
cuTpDetachUnload(
303 CSSM_TP_HANDLE tpHand
)
305 CSSM_RETURN crtn
= CSSM_ModuleDetach(tpHand
);
309 return CSSM_ModuleUnload(&gGuidAppleX509TP
, NULL
, NULL
);
314 * open a DB, ensure it's empty.
316 CSSM_DB_HANDLE
cuDbStartup(
317 CSSM_DL_HANDLE dlHand
, // from dlStartup()
320 CSSM_DB_HANDLE dbHand
= 0;
324 /* first delete possible existing DB, ignore error */
325 crtn
= CSSM_DL_DbDelete(dlHand
, dbName
, NULL
, NULL
);
327 /* only allowed error is "no such file" */
329 case CSSMERR_DL_DATASTORE_DOESNOT_EXIST
:
332 cuPrintError("CSSM_DL_DbDelete", crtn
);
336 memset(&dbInfo
, 0, sizeof(CSSM_DBINFO
));
339 crtn
= CSSM_DL_DbCreate(dlHand
,
343 // &Security::KeychainCore::Schema::DBInfo,
344 CSSM_DB_ACCESS_PRIVILEGED
,
345 NULL
, // CredAndAclEntry
346 NULL
, // OpenParameters
349 cuPrintError("CSSM_DL_DbCreate", crtn
);
355 * Attach to existing DB or create an empty new one.
357 CSSM_DB_HANDLE
cuDbStartupByName(CSSM_DL_HANDLE dlHand
,
363 CSSM_DB_HANDLE dbHand
;
365 /* try open existing DB in either case */
367 crtn
= CSSM_DL_DbOpen(dlHand
,
370 CSSM_DB_ACCESS_READ
| CSSM_DB_ACCESS_WRITE
,
371 NULL
, // CSSM_ACCESS_CREDENTIALS *AccessCred
372 NULL
, // void *OpenParameters
374 if(crtn
== CSSM_OK
) {
379 printf("***no such data base (%s)\n", dbName
);
380 cuPrintError("CSSM_DL_DbOpen", crtn
);
384 /* have to create one */
385 return cuDbStartup(dlHand
, dbName
);
389 * Given a context specified via a CSSM_CC_HANDLE, add a new
390 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
391 * AttributeLength, and an untyped pointer.
393 CSSM_RETURN
cuAddContextAttribute(CSSM_CC_HANDLE CCHandle
,
394 uint32 AttributeType
,
395 uint32 AttributeLength
,
396 const void *AttributePtr
)
398 CSSM_CONTEXT_ATTRIBUTE newAttr
;
401 newAttr
.AttributeType
= AttributeType
;
402 newAttr
.AttributeLength
= AttributeLength
;
403 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)AttributePtr
;
404 crtn
= CSSM_UpdateContextAttributes(CCHandle
, 1, &newAttr
);
406 cuPrintError("CSSM_UpdateContextAttributes", crtn
);
413 * Derive symmetric key.
414 * Note in the X CSP, we never return an IV.
416 CSSM_RETURN
cuCspDeriveKey(CSSM_CSP_HANDLE cspHand
,
417 uint32 keyAlg
, // CSSM_ALGID_RC5, etc.
418 const char *keyLabel
,
419 unsigned keyLabelLen
,
420 uint32 keyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
421 uint32 keySizeInBits
,
422 CSSM_DATA_PTR password
, // in PKCS-5 lingo
423 CSSM_DATA_PTR salt
, // ditto
424 uint32 iterationCnt
, // ditto
428 CSSM_CC_HANDLE ccHand
;
430 CSSM_DATA dummyLabel
;
431 CSSM_PKCS5_PBKDF2_PARAMS pbeParams
;
433 CSSM_ACCESS_CREDENTIALS creds
;
435 memset(key
, 0, sizeof(CSSM_KEY
));
436 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
437 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
438 CSSM_ALGID_PKCS5_PBKDF2
,
448 cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
451 keyAttr
= CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
|
452 CSSM_KEYATTR_SENSITIVE
;
453 dummyLabel
.Length
= keyLabelLen
;
454 dummyLabel
.Data
= (uint8
*)keyLabel
;
456 /* passing in password is pretty strange....*/
457 pbeParams
.Passphrase
= *password
;
458 pbeParams
.PseudoRandomFunction
= CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1
;
459 pbeData
.Data
= (uint8
*)&pbeParams
;
460 pbeData
.Length
= sizeof(pbeParams
);
461 crtn
= CSSM_DeriveKey(ccHand
,
466 NULL
, // cred and acl
469 cuPrintError("CSSM_DeriveKey", crtn
);
472 crtn
= CSSM_DeleteContext(ccHand
);
474 cuPrintError("CSSM_DeleteContext", crtn
);
480 * Generate key pair of arbitrary algorithm.
483 /* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
484 #define DO_DSA_GEN_PARAMS 0
486 CSSM_RETURN
cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand
,
487 CSSM_DL_DB_HANDLE
*dlDbHand
, // optional
489 const char *keyLabel
,
490 unsigned keyLabelLen
,
491 uint32 keySize
, // in bits
492 CSSM_KEY_PTR pubKey
, // mallocd by caller
493 CSSM_KEYUSE pubKeyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
494 CSSM_KEYATTR_FLAGS pubAttrs
, // CSSM_KEYATTR_EXTRACTABLE, etc.
495 CSSM_KEY_PTR privKey
, // mallocd by caller
496 CSSM_KEYUSE privKeyUsage
, // CSSM_KEYUSE_DECRYPT, etc.
497 CSSM_KEYATTR_FLAGS privAttrs
) // CSSM_KEYATTR_EXTRACTABLE, etc.
501 CSSM_CC_HANDLE ccHand
;
502 CSSM_DATA keyLabelData
;
504 keyLabelData
.Data
= (uint8
*)keyLabel
,
505 keyLabelData
.Length
= keyLabelLen
;
506 memset(pubKey
, 0, sizeof(CSSM_KEY
));
507 memset(privKey
, 0, sizeof(CSSM_KEY
));
509 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
519 cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn
);
523 /* post-context-create algorithm-specific stuff */
525 #if DO_DSA_GEN_PARAMS
528 * extra step - generate params - this just adds some
529 * info to the context
532 CSSM_DATA dummy
= {0, NULL
};
533 crtn
= CSSM_GenerateAlgorithmParams(ccHand
,
536 cuPrintError("CSSM_GenerateAlgorithmParams", crtn
);
537 CSSM_DeleteContext(ccHand
);
540 cuAppFree(dummy
.Data
, NULL
);
543 #endif /* DO_DSA_GEN_PARAMS */
548 /* optionally specify DL/DB storage location */
550 crtn
= cuAddContextAttribute(ccHand
,
551 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
552 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
555 CSSM_DeleteContext(ccHand
);
559 ocrtn
= CSSM_GenerateKeyPair(ccHand
,
566 &keyLabelData
, // same labels
567 NULL
, // CredAndAclEntry
570 cuPrintError("CSSM_GenerateKeyPair", ocrtn
);
572 crtn
= CSSM_DeleteContext(ccHand
);
574 cuPrintError("CSSM_DeleteContext", crtn
);
575 if(ocrtn
== CSSM_OK
) {
576 /* error on CSSM_GenerateKeyPair takes precedence */
585 * Add a certificate to an open Keychain.
587 CSSM_RETURN
cuAddCertToKC(
588 SecKeychainRef keychain
,
589 const CSSM_DATA
*cert
,
590 CSSM_CERT_TYPE certType
,
591 CSSM_CERT_ENCODING certEncoding
,
592 const char *printName
, // C string
593 const CSSM_DATA
*keyLabel
) // ??
595 SecCertificateRef certificate
;
597 OSStatus rslt
= SecCertificateCreateFromData(cert
, certType
, certEncoding
, &certificate
);
600 rslt
= SecCertificateAddToKeychain(certificate
, keychain
);
601 CFRelease(certificate
);
608 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
611 unsigned cuDER_ToInt(const CSSM_DATA
*DER_Data
)
616 while(i
< DER_Data
->Length
) {
617 rtn
|= DER_Data
->Data
[i
];
618 if(++i
== DER_Data
->Length
) {
629 void cuPrintError(const char *op
, CSSM_RETURN err
)
635 * Verify a CRL against system anchors and intermediate certs.
637 CSSM_RETURN
cuCrlVerify(
638 CSSM_TP_HANDLE tpHand
,
639 CSSM_CL_HANDLE clHand
,
640 CSSM_CSP_HANDLE cspHand
,
641 const CSSM_DATA
*crlData
,
642 CSSM_DL_DB_HANDLE_PTR certKeychain
, // intermediate certs
643 const CSSM_DATA
*anchors
, // optional - if NULL, use Trust Settings
646 /* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
647 CSSM_TP_VERIFY_CONTEXT vfyCtx
;
648 CSSM_TP_CALLERAUTH_CONTEXT authCtx
;
650 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
651 memset(&authCtx
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
653 /* CSSM_TP_CALLERAUTH_CONTEXT components */
655 typedef struct cssm_tp_callerauth_context {
656 CSSM_TP_POLICYINFO Policy;
657 CSSM_TIMESTRING VerifyTime;
658 CSSM_TP_STOP_ON VerificationAbortOn;
659 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
660 uint32 NumberOfAnchorCerts;
661 CSSM_DATA_PTR AnchorCerts;
662 CSSM_DL_DB_LIST_PTR DBList;
663 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
664 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
667 CSSM_APPLE_TP_CRL_OPTIONS crlOpts
;
668 policyId
.FieldOid
= CSSMOID_APPLE_TP_REVOCATION_CRL
;
669 policyId
.FieldValue
.Data
= (uint8
*)&crlOpts
;
670 policyId
.FieldValue
.Length
= sizeof(crlOpts
);
671 crlOpts
.Version
= CSSM_APPLE_TP_CRL_OPTS_VERSION
;
672 /* perhaps this should be user-specifiable */
673 crlOpts
.CrlFlags
= CSSM_TP_ACTION_FETCH_CRL_FROM_NET
;
674 crlOpts
.crlStore
= NULL
;
676 authCtx
.Policy
.NumberOfPolicyIds
= 1;
677 authCtx
.Policy
.PolicyIds
= &policyId
;
678 authCtx
.Policy
.PolicyControl
= NULL
;
680 authCtx
.VerifyTime
= NULL
;
681 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
682 authCtx
.CallbackWithVerifiedCert
= NULL
;
685 authCtx
.NumberOfAnchorCerts
= anchorCount
;
686 authCtx
.AnchorCerts
= const_cast<CSSM_DATA_PTR
>(anchors
);
688 /* DBList of intermediate certs, plus possible System.keychain and
690 CSSM_DL_DB_HANDLE handles
[3];
692 CSSM_DL_HANDLE dlHand
= 0;
693 if(certKeychain
!= NULL
) {
694 handles
[0] = *certKeychain
;
697 if(anchors
== NULL
) {
698 /* Trust Settings requires two more DBs */
701 dlHand
= cuDlStartup();
702 handles
[numDbs
].DLHandle
= dlHand
;
703 handles
[numDbs
+ 1].DLHandle
= dlHand
;
706 /* use the same one passed in for certKeychain */
707 handles
[numDbs
].DLHandle
= handles
[0].DLHandle
;
708 handles
[numDbs
+ 1].DLHandle
= handles
[0].DLHandle
;
710 handles
[numDbs
].DBHandle
= cuDbStartupByName(handles
[numDbs
].DLHandle
,
711 (char*) ADMIN_CERT_STORE_PATH
, CSSM_FALSE
, CSSM_TRUE
);
714 handles
[numDbs
].DBHandle
= cuDbStartupByName(handles
[numDbs
].DLHandle
,
715 (char*) SYSTEM_ROOT_STORE_PATH
, CSSM_FALSE
, CSSM_TRUE
);
718 CSSM_DL_DB_LIST dlDbList
;
719 dlDbList
.DLDBHandle
= handles
;
720 dlDbList
.NumHandles
= numDbs
;
722 authCtx
.DBList
= &dlDbList
;
723 authCtx
.CallerCredentials
= NULL
;
725 /* CSSM_TP_VERIFY_CONTEXT */
726 vfyCtx
.ActionData
.Data
= NULL
;
727 vfyCtx
.ActionData
.Length
= 0;
728 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
729 vfyCtx
.Cred
= &authCtx
;
731 /* CSSM_APPLE_TP_ACTION_DATA */
732 CSSM_APPLE_TP_ACTION_DATA tpAction
;
733 if(anchors
== NULL
) {
734 /* enable Trust Settings */
735 tpAction
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
736 tpAction
.ActionFlags
= CSSM_TP_ACTION_TRUST_SETTINGS
;
737 vfyCtx
.ActionData
.Data
= (uint8
*)&tpAction
;
738 vfyCtx
.ActionData
.Length
= sizeof(tpAction
);
741 /* cook up CSSM_ENCODED_CRL */
742 CSSM_ENCODED_CRL encCrl
;
743 encCrl
.CrlType
= CSSM_CRL_TYPE_X_509v2
;
744 encCrl
.CrlEncoding
= CSSM_CRL_ENCODING_DER
;
745 encCrl
.CrlBlob
= *crlData
;
747 /* CDSA API requires a SignerCertGroup; for us, all the certs are in
749 CSSM_CERTGROUP certGroup
;
750 certGroup
.CertType
= CSSM_CERT_X_509v1
;
751 certGroup
.CertEncoding
= CSSM_CERT_ENCODING_DER
;
752 certGroup
.NumCerts
= 0;
753 certGroup
.GroupList
.CertList
= NULL
;
754 certGroup
.CertGroupType
= CSSM_CERTGROUP_DATA
;
756 CSSM_RETURN crtn
= CSSM_TP_CrlVerify(tpHand
,
762 NULL
); // RevokerVerifyResult
764 cuPrintError("CSSM_TP_CrlVerify", crtn
);
766 if(anchors
== NULL
) {
767 /* close the DBs and maybe the DL we opened */
768 unsigned dexToClose
= (certKeychain
== NULL
) ? 0 : 1;
769 CSSM_DL_DbClose(handles
[dexToClose
++]);
770 CSSM_DL_DbClose(handles
[dexToClose
]);
772 cuDlDetachUnload(dlHand
);