#include <utilLib/common.h>
#include <utilLib/cspwrap.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <clAppUtils/CertBuilderApp.h>
#include <clAppUtils/clutils.h>
#include <clAppUtils/timeStr.h>
#include <clAppUtils/tpUtils.h>
#include <security_cdsa_utils/cuPrintCert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Security/cssm.h>
#include <Security/x509defs.h>
#include <Security/oidsattr.h>
#include <Security/oidscert.h>
#include <Security/oidsalg.h>
#include <Security/certextensions.h>
#include <Security/cssmapple.h>
#include <string.h>
#define PUMA_BUILD 0
#define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
#define KEY_ALG_DEFAULT CSSM_ALGID_RSA
#define NUM_CERTS_DEF 5
#define NUM_LOOPS_DEF 100
#if PUMA_BUILD
extern "C" {
void cssmPerror(const char *how, CSSM_RETURN error);
}
#endif
static void usage(char **argv)
{
printf("Usage: %s [options]\n", argv[0]);
printf("Options:\n");
printf(" n=numCerts (default=random from 2 to %d)\n", NUM_CERTS_DEF);
printf(" a=alg where alg is s(RSA/SHA1), 5(RSA/MD5), f(FEE/MD5), "
"F(FEE/SHA1), e(ECDSA), E(ANSI/ECDSA), 6(ECDSA/SHA256)\n");
printf(" k=keySizeInBits\n");
printf(" c (dump certs on error)\n");
printf(" l=numLoops (default = %d)\n", NUM_LOOPS_DEF);
exit(1);
}
void showCerts(
const CSSM_DATA *certs,
unsigned numCerts)
{
unsigned i;
for(i=0; i<numCerts; i++) {
printf("======== cert %d ========\n", i);
printCert(certs[i].Data, certs[i].Length, CSSM_FALSE);
printf("\n\n");
}
}
void writeCerts(
const CSSM_DATA *certs,
unsigned numCerts)
{
unsigned i;
char fileName[80];
for(i=0; i<numCerts; i++) {
sprintf(fileName, "caVerifyCert%u.cer", i);
writeFile(fileName, certs[i].Data, certs[i].Length);
printf("....wrote %lu bytes to %s\n", certs[i].Length, fileName);
}
}
static CSSM_RETURN tpGenCertsExten(
CSSM_CSP_HANDLE cspHand,
CSSM_CL_HANDLE clHand,
CSSM_ALGORITHMS sigAlg,
unsigned numCerts,
const char *nameBase,
CSSM_KEY_PTR pubKeys,
CSSM_KEY_PTR privKeys,
CSSM_X509_EXTENSION **extensions,
unsigned *numExtensions,
CSSM_DATA_PTR certs,
const char *notBeforeStr,
const char *notAfterStr)
{
int dex;
CSSM_RETURN crtn;
CSSM_X509_NAME *issuerName = NULL;
CSSM_X509_NAME *subjectName = NULL;
CSSM_X509_TIME *notBefore; CSSM_X509_TIME *notAfter; CSSM_DATA_PTR rawCert = NULL; CSSM_DATA signedCert; uint32 rtn;
CSSM_KEY_PTR signerKey; CSSM_CC_HANDLE signContext;
char nameStr[100];
CSSM_DATA_PTR thisCert; CB_NameOid nameOid;
nameOid.oid = &CSSMOID_OrganizationName; nameOid.string = nameStr;
for(dex=numCerts-1; dex>=0; dex--) {
thisCert = &certs[dex];
thisCert->Data = NULL;
thisCert->Length = 0;
sprintf(nameStr, "%s%04d", nameBase, dex);
if(issuerName == NULL) {
issuerName = CB_BuildX509Name(&nameOid, 1);
signerKey = &privKeys[dex];
}
else {
CB_FreeX509Name(issuerName);
issuerName = subjectName;
signerKey = &privKeys[dex+1];
}
subjectName = CB_BuildX509Name(&nameOid, 1);
if((subjectName == NULL) || (issuerName == NULL)) {
printf("Error creating X509Names\n");
crtn = CSSMERR_CSSM_MEMORY_ERROR;
break;
}
notBefore = CB_BuildX509Time(0, notBeforeStr);
notAfter = CB_BuildX509Time(0, notAfterStr);
rawCert = CB_MakeCertTemplate(clHand,
0x12345 + dex, issuerName,
subjectName,
notBefore,
notAfter,
&pubKeys[dex],
sigAlg,
NULL, NULL, extensions[dex], numExtensions[dex]);
if(rawCert == NULL) {
crtn = CSSM_ERRCODE_INTERNAL_ERROR;
break;
}
CB_FreeX509Time(notBefore);
CB_FreeX509Time(notAfter);
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
sigAlg,
NULL, signerKey,
&signContext);
if(crtn) {
printError("CreateSignatureContext", crtn);
break;
}
signedCert.Data = NULL;
signedCert.Length = 0;
crtn = CSSM_CL_CertSign(clHand,
signContext,
rawCert, NULL, 0, &signedCert);
if(crtn) {
printError("CSSM_CL_CertSign", crtn);
break;
}
crtn = CSSM_DeleteContext(signContext);
if(crtn) {
printError("CSSM_DeleteContext", crtn);
break;
}
certs[dex] = signedCert;
appFreeCssmData(rawCert, CSSM_TRUE);
rtn = 0;
}
if(issuerName != NULL) {
CB_FreeX509Name(issuerName);
}
if(subjectName != NULL) {
CB_FreeX509Name(subjectName);
}
return crtn;
}
static int doTest(
CSSM_CSP_HANDLE cspHand, CSSM_CL_HANDLE clHand, CSSM_TP_HANDLE tpHand, unsigned numCerts, CSSM_KEY_PTR pubKeys,
CSSM_KEY_PTR privKeys,
CSSM_ALGORITHMS sigAlg,
CSSM_BOOL expectFail,
CSSM_BOOL dumpCerts,
CSSM_BOOL quiet)
{
CSSM_DATA_PTR certs;
CSSM_X509_EXTENSION **extens;
unsigned *numExtens;
char *notBeforeStr = genTimeAtNowPlus(0);
char *notAfterStr = genTimeAtNowPlus(10000);
unsigned certDex;
CE_BasicConstraints *bc;
CSSM_X509_EXTENSION *thisExten;
CE_BasicConstraints *thisBc;
const char *failMode = "not set - internal error";
CSSM_RETURN crtn;
unsigned badCertDex = 0;
certs = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA) * numCerts);
memset(certs, 0, sizeof(CSSM_DATA) * numCerts);
extens = (CSSM_X509_EXTENSION **)malloc(sizeof(CSSM_X509_EXTENSION *) * numCerts);
memset(extens, 0, sizeof(CSSM_X509_EXTENSION *) * numCerts);
numExtens = (unsigned *)malloc(sizeof(unsigned) * numCerts);
bc = (CE_BasicConstraints *)malloc(sizeof(CE_BasicConstraints) * numCerts);
for(certDex=0; certDex<numCerts; certDex++) {
extens[certDex] = (CSSM_X509_EXTENSION *)malloc(sizeof(CSSM_X509_EXTENSION));
numExtens[certDex] = 1;
thisExten = extens[certDex];
thisBc = &bc[certDex];
thisExten->extnId = CSSMOID_BasicConstraints;
thisExten->critical = CSSM_TRUE;
thisExten->format = CSSM_X509_DATAFORMAT_PARSED;
thisExten->value.parsedValue = thisBc;
thisExten->BERvalue.Data = NULL;
thisExten->BERvalue.Length = 0;
if(certDex == 0) {
int coin = genRand(1,2);
if(coin == 1) {
thisBc->cA = CSSM_FALSE;
thisBc->pathLenConstraintPresent = CSSM_FALSE;
thisBc->pathLenConstraint = 0;
}
else {
numExtens[certDex] = 0;
}
}
else if(certDex == (numCerts-1)) {
int coin = genRand(1,2);
if(coin == 1) {
thisBc->cA = CSSM_TRUE;
coin = genRand(1,2);
if(coin == 1) {
thisBc->pathLenConstraintPresent = CSSM_FALSE;
thisBc->pathLenConstraint = 0;
}
else {
thisBc->pathLenConstraintPresent = CSSM_TRUE;
thisBc->pathLenConstraint = genRand(certDex-1, numCerts+1);
}
}
else {
numExtens[certDex] = 0;
}
}
else {
thisBc->cA = CSSM_TRUE;
int coin = genRand(1,2);
if(coin == 1) {
thisBc->pathLenConstraintPresent = CSSM_FALSE;
thisBc->pathLenConstraint = 0;
}
else {
thisBc->pathLenConstraintPresent = CSSM_TRUE;
thisBc->pathLenConstraint = genRand(certDex-1, numCerts+1);
}
}
}
if(expectFail) {
if(numCerts == 2) {
badCertDex = 1;
thisExten = extens[badCertDex];
thisBc = &bc[badCertDex];
thisBc->cA = CSSM_FALSE;
thisBc->pathLenConstraintPresent = CSSM_FALSE;
bc->pathLenConstraint = 0;
numExtens[badCertDex] = 1;
failMode = "Explicit !cA in root";
}
else {
badCertDex = genRand(1, numCerts-2);
thisExten = extens[badCertDex];
if((thisExten == NULL) || (numExtens[badCertDex] == 0)) {
printf("***INTERNAL SCREWUP\n");
exit(1);
}
thisBc = &bc[badCertDex];
int die = genRand(1,3);
if((die == 1) &&
(badCertDex != 1)) { thisBc->pathLenConstraintPresent = CSSM_TRUE;
thisBc->pathLenConstraint = badCertDex - 2; failMode = "Short pathLenConstraint";
}
else if(die == 2) {
thisBc->cA = CSSM_FALSE;
failMode = "Explicit !cA in intermediate";
}
else {
numExtens[badCertDex] = 0;
failMode = "No BasicConstraints in intermediate";
}
}
}
if(!quiet && expectFail) {
printf(" ...bad cert at index %d: %s\n", badCertDex, failMode);
}
crtn = tpGenCertsExten(cspHand,
clHand,
sigAlg,
numCerts,
"caVerify", pubKeys,
privKeys,
extens,
numExtens,
certs,
notBeforeStr,
notAfterStr);
if(crtn) {
printError("tpGenCertsExten", crtn);
return crtn; }
CSSM_CERTGROUP cgrp;
memset(&cgrp, 0, sizeof(CSSM_CERTGROUP));
cgrp.NumCerts = numCerts;
#if PUMA_BUILD
cgrp.CertGroupType = CSSM_CERTGROUP_ENCODED_CERT;
#else
cgrp.CertGroupType = CSSM_CERTGROUP_DATA;
#endif
cgrp.CertType = CSSM_CERT_X_509v3;
cgrp.CertEncoding = CSSM_CERT_ENCODING_DER;
cgrp.GroupList.CertList = certs;
#if PUMA_BUILD
crtn = tpCertGroupVerify(tpHand,
clHand,
cspHand,
NULL, &CSSMOID_APPLE_X509_BASIC, &cgrp,
(CSSM_DATA_PTR)&certs[numCerts-1], 1,
CSSM_TP_STOP_ON_POLICY,
CSSM_FALSE, NULL); #else
crtn = tpCertGroupVerify(tpHand,
clHand,
cspHand,
NULL, &CSSMOID_APPLE_TP_SSL, NULL, NULL, NULL, &cgrp,
(CSSM_DATA_PTR)&certs[numCerts-1], 1,
CSSM_TP_STOP_ON_POLICY,
NULL, NULL); #endif
if(expectFail) {
if(crtn != CSSMERR_TP_VERIFY_ACTION_FAILED) {
cssmPerror("***Expected error TP_VERIFY_ACTION_FAILED; got ", crtn);
printf(" Expected failure due to %s\n", failMode);
if(dumpCerts) {
showCerts(certs, numCerts);
writeCerts(certs, numCerts);
}
return testError(quiet);
}
}
else if(crtn) {
cssmPerror("Unexpected failure on tpCertGroupVerify", crtn);
if(dumpCerts) {
showCerts(certs, numCerts);
}
return testError(quiet);
}
return 0;
}
int main(int argc, char **argv)
{
CSSM_CL_HANDLE clHand; CSSM_CSP_HANDLE cspHand; CSSM_TP_HANDLE tpHand;
CSSM_KEY_PTR pubKeys;
CSSM_KEY_PTR privKeys;
CSSM_RETURN crtn;
int arg;
unsigned certDex;
unsigned loopNum;
unsigned maxCerts;
CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT;
CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT;
uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT;
unsigned numCerts = 0; unsigned numLoops = NUM_LOOPS_DEF;
CSSM_BOOL quiet = CSSM_FALSE;
CSSM_BOOL dumpCerts = CSSM_FALSE;
for(arg=1; arg<argc; arg++) {
switch(argv[arg][0]) {
case 'a':
if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) {
usage(argv);
}
switch(argv[arg][2]) {
case 's':
keyAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_SHA1WithRSA;
break;
case '5':
keyAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_MD5WithRSA;
break;
case 'f':
keyAlg = CSSM_ALGID_FEE;
sigAlg = CSSM_ALGID_FEE_MD5;
break;
case 'F':
keyAlg = CSSM_ALGID_FEE;
sigAlg = CSSM_ALGID_FEE_SHA1;
break;
case 'e':
keyAlg = CSSM_ALGID_FEE;
sigAlg = CSSM_ALGID_SHA1WithECDSA;
break;
case 'E':
keyAlg = CSSM_ALGID_ECDSA;
sigAlg = CSSM_ALGID_SHA1WithECDSA;
break;
case '6':
keyAlg = CSSM_ALGID_ECDSA;
sigAlg = CSSM_ALGID_SHA256WithECDSA;
break;
default:
usage(argv);
}
break;
case 'k':
keySizeInBits = atoi(&argv[arg][2]);
break;
case 'l':
numLoops = atoi(&argv[arg][2]);
break;
case 'n':
numCerts = atoi(&argv[arg][2]);
break;
case 'c':
dumpCerts = CSSM_TRUE;
break;
case 'q':
quiet = CSSM_TRUE;
break;
default:
usage(argv);
}
}
clHand = clStartup();
if(clHand == 0) {
return 0;
}
tpHand = tpStartup();
if(tpHand == 0) {
return 0;
}
cspHand = cspStartup();
if(cspHand == 0) {
return 0;
}
if(numCerts == 0) {
maxCerts = NUM_CERTS_DEF; }
else {
maxCerts = numCerts; }
printf("Starting caVerify; args: ");
for(unsigned i=1; i<(unsigned)argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
if(!quiet) {
printf("generating key pairs...\n");
}
pubKeys = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY) * maxCerts);
privKeys = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY) * maxCerts);
for(certDex=0; certDex<maxCerts; certDex++) {
crtn = cspGenKeyPair(cspHand,
keyAlg,
"a key pair",
9,
keySizeInBits,
&pubKeys[certDex],
CSSM_FALSE, CSSM_KEYUSE_VERIFY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&privKeys[certDex],
CSSM_TRUE, CSSM_KEYUSE_SIGN,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE);
if(crtn) {
printError("cspGenKeyPair", crtn);
printf("***error generating key pair. Aborting.\n");
exit(1);
}
}
for(loopNum=0; loopNum<numLoops; loopNum++) {
unsigned thisNumCerts;
if(numCerts) {
thisNumCerts = numCerts;
}
else {
thisNumCerts = genRand(2, NUM_CERTS_DEF);
}
int coin = genRand(1,2);
CSSM_BOOL expectFail = (coin == 1) ? CSSM_TRUE : CSSM_FALSE;
if(!quiet) {
printf("...loop %d numCerts %u expectFail %s\n", loopNum,
thisNumCerts, expectFail ? "TRUE" : "FALSE");
}
if(doTest(cspHand,
clHand,
tpHand,
thisNumCerts,
pubKeys,
privKeys,
sigAlg,
expectFail,
dumpCerts,
quiet)) {
break;
}
}
return 0;
}