2 * Copyright (c) 2001-2003,2011-2012,2014 Apple 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.
394 CSSM_RETURN
cuAddContextAttribute(CSSM_CC_HANDLE CCHandle
,
395 uint32 AttributeType
,
396 uint32 AttributeLength
,
397 const void *AttributePtr
)
399 CSSM_CONTEXT_ATTRIBUTE newAttr
;
402 newAttr
.AttributeType
= AttributeType
;
403 newAttr
.AttributeLength
= AttributeLength
;
404 newAttr
.Attribute
.Data
= (CSSM_DATA_PTR
)AttributePtr
;
405 crtn
= CSSM_UpdateContextAttributes(CCHandle
, 1, &newAttr
);
407 cuPrintError("CSSM_UpdateContextAttributes", crtn
);
414 * Derive symmetric key.
415 * Note in the X CSP, we never return an IV.
417 CSSM_RETURN
cuCspDeriveKey(CSSM_CSP_HANDLE cspHand
,
418 uint32 keyAlg
, // CSSM_ALGID_RC5, etc.
419 const char *keyLabel
,
420 unsigned keyLabelLen
,
421 uint32 keyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
422 uint32 keySizeInBits
,
423 CSSM_DATA_PTR password
, // in PKCS-5 lingo
424 CSSM_DATA_PTR salt
, // ditto
425 uint32 iterationCnt
, // ditto
429 CSSM_CC_HANDLE ccHand
;
431 CSSM_DATA dummyLabel
;
432 CSSM_PKCS5_PBKDF2_PARAMS pbeParams
;
434 CSSM_ACCESS_CREDENTIALS creds
;
436 memset(key
, 0, sizeof(CSSM_KEY
));
437 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
438 crtn
= CSSM_CSP_CreateDeriveKeyContext(cspHand
,
439 CSSM_ALGID_PKCS5_PBKDF2
,
449 cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn
);
452 keyAttr
= CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
|
453 CSSM_KEYATTR_SENSITIVE
;
454 dummyLabel
.Length
= keyLabelLen
;
455 dummyLabel
.Data
= (uint8
*)keyLabel
;
457 /* passing in password is pretty strange....*/
458 pbeParams
.Passphrase
= *password
;
459 pbeParams
.PseudoRandomFunction
= CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1
;
460 pbeData
.Data
= (uint8
*)&pbeParams
;
461 pbeData
.Length
= sizeof(pbeParams
);
462 crtn
= CSSM_DeriveKey(ccHand
,
467 NULL
, // cred and acl
470 cuPrintError("CSSM_DeriveKey", crtn
);
473 crtn
= CSSM_DeleteContext(ccHand
);
475 cuPrintError("CSSM_DeleteContext", crtn
);
481 * Generate key pair of arbitrary algorithm.
484 /* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
485 #define DO_DSA_GEN_PARAMS 0
487 CSSM_RETURN
cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand
,
488 CSSM_DL_DB_HANDLE
*dlDbHand
, // optional
490 const char *keyLabel
,
491 unsigned keyLabelLen
,
492 uint32 keySize
, // in bits
493 CSSM_KEY_PTR pubKey
, // mallocd by caller
494 CSSM_KEYUSE pubKeyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
495 CSSM_KEYATTR_FLAGS pubAttrs
, // CSSM_KEYATTR_EXTRACTABLE, etc.
496 CSSM_KEY_PTR privKey
, // mallocd by caller
497 CSSM_KEYUSE privKeyUsage
, // CSSM_KEYUSE_DECRYPT, etc.
498 CSSM_KEYATTR_FLAGS privAttrs
) // CSSM_KEYATTR_EXTRACTABLE, etc.
502 CSSM_CC_HANDLE ccHand
;
503 CSSM_DATA keyLabelData
;
505 keyLabelData
.Data
= (uint8
*)keyLabel
;
506 keyLabelData
.Length
= keyLabelLen
;
507 memset(pubKey
, 0, sizeof(CSSM_KEY
));
508 memset(privKey
, 0, sizeof(CSSM_KEY
));
510 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
520 cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn
);
524 /* post-context-create algorithm-specific stuff */
526 #if DO_DSA_GEN_PARAMS
529 * extra step - generate params - this just adds some
530 * info to the context
533 CSSM_DATA dummy
= {0, NULL
};
534 crtn
= CSSM_GenerateAlgorithmParams(ccHand
,
537 cuPrintError("CSSM_GenerateAlgorithmParams", crtn
);
538 CSSM_DeleteContext(ccHand
);
541 cuAppFree(dummy
.Data
, NULL
);
544 #endif /* DO_DSA_GEN_PARAMS */
549 /* optionally specify DL/DB storage location */
551 crtn
= cuAddContextAttribute(ccHand
,
552 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
553 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
556 CSSM_DeleteContext(ccHand
);
560 ocrtn
= CSSM_GenerateKeyPair(ccHand
,
567 &keyLabelData
, // same labels
568 NULL
, // CredAndAclEntry
571 cuPrintError("CSSM_GenerateKeyPair", ocrtn
);
573 crtn
= CSSM_DeleteContext(ccHand
);
575 cuPrintError("CSSM_DeleteContext", crtn
);
576 if(ocrtn
== CSSM_OK
) {
577 /* error on CSSM_GenerateKeyPair takes precedence */
586 * Add a certificate to an open Keychain.
588 CSSM_RETURN
cuAddCertToKC(
589 SecKeychainRef keychain
,
590 const CSSM_DATA
*cert
,
591 CSSM_CERT_TYPE certType
,
592 CSSM_CERT_ENCODING certEncoding
,
593 const char *printName
, // C string
594 const CSSM_DATA
*keyLabel
) // ??
596 SecCertificateRef certificate
;
598 OSStatus rslt
= SecCertificateCreateFromData(cert
, certType
, certEncoding
, &certificate
);
601 rslt
= SecCertificateAddToKeychain(certificate
, keychain
);
602 CFRelease(certificate
);
609 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
612 unsigned cuDER_ToInt(const CSSM_DATA
*DER_Data
)
617 while(i
< DER_Data
->Length
) {
618 rtn
|= DER_Data
->Data
[i
];
619 if(++i
== DER_Data
->Length
) {
630 void cuPrintError(const char *op
, CSSM_RETURN err
)
636 * Verify a CRL against system anchors and intermediate certs.
638 CSSM_RETURN
cuCrlVerify(
639 CSSM_TP_HANDLE tpHand
,
640 CSSM_CL_HANDLE clHand
,
641 CSSM_CSP_HANDLE cspHand
,
642 const CSSM_DATA
*crlData
,
643 CSSM_DL_DB_HANDLE_PTR certKeychain
, // intermediate certs
644 const CSSM_DATA
*anchors
, // optional - if NULL, use Trust Settings
647 /* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
648 CSSM_TP_VERIFY_CONTEXT vfyCtx
;
649 CSSM_TP_CALLERAUTH_CONTEXT authCtx
;
651 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
652 memset(&authCtx
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
654 /* CSSM_TP_CALLERAUTH_CONTEXT components */
656 typedef struct cssm_tp_callerauth_context {
657 CSSM_TP_POLICYINFO Policy;
658 CSSM_TIMESTRING VerifyTime;
659 CSSM_TP_STOP_ON VerificationAbortOn;
660 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
661 uint32 NumberOfAnchorCerts;
662 CSSM_DATA_PTR AnchorCerts;
663 CSSM_DL_DB_LIST_PTR DBList;
664 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
665 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
668 CSSM_APPLE_TP_CRL_OPTIONS crlOpts
;
669 policyId
.FieldOid
= CSSMOID_APPLE_TP_REVOCATION_CRL
;
670 policyId
.FieldValue
.Data
= (uint8
*)&crlOpts
;
671 policyId
.FieldValue
.Length
= sizeof(crlOpts
);
672 crlOpts
.Version
= CSSM_APPLE_TP_CRL_OPTS_VERSION
;
673 /* perhaps this should be user-specifiable */
674 crlOpts
.CrlFlags
= CSSM_TP_ACTION_FETCH_CRL_FROM_NET
;
675 crlOpts
.crlStore
= NULL
;
677 authCtx
.Policy
.NumberOfPolicyIds
= 1;
678 authCtx
.Policy
.PolicyIds
= &policyId
;
679 authCtx
.Policy
.PolicyControl
= NULL
;
681 authCtx
.VerifyTime
= NULL
;
682 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
683 authCtx
.CallbackWithVerifiedCert
= NULL
;
686 authCtx
.NumberOfAnchorCerts
= anchorCount
;
687 authCtx
.AnchorCerts
= const_cast<CSSM_DATA_PTR
>(anchors
);
689 /* DBList of intermediate certs, plus possible System.keychain and
691 CSSM_DL_DB_HANDLE handles
[3];
693 CSSM_DL_HANDLE dlHand
= 0;
694 if(certKeychain
!= NULL
) {
695 handles
[0] = *certKeychain
;
698 if(anchors
== NULL
) {
699 /* Trust Settings requires two more DBs */
702 dlHand
= cuDlStartup();
703 handles
[numDbs
].DLHandle
= dlHand
;
704 handles
[numDbs
+ 1].DLHandle
= dlHand
;
707 /* use the same one passed in for certKeychain */
708 handles
[numDbs
].DLHandle
= handles
[0].DLHandle
;
709 handles
[numDbs
+ 1].DLHandle
= handles
[0].DLHandle
;
711 handles
[numDbs
].DBHandle
= cuDbStartupByName(handles
[numDbs
].DLHandle
,
712 (char*) ADMIN_CERT_STORE_PATH
, CSSM_FALSE
, CSSM_TRUE
);
715 handles
[numDbs
].DBHandle
= cuDbStartupByName(handles
[numDbs
].DLHandle
,
716 (char*) SYSTEM_ROOT_STORE_PATH
, CSSM_FALSE
, CSSM_TRUE
);
719 CSSM_DL_DB_LIST dlDbList
;
720 dlDbList
.DLDBHandle
= handles
;
721 dlDbList
.NumHandles
= numDbs
;
723 authCtx
.DBList
= &dlDbList
;
724 authCtx
.CallerCredentials
= NULL
;
726 /* CSSM_TP_VERIFY_CONTEXT */
727 vfyCtx
.ActionData
.Data
= NULL
;
728 vfyCtx
.ActionData
.Length
= 0;
729 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
730 vfyCtx
.Cred
= &authCtx
;
732 /* CSSM_APPLE_TP_ACTION_DATA */
733 CSSM_APPLE_TP_ACTION_DATA tpAction
;
734 if(anchors
== NULL
) {
735 /* enable Trust Settings */
736 tpAction
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
737 tpAction
.ActionFlags
= CSSM_TP_ACTION_TRUST_SETTINGS
;
738 vfyCtx
.ActionData
.Data
= (uint8
*)&tpAction
;
739 vfyCtx
.ActionData
.Length
= sizeof(tpAction
);
742 /* cook up CSSM_ENCODED_CRL */
743 CSSM_ENCODED_CRL encCrl
;
744 encCrl
.CrlType
= CSSM_CRL_TYPE_X_509v2
;
745 encCrl
.CrlEncoding
= CSSM_CRL_ENCODING_DER
;
746 encCrl
.CrlBlob
= *crlData
;
748 /* CDSA API requires a SignerCertGroup; for us, all the certs are in
750 CSSM_CERTGROUP certGroup
;
751 certGroup
.CertType
= CSSM_CERT_X_509v1
;
752 certGroup
.CertEncoding
= CSSM_CERT_ENCODING_DER
;
753 certGroup
.NumCerts
= 0;
754 certGroup
.GroupList
.CertList
= NULL
;
755 certGroup
.CertGroupType
= CSSM_CERTGROUP_DATA
;
757 CSSM_RETURN crtn
= CSSM_TP_CrlVerify(tpHand
,
763 NULL
); // RevokerVerifyResult
765 cuPrintError("CSSM_TP_CrlVerify", crtn
);
767 if(anchors
== NULL
) {
768 /* close the DBs and maybe the DL we opened */
769 unsigned dexToClose
= (certKeychain
== NULL
) ? 0 : 1;
770 CSSM_DL_DbClose(handles
[dexToClose
++]);
771 CSSM_DL_DbClose(handles
[dexToClose
]);
773 cuDlDetachUnload(dlHand
);