--- /dev/null
+/*
+ * certTime - measure performacne of cert parse and build.
+ */
+
+#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);
+}
+
+/*
+ * The certs we'll be parsing
+ */
+static const char *certNames[] =
+{
+ "anchor_0", // GTE CyberTrust Root, no extens
+ "anchor_9", // VeriSign, no extens
+ "anchor_34", // TrustCenter, 6 extens
+ "anchor_44", // USERTRUST, 5 extens, incl. cRLDistributionPoints
+ "anchor_76", // QuoVadis, 6 extens, incl. authorityInfoAccess
+ "anchor_80", // KMD-CA Kvalificeret3 6 extens
+};
+
+#define NUM_PARSED_CERTS (sizeof(certNames) / sizeof(certNames[0]))
+
+/* dummy RDN - subject and issuer - we aren't testing this */
+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"
+
+
+/*
+ * Set of extensions we'll be creating
+ */
+/* empty freeFcn means no extension-specific resources to free */
+#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;
+}
+
+/* Emulate TPCertInfo constructor */
+
+static CSSM_RETURN fetchCertField(
+ CSSM_CL_HANDLE clHand,
+ CSSM_HANDLE certHand,
+ const CSSM_OID *fieldOid,
+ CSSM_DATA_PTR *fieldData) // mallocd by CL and RETURNED
+{
+ 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;
+
+ /* fetched by TPClItemInfo constructor */
+ CSSM_DATA_PTR issuerName;
+ CSSM_DATA_PTR sigAlg;
+ CSSM_DATA_PTR notBefore;
+ CSSM_DATA_PTR notAfter;
+ /* fetched by TPCertInfo */
+ 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++) {
+ /* parse and cache */
+ crtn = CSSM_CL_CertCache(clHand, &cert, &cacheHand);
+ if(crtn) {
+ printError("CSSM_CL_CertCache", crtn);
+ return 1;
+ }
+ /* fetch the fields */
+ 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
+
+ /* free the fields */
+ 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, // VerifyScope
+ 0); // ScopeSize
+ if(crtn) {
+ printError("CSSM_CL_CertVerify", crtn);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Stuff to be created before entering the timed cert create routine.
+ */
+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;
+
+/*
+ * One-time only setup of cert creation params.
+ */
+ 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, // pubIsRef
+ CSSM_KEYUSE_VERIFY,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ ¶ms.privKey,
+ CSSM_TRUE, // privIsRef - doesn't matter
+ 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);
+
+ /* now some extensions */
+ 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, // serial number
+ params.dummyName,
+ params.dummyName,
+ params.notBefore,
+ params.notAfter,
+ ¶ms.pubKey,
+ SIG_ALG,
+ NULL, // subjUniqueId
+ NULL, // issuerUniqueId
+ params.extens, // extensions
+ /* vary numExtensions per loop */
+ 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, // no passphrase for now
+ ¶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, // CertToBeSigned
+ NULL, // SignScope per spec
+ 0, // ScopeSize per spec
+ &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, // sign is an option for this one
+ 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];
+
+ /* user-specificied params */
+ 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);
+ }
+ }
+
+ /* common setup */
+ clHand = clStartup();
+ if(clHand == 0) {
+ return 0;
+ }
+ cspHand = cspStartup();
+ if(cspHand == 0) {
+ return 0;
+ }
+
+ /* per-test setup */
+ switch(op) {
+ unsigned dex;
+ unsigned len;
+
+ case CTO_Parse:
+ case CTO_GetFields:
+ case CTO_GetSomeFields:
+ case CTO_Verify:
+ /* read in the certs */
+ 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:
+ /* set up keys, names */
+ if(createSetup(clHand, cspHand, keySize, params)) {
+ exit(1);
+ }
+ break;
+ }
+
+ /* one loop outside of timer to heat up test bed */
+ 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();
+
+ /* begin timed loop */
+ 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);
+
+ /* cleanup */
+ 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;
+}
+