#include <security_cdsa_utils/cuFileIo.h>
#include <clAppUtils/CertBuilderApp.h>
#include <utilLib/common.h>
#include <utilLib/cspwrap.h>
#include <clAppUtils/clutils.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <Security/cssm.h>
#include <Security/x509defs.h>
#include <Security/oidsattr.h>
#include <Security/oidscert.h>
#include <Security/certextensions.h>
#include <CoreFoundation/CoreFoundation.h>
#include "extenCooker.h"
#define KEYSIZE_DEF 1024
#define CL_KEY_VIA_GET_KEY 0
static void usage(char **argv)
{
printf("Usage: %s op loops [options]\n", argv[0]);
printf("Op:\n");
printf(" p parse\n");
printf(" g parse & get all fields\n");
#if CL_KEY_VIA_GET_KEY
printf(" t parse & get some fields, emulating TPCertInfo, GetKeyInfo\n");
#else
printf(" t parse & get some fields, emulating TPCertInfo, fetchField(key)\n");
#endif
printf(" c create\n");
printf(" s create & sign\n");
printf(" v verify\n");
printf("Options:\n");
printf(" b RSA blinding on\n");
printf(" k=keysize (default = %d)\n", KEYSIZE_DEF);
exit(1);
}
static const char *certNames[] =
{
"anchor_0", "anchor_9", "anchor_34", "anchor_44", "anchor_76", "anchor_80", };
#define NUM_PARSED_CERTS (sizeof(certNames) / sizeof(certNames[0]))
CB_NameOid dummyRdn[] =
{
{ "Apple Computer", &CSSMOID_OrganizationName },
{ "Doug Mitchell", &CSSMOID_CommonName }
};
#define NUM_DUMMY_NAMES (sizeof(dummyRdn) / sizeof(CB_NameOid))
#define KEY_ALG CSSM_ALGID_RSA
#define SIG_ALG CSSM_ALGID_SHA1WithRSA
#define SUBJ_KEY_LABEL "subjectKey"
#define NO_FREE NULL
static ExtenTest extenTests[] = {
{ kuCreate, kuCompare, NO_FREE,
sizeof(CE_KeyUsage), CSSMOID_KeyUsage,
"KeyUsage", 'k' },
{ ekuCreate, ekuCompare, NO_FREE,
sizeof(CE_ExtendedKeyUsage), CSSMOID_ExtendedKeyUsage,
"ExtendedKeyUsage", 'x' },
{ authKeyIdCreate, authKeyIdCompare, authKeyIdFree,
sizeof(CE_AuthorityKeyID), CSSMOID_AuthorityKeyIdentifier,
"AuthorityKeyID", 'a' },
{ genNamesCreate, genNamesCompare, genNamesFree,
sizeof(CE_GeneralNames), CSSMOID_SubjectAltName,
"SubjectAltName", 't' },
};
#define MAX_EXTENSIONS (sizeof(extenTests) / sizeof(ExtenTest))
static int doParse(
CSSM_CL_HANDLE clHand,
const CSSM_DATA &cert,
unsigned loops)
{
CSSM_HANDLE cacheHand;
CSSM_RETURN crtn;
for(unsigned loop=0; loop<loops; loop++) {
crtn = CSSM_CL_CertCache(clHand, &cert, &cacheHand);
if(crtn) {
printError("CSSM_CL_CertCache", crtn);
return 1;
}
crtn = CSSM_CL_CertAbortCache(clHand, cacheHand);
if(crtn) {
printError("CSSM_CL_CrlAbortCache", crtn);
return 1;
}
}
return 0;
}
static CSSM_RETURN fetchCertField(
CSSM_CL_HANDLE clHand,
CSSM_HANDLE certHand,
const CSSM_OID *fieldOid,
CSSM_DATA_PTR *fieldData) {
CSSM_RETURN crtn;
uint32 NumberOfFields = 0;
CSSM_HANDLE resultHand = 0;
*fieldData = NULL;
crtn = CSSM_CL_CertGetFirstCachedFieldValue(
clHand,
certHand,
fieldOid,
&resultHand,
&NumberOfFields,
fieldData);
if(crtn) {
printError("fetchCertField", crtn);
return crtn;
}
if(NumberOfFields != 1) {
printf("***fetchCertField: numFields %d, expected 1\n",
(int)NumberOfFields);
}
CSSM_CL_CertAbortQuery(clHand, resultHand);
return CSSM_OK;
}
static int doGetSomeFields(
CSSM_CL_HANDLE clHand,
const CSSM_DATA &cert,
unsigned loops)
{
CSSM_HANDLE cacheHand;
CSSM_RETURN crtn;
CSSM_DATA_PTR issuerName;
CSSM_DATA_PTR sigAlg;
CSSM_DATA_PTR notBefore;
CSSM_DATA_PTR notAfter;
CSSM_DATA_PTR subjectName;
#if CL_KEY_VIA_GET_KEY
CSSM_KEY_PTR subjPubKey;
#else
CSSM_DATA_PTR subjPubKeyData;
#endif
for(unsigned loop=0; loop<loops; loop++) {
crtn = CSSM_CL_CertCache(clHand, &cert, &cacheHand);
if(crtn) {
printError("CSSM_CL_CertCache", crtn);
return 1;
}
fetchCertField(clHand, cacheHand, &CSSMOID_X509V1IssuerName, &issuerName);
fetchCertField(clHand, cacheHand, &CSSMOID_X509V1SignatureAlgorithmTBS,
&sigAlg);
fetchCertField(clHand, cacheHand, &CSSMOID_X509V1ValidityNotBefore,
¬Before);
fetchCertField(clHand, cacheHand, &CSSMOID_X509V1ValidityNotAfter, ¬After);
fetchCertField(clHand, cacheHand, &CSSMOID_X509V1SubjectName, &subjectName);
#if CL_KEY_VIA_GET_KEY
CSSM_CL_CertGetKeyInfo(clHand, &cert, &subjPubKey);
#else
fetchCertField(clHand, cacheHand, &CSSMOID_CSSMKeyStruct, &subjPubKeyData);
#endif
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1IssuerName, issuerName);
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SignatureAlgorithmTBS, sigAlg);
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1ValidityNotBefore, notBefore);
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1ValidityNotAfter, notAfter);
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SubjectName, subjectName);
#if CL_KEY_VIA_GET_KEY
appFree(subjPubKey->KeyData.Data, 0);
appFree(subjPubKey, 0);
#else
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_CSSMKeyStruct, subjPubKeyData);
#endif
crtn = CSSM_CL_CertAbortCache(clHand, cacheHand);
if(crtn) {
printError("CSSM_CL_CrlAbortCache", crtn);
return 1;
}
}
return 0;
}
static int doGetFields(
CSSM_CL_HANDLE clHand,
const CSSM_DATA &cert,
unsigned loops)
{
uint32 numFields;
CSSM_FIELD_PTR certFields;
CSSM_RETURN crtn;
for(unsigned loop=0; loop<loops; loop++) {
crtn = CSSM_CL_CertGetAllFields(clHand, &cert, &numFields,
&certFields);
if(crtn) {
printError("CSSM_CL_CertGetAllFields", crtn);
return 1;
}
crtn = CSSM_CL_FreeFields(clHand, numFields, &certFields);
if(crtn) {
printError("CSSM_CL_FreeFields", crtn);
return 1;
}
}
return 0;
}
static int doVerify(
CSSM_CL_HANDLE clHand,
const CSSM_DATA &cert,
unsigned loops)
{
CSSM_RETURN crtn;
for(unsigned loop=0; loop<loops; loop++) {
crtn = CSSM_CL_CertVerify(clHand,
CSSM_INVALID_HANDLE,
&cert,
&cert,
NULL, 0); if(crtn) {
printError("CSSM_CL_CertVerify", crtn);
return 1;
}
}
return 0;
}
typedef struct {
CSSM_KEY privKey;
CSSM_KEY pubKey;
CSSM_X509_NAME *dummyName;
CSSM_X509_TIME *notBefore;
CSSM_X509_TIME *notAfter;
CSSM_X509_EXTENSION extens[MAX_EXTENSIONS];
} PresetParams;
static int createSetup(
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
unsigned keySize,
PresetParams ¶ms)
{
CSSM_RETURN crtn;
crtn = cspGenKeyPair(cspHand,
KEY_ALG,
SUBJ_KEY_LABEL,
strlen(SUBJ_KEY_LABEL),
keySize,
¶ms.pubKey,
CSSM_FALSE, CSSM_KEYUSE_VERIFY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
¶ms.privKey,
CSSM_TRUE, CSSM_KEYUSE_SIGN,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE);
if(crtn) {
return 1;
}
params.dummyName = CB_BuildX509Name(dummyRdn, NUM_DUMMY_NAMES);
if(params.dummyName == NULL) {
printf("CB_BuildX509Name failure");
return 1;
}
params.notBefore = CB_BuildX509Time(0);
params.notAfter = CB_BuildX509Time(10000);
for(unsigned dex=0; dex<MAX_EXTENSIONS; dex++) {
CSSM_X509_EXTENSION &extn = params.extens[dex];
ExtenTest &etest = extenTests[dex];
void *extVal = CSSM_MALLOC(etest.extenSize);
memset(extVal, 0, etest.extenSize);
etest.createFcn(extVal);
extn.extnId = etest.extenOid;
extn.critical = randBool();
extn.format = CSSM_X509_DATAFORMAT_PARSED;
extn.value.parsedValue = extVal;
extn.BERvalue.Data = NULL;
extn.BERvalue.Length = 0;
}
return 0;
}
static int doCreate(
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
unsigned loops,
PresetParams ¶ms,
bool doSign,
bool rsaBlind)
{
for(unsigned loop=0; loop<loops; loop++) {
CSSM_DATA_PTR rawCert = CB_MakeCertTemplate(clHand,
0x12345678, params.dummyName,
params.dummyName,
params.notBefore,
params.notAfter,
¶ms.pubKey,
SIG_ALG,
NULL, NULL, params.extens,
loop % MAX_EXTENSIONS);
if(rawCert == NULL) {
printf("Error creating cert template.\n");
return 1;
}
if(doSign) {
CSSM_DATA signedCert = {0, NULL};
CSSM_CC_HANDLE sigHand;
CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
SIG_ALG,
NULL, ¶ms.privKey,
&sigHand);
if(crtn) {
printError("CreateSignatureContext", crtn);
return 1;
}
if(rsaBlind) {
CSSM_CONTEXT_ATTRIBUTE newAttr;
newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
newAttr.AttributeLength = sizeof(uint32);
newAttr.Attribute.Uint32 = 1;
crtn = CSSM_UpdateContextAttributes(sigHand, 1, &newAttr);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
crtn = CSSM_CL_CertSign(clHand,
sigHand,
rawCert, NULL, 0, &signedCert);
if(crtn) {
printError("CSSM_CL_CertSign", crtn);
return 1;
}
CSSM_DeleteContext(sigHand);
CSSM_FREE(signedCert.Data);
}
CSSM_FREE(rawCert->Data);
CSSM_FREE(rawCert);
}
return 0;
}
typedef enum {
CTO_Parse,
CTO_GetFields,
CTO_GetSomeFields,
CTO_Create, CTO_Verify
} CT_Op;
int main(int argc, char **argv)
{
CSSM_CL_HANDLE clHand;
CSSM_CSP_HANDLE cspHand;
int arg;
int rtn;
char *argp;
unsigned i;
PresetParams params;
CSSM_DATA certData[NUM_PARSED_CERTS];
CT_Op op;
unsigned loops = 0;
bool doSign = false;
const char *opStr = NULL;
bool rsaBlinding = false;
unsigned keySize = KEYSIZE_DEF;
if(argc < 3) {
usage(argv);
}
switch(argv[1][0]) {
case 'p':
op = CTO_Parse;
opStr = "Parsed";
break;
case 'g':
op = CTO_GetFields;
opStr = "Parsed with GetAllFields";
break;
case 't':
op = CTO_GetSomeFields;
#if CL_KEY_VIA_GET_KEY
opStr = "Parsed with some GetFields and GetKeyInfo";
#else
opStr = "Parsed with some GetFields";
#endif
break;
case 'c':
op = CTO_Create;
opStr = "Created";
break;
case 's':
op = CTO_Create;
opStr = "Created and Signed";
doSign = true;
break;
case 'v':
op = CTO_Verify;
opStr = "Verified";
break;
default:
usage(argv);
}
loops = atoi(argv[2]);
for(arg=3; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'b':
rsaBlinding = true;
break;
case 'k':
keySize = atoi(&argp[2]);
break;
default:
usage(argv);
}
}
clHand = clStartup();
if(clHand == 0) {
return 0;
}
cspHand = cspStartup();
if(cspHand == 0) {
return 0;
}
switch(op) {
unsigned dex;
unsigned len;
case CTO_Parse:
case CTO_GetFields:
case CTO_GetSomeFields:
case CTO_Verify:
for(dex=0; dex<NUM_PARSED_CERTS; dex++) {
CSSM_DATA &cdata = certData[dex];
if(readFile(certNames[dex],
(unsigned char **)&cdata.Data,
&len)) {
printf("Error reading cert %s. Aborting.\n",
certNames[dex]);
exit(1);
}
cdata.Length = len;
}
break;
case CTO_Create:
if(createSetup(clHand, cspHand, keySize, params)) {
exit(1);
}
break;
}
switch(op) {
case CTO_Parse:
rtn = doParse(clHand, certData[0], 1);
break;
case CTO_GetFields:
rtn = doGetFields(clHand, certData[0], 1);
break;
case CTO_GetSomeFields:
rtn = doGetSomeFields(clHand, certData[0], 1);
break;
case CTO_Verify:
rtn = doVerify(clHand, certData[0], 1);
break;
case CTO_Create:
rtn = doCreate(clHand, cspHand, 1, params, true, rsaBlinding);
break;
}
if(rtn) {
printf("This program needs work. Try again.\n");
return 1;
}
CFAbsoluteTime startTime, endTime;
startTime = CFAbsoluteTimeGetCurrent();
switch(op) {
case CTO_Parse:
for(i=0; i<NUM_PARSED_CERTS; i++) {
rtn = doParse(clHand, certData[i], loops);
if(rtn) {
break;
}
}
break;
case CTO_GetFields:
for(i=0; i<NUM_PARSED_CERTS; i++) {
rtn = doGetFields(clHand, certData[i], loops);
if(rtn) {
break;
}
}
break;
case CTO_GetSomeFields:
for(i=0; i<NUM_PARSED_CERTS; i++) {
rtn = doGetSomeFields(clHand, certData[i], loops);
if(rtn) {
break;
}
}
break;
case CTO_Verify:
for(i=0; i<NUM_PARSED_CERTS; i++) {
rtn = doVerify(clHand, certData[i], loops);
if(rtn) {
break;
}
}
break;
case CTO_Create:
rtn = doCreate(clHand, cspHand, loops, params, doSign,
rsaBlinding);
break;
}
endTime = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime deltaTime = endTime - startTime;
if(rtn) {
printf("Error in main loop. Try again.\n");
return 1;
}
unsigned numCerts = loops;
if(op != CTO_Create) {
numCerts *= NUM_PARSED_CERTS;
}
printf("=== %u certs %s ===\n", numCerts, opStr);
printf("Total time %g s\n", deltaTime);
printf("%g ms per cert\n", (deltaTime / (double)numCerts) * 1000.0);
if(op == CTO_Create) {
CB_FreeX509Name(params.dummyName);
CB_FreeX509Time(params.notBefore);
CB_FreeX509Time(params.notAfter);
cspFreeKey(cspHand, ¶ms.pubKey);
cspFreeKey(cspHand, ¶ms.privKey);
}
else {
for(i=0; i<NUM_PARSED_CERTS; i++) {
free(certData[i].Data);
}
}
CSSM_ModuleDetach(cspHand);
CSSM_ModuleDetach(clHand);
return 0;
}