#include "testParams.h"
#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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <Security/oidsalg.h>
#define DO_PAUSE 0
#define NUM_CERTS_MIN 4
#define KEYGEN_ALG_DEF CSSM_ALGID_RSA
#define SIG_ALG_DEF CSSM_ALGID_SHA1WithRSA
#define LOOPS_DEF 10
#define CG_KEY_SIZE_DEFAULT CSP_RSA_KEY_SIZE_DEFAULT
#define SECONDS_TO_LIVE (60 * 60 * 24)
#define CERT_IN_DB 0
typedef enum {
ER_InvalidAnchor, ER_RootInCertGroup, ER_AnchorVerify, ER_NoRoot } ExpectResult;
static int testError()
{
char resp;
printf("Attach via debugger for more info.\n");
printf("a to abort, c to continue: ");
resp = getchar();
return (resp == 'a');
}
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_BOOL useDb,
ExpectResult expectResult,
CSSM_BOOL verbose)
{
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_DL_DB_HANDLE_PTR dlDbPtr;
CSSM_RETURN expErr; int rtn = 0;
const char *expResStr;
uint32 expEvidenceSize; unsigned evidenceSize; CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult;
CSSM_CERTGROUP_PTR outGrp = NULL;
CSSM_RETURN crtn;
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(1, numCerts-3);
cgEnd = die; anchorStart = 0; anchorEnd = numCerts - 1;
expErr = CSSM_OK;
expEvidenceSize = die + 2;
expResStr = "Good (root ONLY in anchors)";
break;
case ER_NoRoot:
die = genRand(1, numCerts-2);
cgEnd = die;
anchorStart = die + 2; anchorEnd = numCerts - 1;
expErr = CSSMERR_TP_NOT_TRUSTED;
expEvidenceSize = die + 1;
expResStr = "Not Trusted (no root, no anchor verify)";
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("\nError in tpMakeRandCertGroup\n");
return 1;
}
if(anchorStart > anchorEnd) {
if((expectResult != ER_NoRoot) || (anchorStart != numCerts)) {
printf("Try again, pal.\n");
exit(1);
}
}
if(verbose) {
printf(" ...building anchorCerts from certs[%d..%d]\n",
anchorStart, anchorEnd);
}
if(anchorEnd > (numCerts - 1)) {
printf("anchorEnd overflow\n");
exit(1);
}
if(tpMakeRandCertGroup(clHand,
NULL,
certs + anchorStart,
anchorEnd - anchorStart + 1, &anchorCerts,
CSSM_FALSE, verbose,
CSSM_FALSE, CSSM_FALSE)) { printf("\nError in tpMakeRandCertGroup\n");
return 1;
}
crtn = tpCertGroupVerify(
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");
return 1;
}
if((vfyResult.Evidence != NULL) && (vfyResult.Evidence[1].Evidence != NULL)) {
outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence;
evidenceSize = outGrp->NumCerts;
}
else {
evidenceSize = 0;
}
if ((evidenceSize > 1) && (evidenceSize < expEvidenceSize) &&
(crtn == CSSM_OK || crtn == CSSMERR_TP_CERTIFICATE_CANT_OPERATE)) {
expErr = crtn;
expEvidenceSize = evidenceSize;
}
if((crtn != expErr) ||
(evidenceSize != expEvidenceSize)) {
printf("\n***cgVerify: Error on tpCertGroupVerify expectResult %s\n",
expResStr);
printf(" err %s expErr %s\n",
cssmErrToStr(crtn), cssmErrToStr(expErr));
printf(" evidenceSize %d expEvidenceSize %u\n",
evidenceSize, (unsigned)expEvidenceSize);
printf(" numCerts %d cgEnd %d anchorStart %d anchorEnd %d\n",
numCerts, cgEnd, anchorStart, anchorEnd);
rtn = testError();
}
else {
rtn = 0;
}
tpFreeCertGroup(&certGroupFrag,
CSSM_FALSE, CSSM_FALSE); tpFreeCertGroup(&anchorCerts,
CSSM_FALSE, CSSM_FALSE); freeVfyResult(&vfyResult);
if(useDb) {
clDeleteAllCerts(dlDb);
}
return rtn;
}
int comparePubKeys(
unsigned numKeys,
const CSSM_KEY *pubKeys)
{
unsigned i,j;
for(i=0; i<numKeys-1; i++) {
for(j=i+1; j<numKeys; j++) {
if(appCompareCssmData(&pubKeys[i].KeyData, &pubKeys[j].KeyData)) {
printf("***HEY! DUPLICATE PUBLIC KEYS in cgVerify!\n");
return testError();
}
}
}
return 0;
}
typedef struct {
CSSM_KEY_PTR pubKeys;
CSSM_KEY_PTR privKeys;
unsigned numKeys;
char *notBeforeStr; char *notAfterStr; } TT_KeyPairs;
int cgVerifyInit(TestParams *testParams)
{
unsigned numKeys = NUM_CERTS_MIN + testParams->threadNum;
TT_KeyPairs *keyPairs;
if(testParams->verbose) {
printf("cgVerify thread %d: generating keys...\n",
testParams->threadNum);
}
keyPairs = (TT_KeyPairs *)CSSM_MALLOC(sizeof(TT_KeyPairs));
keyPairs->numKeys = numKeys;
keyPairs->pubKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY));
keyPairs->privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY));
CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
if(tpGenKeys(testParams->cspHand,
dlDbHand,
numKeys,
KEYGEN_ALG_DEF,
CG_KEY_SIZE_DEFAULT,
"cgVerify", keyPairs->pubKeys,
keyPairs->privKeys)) {
goto abort;
}
if(comparePubKeys(numKeys, keyPairs->pubKeys)) {
return 1;
}
keyPairs->notBeforeStr = genTimeAtNowPlus(0);
keyPairs->notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE);
testParams->perThread = keyPairs;
return 0;
abort:
printf("Error generating keys; aborting\n");
CSSM_FREE(keyPairs->pubKeys);
CSSM_FREE(keyPairs->privKeys);
CSSM_FREE(keyPairs);
return 1;
}
int cgVerify(TestParams *testParams)
{
unsigned loopNum;
int status = -1; unsigned dex;
TT_KeyPairs *keyPairs = (TT_KeyPairs *)testParams->perThread;
CSSM_KEY_PTR pubKeys = keyPairs->pubKeys;
CSSM_KEY_PTR privKeys = keyPairs->privKeys;
CSSM_DATA_PTR certs = NULL;
unsigned numCerts = keyPairs->numKeys;
uint32 sigAlg = SIG_ALG_DEF;
ExpectResult expectResult;
#if CERT_IN_DB
CSSM_BOOL useDb = CSSM_TRUE;
#else
CSSM_BOOL useDb = CSSM_FALSE;
#endif
CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
certs = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA));
if(certs == NULL) {
printf("not enough memory for %u certs.\n", numCerts);
goto abort;
}
memset(certs, 0, numCerts * sizeof(CSSM_DATA));
for(loopNum=0; loopNum<testParams->numLoops; loopNum++) {
if(testParams->verbose) {
printf("generating certs...\n");
}
else if(!testParams->quiet) {
printChar(testParams->progressChar);
}
if(tpGenCerts(testParams->cspHand,
testParams->clHand,
numCerts,
sigAlg,
"cgConstruct", pubKeys,
privKeys,
certs,
keyPairs->notBeforeStr,
keyPairs->notAfterStr)) {
goto abort;
}
switch(loopNum % 4) {
case 0:
expectResult = ER_InvalidAnchor;
break;
case 1:
expectResult = ER_RootInCertGroup;
break;
case 2:
expectResult = ER_AnchorVerify;
break;
case 3:
expectResult = ER_NoRoot;
break;
}
status = doTest(testParams->tpHand,
testParams->clHand,
testParams->cspHand,
dlDbHand,
certs,
numCerts,
useDb,
expectResult,
testParams->verbose);
if(status) {
break;
}
for(dex=0; dex<numCerts; dex++) {
CSSM_FREE(certs[dex].Data);
}
memset(certs, 0, numCerts * sizeof(CSSM_DATA));
#if DO_PAUSE
fpurge(stdin);
printf("Hit CR to proceed: ");
getchar();
#endif
}
abort:
for(dex=0; dex<numCerts; dex++) {
if(certs[dex].Data) {
CSSM_FREE(certs[dex].Data);
}
}
CSSM_FREE(keyPairs->pubKeys);
CSSM_FREE(keyPairs->privKeys);
CSSM_FREE(keyPairs);
return status;
}