#include "cuCdsaUtils.h"
#include <stdlib.h>
#include <stdio.h>
#include <Security/SecCertificate.h>
#include <Security/cssmapple.h>
#include <Security/oidsalg.h>
#include <Security/TrustSettingsSchema.h>
#include <strings.h>
static CSSM_VERSION vers = {2, 0};
static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
void * cuAppMalloc (CSSM_SIZE size, void *allocRef) {
return( malloc(size) );
}
void cuAppFree (void *mem_ptr, void *allocRef) {
free(mem_ptr);
return;
}
void * cuAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
return( realloc( ptr, size ) );
}
void * cuAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
return( calloc( num, size ) );
}
static CSSM_API_MEMORY_FUNCS memFuncs = {
cuAppMalloc,
cuAppFree,
cuAppRealloc,
cuAppCalloc,
NULL
};
CSSM_BOOL cuCompareCssmData(const CSSM_DATA *d1,
const CSSM_DATA *d2)
{
if(d1->Length != d2->Length) {
return CSSM_FALSE;
}
if(memcmp(d1->Data, d2->Data, d1->Length)) {
return CSSM_FALSE;
}
return CSSM_TRUE;
}
static CSSM_BOOL cssmInitd = CSSM_FALSE;
CSSM_BOOL cuCssmStartup()
{
CSSM_RETURN crtn;
CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
if(cssmInitd) {
return CSSM_TRUE;
}
crtn = CSSM_Init (&vers,
CSSM_PRIVILEGE_SCOPE_NONE,
&testGuid,
CSSM_KEY_HIERARCHY_NONE,
&pvcPolicy,
NULL );
if(crtn != CSSM_OK)
{
cuPrintError("CSSM_Init", crtn);
return CSSM_FALSE;
}
else {
cssmInitd = CSSM_TRUE;
return CSSM_TRUE;
}
}
CSSM_CSP_HANDLE cuCspStartup(
CSSM_BOOL bareCsp) {
CSSM_CSP_HANDLE cspHand;
CSSM_RETURN crtn;
const CSSM_GUID *guid;
if(cuCssmStartup() == CSSM_FALSE) {
return 0;
}
if(bareCsp) {
guid = &gGuidAppleCSP;
}
else {
guid = &gGuidAppleCSPDL;
}
crtn = CSSM_ModuleLoad(guid,
CSSM_KEY_HIERARCHY_NONE,
NULL, NULL); if(crtn) {
cuPrintError("CSSM_ModuleLoad()", crtn);
return 0;
}
crtn = CSSM_ModuleAttach (guid,
&vers,
&memFuncs, 0, CSSM_SERVICE_CSP,
0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &cspHand);
if(crtn) {
cuPrintError("CSSM_ModuleAttach()", crtn);
return 0;
}
return cspHand;
}
CSSM_DL_HANDLE cuDlStartup()
{
CSSM_DL_HANDLE dlHand = 0;
CSSM_RETURN crtn;
if(cuCssmStartup() == CSSM_FALSE) {
return 0;
}
crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
CSSM_KEY_HIERARCHY_NONE,
NULL, NULL); if(crtn) {
cuPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
return 0;
}
crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
&vers,
&memFuncs, 0, CSSM_SERVICE_DL,
0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &dlHand);
if(crtn) {
cuPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
return 0;
}
return dlHand;
}
CSSM_CL_HANDLE cuClStartup()
{
CSSM_CL_HANDLE clHand;
CSSM_RETURN crtn;
if(cuCssmStartup() == CSSM_FALSE) {
return 0;
}
crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
CSSM_KEY_HIERARCHY_NONE,
NULL, NULL); if(crtn) {
cuPrintError("CSSM_ModuleLoad(AppleCL)", crtn);
return 0;
}
crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
&vers,
&memFuncs, 0, CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &clHand);
if(crtn) {
cuPrintError("CSSM_ModuleAttach(AppleCL)", crtn);
return 0;
}
else {
return clHand;
}
}
CSSM_TP_HANDLE cuTpStartup()
{
CSSM_TP_HANDLE tpHand;
CSSM_RETURN crtn;
if(cuCssmStartup() == CSSM_FALSE) {
return 0;
}
crtn = CSSM_ModuleLoad(&gGuidAppleX509TP,
CSSM_KEY_HIERARCHY_NONE,
NULL, NULL); if(crtn) {
cuPrintError("CSSM_ModuleLoad(AppleTP)", crtn);
return 0;
}
crtn = CSSM_ModuleAttach (&gGuidAppleX509TP,
&vers,
&memFuncs, 0, CSSM_SERVICE_TP, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &tpHand);
if(crtn) {
cuPrintError("CSSM_ModuleAttach(AppleTP)", crtn);
return 0;
}
else {
return tpHand;
}
}
CSSM_RETURN cuCspDetachUnload(
CSSM_CSP_HANDLE cspHand,
CSSM_BOOL bareCsp) {
CSSM_RETURN crtn = CSSM_ModuleDetach(cspHand);
if(crtn) {
return crtn;
}
const CSSM_GUID *guid;
if(bareCsp) {
guid = &gGuidAppleCSP;
}
else {
guid = &gGuidAppleCSPDL;
}
return CSSM_ModuleUnload(guid, NULL, NULL);
}
CSSM_RETURN cuClDetachUnload(
CSSM_CL_HANDLE clHand)
{
CSSM_RETURN crtn = CSSM_ModuleDetach(clHand);
if(crtn) {
return crtn;
}
return CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
}
CSSM_RETURN cuDlDetachUnload(
CSSM_DL_HANDLE dlHand)
{
CSSM_RETURN crtn = CSSM_ModuleDetach(dlHand);
if(crtn) {
return crtn;
}
return CSSM_ModuleUnload(&gGuidAppleCSPDL, NULL, NULL);
}
CSSM_RETURN cuTpDetachUnload(
CSSM_TP_HANDLE tpHand)
{
CSSM_RETURN crtn = CSSM_ModuleDetach(tpHand);
if(crtn) {
return crtn;
}
return CSSM_ModuleUnload(&gGuidAppleX509TP, NULL, NULL);
}
CSSM_DB_HANDLE cuDbStartup(
CSSM_DL_HANDLE dlHand, const char *dbName)
{
CSSM_DB_HANDLE dbHand = 0;
CSSM_RETURN crtn;
CSSM_DBINFO dbInfo;
crtn = CSSM_DL_DbDelete(dlHand, dbName, NULL, NULL);
switch(crtn) {
case CSSM_OK:
case CSSMERR_DL_DATASTORE_DOESNOT_EXIST:
break;
default:
cuPrintError("CSSM_DL_DbDelete", crtn);
return 0;
}
memset(&dbInfo, 0, sizeof(CSSM_DBINFO));
crtn = CSSM_DL_DbCreate(dlHand,
dbName,
NULL, &dbInfo,
CSSM_DB_ACCESS_PRIVILEGED,
NULL, NULL, &dbHand);
if(crtn) {
cuPrintError("CSSM_DL_DbCreate", crtn);
}
return dbHand;
}
CSSM_DB_HANDLE cuDbStartupByName(CSSM_DL_HANDLE dlHand,
char *dbName,
CSSM_BOOL doCreate,
CSSM_BOOL quiet)
{
CSSM_RETURN crtn;
CSSM_DB_HANDLE dbHand;
crtn = CSSM_DL_DbOpen(dlHand,
dbName,
NULL, CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
NULL, NULL, &dbHand);
if(crtn == CSSM_OK) {
return dbHand;
}
if(!doCreate) {
if(!quiet) {
printf("***no such data base (%s)\n", dbName);
cuPrintError("CSSM_DL_DbOpen", crtn);
}
return 0;
}
return cuDbStartup(dlHand, dbName);
}
static
CSSM_RETURN cuAddContextAttribute(CSSM_CC_HANDLE CCHandle,
uint32 AttributeType,
uint32 AttributeLength,
const void *AttributePtr)
{
CSSM_CONTEXT_ATTRIBUTE newAttr;
CSSM_RETURN crtn;
newAttr.AttributeType = AttributeType;
newAttr.AttributeLength = AttributeLength;
newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
if(crtn) {
cuPrintError("CSSM_UpdateContextAttributes", crtn);
}
return crtn;
}
CSSM_RETURN cuCspDeriveKey(CSSM_CSP_HANDLE cspHand,
uint32 keyAlg, const char *keyLabel,
unsigned keyLabelLen,
uint32 keyUsage, uint32 keySizeInBits,
CSSM_DATA_PTR password, CSSM_DATA_PTR salt, uint32 iterationCnt, CSSM_KEY_PTR key)
{
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHand;
uint32 keyAttr;
CSSM_DATA dummyLabel;
CSSM_PKCS5_PBKDF2_PARAMS pbeParams;
CSSM_DATA pbeData;
CSSM_ACCESS_CREDENTIALS creds;
memset(key, 0, sizeof(CSSM_KEY));
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
CSSM_ALGID_PKCS5_PBKDF2,
keyAlg,
keySizeInBits,
&creds,
NULL, iterationCnt,
salt,
NULL, &ccHand);
if(crtn) {
cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
return crtn;
}
keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
CSSM_KEYATTR_SENSITIVE;
dummyLabel.Length = keyLabelLen;
dummyLabel.Data = (uint8 *)keyLabel;
pbeParams.Passphrase = *password;
pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
pbeData.Data = (uint8 *)&pbeParams;
pbeData.Length = sizeof(pbeParams);
crtn = CSSM_DeriveKey(ccHand,
&pbeData,
keyUsage,
keyAttr,
&dummyLabel,
NULL, key);
if(crtn) {
cuPrintError("CSSM_DeriveKey", crtn);
return crtn;
}
crtn = CSSM_DeleteContext(ccHand);
if(crtn) {
cuPrintError("CSSM_DeleteContext", crtn);
}
return crtn;
}
#define DO_DSA_GEN_PARAMS 0
CSSM_RETURN cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
CSSM_DL_DB_HANDLE *dlDbHand, uint32 algorithm,
const char *keyLabel,
unsigned keyLabelLen,
uint32 keySize, CSSM_KEY_PTR pubKey, CSSM_KEYUSE pubKeyUsage, CSSM_KEYATTR_FLAGS pubAttrs, CSSM_KEY_PTR privKey, CSSM_KEYUSE privKeyUsage, CSSM_KEYATTR_FLAGS privAttrs) {
CSSM_RETURN crtn;
CSSM_RETURN ocrtn;
CSSM_CC_HANDLE ccHand;
CSSM_DATA keyLabelData;
keyLabelData.Data = (uint8 *)keyLabel,
keyLabelData.Length = keyLabelLen;
memset(pubKey, 0, sizeof(CSSM_KEY));
memset(privKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
algorithm,
keySize,
NULL, NULL, NULL, NULL, NULL, &ccHand);
if(crtn) {
cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
return crtn;
}
switch(algorithm) {
#if DO_DSA_GEN_PARAMS
case CSSM_ALGID_DSA:
{
CSSM_DATA dummy = {0, NULL};
crtn = CSSM_GenerateAlgorithmParams(ccHand,
keySize, &dummy);
if(crtn) {
cuPrintError("CSSM_GenerateAlgorithmParams", crtn);
CSSM_DeleteContext(ccHand);
return crtn;
}
cuAppFree(dummy.Data, NULL);
}
break;
#endif
default:
break;
}
if(dlDbHand) {
crtn = cuAddContextAttribute(ccHand,
CSSM_ATTRIBUTE_DL_DB_HANDLE,
sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
dlDbHand);
if(crtn) {
CSSM_DeleteContext(ccHand);
return crtn;
}
}
ocrtn = CSSM_GenerateKeyPair(ccHand,
pubKeyUsage,
pubAttrs,
&keyLabelData,
pubKey,
privKeyUsage,
privAttrs,
&keyLabelData, NULL, privKey);
if(ocrtn) {
cuPrintError("CSSM_GenerateKeyPair", ocrtn);
}
crtn = CSSM_DeleteContext(ccHand);
if(crtn) {
cuPrintError("CSSM_DeleteContext", crtn);
if(ocrtn == CSSM_OK) {
ocrtn = crtn;
}
}
return ocrtn;
}
CSSM_RETURN cuAddCertToKC(
SecKeychainRef keychain,
const CSSM_DATA *cert,
CSSM_CERT_TYPE certType,
CSSM_CERT_ENCODING certEncoding,
const char *printName, const CSSM_DATA *keyLabel) {
SecCertificateRef certificate;
OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
if (!rslt)
{
rslt = SecCertificateAddToKeychain(certificate, keychain);
CFRelease(certificate);
}
return rslt;
}
unsigned cuDER_ToInt(const CSSM_DATA *DER_Data)
{
uint32 rtn = 0;
unsigned i = 0;
while(i < DER_Data->Length) {
rtn |= DER_Data->Data[i];
if(++i == DER_Data->Length) {
break;
}
rtn <<= 8;
}
return rtn;
}
void cuPrintError(const char *op, CSSM_RETURN err)
{
cssmPerror(op, err);
}
CSSM_RETURN cuCrlVerify(
CSSM_TP_HANDLE tpHand,
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
const CSSM_DATA *crlData,
CSSM_DL_DB_HANDLE_PTR certKeychain, const CSSM_DATA *anchors, uint32 anchorCount)
{
CSSM_TP_VERIFY_CONTEXT vfyCtx;
CSSM_TP_CALLERAUTH_CONTEXT authCtx;
memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
memset(&authCtx, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
CSSM_FIELD policyId;
CSSM_APPLE_TP_CRL_OPTIONS crlOpts;
policyId.FieldOid = CSSMOID_APPLE_TP_REVOCATION_CRL;
policyId.FieldValue.Data = (uint8 *)&crlOpts;
policyId.FieldValue.Length = sizeof(crlOpts);
crlOpts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
crlOpts.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
crlOpts.crlStore = NULL;
authCtx.Policy.NumberOfPolicyIds = 1;
authCtx.Policy.PolicyIds = &policyId;
authCtx.Policy.PolicyControl = NULL;
authCtx.VerifyTime = NULL;
authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
authCtx.CallbackWithVerifiedCert = NULL;
authCtx.NumberOfAnchorCerts = anchorCount;
authCtx.AnchorCerts = const_cast<CSSM_DATA_PTR>(anchors);
CSSM_DL_DB_HANDLE handles[3];
unsigned numDbs = 0;
CSSM_DL_HANDLE dlHand = 0;
if(certKeychain != NULL) {
handles[0] = *certKeychain;
numDbs++;
}
if(anchors == NULL) {
if(numDbs == 0) {
dlHand = cuDlStartup();
handles[numDbs].DLHandle = dlHand;
handles[numDbs + 1].DLHandle = dlHand;
}
else {
handles[numDbs].DLHandle = handles[0].DLHandle;
handles[numDbs + 1].DLHandle = handles[0].DLHandle;
}
handles[numDbs].DBHandle = cuDbStartupByName(handles[numDbs].DLHandle,
(char*) ADMIN_CERT_STORE_PATH, CSSM_FALSE, CSSM_TRUE);
numDbs++;
handles[numDbs].DBHandle = cuDbStartupByName(handles[numDbs].DLHandle,
(char*) SYSTEM_ROOT_STORE_PATH, CSSM_FALSE, CSSM_TRUE);
numDbs++;
}
CSSM_DL_DB_LIST dlDbList;
dlDbList.DLDBHandle = handles;
dlDbList.NumHandles = numDbs;
authCtx.DBList = &dlDbList;
authCtx.CallerCredentials = NULL;
vfyCtx.ActionData.Data = NULL;
vfyCtx.ActionData.Length = 0;
vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
vfyCtx.Cred = &authCtx;
CSSM_APPLE_TP_ACTION_DATA tpAction;
if(anchors == NULL) {
tpAction.Version = CSSM_APPLE_TP_ACTION_VERSION;
tpAction.ActionFlags = CSSM_TP_ACTION_TRUST_SETTINGS;
vfyCtx.ActionData.Data = (uint8 *)&tpAction;
vfyCtx.ActionData.Length = sizeof(tpAction);
}
CSSM_ENCODED_CRL encCrl;
encCrl.CrlType = CSSM_CRL_TYPE_X_509v2;
encCrl.CrlEncoding = CSSM_CRL_ENCODING_DER;
encCrl.CrlBlob = *crlData;
CSSM_CERTGROUP certGroup;
certGroup.CertType = CSSM_CERT_X_509v1;
certGroup.CertEncoding = CSSM_CERT_ENCODING_DER;
certGroup.NumCerts = 0;
certGroup.GroupList.CertList = NULL;
certGroup.CertGroupType = CSSM_CERTGROUP_DATA;
CSSM_RETURN crtn = CSSM_TP_CrlVerify(tpHand,
clHand,
cspHand,
&encCrl,
&certGroup,
&vfyCtx,
NULL); if(crtn) {
cuPrintError("CSSM_TP_CrlVerify", crtn);
}
if(anchors == NULL) {
unsigned dexToClose = (certKeychain == NULL) ? 0 : 1;
CSSM_DL_DbClose(handles[dexToClose++]);
CSSM_DL_DbClose(handles[dexToClose]);
if(dlHand != 0) {
cuDlDetachUnload(dlHand);
}
}
return crtn;
}