X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/threadTest/cgVerifyThr.cpp diff --git a/SecurityTests/clxutils/threadTest/cgVerifyThr.cpp b/SecurityTests/clxutils/threadTest/cgVerifyThr.cpp new file mode 100644 index 00000000..ffd333ed --- /dev/null +++ b/SecurityTests/clxutils/threadTest/cgVerifyThr.cpp @@ -0,0 +1,453 @@ +/* cgVerifyThr.cpp - simple version CertGroupVerify test */ + +#include "testParams.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 , + * 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; iperThread + */ +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; loopNumnumLoops; 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; dexpubKeys); + CSSM_FREE(keyPairs->privKeys); + CSSM_FREE(keyPairs); + return status; +} +