#include <Security/SecKeychainItem.h>
#include <Security/SecKeychain.h>
#include <Security/SecKey.h>
#include <Security/SecAccess.h>
#include <Security/SecACL.h>
#include <Security/certextensions.h>
#include <Security/cssmapple.h>
#include <Security/oidsattr.h>
#include <Security/oidscert.h>
#include <Security/oidsalg.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <sys/param.h>
#include <cdsaUtils/cdsaUtils.h>
#include <cdsaUtils/printCert.h>
#include <cdsaUtils/fileIo.h>
#include <cdsaUtils/pem.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include "CertUI.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Security/utilities.h>
#include <Security/aclclient.h>
#include <Security/SecCertificate.h>
#define SEC_KEYCHAIN_GET_CSP 0
#define SEC_CERT_ADD_TO_KC 1
#define SEC_KEY_CREATE_PAIR 0
#if !SEC_KEY_CREATE_PAIR
#define MUNGE_LABEL_ATTR 1
#endif
#define KC_DB_PATH "Library/Keychains"
#define ZDEF_KEY_LABEL "testCert"
#define ZDEF_KEY_ALG CSSM_ALGID_RSA
#define ZDEF_KEY_SIZE 512
#define ZDEF_KEY_USAGE (kKeyUseSigning | kKeyUseEncrypting)
#define ZDEF_SIG_ALG CSSM_ALGID_SHA1WithRSA
#define ZDEF_SIG_OID CSSMOID_SHA1WithRSA
#define ZDEF_COMMON_NAME "10.0.61.5"
#define ZDEF_ORG_NAME "Apple Computer - DEBUG ONLY"
#define ZDEF_COUNTRY "US"
#define ZDEF_STATE "Washington"
#define ZDEF_CHALLENGE "someChallenge"
static void usage(char **argv)
{
printf("usage:\n");
printf(" Create a keypair and cert: %s c [options]\n", argv[0]);
printf(" Create a CSR: %s r outFileName [options]\n",
argv[0]);
printf(" Verify a CSR: %s v infileName [options]\n", argv[0]);
#if SEC_CERT_ADD_TO_KC
printf(" Import a certificate: %s i inFileName [options]\n", argv[0]);
#else
printf(" Import a certificate: %s i inFileName printName [options]\n",
argv[0]);
#endif
printf(" Display a certificate: %s d inFileName [options]\n", argv[0]);
printf("Options:\n");
printf(" k=keychainName\n");
printf(" c(reate the keychain)\n");
printf(" v(erbose)\n");
printf(" d (CSR in DER format; default is PEM)\n");
printf(" h(elp)\n");
exit(1);
}
#if SEC_KEY_CREATE_PAIR
#else
#if MUNGE_LABEL_ATTR
static CSSM_RETURN refKeyToRaw(
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY *refKey,
CSSM_KEY_PTR rawKey) {
CSSM_CC_HANDLE ccHand;
CSSM_RETURN crtn;
CSSM_ACCESS_CREDENTIALS creds;
memset(rawKey, 0, sizeof(CSSM_KEY));
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
&creds, NULL, NULL, CSSM_PADDING_NONE, 0, &ccHand);
if(crtn) {
showError(crtn, "refKeyToRaw: context err");
return crtn;
}
crtn = CSSM_WrapKey(ccHand,
&creds,
refKey,
NULL, rawKey);
if(crtn != CSSM_OK) {
showError(crtn, "refKeyToRaw: CSSM_WrapKey");
return crtn;
}
CSSM_DeleteContext(ccHand);
return CSSM_OK;
}
static CSSM_RETURN setPubKeyHash(
CSSM_CSP_HANDLE cspHand,
CSSM_DL_DB_HANDLE dlDbHand,
const CSSM_KEY *pubKey, CSSM_KEY_PTR privKey, const char *keyLabel) {
CSSM_QUERY query;
CSSM_SELECTION_PREDICATE predicate;
CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
CSSM_RETURN crtn;
CSSM_DATA labelData;
CSSM_HANDLE resultHand;
labelData.Data = (uint8 *)keyLabel;
labelData.Length = strlen(keyLabel) + 1; query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
query.Conjunctive = CSSM_DB_NONE;
query.NumSelectionPredicates = 1;
predicate.DbOperator = CSSM_DB_EQUAL;
predicate.Attribute.Info.AttributeNameFormat =
CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
predicate.Attribute.Info.Label.AttributeName = "Label";
predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
predicate.Attribute.Value = &labelData;
query.SelectionPredicate = &predicate;
query.QueryLimits.TimeLimit = 0; query.QueryLimits.SizeLimit = 1; query.QueryFlags = 0;
CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
CSSM_DB_ATTRIBUTE_DATA attr;
attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr.Info.Label.AttributeName = "Label";
attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
recordAttrs.NumberOfAttributes = 1;
recordAttrs.AttributeData = &attr;
crtn = CSSM_DL_DataGetFirst(dlDbHand,
&query,
&resultHand,
&recordAttrs,
NULL, &record);
if(crtn != CSSM_OK) {
showError(crtn, "CSSM_DL_DataGetFirst");
printf("***setPubKeyHash: can't find private key\n");
return crtn;
}
CSSM_KEY rawPubKey;
crtn = refKeyToRaw(cspHand, pubKey, &rawPubKey);
if(crtn) {
printf("***Error converting public key to raw format\n");
return crtn;
}
CSSM_CSP_HANDLE rawCspHand = cuCspStartup(CSSM_TRUE);
if(rawCspHand == 0) {
printf("***Error connecting to raw CSP; aborting.\n");
return -1;
}
CSSM_DATA_PTR keyDigest = NULL;
CSSM_CC_HANDLE ccHand;
crtn = CSSM_CSP_CreatePassThroughContext(rawCspHand,
&rawPubKey,
&ccHand);
if(ccHand == 0) {
showError(crtn, "CSSM_CSP_CreatePassThroughContext");
printf("***Error calculating public key hash. Aborting.\n");
return -1;
}
crtn = CSSM_CSP_PassThrough(ccHand,
CSSM_APPLECSP_KEYDIGEST,
NULL,
(void **)&keyDigest);
if(crtn) {
showError(crtn, "CSSM_CSP_PassThrough(PUBKEYHASH)");
printf("***Error calculating public key hash. Aborting.\n");
return -1;
}
CSSM_FreeKey(cspHand, NULL, &rawPubKey, CSSM_FALSE);
CSSM_DeleteContext(ccHand);
CSSM_ModuleDetach(rawCspHand);
CSSM_API_MEMORY_FUNCS memFuncs;
crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs);
if(crtn) {
showError(crtn, "CSSM_GetAPIMemoryFunctions(DLHandle)");
}
else {
memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef);
memFuncs.free_func(attr.Value, memFuncs.AllocRef);
}
attr.Value = keyDigest;
crtn = CSSM_DL_DataModify(dlDbHand,
CSSM_DL_DB_RECORD_PRIVATE_KEY,
record,
&recordAttrs,
NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
if(crtn) {
showError(crtn, "CSSM_DL_DataModify(PUBKEYHASH)");
printf("***Error setting public key hash. Aborting.\n");
return crtn;
}
crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
if(crtn) {
showError(crtn, "CSSM_DL_DataAbortQuery");
}
crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record);
if(crtn) {
showError(crtn, "CSSM_DL_FreeUniqueRecord");
crtn = CSSM_OK;
}
cuAppFree(keyDigest->Data, NULL);
return CSSM_OK;
}
#endif
static OSStatus generateKeyPair(
CSSM_CSP_HANDLE cspHand,
CSSM_DL_DB_HANDLE dlDbHand,
CSSM_ALGORITHMS keyAlg, uint32 keySizeInBits,
const char *keyLabel, CU_KeyUsage keyUsage, CSSM_BOOL verbose,
const CSSM_KEY **pubKeyPtr, const CSSM_KEY **privKeyPtr) {
CSSM_KEY_PTR pubKey = reinterpret_cast<CSSM_KEY_PTR>(
APP_MALLOC(sizeof(CSSM_KEY)));
CSSM_KEY_PTR privKey = reinterpret_cast<CSSM_KEY_PTR>(
APP_MALLOC(sizeof(CSSM_KEY)));
if((pubKey == NULL) || (privKey == NULL)) {
return memFullErr;
}
CSSM_RETURN crtn;
CSSM_KEYUSE pubKeyUse = 0;
CSSM_KEYUSE privKeyUse = 0;
if(keyUsage & kKeyUseSigning) {
pubKeyUse |= CSSM_KEYUSE_VERIFY;
privKeyUse |= CSSM_KEYUSE_SIGN;
}
if(keyUsage & kKeyUseEncrypting) {
pubKeyUse |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP);
privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP);
}
crtn = cuCspGenKeyPair(cspHand,
&dlDbHand,
keyAlg,
keyLabel,
strlen(keyLabel) + 1,
keySizeInBits,
pubKey,
pubKeyUse,
CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
privKey,
privKeyUse,
CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT);
if(crtn) {
APP_FREE(pubKey);
APP_FREE(privKey);
return paramErr;
}
if(verbose) {
printf("...%u bit key pair generated.\n",
(unsigned)keySizeInBits);
}
#if MUNGE_LABEL_ATTR
crtn = setPubKeyHash(cspHand,
dlDbHand,
pubKey,
privKey,
keyLabel);
if(crtn) {
printf("***Error setting public key hash. Continuing at peril.\n");
}
#endif
*pubKeyPtr = pubKey;
*privKeyPtr = privKey;
return noErr;
}
#endif
static void verifyCsr(
CSSM_CL_HANDLE clHand,
const char *fileName,
CSSM_BOOL pemFormat)
{
unsigned char *csr = NULL;
unsigned csrLen;
CSSM_DATA csrData;
unsigned char *der = NULL;
unsigned derLen = 0;
if(readFile(fileName, &csr, &csrLen)) {
printf("***Error reading CSR from file %s. Aborting.\n",
fileName);
return;
}
if(pemFormat) {
int rtn = pemDecode(csr, csrLen, &der, &derLen);
if(rtn) {
printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
return;
}
csrData.Data = der;
csrData.Length = derLen;
}
else {
csrData.Data = csr;
csrData.Length = csrLen;
}
CSSM_RETURN crtn = CSSM_CL_PassThrough(clHand,
0, CSSM_APPLEX509CL_VERIFY_CSR,
&csrData,
NULL);
if(crtn) {
cuPrintError("Verify CSR", crtn);
}
else {
printf("...CSR verified successfully.\n");
}
if(der) {
free(der);
}
if(csr) {
free(csr);
}
}
static void displayCert(
const char *fileName,
CSSM_BOOL pemFormat)
{
unsigned char *rawCert = NULL;
unsigned rawCertSize;
unsigned char *derCert = NULL;
unsigned derCertSize;
int rtn;
rtn = readFile(fileName, &rawCert, &rawCertSize);
if(rtn) {
printf("Error reading %s; aborting.\n", fileName);
return;
}
if(pemFormat) {
rtn = pemDecode(rawCert, rawCertSize, &derCert, &derCertSize);
if(rtn) {
printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
return;
}
printCert(derCert, derCertSize, CSSM_TRUE);
free(derCert);
}
else {
printCert(rawCert, rawCertSize, CSSM_TRUE);
}
}
static void importCert(
SecKeychainRef kcRef, CSSM_DL_DB_HANDLE dlDbHand, const char *fileName,
CSSM_BOOL pemFormat,
const char *printName) {
unsigned char *cert = NULL;
unsigned certLen;
CSSM_DATA certData;
unsigned char *der = NULL;
unsigned derLen = 0;
#if !SEC_CERT_ADD_TO_KC
CSSM_DATA pubKeyHash = {3, (uint8 *)"foo"};
#endif
if(readFile(fileName, &cert, &certLen)) {
printf("***Error reading certificate from file %s. Aborting.\n",
fileName);
return;
}
if(pemFormat) {
int rtn = pemDecode(cert, certLen, &der, &derLen);
if(rtn) {
printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
return;
}
certData.Data = der;
certData.Length = derLen;
}
else {
certData.Data = cert;
certData.Length = certLen;
}
#if SEC_CERT_ADD_TO_KC
SecCertificateRef certRef;
OSStatus ortn = SecCertificateCreateFromData(
&certData,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&certRef);
if(ortn) {
printf("***SecCertificateCreateFromData returned %d; aborting.\n",
(int)ortn);
return;
}
ortn = SecCertificateAddToKeychain(certRef, kcRef);
if(ortn) {
printf("***SecCertificateAddToKeychain returned %d; aborting.\n",
(int)ortn);
return;
}
#else
CSSM_RETURN crtn = cuAddCertToDb(dlDbHand,
&certData,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
printName, &pubKeyHash);
if(crtn) {
printf("***Error adding cert to keychain. Aborting.\n");
return;
}
#endif
printf("...certificate successfully imported.\n");
if(der) {
free(der);
}
if(cert) {
free(cert);
}
}
static OSStatus createCertCsr(
CSSM_BOOL createCsr, CSSM_TP_HANDLE tpHand, CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY *subjPubKey,
const CSSM_KEY *signerPrivKey,
CSSM_ALGORITHMS sigAlg,
const CSSM_OID *sigOid,
CU_KeyUsage keyUsage,
const CSSM_DATA *issuerCert,
CSSM_BOOL useAllDefaults,
CSSM_DATA_PTR certData) {
CE_DataAndType exts[2];
CE_DataAndType *extp = exts;
unsigned numExts;
CSSM_DATA refId; CSSM_APPLE_TP_CERT_REQUEST certReq;
CSSM_TP_REQUEST_SET reqSet;
sint32 estTime;
CSSM_BOOL confirmRequired;
CSSM_TP_RESULT_SET_PTR resultSet;
CSSM_ENCODED_CERT *encCert;
CSSM_APPLE_TP_NAME_OID subjectNames[MAX_NAMES];
uint32 numNames;
CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext;
CSSM_FIELD policyId;
if(issuerCert != NULL) {
printf("createCertCsr: issuerCert not implemented\n");
return unimpErr;
}
numExts = 0;
char challengeBuf[400];
if(createCsr) {
if(useAllDefaults) {
strcpy(challengeBuf, ZDEF_CHALLENGE);
}
else {
while(1) {
getStringWithPrompt("Enter challenge string: ",
challengeBuf, sizeof(challengeBuf));
if(challengeBuf[0] != '\0') {
break;
}
}
}
certReq.challengeString = challengeBuf;
}
else {
certReq.challengeString = NULL;
extp->type = DT_KeyUsage;
extp->critical = CSSM_FALSE;
extp->extension.keyUsage = 0;
if(keyUsage & kKeyUseSigning) {
extp->extension.keyUsage |=
(CE_KU_DigitalSignature | CE_KU_KeyCertSign);
}
if(keyUsage & kKeyUseEncrypting) {
extp->extension.keyUsage |=
(CE_KU_KeyEncipherment | CE_KU_DataEncipherment);
}
extp++;
numExts++;
extp->type = DT_BasicConstraints;
extp->critical = CSSM_TRUE;
extp->extension.basicConstraints.cA = CSSM_TRUE;
extp->extension.basicConstraints.pathLenConstraintPresent = CSSM_FALSE;
extp++;
numExts++;
}
if(useAllDefaults) {
subjectNames[0].string = ZDEF_COMMON_NAME;
subjectNames[0].oid = &CSSMOID_CommonName;
subjectNames[1].string = ZDEF_ORG_NAME;
subjectNames[1].oid = &CSSMOID_OrganizationName;
subjectNames[2].string = ZDEF_COUNTRY;
subjectNames[2].oid = &CSSMOID_CountryName;
subjectNames[3].string = ZDEF_STATE;
subjectNames[3].oid = &CSSMOID_StateProvinceName;
numNames = 4;
}
else {
getNameOids(subjectNames, &numNames);
}
certReq.cspHand = cspHand;
certReq.clHand = clHand;
certReq.serialNumber = 0x12345678; certReq.numSubjectNames = numNames;
certReq.subjectNames = subjectNames;
certReq.numIssuerNames = 0; certReq.issuerNames = NULL;
certReq.issuerNameX509 = NULL;
certReq.certPublicKey = subjPubKey;
certReq.issuerPrivateKey = signerPrivKey;
certReq.signatureAlg = sigAlg;
certReq.signatureOid = *sigOid;
certReq.notBefore = 0; certReq.notAfter = 60 * 60 * 24 * 30; certReq.numExtensions = numExts;
certReq.extensions = exts;
reqSet.NumberOfRequests = 1;
reqSet.Requests = &certReq;
memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
memset(&policyId, 0, sizeof(CSSM_FIELD));
if(createCsr) {
policyId.FieldOid = CSSMOID_APPLE_TP_CSR_GEN;
}
else {
policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
}
CallerAuthContext.Policy.NumberOfPolicyIds = 1;
CallerAuthContext.Policy.PolicyIds = &policyId;
CssmClient::AclFactory factory;
CallerAuthContext.CallerCredentials = const_cast<Security::AccessCredentials *>(factory.promptCred());
CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tpHand,
NULL, CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
&reqSet,
&CallerAuthContext,
&estTime,
&refId);
if(!useAllDefaults) {
freeNameOids(subjectNames, numNames);
}
if(crtn) {
cuPrintError("CSSM_TP_SubmitCredRequest", crtn);
return crtn;
}
crtn = CSSM_TP_RetrieveCredResult(tpHand,
&refId,
NULL, &estTime,
&confirmRequired,
&resultSet);
if(crtn) {
cuPrintError("CSSM_TP_RetrieveCredResult", crtn);
return crtn;
}
if(resultSet == NULL) {
printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
return ioErr;
}
encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
*certData = encCert->CertBlob;
APP_FREE(refId.Data);
APP_FREE(encCert);
APP_FREE(resultSet);
return noErr;
}
typedef enum {
CO_Nop,
CO_CreateCert,
CO_CreateCSR,
CO_VerifyCSR,
CO_ImportCert,
CO_DisplayCert
} CertOp;
int main(int argc, char **argv)
{
SecKeychainRef kcRef = nil;
char kcPath[MAXPATHLEN + 1];
UInt32 kcPathLen = MAXPATHLEN + 1;
CSSM_BOOL createKc = CSSM_FALSE;
OSStatus ortn;
CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
CSSM_CSP_HANDLE cspHand = 0;
CSSM_TP_HANDLE tpHand = 0;
CSSM_CL_HANDLE clHand = 0;
const CSSM_KEY *pubKey;
const CSSM_KEY *privKey;
int arg;
char *argp;
CSSM_BOOL verbose = CSSM_FALSE;
CSSM_ALGORITHMS keyAlg;
CSSM_ALGORITHMS sigAlg;
const CSSM_OID *sigOid;
CSSM_DATA certData = {0, NULL};
CSSM_RETURN crtn;
CU_KeyUsage keyUsage = 0;
bool isRoot;
CSSM_DATA keyLabel;
#if SEC_KEY_CREATE_PAIR
CSSM_KEYUSE pubKeyUse = 0;
CSSM_KEYUSE privKeyUse = 0;
CSSM_KEYATTR_FLAGS pubKeyAttrs;
CSSM_KEYATTR_FLAGS privKeyAttrs;
CFStringRef description = NULL;
SecAccessRef access = NULL;
CFArrayRef acls = NULL;
SecACLRef acl = NULL;
bool aclFound = false;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector =
{
CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION, 0
};
SecKeyRef pubKeyRef = 0, privKeyRef = 0;
#elif !MUNGE_LABEL_ATTR
CSSM_DATA pubKeyHash = {3, (uint8 *)"foo"};
#endif
CSSM_BOOL createCsr = CSSM_FALSE; int optArgs = 0;
char *fileName = NULL;
CSSM_BOOL pemFormat = CSSM_TRUE;
char *certPrintName = NULL;
CertOp op = CO_Nop;
uint32 keySizeInBits;
char *kcName = NULL;
CSSM_BOOL useAllDefaults = CSSM_FALSE;
if(argc < 2) {
usage(argv);
}
switch(argv[1][0]) {
case 'c':
op = CO_CreateCert;
optArgs = 2;
break;
case 'r':
if(argc < 3) {
usage(argv);
}
op = CO_CreateCSR;
createCsr = CSSM_TRUE;
fileName = argv[2];
optArgs = 3;
break;
case 'v':
if(argc < 3) {
usage(argv);
}
op = CO_VerifyCSR;
fileName = argv[2];
optArgs = 3;
break;
case 'i':
#if SEC_CERT_ADD_TO_KC
if(argc < 3) {
usage(argv);
}
optArgs = 3;
#else
if(argc < 4) {
usage(argv);
}
certPrintName = argv[3];
optArgs = 4;
#endif
op = CO_ImportCert;
fileName = argv[2];
break;
case 'd':
if(argc < 3) {
usage(argv);
}
op = CO_DisplayCert;
fileName = argv[2];
optArgs = 3;
break;
default:
usage(argv);
}
for(arg=optArgs; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'k':
kcName = &argp[2];
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'd':
pemFormat = CSSM_FALSE;
break;
case 'c':
createKc = CSSM_TRUE;
break;
case 'Z':
useAllDefaults = CSSM_TRUE;
break;
default:
usage(argv);
}
}
if(op == CO_DisplayCert) {
displayCert(fileName, pemFormat);
return 0;
}
clHand = cuClStartup();
if(clHand == 0) {
printf("Error connecting to CL. Aborting.\n");
exit(1);
}
if(op == CO_VerifyCSR) {
verifyCsr(clHand, fileName, pemFormat);
goto abort;
}
#if !SEC_KEYCHAIN_GET_CSP
cspHand = cuCspStartup(CSSM_FALSE);
if(cspHand == 0) {
printf("Error connecting to CSP/DL. Aborting.\n");
exit(1);
}
#endif
tpHand = cuTpStartup();
if(tpHand == 0) {
printf("Error connecting to TP. Aborting.\n");
exit(1);
}
if(kcName) {
char *userHome = getenv("HOME");
if(userHome == NULL) {
userHome = "";
}
sprintf(kcPath, "%s/%s/%s", userHome, KC_DB_PATH, kcName);
}
else {
ortn = SecKeychainCopyDefault(&kcRef);
if(ortn) {
showError(ortn, "SecKeychainCopyDefault");
exit(1);
}
ortn = SecKeychainGetPath(kcRef, &kcPathLen, kcPath);
if(ortn) {
showError(ortn, "SecKeychainGetPath");
exit(1);
}
CFRelease(kcRef);
}
if(createKc) {
ortn = SecKeychainCreate(kcPath,
0, NULL, true, nil, &kcRef);
if(ortn) {
showError(ortn, "SecKeychainCreateNew");
printf("***Error creating keychain at %s; aborting.\n", kcPath);
exit(1);
}
}
else {
ortn = SecKeychainOpen(kcPath, &kcRef);
if(ortn) {
showError(ortn, "SecKeychainOpen");
printf("Cannot open keychain at %s. Aborting.\n", kcPath);
exit(1);
}
}
ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand);
if(ortn) {
showError(ortn, "SecKeychainGetDLDBHandle");
exit(1);
}
if(op == CO_ImportCert) {
importCert(kcRef, dlDbHand, fileName, pemFormat, certPrintName);
goto abort;
}
#if SEC_KEYCHAIN_GET_CSP
ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
if(ortn) {
showError(ortn, "SecKeychainGetCSPHandle");
exit(1);
}
#endif
isRoot = true;
char labelBuf[200];
if(useAllDefaults) {
strcpy(labelBuf, ZDEF_KEY_LABEL);
}
else {
while(1) {
getStringWithPrompt("Enter key and certificate label: ", labelBuf,
sizeof(labelBuf));
if(labelBuf[0] != '\0') {
break;
}
}
}
keyLabel.Data = (uint8 *)labelBuf;
keyLabel.Length = strlen(labelBuf);
if(useAllDefaults) {
keyAlg = ZDEF_KEY_ALG;
keySizeInBits = ZDEF_KEY_SIZE;
}
else {
getKeyParams(keyAlg, keySizeInBits);
}
if(useAllDefaults) {
keyUsage = ZDEF_KEY_USAGE;
}
else {
keyUsage = getKeyUsage(isRoot);
}
printf("...Generating key pair...\n");
#if SEC_KEY_CREATE_PAIR
description = CFStringCreateWithCString(NULL, labelBuf, kCFStringEncodingMacRoman);
ortn = SecAccessCreate(description, NULL, &access);
if(ortn) {
printf("Error creating SecAccessRef; aborting.\n");
goto abort;
}
ortn = SecAccessCopyACLList(access, &acls);
if (ortn) {
printf("Error calling SecAccessCopyACLList; aborting.\n");
goto abort;
}
for (CFIndex ix = 0; ix < CFArrayGetCount(acls); ++ix)
{
CSSM_ACL_AUTHORIZATION_TAG tags[20];
uint32 tagCount = 20;
acl = (SecACLRef)CFArrayGetValueAtIndex(acls, ix);
ortn = SecACLGetAuthorizations(acl, tags, &tagCount);
if(ortn) {
printf("Error calling SecACLGetAuthorizations; aborting.\n");
goto abort;
}
for (uint32 tix = 0; tix < tagCount; ++tix)
{
if (tags[tix] == CSSM_ACL_AUTHORIZATION_DECRYPT
|| tags[tix] == CSSM_ACL_AUTHORIZATION_ANY)
{
aclFound = true;
break;
}
}
if (aclFound)
break;
}
if (!aclFound) {
printf("Could not find ACL for decrypt right; aborting.\n");
goto abort;
}
ortn = SecACLSetSimpleContents(acl, NULL, description, &promptSelector);
if(ortn) {
printf("Error calling SecACLSetSimpleContents; aborting.\n");
goto abort;
}
pubKeyAttrs = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT;
privKeyAttrs = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT;
if(keyUsage & kKeyUseSigning) {
pubKeyUse |= CSSM_KEYUSE_VERIFY;
privKeyUse |= CSSM_KEYUSE_SIGN;
}
if(keyUsage & kKeyUseEncrypting) {
pubKeyUse |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP);
privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP);
}
ortn = SecKeyCreatePair(kcRef, keyAlg, keySizeInBits, 0, pubKeyUse, pubKeyAttrs, privKeyUse, privKeyAttrs, access, &pubKeyRef, &privKeyRef);
if (!ortn)
ortn = SecKeyGetCSSMKey(pubKeyRef, &pubKey);
if (!ortn)
ortn = SecKeyGetCSSMKey(privKeyRef, &privKey);
#else
ortn = generateKeyPair(cspHand,
dlDbHand,
keyAlg,
keySizeInBits,
labelBuf,
keyUsage,
verbose,
&pubKey,
&privKey);
#endif
if(ortn) {
printf("Error generating keys; aborting.\n");
goto abort;
}
if(useAllDefaults) {
sigAlg = ZDEF_SIG_ALG;
sigOid = &ZDEF_SIG_OID;
}
else {
ortn = getSigAlg(privKey, sigAlg, sigOid);
if(ortn) {
printf("Can not sign with this private key. Aborting.\n");
goto abort;
}
}
if(createCsr) {
printf("...creating CSR...\n");
}
else {
printf("...creating certificate...\n");
}
ortn = createCertCsr(createCsr,
tpHand,
clHand,
cspHand,
pubKey,
privKey,
sigAlg,
sigOid,
keyUsage,
NULL, useAllDefaults,
&certData);
if(ortn) {
goto abort;
}
if(verbose) {
printCert(certData.Data, certData.Length, CSSM_FALSE);
printCertShutdown();
}
if(createCsr) {
unsigned char *pem = NULL;
unsigned pemLen;
int rtn;
if(pemFormat) {
rtn = pemEncode(certData.Data, certData.Length, &pem, &pemLen,
"CERTIFICATE REQUEST");
if(rtn) {
printf("***Error PEM-encoding CSR. Aborting.\n");
goto abort;
}
rtn = writeFile(fileName, pem, pemLen);
}
else {
rtn = writeFile(fileName, certData.Data, certData.Length);
}
if(rtn) {
printf("***Error writing CSR to %s\n", fileName);
}
else {
printf("Wrote %u bytes of CSR to %s\n", (unsigned)certData.Length,
fileName);
}
if(pem) {
free(pem);
}
}
else {
#if SEC_CERT_ADD_TO_KC
crtn = cuAddCertToKC(kcRef,
&certData,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
labelBuf, &keyLabel);
#else
crtn = cuAddCertToDb(dlDbHand,
&certData,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
labelBuf, &pubKeyHash);
#endif
if(crtn == CSSM_OK) {
printf("..cert stored in Keychain.\n");
}
}
abort:
#if SEC_KEY_CREATE_PAIR
if (description) CFRelease(description);
if (access) CFRelease(access);
if (acls) CFRelease(acls);
if (pubKeyRef) CFRelease(pubKeyRef);
if (privKeyRef) CFRelease(privKeyRef);
#endif
return 0;
}