-/* cgVerifyThr.cpp - simple version CertGroupVerify test */
-
-#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>
-
-/* for memory leak debug only, with only one thread running */
-#define DO_PAUSE 0
-
-/*** start of code directly copied from ../cgVerify/cgVerify.cpp ***/
-#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) /* certs are valid for this long */
-
-#define CERT_IN_DB 0
-
-/*
- * How we define the "expected result".
- */
-typedef enum {
- ER_InvalidAnchor, // root in certGroup, not found in AnchorCerts
- ER_RootInCertGroup, // root in certGroup, copy in AnchorCerts
- ER_AnchorVerify, // end of chain verified by an anchor
- ER_NoRoot // no root, no anchor verify
-} 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; // last cert in certGroupFrag
- unsigned anchorStart; // first cert in anchorGroup
- unsigned anchorEnd; // last cert in anchorGroup
- CSSM_CERTGROUP certGroupFrag; // INPUT to CertGroupVerify
- CSSM_CERTGROUP anchorCerts; // ditto
- unsigned die; // random number
- CSSM_DL_DB_LIST dbList;
- CSSM_DL_DB_LIST_PTR dbListPtr;
- CSSM_DL_DB_HANDLE_PTR dlDbPtr;
- CSSM_RETURN expErr; // expected rtn from GroupVfy()
- int rtn = 0;
- const char *expResStr;
- uint32 expEvidenceSize; // expected evidenceSize
- unsigned evidenceSize; // actual evidence size
- 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 {
- /* not yet */
- dlDbPtr = NULL;
- dbListPtr = NULL;
- }
-
- /* the four test cases */
- switch(expectResult) {
- case ER_InvalidAnchor:
- /* root in certGroup, not found in AnchorCerts */
- cgEnd = numCerts - 1; // certGroupFrag is the whole pile
- anchorStart = 0; // anchors = all except root
- anchorEnd = numCerts - 2;
- expErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
- expEvidenceSize = numCerts;
- expResStr = "InvalidAnchor (root in certGroup but not in anchors)";
- break;
-
- case ER_RootInCertGroup:
- /* root in certGroup, copy in AnchorCerts */
- cgEnd = numCerts - 1; // certGroupFrag = the whole pile
- anchorStart = 0; // anchors = the whole pile
- anchorEnd = numCerts - 1;
- expErr = CSSM_OK;
- expEvidenceSize = numCerts;
- expResStr = "Good (root in certGroup AND in anchors)";
- break;
-
- case ER_AnchorVerify:
- /* non-root end of chain verified by an anchor */
- /* break chain at random place other than start and end-2 */
- die = genRand(1, numCerts-3);
- cgEnd = die; // certGroupFrag up to break point
- anchorStart = 0; // anchors = all
- anchorEnd = numCerts - 1;
- expErr = CSSM_OK;
- /* size = # certs in certGroupFrag, plus one anchor */
- expEvidenceSize = die + 2;
- expResStr = "Good (root ONLY in anchors)";
- break;
-
- case ER_NoRoot:
- /* no root, no anchor verify */
- /* break chain at random place other than start and end-1 */
- die = genRand(1, numCerts-2);
- cgEnd = die; // certGroupFrag up to break point
- /* and skip one cert */
- anchorStart = die + 2; // anchors = n+1...numCerts-2
- // may be empty if n == numCerts-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);
- }
-
- /* cook up two cert groups */
- if(verbose) {
- printf(" ...building certGroupFrag from certs[0..%d]\n",
- cgEnd);
- }
- if(tpMakeRandCertGroup(clHand,
- dbListPtr,
- certs, // certGroupFrag always starts at 0
- cgEnd+1, // # of certs
- &certGroupFrag,
- CSSM_TRUE, // firstCertIsSubject
- verbose,
- CSSM_FALSE, // allInDbs
- CSSM_FALSE)) { // skipFirstDb
- printf("\nError in tpMakeRandCertGroup\n");
- return 1;
- }
-
- if(anchorStart > anchorEnd) {
- /* legal for ER_NoRoot */
- 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);
- }
- /* anchors do not go in DB */
- if(tpMakeRandCertGroup(clHand,
- NULL,
- certs + anchorStart,
- anchorEnd - anchorStart + 1, // # of certs
- &anchorCerts,
- CSSM_FALSE, // firstCertIsSubject
- verbose,
- CSSM_FALSE, // allInDbs
- CSSM_FALSE)) { // skipFirstDb
- printf("\nError in tpMakeRandCertGroup\n");
- return 1;
- }
-
- crtn = tpCertGroupVerify(
- tpHand,
- clHand,
- cspHand,
- dbListPtr,
- &CSSMOID_APPLE_X509_BASIC, // Policy
- NULL, // fieldOpts
- NULL, // actionData
- NULL, // policyOpts
- &certGroupFrag,
- anchorCerts.GroupList.CertList, // passed as CSSM_DATA_PTR, not CERTGROUP....
- anchorCerts.NumCerts,
- CSSM_TP_STOP_ON_POLICY,
- NULL, // cssmTimeStr
- &vfyResult);
-
- /* first verify format of result */
- 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 {
- /* in case no evidence returned */
- evidenceSize = 0;
- }
-
- /* %%% since non-root anchors are permitted as of <rdar://5685316>,
- * the test assumptions have become invalid: these tests generate
- * an anchors list which always includes the full chain, so by
- * definition, the evidence chain will never be longer than 2,
- * since the leaf's issuer is always an anchor.
- * %%% need to revisit and rewrite these tests. -kcm
- */
- if ((evidenceSize > 1) && (evidenceSize < expEvidenceSize) &&
- (crtn == CSSM_OK || crtn == CSSMERR_TP_CERTIFICATE_CANT_OPERATE)) {
- /* ignore, for now */
- 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;
- }
-
- /* free resources */
- tpFreeCertGroup(&certGroupFrag,
- CSSM_FALSE, // caller malloc'd the actual certs
- CSSM_FALSE); // struct is on stack
- tpFreeCertGroup(&anchorCerts,
- CSSM_FALSE, // caller malloc'd the actual certs
- CSSM_FALSE); // struct is on stack
- freeVfyResult(&vfyResult);
- if(useDb) {
- clDeleteAllCerts(dlDb);
- }
- return rtn;
-}
-
-/*** end of code directly copied from ../cgVerify/cgVerify.cpp ***/
-
-/*
- * For debug only - ensure that the given array of public keys are all unique
- * Only saw this when using FEE RNG (i.e., no SecurityServer running).
- */
-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;
-}
-
-
-/*
- * key pairs - created in cgConstructInit, stored in testParams->perThread
- */
-typedef struct {
- CSSM_KEY_PTR pubKeys;
- CSSM_KEY_PTR privKeys;
- unsigned numKeys;
- char *notBeforeStr; // to use thread-safe tpGenCerts()
- char *notAfterStr; // to use thread-safe tpGenCerts()
-} 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", // keyLabelBase
- 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; // exit status
- unsigned dex;
-
- TT_KeyPairs *keyPairs = (TT_KeyPairs *)testParams->perThread;
-
- /* all three of these are arrays with numCert elements */
- 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};
-
- /* malloc empty certs */
- 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++) {
- /* generate certs */
- if(testParams->verbose) {
- printf("generating certs...\n");
- }
- else if(!testParams->quiet) {
- printChar(testParams->progressChar);
- }
- if(tpGenCerts(testParams->cspHand,
- testParams->clHand,
- numCerts,
- sigAlg,
- "cgConstruct", // nameBase
- pubKeys,
- privKeys,
- certs,
- keyPairs->notBeforeStr,
- keyPairs->notAfterStr)) {
- goto abort;
- }
-
- /* cycle thru test scenarios */
- 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;
- }
- /* free certs */
- 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:
- /* free resources */
- 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;
-}
-