]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/caVerify/caVerify.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / caVerify / caVerify.cpp
1 /* Copyright (c) 1998,2003-2006,2008 Apple Inc.
2 *
3 * caVerify.cpp
4 *
5 * Verify proper detection of basicConstraints.cA
6 */
7
8 #include <utilLib/common.h>
9 #include <utilLib/cspwrap.h>
10 #include <security_cdsa_utils/cuFileIo.h>
11 #include <clAppUtils/CertBuilderApp.h>
12 #include <clAppUtils/clutils.h>
13 #include <clAppUtils/timeStr.h>
14 #include <clAppUtils/tpUtils.h>
15 #include <security_cdsa_utils/cuPrintCert.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <Security/cssm.h>
20 #include <Security/x509defs.h>
21 #include <Security/oidsattr.h>
22 #include <Security/oidscert.h>
23 #include <Security/oidsalg.h>
24 #include <Security/certextensions.h>
25 #include <Security/cssmapple.h>
26 #include <string.h>
27
28 /* define nonzero to build on Puma */
29 #define PUMA_BUILD 0
30
31 /* default key and signature algorithm */
32 #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
33 #define KEY_ALG_DEFAULT CSSM_ALGID_RSA
34
35 #define NUM_CERTS_DEF 5 /* default is random from 2 to this */
36 #define NUM_LOOPS_DEF 100
37
38 #if PUMA_BUILD
39 extern "C" {
40 void cssmPerror(const char *how, CSSM_RETURN error);
41 }
42 #endif /* PUMA_BUILD */
43
44 static void usage(char **argv)
45 {
46 printf("Usage: %s [options]\n", argv[0]);
47 printf("Options:\n");
48 printf(" n=numCerts (default=random from 2 to %d)\n", NUM_CERTS_DEF);
49 printf(" a=alg where alg is s(RSA/SHA1), 5(RSA/MD5), f(FEE/MD5), "
50 "F(FEE/SHA1), e(ECDSA), E(ANSI/ECDSA), 6(ECDSA/SHA256)\n");
51 printf(" k=keySizeInBits\n");
52 printf(" c (dump certs on error)\n");
53 printf(" l=numLoops (default = %d)\n", NUM_LOOPS_DEF);
54 exit(1);
55 }
56
57 void showCerts(
58 const CSSM_DATA *certs,
59 unsigned numCerts)
60 {
61 unsigned i;
62
63 for(i=0; i<numCerts; i++) {
64 printf("======== cert %d ========\n", i);
65 printCert(certs[i].Data, certs[i].Length, CSSM_FALSE);
66 printf("\n\n");
67 }
68 }
69
70 void writeCerts(
71 const CSSM_DATA *certs,
72 unsigned numCerts)
73 {
74 unsigned i;
75 char fileName[80];
76
77 for(i=0; i<numCerts; i++) {
78 sprintf(fileName, "caVerifyCert%u.cer", i);
79 writeFile(fileName, certs[i].Data, certs[i].Length);
80 printf("....wrote %lu bytes to %s\n", certs[i].Length, fileName);
81 }
82 }
83
84 /*
85 * Generate a cert chain using specified key pairs and extensions.
86 * The last cert in the chain (certs[numCerts-1]) is a root cert,
87 * self-signed.
88 */
89 static CSSM_RETURN tpGenCertsExten(
90 CSSM_CSP_HANDLE cspHand,
91 CSSM_CL_HANDLE clHand,
92 CSSM_ALGORITHMS sigAlg, /* CSSM_ALGID_SHA1WithRSA, etc. */
93 unsigned numCerts,
94 /* per-cert arrays */
95 const char *nameBase, /* C string */
96 CSSM_KEY_PTR pubKeys, /* array of public keys */
97 CSSM_KEY_PTR privKeys, /* array of private keys */
98 CSSM_X509_EXTENSION **extensions,
99 unsigned *numExtensions,
100 CSSM_DATA_PTR certs, /* array of certs RETURNED here */
101 const char *notBeforeStr, /* from genTimeAtNowPlus() */
102 const char *notAfterStr) /* from genTimeAtNowPlus() */
103
104 {
105 int dex;
106 CSSM_RETURN crtn;
107 CSSM_X509_NAME *issuerName = NULL;
108 CSSM_X509_NAME *subjectName = NULL;
109 CSSM_X509_TIME *notBefore; // UTC-style "not before" time
110 CSSM_X509_TIME *notAfter; // UTC-style "not after" time
111 CSSM_DATA_PTR rawCert = NULL; // from CSSM_CL_CertCreateTemplate
112 CSSM_DATA signedCert; // from CSSM_CL_CertSign
113 uint32 rtn;
114 CSSM_KEY_PTR signerKey; // signs the cert
115 CSSM_CC_HANDLE signContext;
116 char nameStr[100];
117 CSSM_DATA_PTR thisCert; // ptr into certs[]
118 CB_NameOid nameOid;
119
120 nameOid.oid = &CSSMOID_OrganizationName; // const
121 nameOid.string = nameStr;
122
123 /* main loop - once per keypair/cert - starting at end/root */
124 for(dex=numCerts-1; dex>=0; dex--) {
125 thisCert = &certs[dex];
126
127 thisCert->Data = NULL;
128 thisCert->Length = 0;
129
130 sprintf(nameStr, "%s%04d", nameBase, dex);
131 if(issuerName == NULL) {
132 /* last (root) cert - subject same as issuer */
133 issuerName = CB_BuildX509Name(&nameOid, 1);
134 /* self-signed */
135 signerKey = &privKeys[dex];
136 }
137 else {
138 /* previous subject becomes current issuer */
139 CB_FreeX509Name(issuerName);
140 issuerName = subjectName;
141 signerKey = &privKeys[dex+1];
142 }
143 subjectName = CB_BuildX509Name(&nameOid, 1);
144 if((subjectName == NULL) || (issuerName == NULL)) {
145 printf("Error creating X509Names\n");
146 crtn = CSSMERR_CSSM_MEMORY_ERROR;
147 break;
148 }
149
150 /*
151 * not before/after in Y2k-compliant generalized time format.
152 * These come preformatted from our caller.
153 */
154 notBefore = CB_BuildX509Time(0, notBeforeStr);
155 notAfter = CB_BuildX509Time(0, notAfterStr);
156
157 /*
158 * Cook up cert template
159 * Note serial number would be app-specified in real world
160 */
161 rawCert = CB_MakeCertTemplate(clHand,
162 0x12345 + dex, // serial number
163 issuerName,
164 subjectName,
165 notBefore,
166 notAfter,
167 &pubKeys[dex],
168 sigAlg,
169 NULL, // subj unique ID
170 NULL, // issuer unique ID
171 extensions[dex], // extensions
172 numExtensions[dex]); // numExtensions
173
174 if(rawCert == NULL) {
175 crtn = CSSM_ERRCODE_INTERNAL_ERROR;
176 break;
177 }
178
179 /* Free the stuff we allocd to get here */
180 CB_FreeX509Time(notBefore);
181 CB_FreeX509Time(notAfter);
182
183 /**** sign the cert ****/
184 /* 1. get a signing context */
185 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
186 sigAlg,
187 NULL, // no passphrase for now
188 signerKey,
189 &signContext);
190 if(crtn) {
191 printError("CreateSignatureContext", crtn);
192 break;
193 }
194
195 /* 2. use CL to sign the cert */
196 signedCert.Data = NULL;
197 signedCert.Length = 0;
198 crtn = CSSM_CL_CertSign(clHand,
199 signContext,
200 rawCert, // CertToBeSigned
201 NULL, // SignScope per spec
202 0, // ScopeSize per spec
203 &signedCert);
204 if(crtn) {
205 printError("CSSM_CL_CertSign", crtn);
206 break;
207 }
208
209 /* 3. delete signing context */
210 crtn = CSSM_DeleteContext(signContext);
211 if(crtn) {
212 printError("CSSM_DeleteContext", crtn);
213 break;
214 }
215
216 /*
217 * CSSM_CL_CertSign() returned us a mallocd CSSM_DATA. Copy
218 * its fields to caller's cert.
219 */
220 certs[dex] = signedCert;
221
222 /* and the raw unsigned cert as well */
223 appFreeCssmData(rawCert, CSSM_TRUE);
224 rtn = 0;
225 }
226
227 /* free resources */
228 if(issuerName != NULL) {
229 CB_FreeX509Name(issuerName);
230 }
231 if(subjectName != NULL) {
232 CB_FreeX509Name(subjectName);
233 }
234 return crtn;
235 }
236
237 static int doTest(
238 CSSM_CSP_HANDLE cspHand, // CSP handle
239 CSSM_CL_HANDLE clHand, // CL handle
240 CSSM_TP_HANDLE tpHand, // TP handle
241 unsigned numCerts, // >= 2
242 CSSM_KEY_PTR pubKeys,
243 CSSM_KEY_PTR privKeys,
244 CSSM_ALGORITHMS sigAlg,
245 CSSM_BOOL expectFail,
246 CSSM_BOOL dumpCerts,
247 CSSM_BOOL quiet)
248 {
249 CSSM_DATA_PTR certs;
250 CSSM_X509_EXTENSION **extens;
251 unsigned *numExtens;
252 char *notBeforeStr = genTimeAtNowPlus(0);
253 char *notAfterStr = genTimeAtNowPlus(10000);
254 unsigned certDex;
255 CE_BasicConstraints *bc;
256 CSSM_X509_EXTENSION *thisExten;
257 CE_BasicConstraints *thisBc;
258 const char *failMode = "not set - internal error";
259 CSSM_RETURN crtn;
260 unsigned badCertDex = 0;
261
262 certs = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA) * numCerts);
263 memset(certs, 0, sizeof(CSSM_DATA) * numCerts);
264
265 /*
266 * For now just zero or one extension per cert - basicConstraints.
267 * Eventually we'll want to test keyUsage as well.
268 */
269 extens = (CSSM_X509_EXTENSION **)malloc(sizeof(CSSM_X509_EXTENSION *) * numCerts);
270 memset(extens, 0, sizeof(CSSM_X509_EXTENSION *) * numCerts);
271 numExtens = (unsigned *)malloc(sizeof(unsigned) * numCerts);
272 bc = (CE_BasicConstraints *)malloc(sizeof(CE_BasicConstraints) * numCerts);
273
274 /*
275 * Set up all extensions for success
276 */
277 for(certDex=0; certDex<numCerts; certDex++) {
278 extens[certDex] = (CSSM_X509_EXTENSION *)malloc(sizeof(CSSM_X509_EXTENSION));
279 numExtens[certDex] = 1;
280 thisExten = extens[certDex];
281 thisBc = &bc[certDex];
282
283 thisExten->extnId = CSSMOID_BasicConstraints;
284 thisExten->critical = CSSM_TRUE;
285 thisExten->format = CSSM_X509_DATAFORMAT_PARSED;
286 thisExten->value.parsedValue = thisBc;
287 thisExten->BERvalue.Data = NULL;
288 thisExten->BERvalue.Length = 0;
289
290 if(certDex == 0) {
291 /* leaf - flip coin to determine presence of basicConstraints */
292 int coin = genRand(1,2);
293 if(coin == 1) {
294 /* basicConstraints, !cA */
295 thisBc->cA = CSSM_FALSE;
296 thisBc->pathLenConstraintPresent = CSSM_FALSE;
297 thisBc->pathLenConstraint = 0;
298 }
299 else {
300 /* !basicConstraints, !cA by default */
301 numExtens[certDex] = 0;
302 }
303 }
304 else if(certDex == (numCerts-1)) {
305 /* root - flip coin to determine presence of basicConstraints */
306 int coin = genRand(1,2);
307 if(coin == 1) {
308 /* basicConstraints, cA */
309 thisBc->cA = CSSM_TRUE;
310 /* flip coin to determine present of pathLenConstraint */
311 coin = genRand(1,2);
312 if(coin == 1) {
313 thisBc->pathLenConstraintPresent = CSSM_FALSE;
314 thisBc->pathLenConstraint = 0;
315 }
316 else {
317 thisBc->pathLenConstraintPresent = CSSM_TRUE;
318 thisBc->pathLenConstraint = genRand(certDex-1, numCerts+1);
319 }
320 }
321 else {
322 /* !basicConstraints, cA by default */
323 numExtens[certDex] = 0;
324 }
325 }
326 else {
327 /* intermediate = cA required */
328 thisBc->cA = CSSM_TRUE;
329 /* flip coin to determine presence of pathLenConstraint */
330 int coin = genRand(1,2);
331 if(coin == 1) {
332 thisBc->pathLenConstraintPresent = CSSM_FALSE;
333 thisBc->pathLenConstraint = 0;
334 }
335 else {
336 thisBc->pathLenConstraintPresent = CSSM_TRUE;
337 thisBc->pathLenConstraint = genRand(certDex-1, numCerts+1);
338 }
339 }
340 }
341
342 if(expectFail) {
343 /* introduce a failure */
344 if(numCerts == 2) {
345 /* only possible failure is explicit !cA in root */
346 /* don't assume presence of BC exten */
347 badCertDex = 1;
348 thisExten = extens[badCertDex];
349 thisBc = &bc[badCertDex];
350 thisBc->cA = CSSM_FALSE;
351 thisBc->pathLenConstraintPresent = CSSM_FALSE;
352 bc->pathLenConstraint = 0;
353 numExtens[badCertDex] = 1;
354 failMode = "Explicit !cA in root";
355 }
356 else {
357 /* roll the dice to select an intermediate cert */
358 badCertDex = genRand(1, numCerts-2);
359 thisExten = extens[badCertDex];
360 if((thisExten == NULL) || (numExtens[badCertDex] == 0)) {
361 printf("***INTERNAL SCREWUP\n");
362 exit(1);
363 }
364 thisBc = &bc[badCertDex];
365
366 /*
367 * roll die: fail by
368 * -- no BasicConstraints
369 * -- !cA
370 * -- bad pathLenConstraint
371 */
372 int die = genRand(1,3);
373 if((die == 1) &&
374 (badCertDex != 1)) { // last cA doesn't need pathLenConstraint
375 thisBc->pathLenConstraintPresent = CSSM_TRUE;
376 thisBc->pathLenConstraint = badCertDex - 2; // one short
377 failMode = "Short pathLenConstraint";
378 }
379 else if(die == 2) {
380 thisBc->cA = CSSM_FALSE;
381 failMode = "Explicit !cA in intermediate";
382 }
383 else {
384 /* no extension */
385 numExtens[badCertDex] = 0;
386 failMode = "No BasicConstraints in intermediate";
387 }
388 }
389 }
390 if(!quiet && expectFail) {
391 printf(" ...bad cert at index %d: %s\n", badCertDex, failMode);
392 }
393
394 /* here we go - create cert chain */
395 crtn = tpGenCertsExten(cspHand,
396 clHand,
397 sigAlg,
398 numCerts,
399 "caVerify", // nameBase
400 pubKeys,
401 privKeys,
402 extens,
403 numExtens,
404 certs,
405 notBeforeStr,
406 notAfterStr);
407 if(crtn) {
408 printError("tpGenCertsExten", crtn);
409 return crtn; // and leak like crazy
410 }
411
412 CSSM_CERTGROUP cgrp;
413 memset(&cgrp, 0, sizeof(CSSM_CERTGROUP));
414 cgrp.NumCerts = numCerts;
415 #if PUMA_BUILD
416 cgrp.CertGroupType = CSSM_CERTGROUP_ENCODED_CERT;
417 #else
418 /* Jaguar */
419 cgrp.CertGroupType = CSSM_CERTGROUP_DATA;
420 #endif /* PUMA_BUILD */
421 cgrp.CertType = CSSM_CERT_X_509v3;
422 cgrp.CertEncoding = CSSM_CERT_ENCODING_DER;
423 cgrp.GroupList.CertList = certs;
424
425 #if PUMA_BUILD
426 crtn = tpCertGroupVerify(tpHand,
427 clHand,
428 cspHand,
429 NULL, // DlDbList
430 &CSSMOID_APPLE_X509_BASIC, // SSL requires built-in root match
431 &cgrp,
432 /* pass in OUR ROOT as anchors */
433 (CSSM_DATA_PTR)&certs[numCerts-1], // anchorCerts
434 1,
435 CSSM_TP_STOP_ON_POLICY,
436 CSSM_FALSE, // allowExpired
437 NULL); // vfyResult
438 #else
439 /* Jaguar */
440 crtn = tpCertGroupVerify(tpHand,
441 clHand,
442 cspHand,
443 NULL, // DlDbList
444 &CSSMOID_APPLE_TP_SSL, // may want to parameterize this
445 NULL, // fieldOpts for server name
446 NULL, // actionDataPtr for allow expired
447 NULL, // policyOpts
448 &cgrp,
449 /* pass in OUR ROOT as anchors */
450 (CSSM_DATA_PTR)&certs[numCerts-1], // anchorCerts
451 1,
452 CSSM_TP_STOP_ON_POLICY,
453 NULL, // cssmTimeStr
454 NULL); // vfyResult
455 #endif /* PUMA_BUILD */
456 if(expectFail) {
457 if(crtn != CSSMERR_TP_VERIFY_ACTION_FAILED) {
458 cssmPerror("***Expected error TP_VERIFY_ACTION_FAILED; got ", crtn);
459 printf(" Expected failure due to %s\n", failMode);
460 if(dumpCerts) {
461 showCerts(certs, numCerts);
462 writeCerts(certs, numCerts);
463 }
464 return testError(quiet);
465 }
466 }
467 else if(crtn) {
468 cssmPerror("Unexpected failure on tpCertGroupVerify", crtn);
469 if(dumpCerts) {
470 showCerts(certs, numCerts);
471 }
472 return testError(quiet);
473 }
474
475 /* clean up */
476 return 0;
477 }
478
479 int main(int argc, char **argv)
480 {
481 CSSM_CL_HANDLE clHand; // CL handle
482 CSSM_CSP_HANDLE cspHand; // CSP handle
483 CSSM_TP_HANDLE tpHand;
484 CSSM_KEY_PTR pubKeys;
485 CSSM_KEY_PTR privKeys;
486 CSSM_RETURN crtn;
487 int arg;
488 unsigned certDex;
489 unsigned loopNum;
490 unsigned maxCerts;
491
492 /* user-spec'd variables */
493 CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT;
494 CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT;
495 uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT;
496 unsigned numCerts = 0; // means random per loop
497 unsigned numLoops = NUM_LOOPS_DEF;
498 CSSM_BOOL quiet = CSSM_FALSE;
499 CSSM_BOOL dumpCerts = CSSM_FALSE;
500
501 for(arg=1; arg<argc; arg++) {
502 switch(argv[arg][0]) {
503 case 'a':
504 if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) {
505 usage(argv);
506 }
507 switch(argv[arg][2]) {
508 case 's':
509 keyAlg = CSSM_ALGID_RSA;
510 sigAlg = CSSM_ALGID_SHA1WithRSA;
511 break;
512 case '5':
513 keyAlg = CSSM_ALGID_RSA;
514 sigAlg = CSSM_ALGID_MD5WithRSA;
515 break;
516 case 'f':
517 keyAlg = CSSM_ALGID_FEE;
518 sigAlg = CSSM_ALGID_FEE_MD5;
519 break;
520 case 'F':
521 keyAlg = CSSM_ALGID_FEE;
522 sigAlg = CSSM_ALGID_FEE_SHA1;
523 break;
524 case 'e':
525 keyAlg = CSSM_ALGID_FEE;
526 sigAlg = CSSM_ALGID_SHA1WithECDSA;
527 break;
528 case 'E':
529 keyAlg = CSSM_ALGID_ECDSA;
530 sigAlg = CSSM_ALGID_SHA1WithECDSA;
531 break;
532 case '6':
533 keyAlg = CSSM_ALGID_ECDSA;
534 sigAlg = CSSM_ALGID_SHA256WithECDSA;
535 break;
536 default:
537 usage(argv);
538 }
539 break;
540 case 'k':
541 keySizeInBits = atoi(&argv[arg][2]);
542 break;
543 case 'l':
544 numLoops = atoi(&argv[arg][2]);
545 break;
546 case 'n':
547 numCerts = atoi(&argv[arg][2]);
548 break;
549 case 'c':
550 dumpCerts = CSSM_TRUE;
551 break;
552 case 'q':
553 quiet = CSSM_TRUE;
554 break;
555 default:
556 usage(argv);
557 }
558 }
559
560 /* connect to CL, TP, and CSP */
561 clHand = clStartup();
562 if(clHand == 0) {
563 return 0;
564 }
565 tpHand = tpStartup();
566 if(tpHand == 0) {
567 return 0;
568 }
569 cspHand = cspStartup();
570 if(cspHand == 0) {
571 return 0;
572 }
573
574 if(numCerts == 0) {
575 maxCerts = NUM_CERTS_DEF; // random, this is the max $
576 }
577 else {
578 maxCerts = numCerts; // user-specd
579 }
580
581 printf("Starting caVerify; args: ");
582 for(unsigned i=1; i<(unsigned)argc; i++) {
583 printf("%s ", argv[i]);
584 }
585 printf("\n");
586
587 /* cook up maxCerts key pairs */
588 if(!quiet) {
589 printf("generating key pairs...\n");
590 }
591 pubKeys = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY) * maxCerts);
592 privKeys = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY) * maxCerts);
593 for(certDex=0; certDex<maxCerts; certDex++) {
594 crtn = cspGenKeyPair(cspHand,
595 keyAlg,
596 "a key pair",
597 9,
598 keySizeInBits,
599 &pubKeys[certDex],
600 CSSM_FALSE, // pubIsRef - should work both ways, but not yet
601 CSSM_KEYUSE_VERIFY,
602 CSSM_KEYBLOB_RAW_FORMAT_NONE,
603 &privKeys[certDex],
604 CSSM_TRUE, // privIsRef - doesn't matter
605 CSSM_KEYUSE_SIGN,
606 CSSM_KEYBLOB_RAW_FORMAT_NONE,
607 CSSM_FALSE);
608 if(crtn) {
609 printError("cspGenKeyPair", crtn);
610 printf("***error generating key pair. Aborting.\n");
611 exit(1);
612 }
613 }
614
615 for(loopNum=0; loopNum<numLoops; loopNum++) {
616 unsigned thisNumCerts;
617
618 /* random: num certs and whether this loop is to test a failure */
619 if(numCerts) {
620 thisNumCerts = numCerts;
621 }
622 else {
623 thisNumCerts = genRand(2, NUM_CERTS_DEF);
624 }
625 int coin = genRand(1,2);
626 CSSM_BOOL expectFail = (coin == 1) ? CSSM_TRUE : CSSM_FALSE;
627 if(!quiet) {
628 printf("...loop %d numCerts %u expectFail %s\n", loopNum,
629 thisNumCerts, expectFail ? "TRUE" : "FALSE");
630 }
631 if(doTest(cspHand,
632 clHand,
633 tpHand,
634 thisNumCerts,
635 pubKeys,
636 privKeys,
637 sigAlg,
638 expectFail,
639 dumpCerts,
640 quiet)) {
641 break;
642 }
643 }
644 /* clean up */
645 return 0;
646 }
647
648