#include "key_create.h"
#include "keychain_utilities.h"
#include "security_tool.h"
#include <CoreFoundation/CFDateFormatter.h>
#include <CoreFoundation/CFString.h>
#include <Security/SecAccess.h>
#include <Security/SecKey.h>
#include <Security/SecKeychainItem.h>
#include <Security/SecTrustedApplication.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int
do_key_create_pair(const char *keychainName, SecAccessRef access, CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFAbsoluteTime from_time, CFAbsoluteTime to_time, Boolean print_hash)
{
SecKeychainRef keychain = NULL;
OSStatus status;
int result = 0;
CSSM_CC_HANDLE contextHandle = 0;
CSSM_KEYUSE publicKeyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_DERIVE;
uint32 publicKeyAttr = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE;
CSSM_KEYUSE privateKeyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_DERIVE;
uint32 privateKeyAttr = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL;
SecKeychainAttributeList *attrList = NULL;
if (keychainName)
{
keychain = keychain_open(keychainName);
if (!keychain)
{
result = 1;
goto loser;
}
}
status = SecKeyCreatePair(keychain, algorithm, keySizeInBits, contextHandle,
publicKeyUsage,
publicKeyAttr,
privateKeyUsage,
privateKeyAttr,
access,
&publicKey,
&privateKey);
if (status)
{
sec_error("SecKeyCreatePair %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(status));
result = 1;
goto loser;
}
if (print_hash)
{
SecItemClass itemClass = 0;
UInt32 tag = 0x00000006;
UInt32 format = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
SecKeychainAttributeInfo info = { 1, &tag, &format };
status = SecKeychainItemCopyAttributesAndData((SecKeychainItemRef)privateKey, &info, &itemClass, &attrList, NULL, NULL);
if (status)
{
sec_perror("SecKeychainItemCopyAttributesAndData", status);
result = 1;
goto loser;
}
if (info.count != attrList->count)
{
sec_error("info count: %ld != attribute count: %ld", info.count, attrList->count);
result = 1;
goto loser;
}
if (tag != attrList->attr[0].tag)
{
sec_error("attribute info tag: %ld != attribute tag: %ld", tag, attrList->attr[0].tag);
result = 1;
goto loser;
}
print_buffer_pem(stdout, "PUBLIC KEY HASH", attrList->attr[0].length, attrList->attr[0].data);
}
loser:
if (attrList)
{
status = SecKeychainItemFreeAttributesAndData(attrList, NULL);
if (status)
sec_perror("SecKeychainItemFreeAttributesAndData", status);
}
if (keychain)
CFRelease(keychain);
if (publicKey)
CFRelease(publicKey);
if (privateKey)
CFRelease(privateKey);
return result;
}
static int
parse_algorithm(const char *name, CSSM_ALGORITHMS *algorithm)
{
size_t len = strlen(name);
if (!strncmp("rsa", name, len))
*algorithm = CSSM_ALGID_RSA;
else if (!strncmp("dsa", name, len))
*algorithm = CSSM_ALGID_DSA;
else if (!strncmp("dh", name, len))
*algorithm = CSSM_ALGID_DH;
else if (!strncmp("fee", name, len))
*algorithm = CSSM_ALGID_FEE;
else
{
sec_error("Invalid algorithm: %s", name);
return 2;
}
return 0;
}
static int
parse_time(const char *time, CFAbsoluteTime *ptime)
{
CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, NULL, kCFDateFormatterShortStyle, kCFDateFormatterShortStyle);
CFStringRef time_string = CFStringCreateWithCString(NULL, time, kCFStringEncodingUTF8);
int result = 0;
if (!CFDateFormatterGetAbsoluteTimeFromString(formatter, time_string, NULL, ptime))
{
sec_error("%s is not a valid date", time);
result = 1;
}
if (formatter)
CFRelease(formatter);
if (time_string)
CFRelease(time_string);
return result;
}
int
key_create_pair(int argc, char * const *argv)
{
const char *keychainName = NULL;
CSSM_ALGORITHMS algorithm = CSSM_ALGID_RSA;
uint32 keySizeInBits = 512;
int ch, result = 0;
OSStatus status;
Boolean always_allow = FALSE;
Boolean print_hash = FALSE;
CFAbsoluteTime from_time = 0.0, to_time = 0.0;
double days = 0.0;
SecAccessRef access = NULL;
CFMutableArrayRef trusted_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFStringRef description = NULL;
while ((ch = getopt(argc, argv, "a:s:f:t:d:k:AHT:h")) != -1)
{
switch (ch)
{
case 'a':
result = parse_algorithm(optarg, &algorithm);
if (result)
goto loser;
break;
case 's':
keySizeInBits = atoi(optarg);
break;
case 'k':
keychainName = optarg;
break;
case 'A':
always_allow = TRUE;
break;
case 'H':
print_hash = TRUE;
break;
case 'T':
{
if (optarg[0])
{
SecTrustedApplicationRef app = NULL;
status = SecTrustedApplicationCreateFromPath(optarg, &app);
if (status)
{
sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg, sec_errstr(status));
result = 1;
goto loser;
}
CFArrayAppendValue(trusted_list, app);
CFRelease(app);
}
break;
}
case 'f':
result = parse_time(optarg, &from_time);
if (result)
goto loser;
break;
case 't':
result = parse_time(optarg, &to_time);
if (result)
goto loser;
break;
case 'd':
days = atof(optarg);
if (days < 1)
{
result = 2;
goto loser;
}
from_time = CFAbsoluteTimeGetCurrent();
to_time = from_time + days * 86400.0;
break;
case '?':
default:
return 2;
}
}
argc -= optind;
argv += optind;
if (argc == 1)
{
if (*argv[0] == '\0')
{
result = 2;
goto loser;
}
description = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
}
else if (argc != 0)
return 2;
else
description = CFStringCreateWithCString(NULL, "<key>", kCFStringEncodingUTF8);
if (always_allow)
{
status = SecAccessCreate(description, NULL, &access);
if (status)
{
sec_perror("SecAccessCreate", status);
result = 1;
}
}
else
{
status = SecAccessCreate(description, trusted_list, &access);
if (status)
{
sec_perror("SecAccessCreate", status);
result = 1;
}
}
if (result)
goto loser;
result = do_key_create_pair(keychainName, access, algorithm, keySizeInBits, from_time, to_time, print_hash);
loser:
if (description)
CFRelease(description);
if (trusted_list)
CFRelease(trusted_list);
if (access)
CFRelease(access);
return result;
}
#if 0
static OSStatus
createCertCsr(
CSSM_TP_HANDLE tpHand, CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
SecKeyRef subjPubKey,
SecKeyRef signerPrivKey,
CSSM_ALGORITHMS sigAlg,
const CSSM_OID *sigOid,
CSSM_BOOL useAllDefaults,
CSSM_DATA_PTR csrData) {
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;
numExts = 0;
char challengeBuf[400];
if(useAllDefaults) {
strcpy(challengeBuf, ZDEF_CHALLENGE);
}
else {
while(1) {
getStringWithPrompt("Enter challenge string: ",
challengeBuf, sizeof(challengeBuf));
if(challengeBuf[0] != '\0') {
break;
}
}
}
certReq.challengeString = challengeBuf;
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));
policyId.FieldOid = CSSMOID_APPLE_TP_CSR_GEN;
CallerAuthContext.Policy.NumberOfPolicyIds = 1;
CallerAuthContext.Policy.PolicyIds = &policyId;
CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tpHand,
NULL, CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
&reqSet,
&CallerAuthContext,
&estTime,
&refId);
if(!useAllDefaults) {
freeNameOids(subjectNames, numNames);
}
if(crtn) {
printError("***Error submitting credential request","CSSM_TP_SubmitCredRequest",crtn);
return crtn;
}
crtn = CSSM_TP_RetrieveCredResult(tpHand,
&refId,
NULL, &estTime,
&confirmRequired,
&resultSet);
if(crtn) {
printError("***Error retreiving credential request","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;
*csrData = encCert->CertBlob;
APP_FREE(refId.Data);
APP_FREE(encCert);
APP_FREE(resultSet);
return noErr;
}
#endif
#if 0
int
csr_create(int argc, char * const *argv)
{
int result = 0;
int ch;
const char *keychainName = NULL;
CSSM_ALGORITHMS algorithm = CSSM_ALGID_RSA;
uint32 keySizeInBits = 512;
OSStatus status;
Boolean always_allow = FALSE;
CFAbsoluteTime from_time = 0.0, to_time = 0.0;
double days = 0.0;
SecAccessRef access = NULL;
CFMutableArrayRef trusted_list = NULL;
CFStringRef description = NULL;
while ((ch = getopt(argc, argv, "a:s:f:t:d:k:AT:h")) != -1)
{
switch (ch)
{
case 'a':
result = parse_algorithm(optarg, &algorithm);
if (result)
goto loser;
break;
case 's':
keySizeInBits = atoi(optarg);
break;
case 'k':
keychainName = optarg;
break;
case 'A':
always_allow = TRUE;
break;
case 'T':
{
if (!trusted_list)
{
trusted_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
if (optarg[0])
{
SecTrustedApplicationRef app = NULL;
status = SecTrustedApplicationCreateFromPath(optarg, &app);
if (status)
{
sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg, sec_errstr(status));
result = 1;
goto loser;
}
CFArrayAppendValue(trusted_list, app);
CFRelease(app);
break;
}
}
case 'f':
result = parse_time(optarg, &from_time);
if (result)
goto loser;
break;
case 't':
result = parse_time(optarg, &to_time);
if (result)
goto loser;
break;
case 'd':
days = atof(optarg);
if (days < 1)
{
result = 2;
goto loser;
}
from_time = CFAbsoluteTimeGetCurrent();
to_time = from_time + days * 86400.0;
break;
case '?':
default:
return 2;
}
}
argc -= optind;
argv += optind;
if (argc == 1)
{
if (*argv[0] == '\0')
{
result = 2;
goto loser;
}
description = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
}
else if (argc != 0)
return 2;
else
description = CFStringCreateWithCString(NULL, "<key>", kCFStringEncodingUTF8);
if (always_allow)
{
status = SecAccessCreate(description, NULL, &access);
if (status)
{
sec_perror("SecAccessCreate", status);
result = 1;
}
}
else
{
status = SecAccessCreate(description, trusted_list, &access);
if (status)
{
sec_perror("SecAccessCreate", status);
result = 1;
}
}
if (result)
goto loser;
result = do_csr_create(keychainName, access, algorithm, keySizeInBits, from_time, to_time);
loser:
if (description)
CFRelease(description);
if (trusted_list)
CFRelease(trusted_list);
if (access)
CFRelease(access);
return result;
}
#endif