1/* cgVerifyThr.cpp - simple version CertGroupVerify test */ 2 3#include "testParams.h" 4#include <Security/cssm.h> 5#include <utilLib/common.h> 6#include <utilLib/cspwrap.h> 7#include <clAppUtils/clutils.h> 8#include <clAppUtils/tpUtils.h> 9#include <clAppUtils/timeStr.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <time.h> 13#include <string.h> 14#include <Security/oidsalg.h> 15 16/* for memory leak debug only, with only one thread running */ 17#define DO_PAUSE 0 18 19/*** start of code directly copied from ../cgVerify/cgVerify.cpp ***/ 20#define NUM_CERTS_MIN 4 21#define KEYGEN_ALG_DEF CSSM_ALGID_RSA 22#define SIG_ALG_DEF CSSM_ALGID_SHA1WithRSA 23#define LOOPS_DEF 10 24#define CG_KEY_SIZE_DEFAULT CSP_RSA_KEY_SIZE_DEFAULT 25#define SECONDS_TO_LIVE (60 * 60 * 24) /* certs are valid for this long */ 26 27#define CERT_IN_DB 0 28 29/* 30 * How we define the "expected result". 31 */ 32typedef enum { 33 ER_InvalidAnchor, // root in certGroup, not found in AnchorCerts 34 ER_RootInCertGroup, // root in certGroup, copy in AnchorCerts 35 ER_AnchorVerify, // end of chain verified by an anchor 36 ER_NoRoot // no root, no anchor verify 37} ExpectResult; 38 39static int testError() 40{ 41 char resp; 42 43 printf("Attach via debugger for more info.\n"); 44 printf("a to abort, c to continue: "); 45 resp = getchar(); 46 return (resp == 'a'); 47} 48 49static int doTest( 50 CSSM_TP_HANDLE tpHand, 51 CSSM_CL_HANDLE clHand, 52 CSSM_CSP_HANDLE cspHand, 53 CSSM_DL_DB_HANDLE dlDb, 54 CSSM_DATA_PTR certs, 55 unsigned numCerts, 56 CSSM_BOOL useDb, 57 ExpectResult expectResult, 58 CSSM_BOOL verbose) 59{ 60 unsigned cgEnd; // last cert in certGroupFrag 61 unsigned anchorStart; // first cert in anchorGroup 62 unsigned anchorEnd; // last cert in anchorGroup 63 CSSM_CERTGROUP certGroupFrag; // INPUT to CertGroupVerify 64 CSSM_CERTGROUP anchorCerts; // ditto 65 unsigned die; // random number 66 CSSM_DL_DB_LIST dbList; 67 CSSM_DL_DB_LIST_PTR dbListPtr; 68 CSSM_DL_DB_HANDLE_PTR dlDbPtr; 69 CSSM_RETURN expErr; // expected rtn from GroupVfy() 70 int rtn = 0; 71 const char *expResStr; 72 uint32 expEvidenceSize; // expected evidenceSize 73 unsigned evidenceSize; // actual evidence size 74 CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult; 75 CSSM_CERTGROUP_PTR outGrp = NULL; 76 CSSM_RETURN crtn; 77 78 memset(&vfyResult, 0, sizeof(CSSM_TP_VERIFY_CONTEXT_RESULT)); 79 80 if(useDb) { 81 dlDbPtr = &dlDb; 82 dbList.NumHandles = 1; 83 dbList.DLDBHandle = &dlDb; 84 dbListPtr = &dbList; 85 } 86 else { 87 /* not yet */ 88 dlDbPtr = NULL; 89 dbListPtr = NULL; 90 } 91 92 /* the four test cases */ 93 switch(expectResult) { 94 case ER_InvalidAnchor: 95 /* root in certGroup, not found in AnchorCerts */ 96 cgEnd = numCerts - 1; // certGroupFrag is the whole pile 97 anchorStart = 0; // anchors = all except root 98 anchorEnd = numCerts - 2; 99 expErr = CSSMERR_TP_INVALID_ANCHOR_CERT; 100 expEvidenceSize = numCerts; 101 expResStr = "InvalidAnchor (root in certGroup but not in anchors)"; 102 break; 103 104 case ER_RootInCertGroup: 105 /* root in certGroup, copy in AnchorCerts */ 106 cgEnd = numCerts - 1; // certGroupFrag = the whole pile 107 anchorStart = 0; // anchors = the whole pile 108 anchorEnd = numCerts - 1; 109 expErr = CSSM_OK; 110 expEvidenceSize = numCerts; 111 expResStr = "Good (root in certGroup AND in anchors)"; 112 break; 113 114 case ER_AnchorVerify: 115 /* non-root end of chain verified by an anchor */ 116 /* break chain at random place other than start and end-2 */ 117 die = genRand(1, numCerts-3); 118 cgEnd = die; // certGroupFrag up to break point 119 anchorStart = 0; // anchors = all 120 anchorEnd = numCerts - 1; 121 expErr = CSSM_OK; 122 /* size = # certs in certGroupFrag, plus one anchor */ 123 expEvidenceSize = die + 2; 124 expResStr = "Good (root ONLY in anchors)"; 125 break; 126 127 case ER_NoRoot: 128 /* no root, no anchor verify */ 129 /* break chain at random place other than start and end-1 */ 130 die = genRand(1, numCerts-2); 131 cgEnd = die; // certGroupFrag up to break point 132 /* and skip one cert */ 133 anchorStart = die + 2; // anchors = n+1...numCerts-2 134 // may be empty if n == numCerts-2 135 anchorEnd = numCerts - 1; 136 expErr = CSSMERR_TP_NOT_TRUSTED; 137 expEvidenceSize = die + 1; 138 expResStr = "Not Trusted (no root, no anchor verify)"; 139 break; 140 } 141 142 if(verbose) { 143 printf(" ...expectResult = %s\n", expResStr); 144 } 145 146 /* cook up two cert groups */ 147 if(verbose) { 148 printf(" ...building certGroupFrag from certs[0..%d]\n", 149 cgEnd); 150 } 151 if(tpMakeRandCertGroup(clHand, 152 dbListPtr, 153 certs, // certGroupFrag always starts at 0 154 cgEnd+1, // # of certs 155 &certGroupFrag, 156 CSSM_TRUE, // firstCertIsSubject 157 verbose, 158 CSSM_FALSE, // allInDbs 159 CSSM_FALSE)) { // skipFirstDb 160 printf("\nError in tpMakeRandCertGroup\n"); 161 return 1; 162 } 163 164 if(anchorStart > anchorEnd) { 165 /* legal for ER_NoRoot */ 166 if((expectResult != ER_NoRoot) || (anchorStart != numCerts)) { 167 printf("Try again, pal.\n"); 168 exit(1); 169 } 170 } 171 if(verbose) { 172 printf(" ...building anchorCerts from certs[%d..%d]\n", 173 anchorStart, anchorEnd); 174 } 175 if(anchorEnd > (numCerts - 1)) { 176 printf("anchorEnd overflow\n"); 177 exit(1); 178 } 179 /* anchors do not go in DB */ 180 if(tpMakeRandCertGroup(clHand, 181 NULL, 182 certs + anchorStart, 183 anchorEnd - anchorStart + 1, // # of certs 184 &anchorCerts, 185 CSSM_FALSE, // firstCertIsSubject 186 verbose, 187 CSSM_FALSE, // allInDbs 188 CSSM_FALSE)) { // skipFirstDb 189 printf("\nError in tpMakeRandCertGroup\n"); 190 return 1; 191 } 192 193 crtn = tpCertGroupVerify( 194 tpHand, 195 clHand, 196 cspHand, 197 dbListPtr, 198 &CSSMOID_APPLE_X509_BASIC, // Policy 199 NULL, // fieldOpts 200 NULL, // actionData 201 NULL, // policyOpts 202 &certGroupFrag, 203 anchorCerts.GroupList.CertList, // passed as CSSM_DATA_PTR, not CERTGROUP.... 204 anchorCerts.NumCerts, 205 CSSM_TP_STOP_ON_POLICY, 206 NULL, // cssmTimeStr 207 &vfyResult); 208 209 /* first verify format of result */ 210 if( (vfyResult.NumberOfEvidences != 3) || 211 (vfyResult.Evidence == NULL) || 212 (vfyResult.Evidence[0].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_HEADER) || 213 (vfyResult.Evidence[1].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERTGROUP) || 214 (vfyResult.Evidence[2].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) || 215 (vfyResult.Evidence[0].Evidence == NULL) || 216 (vfyResult.Evidence[1].Evidence == NULL) || 217 (vfyResult.Evidence[2].Evidence == NULL)) { 218 printf("***Malformed VerifyContextResult\n"); 219 return 1; 220 } 221 if((vfyResult.Evidence != NULL) && (vfyResult.Evidence[1].Evidence != NULL)) { 222 outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence; 223 evidenceSize = outGrp->NumCerts; 224 } 225 else { 226 /* in case no evidence returned */ 227 evidenceSize = 0; 228 } 229 230 /* %%% since non-root anchors are permitted as of <rdar://5685316>, 231 * the test assumptions have become invalid: these tests generate 232 * an anchors list which always includes the full chain, so by 233 * definition, the evidence chain will never be longer than 2, 234 * since the leaf's issuer is always an anchor. 235 * %%% need to revisit and rewrite these tests. -kcm 236 */ 237 if ((evidenceSize > 1) && (evidenceSize < expEvidenceSize) && 238 (crtn == CSSM_OK || crtn == CSSMERR_TP_CERTIFICATE_CANT_OPERATE)) { 239 /* ignore, for now */ 240 expErr = crtn; 241 expEvidenceSize = evidenceSize; 242 } 243 244 if((crtn != expErr) || 245 (evidenceSize != expEvidenceSize)) { 246 printf("\n***cgVerify: Error on tpCertGroupVerify expectResult %s\n", 247 expResStr); 248 printf(" err %s expErr %s\n", 249 cssmErrToStr(crtn), cssmErrToStr(expErr)); 250 printf(" evidenceSize %d expEvidenceSize %u\n", 251 evidenceSize, (unsigned)expEvidenceSize); 252 printf(" numCerts %d cgEnd %d anchorStart %d anchorEnd %d\n", 253 numCerts, cgEnd, anchorStart, anchorEnd); 254 rtn = testError(); 255 } 256 else { 257 rtn = 0; 258 } 259 260 /* free resources */ 261 tpFreeCertGroup(&certGroupFrag, 262 CSSM_FALSE, // caller malloc'd the actual certs 263 CSSM_FALSE); // struct is on stack 264 tpFreeCertGroup(&anchorCerts, 265 CSSM_FALSE, // caller malloc'd the actual certs 266 CSSM_FALSE); // struct is on stack 267 freeVfyResult(&vfyResult); 268 if(useDb) { 269 clDeleteAllCerts(dlDb); 270 } 271 return rtn; 272} 273 274/*** end of code directly copied from ../cgVerify/cgVerify.cpp ***/ 275 276/* 277 * For debug only - ensure that the given array of public keys are all unique 278 * Only saw this when using FEE RNG (i.e., no SecurityServer running). 279 */ 280int comparePubKeys( 281 unsigned numKeys, 282 const CSSM_KEY *pubKeys) 283{ 284 unsigned i,j; 285 286 for(i=0; i<numKeys-1; i++) { 287 for(j=i+1; j<numKeys; j++) { 288 if(appCompareCssmData(&pubKeys[i].KeyData, &pubKeys[j].KeyData)) { 289 printf("***HEY! DUPLICATE PUBLIC KEYS in cgVerify!\n"); 290 return testError(); 291 } 292 } 293 } 294 return 0; 295} 296 297 298/* 299 * key pairs - created in cgConstructInit, stored in testParams->perThread 300 */ 301typedef struct { 302 CSSM_KEY_PTR pubKeys; 303 CSSM_KEY_PTR privKeys; 304 unsigned numKeys; 305 char *notBeforeStr; // to use thread-safe tpGenCerts() 306 char *notAfterStr; // to use thread-safe tpGenCerts() 307} TT_KeyPairs; 308 309 310int cgVerifyInit(TestParams *testParams) 311{ 312 unsigned numKeys = NUM_CERTS_MIN + testParams->threadNum; 313 TT_KeyPairs *keyPairs; 314 315 if(testParams->verbose) { 316 printf("cgVerify thread %d: generating keys...\n", 317 testParams->threadNum); 318 } 319 keyPairs = (TT_KeyPairs *)CSSM_MALLOC(sizeof(TT_KeyPairs)); 320 keyPairs->numKeys = numKeys; 321 keyPairs->pubKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY)); 322 keyPairs->privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY)); 323 CSSM_DL_DB_HANDLE dlDbHand = {0, 0}; 324 if(tpGenKeys(testParams->cspHand, 325 dlDbHand, 326 numKeys, 327 KEYGEN_ALG_DEF, 328 CG_KEY_SIZE_DEFAULT, 329 "cgVerify", // keyLabelBase 330 keyPairs->pubKeys, 331 keyPairs->privKeys)) { 332 goto abort; 333 } 334 if(comparePubKeys(numKeys, keyPairs->pubKeys)) { 335 return 1; 336 } 337 keyPairs->notBeforeStr = genTimeAtNowPlus(0); 338 keyPairs->notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE); 339 340 testParams->perThread = keyPairs; 341 return 0; 342 343abort: 344 printf("Error generating keys; aborting\n"); 345 CSSM_FREE(keyPairs->pubKeys); 346 CSSM_FREE(keyPairs->privKeys); 347 CSSM_FREE(keyPairs); 348 return 1; 349} 350 351int cgVerify(TestParams *testParams) 352{ 353 unsigned loopNum; 354 int status = -1; // exit status 355 unsigned dex; 356 357 TT_KeyPairs *keyPairs = (TT_KeyPairs *)testParams->perThread; 358 359 /* all three of these are arrays with numCert elements */ 360 CSSM_KEY_PTR pubKeys = keyPairs->pubKeys; 361 CSSM_KEY_PTR privKeys = keyPairs->privKeys; 362 CSSM_DATA_PTR certs = NULL; 363 364 unsigned numCerts = keyPairs->numKeys; 365 uint32 sigAlg = SIG_ALG_DEF; 366 ExpectResult expectResult; 367 #if CERT_IN_DB 368 CSSM_BOOL useDb = CSSM_TRUE; 369 #else 370 CSSM_BOOL useDb = CSSM_FALSE; 371 #endif 372 CSSM_DL_DB_HANDLE dlDbHand = {0, 0}; 373 374 /* malloc empty certs */ 375 certs = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA)); 376 if(certs == NULL) { 377 printf("not enough memory for %u certs.\n", numCerts); 378 goto abort; 379 } 380 memset(certs, 0, numCerts * sizeof(CSSM_DATA)); 381 382 for(loopNum=0; loopNum<testParams->numLoops; loopNum++) { 383 /* generate certs */ 384 if(testParams->verbose) { 385 printf("generating certs...\n"); 386 } 387 else if(!testParams->quiet) { 388 printChar(testParams->progressChar); 389 } 390 if(tpGenCerts(testParams->cspHand, 391 testParams->clHand, 392 numCerts, 393 sigAlg, 394 "cgConstruct", // nameBase 395 pubKeys, 396 privKeys, 397 certs, 398 keyPairs->notBeforeStr, 399 keyPairs->notAfterStr)) { 400 goto abort; 401 } 402 403 /* cycle thru test scenarios */ 404 switch(loopNum % 4) { 405 case 0: 406 expectResult = ER_InvalidAnchor; 407 break; 408 case 1: 409 expectResult = ER_RootInCertGroup; 410 break; 411 case 2: 412 expectResult = ER_AnchorVerify; 413 break; 414 case 3: 415 expectResult = ER_NoRoot; 416 break; 417 } 418 status = doTest(testParams->tpHand, 419 testParams->clHand, 420 testParams->cspHand, 421 dlDbHand, 422 certs, 423 numCerts, 424 useDb, 425 expectResult, 426 testParams->verbose); 427 if(status) { 428 break; 429 } 430 /* free certs */ 431 for(dex=0; dex<numCerts; dex++) { 432 CSSM_FREE(certs[dex].Data); 433 } 434 memset(certs, 0, numCerts * sizeof(CSSM_DATA)); 435 #if DO_PAUSE 436 fpurge(stdin); 437 printf("Hit CR to proceed: "); 438 getchar(); 439 #endif 440 } 441abort: 442 /* free resources */ 443 for(dex=0; dex<numCerts; dex++) { 444 if(certs[dex].Data) { 445 CSSM_FREE(certs[dex].Data); 446 } 447 } 448 CSSM_FREE(keyPairs->pubKeys); 449 CSSM_FREE(keyPairs->privKeys); 450 CSSM_FREE(keyPairs); 451 return status; 452} 453 454