cgVerifyParsed.cpp [plain text]
#include <Security/cssm.h>
#include <utilLib/common.h>
#include <utilLib/cspwrap.h>
#include <clAppUtils/clutils.h>
#include <clAppUtils/tpUtils.h>
#include <clAppUtils/timeStr.h>
#include <utilLib/nssAppUtils.h>
#include <utilLib/fileIo.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <Security/oidsalg.h>
#include "tpVerifyParsed.h"
#define NUM_CERTS_DEF 10
#define KEYGEN_ALG_DEF CSSM_ALGID_RSA
#define SIG_ALG_DEF CSSM_ALGID_SHA1WithRSA
#define LOOPS_DEF 10
#define SECONDS_TO_LIVE (60 * 60 * 24)
#define CERT_IN_DB 1
#define DB_NAME "cgVerify.db"
#define DSA_PARAM_FILE "dsaParam512.der"
typedef enum {
ER_InvalidAnchor, ER_RootInCertGroup, ER_AnchorVerify, ER_NoRoot, ER_IncompleteKey } ExpectResult;
static void usage(char **argv)
{
printf("Usage: %s [options]\n", argv[0]);
printf(" Options:\n");
printf(" n=numCerts; default = %d\n", NUM_CERTS_DEF);
printf(" l=loops; default=%d; 0=forever\n", LOOPS_DEF);
printf(" a=alg (f=FEE/MD5, F=FEE/SHA1, e=FEE/ECDSA, s=RSA/SHA1, m=RSA/MD5,\n");
printf(" d=DSA; 6=RSA/SHA256, 3=RSA/SHA384, 5=RSA/SHA512; default = RSA/SHA1\n");
printf(" k=keySizeInBits\n");
printf(" d(isable DB)\n");
printf(" P(ause on each loop)\n");
printf(" N (no partial pub keys)\n");
printf(" v(erbose)\n");
printf(" q(uiet)\n");
printf(" h(elp)\n");
exit(1);
}
static int doTest(
CSSM_TP_HANDLE tpHand,
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
CSSM_DL_DB_HANDLE dlDb,
CSSM_DATA_PTR certs,
unsigned numCerts,
CSSM_KEY_PTR pubKeys, CSSM_BOOL useDb,
ExpectResult expectResult,
CSSM_BOOL verbose,
CSSM_BOOL quiet)
{
unsigned cgEnd; unsigned anchorStart; unsigned anchorEnd; CSSM_CERTGROUP certGroupFrag; CSSM_CERTGROUP anchorCerts; unsigned die; CSSM_DL_DB_LIST dbList;
CSSM_DL_DB_LIST_PTR dbListPtr;
CSSM_RETURN expErr; int rtn = 0;
char *expResStr;
uint32 expEvidenceSize; unsigned evidenceSize; CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult;
CSSM_CERTGROUP_PTR outGrp = NULL;
CSSM_RETURN crtn;
CSSM_DL_DB_HANDLE_PTR dlDbPtr;
unsigned numAnchors;
memset(&vfyResult, 0, sizeof(CSSM_TP_VERIFY_CONTEXT_RESULT));
if(useDb) {
dlDbPtr = &dlDb;
dbList.NumHandles = 1;
dbList.DLDBHandle = &dlDb;
dbListPtr = &dbList;
}
else {
dlDbPtr = NULL;
dbListPtr = NULL;
}
switch(expectResult) {
case ER_InvalidAnchor:
cgEnd = numCerts - 1; anchorStart = 0; anchorEnd = numCerts - 2;
expErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
expEvidenceSize = numCerts;
expResStr = "InvalidAnchor (root in certGroup but not in anchors)";
break;
case ER_RootInCertGroup:
cgEnd = numCerts - 1; anchorStart = 0; anchorEnd = numCerts - 1;
expErr = CSSM_OK;
expEvidenceSize = numCerts;
expResStr = "Good (root in certGroup AND in anchors)";
break;
case ER_AnchorVerify:
die = genRand(0, numCerts-2);
cgEnd = die; anchorStart = 0; anchorEnd = numCerts - 1;
if(pubKeys[die+1].KeyHeader.KeyAttr & CSSM_KEYATTR_PARTIAL) {
expErr = CSSMERR_TP_CERTIFICATE_CANT_OPERATE;
expResStr = "Root ONLY in anchors but has partial pub key";
}
else {
expErr = CSSM_OK;
expResStr = "Good (root ONLY in anchors)";
}
expEvidenceSize = die + 2;
break;
case ER_NoRoot:
die = genRand(0, numCerts-2);
cgEnd = die; anchorStart = die + 2; anchorEnd = numCerts - 2;
if((die != 0) && (pubKeys[die].KeyHeader.KeyAttr & CSSM_KEYATTR_PARTIAL)) {
expErr = CSSMERR_TP_CERTIFICATE_CANT_OPERATE;
expResStr = "Not Trusted (no root, no anchor verify), partial";
}
else {
expErr = CSSMERR_TP_NOT_TRUSTED;
expResStr = "Not Trusted (no root, no anchor verify)";
}
expEvidenceSize = die + 1;
break;
case ER_IncompleteKey:
cgEnd = numCerts - 2; anchorStart = 0; anchorEnd = numCerts - 1;
expErr = CSSMERR_TP_CERTIFICATE_CANT_OPERATE;
expEvidenceSize = numCerts;
expResStr = "Partial public key in anchor";
break;
}
if(verbose) {
printf(" ...expectResult = %s\n", expResStr);
}
if(verbose) {
printf(" ...building certGroupFrag from certs[0..%d]\n",
cgEnd);
}
if(tpMakeRandCertGroup(clHand,
dbListPtr,
certs, cgEnd+1, &certGroupFrag,
CSSM_TRUE, verbose,
CSSM_FALSE, CSSM_FALSE)) { printf("Error in tpMakeRandCertGroup\n");
return 1;
}
if(verbose) {
printf(" ...building anchorCerts from certs[%d..%d]\n",
anchorStart, anchorEnd);
}
if(anchorEnd > (numCerts - 1)) {
printf("anchorEnd overflow\n");
exit(1);
}
if(anchorStart >= anchorEnd) {
numAnchors = 0;
}
else {
numAnchors = anchorEnd - anchorStart + 1;
}
if(tpMakeRandCertGroup(clHand,
NULL,
certs + anchorStart,
numAnchors, &anchorCerts,
CSSM_FALSE, verbose,
CSSM_FALSE, CSSM_FALSE)) { printf("Error in tpMakeRandCertGroup\n");
return 1;
}
crtn = tpCertGroupVerifyParsed(
tpHand,
clHand,
cspHand,
dbListPtr,
&CSSMOID_APPLE_X509_BASIC, NULL, NULL, NULL, &certGroupFrag,
anchorCerts.GroupList.CertList, anchorCerts.NumCerts,
CSSM_TP_STOP_ON_POLICY,
NULL, &vfyResult);
if( (vfyResult.NumberOfEvidences != 3) ||
(vfyResult.Evidence == NULL) ||
(vfyResult.Evidence[0].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_HEADER) ||
(vfyResult.Evidence[1].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERTGROUP) ||
(vfyResult.Evidence[2].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) ||
(vfyResult.Evidence[0].Evidence == NULL) ||
(vfyResult.Evidence[1].Evidence == NULL) ||
(vfyResult.Evidence[2].Evidence == NULL)) {
printf("***Malformed VerifyContextResult\n");
rtn = testError(quiet);
if(rtn) {
return rtn;
}
}
if((vfyResult.Evidence != NULL) && (vfyResult.Evidence[1].Evidence != NULL)) {
outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence;
evidenceSize = outGrp->NumCerts;
}
else {
evidenceSize = 0;
}
if((crtn != expErr) ||
(evidenceSize != expEvidenceSize)) {
printf("***Error on expectResult %s\n", expResStr);
printf(" err %s expErr %s\n",
cssmErrToStr(crtn), cssmErrToStr(expErr));
printf(" evidenceSize %d expEvidenceSize %lu\n",
evidenceSize, expEvidenceSize);
rtn = testError(quiet);
}
else {
rtn = 0;
}
tpFreeCertGroup(&certGroupFrag,
CSSM_FALSE, CSSM_FALSE); tpFreeCertGroup(&anchorCerts,
CSSM_FALSE, CSSM_FALSE); freeVfyResult(&vfyResult);
if(useDb) {
clDeleteAllCerts(dlDb);
}
return rtn;
}
int main(int argc, char **argv)
{
int arg;
char *argp;
unsigned loop;
CSSM_TP_HANDLE tpHand = 0;
CSSM_CL_HANDLE clHand = 0;
CSSM_CSP_HANDLE cspHand = 0;
CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
ExpectResult expectResult;
char *notAfterStr;
char *notBeforeStr;
unsigned i;
CSSM_DATA paramData;
CSSM_DATA_PTR paramDataP = NULL;
unsigned numTests = 4;
CSSM_KEY_PTR pubKeys = NULL;
CSSM_KEY_PTR privKeys = NULL;
CSSM_DATA_PTR certs = NULL;
CSSM_DL_DB_HANDLE keyDb = {0, 0};
CSSM_KEY savedRoot;
unsigned loops = LOOPS_DEF;
CSSM_BOOL verbose = CSSM_FALSE;
CSSM_BOOL quiet = CSSM_FALSE;
unsigned numCerts = NUM_CERTS_DEF;
uint32 keyGenAlg = KEYGEN_ALG_DEF;
uint32 sigAlg = SIG_ALG_DEF;
#if CERT_IN_DB
CSSM_BOOL useDb = CSSM_TRUE;
#else
CSSM_BOOL useDb = CSSM_FALSE;
#endif
CSSM_BOOL doPause = CSSM_FALSE;
uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT;
CSSM_BOOL noPartialKeys = CSSM_FALSE;
char dbName[100];
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'l':
loops = atoi(&argp[2]);
break;
case 'k':
keySizeInBits = atoi(&argp[2]);
break;
case 'n':
numCerts = atoi(&argp[2]);
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'q':
quiet = CSSM_TRUE;
break;
case 'a':
switch(argp[2]) {
case 'f':
keyGenAlg = CSSM_ALGID_FEE;
sigAlg = CSSM_ALGID_FEE_MD5;
break;
case 'F':
keyGenAlg = CSSM_ALGID_FEE;
sigAlg = CSSM_ALGID_FEE_SHA1;
break;
case 'e':
keyGenAlg = CSSM_ALGID_FEE;
sigAlg = CSSM_ALGID_SHA1WithECDSA;
break;
case 's':
keyGenAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_SHA1WithRSA;
break;
case 'm':
keyGenAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_MD5WithRSA;
break;
case 'd':
keyGenAlg = CSSM_ALGID_DSA;
sigAlg = CSSM_ALGID_SHA1WithDSA;
break;
case '6':
keyGenAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_SHA256WithRSA;
break;
case '3':
keyGenAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_SHA512WithRSA;
break;
case '5':
keyGenAlg = CSSM_ALGID_RSA;
sigAlg = CSSM_ALGID_SHA512WithRSA;
break;
default:
usage(argv);
}
break;
case 'N':
noPartialKeys = CSSM_TRUE;
break;
case 'd':
useDb = CSSM_FALSE;
break;
case 'P':
doPause = CSSM_TRUE;
break;
case 'h':
default:
usage(argv);
}
}
sprintf(dbName, "%s_%d", DB_NAME, (int)getpid());
if(numCerts < 2) {
printf("Can't run with cert chain smaller than 2\n");
exit(1);
}
cspHand = cspStartup();
if(cspHand == 0) {
exit(1);
}
#if CERT_IN_DB
if(useDb) {
dlDbHand.DLHandle = dlStartup();
if(dlDbHand.DLHandle == 0) {
exit(1);
}
CSSM_RETURN crtn = tpKcOpen(dlDbHand.DLHandle, dbName, dbName,
CSSM_TRUE, &dlDbHand.DBHandle);
if(crtn) {
printf("Error opening keychain %s; aborting.\n", dbName);
exit(1);
}
}
#endif
clHand = clStartup();
if(clHand == 0) {
goto abort;
}
tpHand = tpStartup();
if(tpHand == 0) {
goto abort;
}
pubKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_KEY));
privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_KEY));
certs = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA));
if((pubKeys == NULL) || (privKeys == NULL) || (certs == NULL)) {
printf("not enough memory for %u keys pairs and certs.\n",
numCerts);
goto abort;
}
printf("Starting cgVerify; args: ");
for(i=1; i<(unsigned)argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
if(!quiet) {
printf("generating keys...\n");
}
if(keyGenAlg == CSSM_ALGID_DSA) {
unsigned len;
if(!readFile(DSA_PARAM_FILE, (unsigned char **)¶mData.Data, &len)) {
if(!quiet) {
printf("...using DSA params from %s\n", DSA_PARAM_FILE);
}
paramData.Length = len;
paramDataP = ¶mData;
}
else {
printf("***warning: no param file. KeyGen is going to be slow!\n");
printf("***You might consider running this from the clxutils/cgVerify "
"directory.\n");
}
}
if(tpGenKeys(cspHand,
keyDb,
numCerts,
keyGenAlg,
keySizeInBits,
"cgVerify", pubKeys,
privKeys,
paramDataP)) {
goto abort;
}
notBeforeStr = genTimeAtNowPlus(0);
notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE);
if((keyGenAlg == CSSM_ALGID_DSA) && !noPartialKeys) {
for(unsigned dex=0; dex<(numCerts-1); dex++) {
int die = genRand(0,1);
if(die) {
CSSM_KEY newKey;
if(verbose) {
printf("...making partial DSA pub key at index %u\n", dex);
}
CSSM_RETURN crtn = extractDsaPartial(cspHand, &pubKeys[dex], &newKey);
if(crtn) {
printf("***Error converting to partial key. Aborting.\n");
exit(1);
}
CSSM_FREE(pubKeys[dex].KeyData.Data);
pubKeys[dex] = newKey;
}
}
}
if(!quiet) {
printf("starting %s test\n", argv[0]);
}
if(keyGenAlg == CSSM_ALGID_DSA) {
numTests = 5;
}
for(loop=1; ; loop++) {
if(!quiet) {
printf("...loop %d\n", loop);
}
switch(loop % numTests) {
case 0:
expectResult = ER_InvalidAnchor;
break;
case 1:
expectResult = ER_RootInCertGroup;
break;
case 2:
expectResult = ER_AnchorVerify;
break;
case 3:
expectResult = ER_NoRoot;
break;
case 4:
expectResult = ER_IncompleteKey;
savedRoot = pubKeys[numCerts-1];
if(extractDsaPartial(cspHand, &savedRoot, &pubKeys[numCerts-1])) {
printf("...error partializing anchor key; aborting\n");
exit(1);
}
break;
}
if(tpGenCerts(cspHand,
clHand,
numCerts,
sigAlg,
"cgConstruct", pubKeys,
privKeys,
certs,
notBeforeStr,
notAfterStr)) {
break;
}
if(doTest(tpHand,
clHand,
cspHand,
dlDbHand,
certs,
numCerts,
pubKeys,
useDb,
expectResult,
verbose,
quiet)) {
break;
}
for(i=0; i<numCerts; i++) {
appFreeCssmData(&certs[i], CSSM_FALSE);
}
if(expectResult == ER_IncompleteKey) {
CSSM_FREE(pubKeys[numCerts-1].KeyData.Data);
pubKeys[numCerts-1] = savedRoot;
}
memset(certs, 0, numCerts * sizeof(CSSM_DATA));
if(loops && (loop == loops)) {
break;
}
if(doPause) {
printf("Hit CR to continue: ");
fpurge(stdin);
getchar();
}
}
abort:
if(privKeys != NULL) {
for(i=0; i<numCerts; i++) {
if(privKeys[i].KeyData.Data != NULL) {
cspFreeKey(cspHand, &privKeys[i]);
}
}
CSSM_FREE(privKeys);
}
if(pubKeys != NULL) {
for(i=0; i<numCerts; i++) {
if(pubKeys[i].KeyData.Data != NULL) {
cspFreeKey(cspHand, &pubKeys[i]);
}
}
CSSM_FREE(pubKeys);
}
if(certs != NULL) {
for(i=0; i<numCerts; i++) {
appFreeCssmData(&certs[i], CSSM_FALSE);
}
CSSM_FREE(certs);
}
if(cspHand != 0) {
CSSM_ModuleDetach(cspHand);
}
if(clHand != 0) {
CSSM_ModuleDetach(clHand);
}
if(tpHand != 0) {
CSSM_ModuleDetach(tpHand);
}
if(!quiet) {
printf("%s test complete\n", argv[0]);
}
return 0;
}