]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/extenTest/extenTest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / extenTest / extenTest.cpp
1 /*
2 * extenTest - verify encoding and decoding of extensions.
3 */
4
5 #include <security_cdsa_utils/cuFileIo.h>
6 #include <clAppUtils/CertBuilderApp.h>
7 #include <utilLib/common.h>
8 #include <utilLib/cspwrap.h>
9 #include <clAppUtils/clutils.h>
10 #include <security_cdsa_utils/cuPrintCert.h>
11 #include <security_cdsa_utils/cuOidParser.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <time.h>
16 #include <Security/cssm.h>
17 #include <Security/x509defs.h>
18 #include <Security/oidsattr.h>
19 #include <Security/oidscert.h>
20 #include <Security/certextensions.h>
21
22 #define KEY_ALG CSSM_ALGID_RSA
23 #define SIG_ALG CSSM_ALGID_SHA1WithRSA
24 #define KEY_SIZE_BITS CSP_RSA_KEY_SIZE_DEFAULT
25 #define SUBJ_KEY_LABEL "subjectKey"
26
27 #define LOOPS_DEF 10
28
29 static void usage(char **argv)
30 {
31 printf("Usage: %s [options]\n", argv[0]);
32 printf("Options:\n");
33 printf(" e=extenSpec (default = all)\n");
34 printf(" k keyUsage\n");
35 printf(" b basicConstraints\n");
36 printf(" x extendedKeyUsage\n");
37 printf(" s subjectKeyId\n");
38 printf(" a authorityKeyId\n");
39 printf(" t SubjectAltName\n");
40 printf(" i IssuerAltName\n");
41 printf(" c certPolicies\n");
42 printf(" n netscapeCertType\n");
43 printf(" p CRLDistributionPoints\n");
44 printf(" A AuthorityInfoAccess\n");
45 printf(" S SubjectInfoAccess\n");
46 printf(" q QualifiedCertStatements\n");
47 printf(" w(rite blobs)\n");
48 printf(" f=fileName (default is extension-specific file name)\n");
49 printf(" d(isplay certs)\n");
50 printf(" l=loops (default = %d)\n", LOOPS_DEF);
51 printf(" p(ause on each loop)\n");
52 printf(" P(ause on each cert)\n");
53 exit(1);
54 }
55
56 /* dummy RDN - subject and issuer - we aren't testing this */
57 CB_NameOid dummyRdn[] =
58 {
59 { "Apple Computer", &CSSMOID_OrganizationName },
60 { "Doug Mitchell", &CSSMOID_CommonName }
61 };
62 #define NUM_DUMMY_NAMES (sizeof(dummyRdn) / sizeof(CB_NameOid))
63
64 /*
65 * Static components we reuse for each encode/decode.
66 */
67 static CSSM_X509_NAME *dummyName;
68 static CSSM_X509_TIME *notBefore; // UTC-style "not before" time
69 static CSSM_X509_TIME *notAfter; // UTC-style "not after" time
70 static CSSM_KEY subjPrivKey;
71 static CSSM_KEY subjPubKey;
72
73 static CSSM_BOOL randBool()
74 {
75 unsigned r = genRand(1, 0x10000000);
76 return (r & 0x1) ? CSSM_TRUE : CSSM_FALSE;
77 }
78
79 /* Fill a CSSM_DATA with random data. Its referent is allocd with malloc. */
80 static void randData(
81 CSSM_DATA_PTR data,
82 uint8 maxLen)
83 {
84 data->Data = (uint8 *)malloc(maxLen);
85 simpleGenData(data, 1, maxLen);
86 }
87
88 /*
89 * Various compare tests
90 */
91 int compBool(
92 CSSM_BOOL pre,
93 CSSM_BOOL post,
94 const char *desc)
95 {
96 if(pre == post) {
97 return 0;
98 }
99 printf("***Boolean miscompare on %s\n", desc);
100 /* in case a CSSM_TRUE isn't exactly right... */
101 switch(post) {
102 case CSSM_FALSE:
103 case CSSM_TRUE:
104 break;
105 default:
106 printf("*** post value is %d expected %d\n",
107 (int)post, (int)pre);
108 break;
109 }
110 return 1;
111 }
112
113 static int compCssmData(
114 CSSM_DATA &d1,
115 CSSM_DATA &d2,
116 const char *desc)
117 {
118 if(appCompareCssmData(&d1, &d2)) {
119 return 0;
120 }
121 printf("CSSM_DATA miscompare on %s\n", desc);
122 return 1;
123 }
124
125 #pragma mark ----- individual extension tests -----
126
127 #pragma mark --- CE_KeyUsage ---
128 static void kuCreate(void *arg)
129 {
130 CE_KeyUsage *ku = (CE_KeyUsage *)arg;
131
132 /* set two random valid bits */
133 *ku = 0;
134 *ku |= 1 << genRand(7, 15);
135 *ku |= 1 << genRand(7, 15);
136 }
137
138 static unsigned kuCompare(const void *pre, const void *post)
139 {
140 const CE_KeyUsage *kuPre = (CE_KeyUsage *)pre;
141 const CE_KeyUsage *kuPost = (CE_KeyUsage *)post;
142 if(*kuPre != *kuPost) {
143 printf("***Miscompare in CE_KeyUsage\n");
144 return 1;
145 }
146 return 0;
147 }
148
149 #pragma mark --- CE_BasicConstraints ---
150 static void bcCreate(void *arg)
151 {
152 CE_BasicConstraints *bc = (CE_BasicConstraints *)arg;
153 bc->cA = randBool();
154 bc->pathLenConstraintPresent = randBool();
155 if(bc->pathLenConstraintPresent) {
156 bc->pathLenConstraint = genRand(1,10);
157 }
158 }
159
160 static unsigned bcCompare(const void *pre, const void *post)
161 {
162 const CE_BasicConstraints *bcpre = (CE_BasicConstraints *)pre;
163 const CE_BasicConstraints *bcpost = (CE_BasicConstraints *)post;
164 unsigned rtn = 0;
165
166 rtn += compBool(bcpre->cA, bcpost->cA, "BasicConstraints.cA");
167 rtn += compBool(bcpre->pathLenConstraintPresent,
168 bcpost->pathLenConstraintPresent,
169 "BasicConstraints.pathLenConstraintPresent");
170 if(bcpre->pathLenConstraint != bcpost->pathLenConstraint) {
171 printf("BasicConstraints.pathLenConstraint mismatch\n");
172 rtn++;
173 }
174 return rtn;
175 }
176
177 #pragma mark --- CE_SubjectKeyID ---
178 static void skidCreate(void *arg)
179 {
180 CSSM_DATA_PTR skid = (CSSM_DATA_PTR)arg;
181 randData(skid, 16);
182 }
183
184 static unsigned skidCompare(const void *pre, const void *post)
185 {
186 CSSM_DATA_PTR spre = (CSSM_DATA_PTR)pre;
187 CSSM_DATA_PTR spost = (CSSM_DATA_PTR)post;
188 return compCssmData(*spre, *spost, "SubjectKeyID");
189 }
190
191 static void skidFree(void *arg)
192 {
193 CSSM_DATA_PTR skid = (CSSM_DATA_PTR)arg;
194 free(skid->Data);
195 }
196
197 #pragma mark --- CE_NetscapeCertType ---
198 static void nctCreate(void *arg)
199 {
200 CE_NetscapeCertType *nct = (CE_NetscapeCertType *)arg;
201
202 /* set two random valid bits */
203 *nct = 0;
204 *nct |= 1 << genRand(8, 15);
205 *nct |= 1 << genRand(8, 15);
206 }
207
208 static unsigned nctCompare(const void *pre, const void *post)
209 {
210 const CE_NetscapeCertType *nPre = (CE_NetscapeCertType *)pre;
211 const CE_NetscapeCertType *nPost = (CE_NetscapeCertType *)post;
212 if(*nPre != *nPost) {
213 printf("***Miscompare in CE_NetscapeCertType\n");
214 return 1;
215 }
216 return 0;
217 }
218
219 #pragma mark --- CE_ExtendedKeyUsage ---
220
221 /* a static array of meaningless OIDs, use 1.. NUM_SKU_OIDS */
222 CSSM_OID ekuOids[] = {
223 CSSMOID_CrlNumber,
224 CSSMOID_CrlReason,
225 CSSMOID_HoldInstructionCode,
226 CSSMOID_InvalidityDate
227 };
228 #define NUM_SKU_OIDS 4
229
230 static void ekuCreate(void *arg)
231 {
232 CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)arg;
233 eku->numPurposes = genRand(1, NUM_SKU_OIDS);
234 eku->purposes = ekuOids;
235 }
236
237 static unsigned ekuCompare(const void *pre, const void *post)
238 {
239 CE_ExtendedKeyUsage *ekupre = (CE_ExtendedKeyUsage *)pre;
240 CE_ExtendedKeyUsage *ekupost = (CE_ExtendedKeyUsage *)post;
241
242 if(ekupre->numPurposes != ekupost->numPurposes) {
243 printf("CE_ExtendedKeyUsage.numPurposes miscompare\n");
244 return 1;
245 }
246 unsigned rtn = 0;
247 for(unsigned dex=0; dex<ekupre->numPurposes; dex++) {
248 rtn += compCssmData(ekupre->purposes[dex],
249 ekupost->purposes[dex], "CE_ExtendedKeyUsage.purposes");
250 }
251 return rtn;
252 }
253
254
255 #pragma mark --- general purpose X509 name generator ---
256
257 /* Attr/Value pairs, pick one of NUM_ATTR_STRINGS */
258 static char *attrStrings[] = {
259 (char *)"thisName",
260 (char *)"anotherName",
261 (char *)"someOtherName"
262 };
263 #define NUM_ATTR_STRINGS 3
264
265 /* A/V type, pick one of NUM_ATTR_TYPES */
266 static CSSM_OID attrTypes[] = {
267 CSSMOID_Surname,
268 CSSMOID_CountryName,
269 CSSMOID_OrganizationName,
270 CSSMOID_Description
271 };
272 #define NUM_ATTR_TYPES 4
273
274 /* A/V tag, pick one of NUM_ATTR_TAGS */
275 static char attrTags[] = {
276 BER_TAG_PRINTABLE_STRING,
277 BER_TAG_IA5_STRING,
278 BER_TAG_T61_STRING
279 };
280 #define NUM_ATTR_TAGS 3
281
282 static void rdnCreate(
283 CSSM_X509_RDN_PTR rdn)
284 {
285 unsigned numPairs = genRand(1,4);
286 rdn->numberOfPairs = numPairs;
287 unsigned len = numPairs * sizeof(CSSM_X509_TYPE_VALUE_PAIR);
288 rdn->AttributeTypeAndValue =
289 (CSSM_X509_TYPE_VALUE_PAIR_PTR)malloc(len);
290 memset(rdn->AttributeTypeAndValue, 0, len);
291
292 for(unsigned atvDex=0; atvDex<numPairs; atvDex++) {
293 CSSM_X509_TYPE_VALUE_PAIR &pair =
294 rdn->AttributeTypeAndValue[atvDex];
295 unsigned die = genRand(1, NUM_ATTR_TYPES);
296 pair.type = attrTypes[die - 1];
297 die = genRand(1, NUM_ATTR_STRINGS);
298 char *str = attrStrings[die - 1];
299 pair.value.Data = (uint8 *)str;
300 pair.value.Length = strlen(str);
301 die = genRand(1, NUM_ATTR_TAGS);
302 pair.valueType = attrTags[die - 1];
303 }
304 }
305
306 static unsigned rdnCompare(
307 CSSM_X509_RDN_PTR rdn1,
308 CSSM_X509_RDN_PTR rdn2)
309 {
310 if(rdn1->numberOfPairs != rdn2->numberOfPairs) {
311 printf("***Mismatch in numberOfPairs\n");
312 return 1;
313 }
314 unsigned rtn = 0;
315 for(unsigned atvDex=0; atvDex<rdn1->numberOfPairs; atvDex++) {
316 CSSM_X509_TYPE_VALUE_PAIR &p1 =
317 rdn1->AttributeTypeAndValue[atvDex];
318 CSSM_X509_TYPE_VALUE_PAIR &p2 =
319 rdn2->AttributeTypeAndValue[atvDex];
320 if(p1.valueType != p2.valueType) {
321 printf("***valueType miscompare\n");
322 rtn++;
323 }
324 if(compCssmData(p1.type, p2.type, "ATV.type")) {
325 rtn++;
326 }
327 if(compCssmData(p1.value, p2.value, "ATV.value")) {
328 rtn++;
329 }
330 }
331 return rtn;
332 }
333
334 static void rdnFree(
335 CSSM_X509_RDN_PTR rdn)
336 {
337 free(rdn->AttributeTypeAndValue);
338 }
339
340 static void x509NameCreate(
341 CSSM_X509_NAME_PTR x509Name)
342 {
343 memset(x509Name, 0, sizeof(*x509Name));
344 unsigned numRdns = genRand(1,4);
345 x509Name->numberOfRDNs = numRdns;
346 unsigned len = numRdns * sizeof(CSSM_X509_RDN);
347 x509Name->RelativeDistinguishedName = (CSSM_X509_RDN_PTR)malloc(len);
348 memset(x509Name->RelativeDistinguishedName, 0, len);
349
350 for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
351 CSSM_X509_RDN &rdn = x509Name->RelativeDistinguishedName[rdnDex];
352 rdnCreate(&rdn);
353 }
354 }
355
356 static unsigned x509NameCompare(
357 const CSSM_X509_NAME_PTR n1,
358 const CSSM_X509_NAME_PTR n2)
359 {
360 if(n1->numberOfRDNs != n2->numberOfRDNs) {
361 printf("***Mismatch in numberOfRDNs\n");
362 return 1;
363 }
364 unsigned rtn = 0;
365 for(unsigned rdnDex=0; rdnDex<n1->numberOfRDNs; rdnDex++) {
366 CSSM_X509_RDN &rdn1 = n1->RelativeDistinguishedName[rdnDex];
367 CSSM_X509_RDN &rdn2 = n2->RelativeDistinguishedName[rdnDex];
368 rtn += rdnCompare(&rdn1, &rdn2);
369 }
370 return rtn;
371 }
372
373 static void x509NameFree(
374 CSSM_X509_NAME_PTR n)
375 {
376 for(unsigned rdnDex=0; rdnDex<n->numberOfRDNs; rdnDex++) {
377 CSSM_X509_RDN &rdn = n->RelativeDistinguishedName[rdnDex];
378 rdnFree(&rdn);
379 }
380 free(n->RelativeDistinguishedName);
381 }
382
383 #pragma mark --- general purpose GeneralNames generator ---
384
385 #define SOME_URL_1 "http://foo.bar.com"
386 #define SOME_URL_2 "http://bar.foo.com"
387 #define SOME_DNS_1 "Some DNS"
388 #define SOME_DNS_2 "Another DNS"
389 unsigned char someIpAdr_1[] = {208, 161, 124, 209 };
390 unsigned char someIpAdr_2[] = {10, 0, 61, 5};
391
392 static void genNameCreate(CE_GeneralName *name)
393 {
394 unsigned type = genRand(1, 5);
395 const char *src;
396 unsigned char *usrc;
397 switch(type) {
398 case 1:
399 name->nameType = GNT_URI;
400 name->berEncoded = CSSM_FALSE;
401 src = randBool() ? SOME_URL_1 : SOME_URL_2;
402 appCopyData(src, strlen(src), &name->name);
403 break;
404
405 case 2:
406 name->nameType = GNT_RegisteredID;
407 name->berEncoded = CSSM_FALSE;
408 appCopyData(CSSMOID_SubjectDirectoryAttributes.Data,
409 CSSMOID_SubjectDirectoryAttributes.Length,
410 &name->name);
411 break;
412
413 case 3:
414 name->nameType = GNT_DNSName;
415 name->berEncoded = CSSM_FALSE;
416 src = randBool() ? SOME_DNS_1 : SOME_DNS_2;
417 appCopyData(src, strlen(src), &name->name);
418 break;
419
420 case 4:
421 name->nameType = GNT_IPAddress;
422 name->berEncoded = CSSM_FALSE;
423 usrc = randBool() ? someIpAdr_1 : someIpAdr_2;
424 appCopyData(usrc, 4, &name->name);
425 break;
426
427 case 5:
428 {
429 /* X509_NAME, the hard one */
430 name->nameType = GNT_DirectoryName;
431 name->berEncoded = CSSM_FALSE;
432 appSetupCssmData(&name->name, sizeof(CSSM_X509_NAME));
433 x509NameCreate((CSSM_X509_NAME_PTR)name->name.Data);
434 }
435 }
436 }
437
438 static void genNamesCreate(void *arg)
439 {
440 CE_GeneralNames *names = (CE_GeneralNames *)arg;
441 names->numNames = genRand(1, 3);
442 // one at a time
443 //names->numNames = 1;
444 names->generalName = (CE_GeneralName *)malloc(names->numNames *
445 sizeof(CE_GeneralName));
446 memset(names->generalName, 0, names->numNames * sizeof(CE_GeneralName));
447
448 for(unsigned i=0; i<names->numNames; i++) {
449 CE_GeneralName *name = &names->generalName[i];
450 genNameCreate(name);
451 }
452 }
453
454 static unsigned genNameCompare(
455 CE_GeneralName *npre,
456 CE_GeneralName *npost)
457 {
458 unsigned rtn = 0;
459 if(npre->nameType != npost->nameType) {
460 printf("***CE_GeneralName.nameType miscompare\n");
461 rtn++;
462 }
463 if(compBool(npre->berEncoded, npost->berEncoded,
464 "CE_GeneralName.berEncoded")) {
465 rtn++;
466 }
467
468 /* nameType-specific compare */
469 switch(npre->nameType) {
470 case GNT_RFC822Name:
471 rtn += compCssmData(npre->name, npost->name,
472 "CE_GeneralName.RFC822Name");
473 break;
474 case GNT_DNSName:
475 rtn += compCssmData(npre->name, npost->name,
476 "CE_GeneralName.DNSName");
477 break;
478 case GNT_URI:
479 rtn += compCssmData(npre->name, npost->name,
480 "CE_GeneralName.URI");
481 break;
482 case GNT_IPAddress:
483 rtn += compCssmData(npre->name, npost->name,
484 "CE_GeneralName.RFIPAddressC822Name");
485 break;
486 case GNT_RegisteredID:
487 rtn += compCssmData(npre->name, npost->name,
488 "CE_GeneralName.RegisteredID");
489 break;
490 case GNT_DirectoryName:
491 rtn += x509NameCompare((CSSM_X509_NAME_PTR)npre->name.Data,
492 (CSSM_X509_NAME_PTR)npost->name.Data);
493 break;
494 default:
495 printf("****BRRZAP! genNamesCompare needs work\n");
496 rtn++;
497 }
498 return rtn;
499 }
500
501 static unsigned genNamesCompare(const void *pre, const void *post)
502 {
503 const CE_GeneralNames *gnPre = (CE_GeneralNames *)pre;
504 const CE_GeneralNames *gnPost = (CE_GeneralNames *)post;
505 unsigned rtn = 0;
506
507 if((gnPre == NULL) || (gnPost == NULL)) {
508 printf("***Bad GenNames pointer\n");
509 return 1;
510 }
511 if(gnPre->numNames != gnPost->numNames) {
512 printf("***CE_GeneralNames.numNames miscompare\n");
513 return 1;
514 }
515 for(unsigned dex=0; dex<gnPre->numNames; dex++) {
516 CE_GeneralName *npre = &gnPre->generalName[dex];
517 CE_GeneralName *npost = &gnPost->generalName[dex];
518 rtn += genNameCompare(npre, npost);
519 }
520 return rtn;
521 }
522
523
524 static void genNameFree(CE_GeneralName *n)
525 {
526 switch(n->nameType) {
527 case GNT_DirectoryName:
528 x509NameFree((CSSM_X509_NAME_PTR)n->name.Data);
529 CSSM_FREE(n->name.Data);
530 break;
531 default:
532 CSSM_FREE(n->name.Data);
533 break;
534 }
535 }
536
537
538 static void genNamesFree(void *arg)
539 {
540 const CE_GeneralNames *gn = (CE_GeneralNames *)arg;
541 for(unsigned dex=0; dex<gn->numNames; dex++) {
542 CE_GeneralName *n = (CE_GeneralName *)&gn->generalName[dex];
543 genNameFree(n);
544 }
545 free(gn->generalName);
546 }
547
548 #pragma mark --- CE_CRLDistPointsSyntax ---
549 static void cdpCreate(void *arg)
550 {
551 CE_CRLDistPointsSyntax *cdp = (CE_CRLDistPointsSyntax *)arg;
552 //cdp->numDistPoints = genRand(1,3);
553 // one at a time
554 cdp->numDistPoints = 1;
555 unsigned len = sizeof(CE_CRLDistributionPoint) * cdp->numDistPoints;
556 cdp->distPoints = (CE_CRLDistributionPoint *)malloc(len);
557 memset(cdp->distPoints, 0, len);
558
559 for(unsigned dex=0; dex<cdp->numDistPoints; dex++) {
560 CE_CRLDistributionPoint *pt = &cdp->distPoints[dex];
561
562 /* all fields optional */
563 if(randBool()) {
564 CE_DistributionPointName *dpn = pt->distPointName =
565 (CE_DistributionPointName *)malloc(
566 sizeof(CE_DistributionPointName));
567 memset(dpn, 0, sizeof(CE_DistributionPointName));
568
569 /* CE_DistributionPointName has two flavors */
570 if(randBool()) {
571 dpn->nameType = CE_CDNT_FullName;
572 dpn->dpn.fullName = (CE_GeneralNames *)malloc(
573 sizeof(CE_GeneralNames));
574 memset(dpn->dpn.fullName, 0, sizeof(CE_GeneralNames));
575 genNamesCreate(dpn->dpn.fullName);
576 }
577 else {
578 dpn->nameType = CE_CDNT_NameRelativeToCrlIssuer;
579 dpn->dpn.rdn = (CSSM_X509_RDN_PTR)malloc(
580 sizeof(CSSM_X509_RDN));
581 memset(dpn->dpn.rdn, 0, sizeof(CSSM_X509_RDN));
582 rdnCreate(dpn->dpn.rdn);
583 }
584 } /* creating CE_DistributionPointName */
585
586 pt->reasonsPresent = randBool();
587 if(pt->reasonsPresent) {
588 CE_CrlDistReasonFlags *cdr = &pt->reasons;
589 /* set two random valid bits */
590 *cdr = 0;
591 *cdr |= 1 << genRand(0,7);
592 *cdr |= 1 << genRand(0,7);
593 }
594
595 /* make sure at least one present */
596 if((!pt->distPointName && !pt->reasonsPresent) || randBool()) {
597 pt->crlIssuer = (CE_GeneralNames *)malloc(sizeof(CE_GeneralNames));
598 memset(pt->crlIssuer, 0, sizeof(CE_GeneralNames));
599 genNamesCreate(pt->crlIssuer);
600 }
601 }
602 }
603
604 static unsigned cdpCompare(const void *pre, const void *post)
605 {
606 CE_CRLDistPointsSyntax *cpre = (CE_CRLDistPointsSyntax *)pre;
607 CE_CRLDistPointsSyntax *cpost = (CE_CRLDistPointsSyntax *)post;
608
609 if(cpre->numDistPoints != cpost->numDistPoints) {
610 printf("***CE_CRLDistPointsSyntax.numDistPoints miscompare\n");
611 return 1;
612 }
613 unsigned rtn = 0;
614 for(unsigned dex=0; dex<cpre->numDistPoints; dex++) {
615 CE_CRLDistributionPoint *ptpre = &cpre->distPoints[dex];
616 CE_CRLDistributionPoint *ptpost = &cpost->distPoints[dex];
617
618 if(ptpre->distPointName) {
619 if(ptpost->distPointName == NULL) {
620 printf("***NULL distPointName post decode\n");
621 rtn++;
622 goto checkReason;
623 }
624 CE_DistributionPointName *dpnpre = ptpre->distPointName;
625 CE_DistributionPointName *dpnpost = ptpost->distPointName;
626 if(dpnpre->nameType != dpnpost->nameType) {
627 printf("***CE_DistributionPointName.nameType miscompare\n");
628 rtn++;
629 goto checkReason;
630 }
631 if(dpnpre->nameType == CE_CDNT_FullName) {
632 rtn += genNamesCompare(dpnpre->dpn.fullName, dpnpost->dpn.fullName);
633 }
634 else {
635 rtn += rdnCompare(dpnpre->dpn.rdn, dpnpost->dpn.rdn);
636 }
637
638 }
639 else if(ptpost->distPointName != NULL) {
640 printf("***NON NULL distPointName post decode\n");
641 rtn++;
642 }
643
644 checkReason:
645 if(ptpre->reasons != ptpost->reasons) {
646 printf("***CE_CRLDistributionPoint.reasons miscompare\n");
647 rtn++;
648 }
649
650 if(ptpre->crlIssuer) {
651 if(ptpost->crlIssuer == NULL) {
652 printf("***NULL crlIssuer post decode\n");
653 rtn++;
654 continue;
655 }
656 CE_GeneralNames *gnpre = ptpre->crlIssuer;
657 CE_GeneralNames *gnpost = ptpost->crlIssuer;
658 rtn += genNamesCompare(gnpre, gnpost);
659 }
660 else if(ptpost->crlIssuer != NULL) {
661 printf("***NON NULL crlIssuer post decode\n");
662 rtn++;
663 }
664 }
665 return rtn;
666 }
667
668 static void cdpFree(void *arg)
669 {
670 CE_CRLDistPointsSyntax *cdp = (CE_CRLDistPointsSyntax *)arg;
671 for(unsigned dex=0; dex<cdp->numDistPoints; dex++) {
672 CE_CRLDistributionPoint *pt = &cdp->distPoints[dex];
673 if(pt->distPointName) {
674 CE_DistributionPointName *dpn = pt->distPointName;
675 if(dpn->nameType == CE_CDNT_FullName) {
676 genNamesFree(dpn->dpn.fullName);
677 free(dpn->dpn.fullName);
678 }
679 else {
680 rdnFree(dpn->dpn.rdn);
681 free(dpn->dpn.rdn);
682 }
683 free(dpn);
684 }
685
686 if(pt->crlIssuer) {
687 genNamesFree(pt->crlIssuer);
688 free(pt->crlIssuer);
689 }
690 }
691 free(cdp->distPoints);
692 }
693
694 #pragma mark --- CE_AuthorityKeyID ---
695 static void authKeyIdCreate(void *arg)
696 {
697 CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)arg;
698
699 /* all three fields optional */
700
701 akid->keyIdentifierPresent = randBool();
702 if(akid->keyIdentifierPresent) {
703 randData(&akid->keyIdentifier, 16);
704 }
705
706 akid->generalNamesPresent = randBool();
707 if(akid->generalNamesPresent) {
708 akid->generalNames =
709 (CE_GeneralNames *)malloc(sizeof(CE_GeneralNames));
710 memset(akid->generalNames, 0, sizeof(CE_GeneralNames));
711 genNamesCreate(akid->generalNames);
712 }
713
714 if(!akid->keyIdentifierPresent & !akid->generalNamesPresent) {
715 /* force at least one to be present */
716 akid->serialNumberPresent = CSSM_TRUE;
717 }
718 else {
719 akid->serialNumberPresent = randBool();
720 }
721 if(akid->serialNumberPresent) {
722 randData(&akid->serialNumber, 16);
723 }
724
725 }
726
727 static unsigned authKeyIdCompare(const void *pre, const void *post)
728 {
729 CE_AuthorityKeyID *akpre = (CE_AuthorityKeyID *)pre;
730 CE_AuthorityKeyID *akpost = (CE_AuthorityKeyID *)post;
731 unsigned rtn = 0;
732
733 if(compBool(akpre->keyIdentifierPresent, akpost->keyIdentifierPresent,
734 "CE_AuthorityKeyID.keyIdentifierPresent")) {
735 rtn++;
736 }
737 else if(akpre->keyIdentifierPresent) {
738 rtn += compCssmData(akpre->keyIdentifier,
739 akpost->keyIdentifier, "CE_AuthorityKeyID.keyIdentifier");
740 }
741
742 if(compBool(akpre->generalNamesPresent, akpost->generalNamesPresent,
743 "CE_AuthorityKeyID.generalNamesPresent")) {
744 rtn++;
745 }
746 else if(akpre->generalNamesPresent) {
747 rtn += genNamesCompare(akpre->generalNames,
748 akpost->generalNames);
749 }
750
751 if(compBool(akpre->serialNumberPresent, akpost->serialNumberPresent,
752 "CE_AuthorityKeyID.serialNumberPresent")) {
753 rtn++;
754 }
755 else if(akpre->serialNumberPresent) {
756 rtn += compCssmData(akpre->serialNumber,
757 akpost->serialNumber, "CE_AuthorityKeyID.serialNumber");
758 }
759 return rtn;
760 }
761
762 static void authKeyIdFree(void *arg)
763 {
764 CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)arg;
765
766 if(akid->keyIdentifier.Data) {
767 free(akid->keyIdentifier.Data);
768 }
769 if(akid->generalNames) {
770 genNamesFree(akid->generalNames); // genNamesCreate mallocd
771 free(akid->generalNames); // we mallocd
772 }
773 if(akid->serialNumber.Data) {
774 free(akid->serialNumber.Data);
775 }
776 }
777
778 #pragma mark --- CE_CertPolicies ---
779
780 /* random OIDs, pick 1..NUM_CP_OIDS */
781 static CSSM_OID cpOids[] =
782 {
783 CSSMOID_EmailAddress,
784 CSSMOID_UnstructuredName,
785 CSSMOID_ContentType,
786 CSSMOID_MessageDigest
787 };
788 #define NUM_CP_OIDS 4
789
790 /* CPS strings, pick one of NUM_CPS_STR */
791 static char *someCPSs[] =
792 {
793 (char *)"http://www.apple.com",
794 (char *)"https://cdnow.com",
795 (char *)"ftp:backwards.com"
796 };
797 #define NUM_CPS_STR 3
798
799 /* make these looks like real sequences */
800 static uint8 someUnotice[] = {0x30, 0x03, BER_TAG_BOOLEAN, 1, 0xff};
801 static uint8 someOtherData[] = {0x30, 0x02, BER_TAG_NULL, 0};
802
803 static void cpCreate(void *arg)
804 {
805 CE_CertPolicies *cp = (CE_CertPolicies *)arg;
806 cp->numPolicies = genRand(1,3);
807 //cp->numPolicies = 1;
808 unsigned len = sizeof(CE_PolicyInformation) * cp->numPolicies;
809 cp->policies = (CE_PolicyInformation *)malloc(len);
810 memset(cp->policies, 0, len);
811
812 for(unsigned polDex=0; polDex<cp->numPolicies; polDex++) {
813 CE_PolicyInformation *pi = &cp->policies[polDex];
814 unsigned die = genRand(1, NUM_CP_OIDS);
815 pi->certPolicyId = cpOids[die - 1];
816 unsigned numQual = genRand(1,3);
817 pi->numPolicyQualifiers = numQual;
818 len = sizeof(CE_PolicyQualifierInfo) * numQual;
819 pi->policyQualifiers = (CE_PolicyQualifierInfo *)
820 malloc(len);
821 memset(pi->policyQualifiers, 0, len);
822 for(unsigned cpiDex=0; cpiDex<numQual; cpiDex++) {
823 CE_PolicyQualifierInfo *qi =
824 &pi->policyQualifiers[cpiDex];
825 if(randBool()) {
826 qi->policyQualifierId = CSSMOID_QT_CPS;
827 die = genRand(1, NUM_CPS_STR);
828 qi->qualifier.Data = (uint8 *)someCPSs[die - 1];
829 qi->qualifier.Length = strlen((char *)qi->qualifier.Data);
830 }
831 else {
832 qi->policyQualifierId = CSSMOID_QT_UNOTICE;
833 if(randBool()) {
834 qi->qualifier.Data = someUnotice;
835 qi->qualifier.Length = 5;
836 }
837 else {
838 qi->qualifier.Data = someOtherData;
839 qi->qualifier.Length = 4;
840 }
841 }
842 }
843 }
844 }
845
846 static unsigned cpCompare(const void *pre, const void *post)
847 {
848 CE_CertPolicies *cppre = (CE_CertPolicies *)pre;
849 CE_CertPolicies *cppost = (CE_CertPolicies *)post;
850
851 if(cppre->numPolicies != cppost->numPolicies) {
852 printf("CE_CertPolicies.numPolicies mismatch\n");
853 return 1;
854 }
855 unsigned rtn = 0;
856 for(unsigned polDex=0; polDex<cppre->numPolicies; polDex++) {
857 CE_PolicyInformation *pipre = &cppre->policies[polDex];
858 CE_PolicyInformation *pipost = &cppost->policies[polDex];
859 rtn += compCssmData(pipre->certPolicyId, pipost->certPolicyId,
860 "CE_PolicyInformation.certPolicyId");
861 if(pipre->numPolicyQualifiers != pipost->numPolicyQualifiers) {
862 printf("CE_PolicyInformation.CE_PolicyInformation mismatch\n");
863 rtn++;
864 continue;
865 }
866
867 for(unsigned qiDex=0; qiDex<pipre->numPolicyQualifiers; qiDex++) {
868 CE_PolicyQualifierInfo *qipre = &pipre->policyQualifiers[qiDex];
869 CE_PolicyQualifierInfo *qipost = &pipost->policyQualifiers[qiDex];
870 rtn += compCssmData(qipre->policyQualifierId,
871 qipost->policyQualifierId,
872 "CE_PolicyQualifierInfo.policyQualifierId");
873 rtn += compCssmData(qipre->qualifier,
874 qipost->qualifier,
875 "CE_PolicyQualifierInfo.qualifier");
876 }
877 }
878 return rtn;
879 }
880
881 static void cpFree(void *arg)
882 {
883 CE_CertPolicies *cp = (CE_CertPolicies *)arg;
884 for(unsigned polDex=0; polDex<cp->numPolicies; polDex++) {
885 CE_PolicyInformation *pi = &cp->policies[polDex];
886 free(pi->policyQualifiers);
887 }
888 free(cp->policies);
889 }
890
891 #pragma mark --- CE_AuthorityInfoAccess ---
892
893 /* random OIDs, pick 1..NUM_AI_OIDS */
894 static CSSM_OID aiOids[] =
895 {
896 CSSMOID_AD_OCSP,
897 CSSMOID_AD_CA_ISSUERS,
898 CSSMOID_AD_TIME_STAMPING,
899 CSSMOID_AD_CA_REPOSITORY
900 };
901 #define NUM_AI_OIDS 4
902
903 static void aiaCreate(void *arg)
904 {
905 CE_AuthorityInfoAccess *aia = (CE_AuthorityInfoAccess *)arg;
906 aia->numAccessDescriptions = genRand(1,3);
907 unsigned len = aia->numAccessDescriptions * sizeof(CE_AccessDescription);
908 aia->accessDescriptions = (CE_AccessDescription *)malloc(len);
909 memset(aia->accessDescriptions, 0, len);
910
911 for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) {
912 CE_AccessDescription *ad = &aia->accessDescriptions[dex];
913 int die = genRand(1, NUM_AI_OIDS);
914 ad->accessMethod = aiOids[die - 1];
915 genNameCreate(&ad->accessLocation);
916 }
917 }
918
919 static unsigned aiaCompare(const void *pre, const void *post)
920 {
921 CE_AuthorityInfoAccess *apre = (CE_AuthorityInfoAccess *)pre;
922 CE_AuthorityInfoAccess *apost = (CE_AuthorityInfoAccess *)post;
923 unsigned rtn = 0;
924
925 if(apre->numAccessDescriptions != apost->numAccessDescriptions) {
926 printf("***CE_AuthorityInfoAccess.numAccessDescriptions miscompare\n");
927 return 1;
928 }
929 for(unsigned dex=0; dex<apre->numAccessDescriptions; dex++) {
930 CE_AccessDescription *adPre = &apre->accessDescriptions[dex];
931 CE_AccessDescription *adPost = &apost->accessDescriptions[dex];
932 if(compCssmData(adPre->accessMethod, adPost->accessMethod,
933 "CE_AccessDescription.accessMethod")) {
934 rtn++;
935 }
936 rtn += genNameCompare(&adPre->accessLocation, &adPost->accessLocation);
937 }
938 return rtn;
939 }
940
941 static void aiaFree(void *arg)
942 {
943 CE_AuthorityInfoAccess *aia = (CE_AuthorityInfoAccess *)arg;
944 for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) {
945 CE_AccessDescription *ad = &aia->accessDescriptions[dex];
946 genNameFree(&ad->accessLocation);
947 }
948 free(aia->accessDescriptions);
949 }
950
951 #pragma mark --- CE_QC_Statements ---
952
953 /* a static array of CE_QC_Statement.statementId */
954 static const CSSM_OID qcsOids[] = {
955 CSSMOID_OID_QCS_SYNTAX_V1,
956 CSSMOID_OID_QCS_SYNTAX_V2,
957 CSSMOID_ETSI_QCS_QC_COMPLIANCE,
958 };
959 #define NUM_QCS_OIDS 3
960 #define WHICH_QCS_V2 1
961
962 static void qcsCreate(void *arg)
963 {
964 CE_QC_Statements *qcss = (CE_QC_Statements *)arg;
965 //unsigned numQcs = genRand(1,3);
966 unsigned numQcs = 1;
967 qcss->numQCStatements = numQcs;
968 qcss->qcStatements = (CE_QC_Statement *)malloc(numQcs * sizeof(CE_QC_Statement));
969 memset(qcss->qcStatements, 0, numQcs * sizeof(CE_QC_Statement));
970
971 for(unsigned dex=0; dex<numQcs; dex++) {
972 CE_QC_Statement *qcs = &qcss->qcStatements[dex];
973 unsigned whichOid = genRand(0, NUM_QCS_OIDS-1);
974 qcs->statementId = qcsOids[whichOid];
975
976 /* three legal combos of (semanticsInfo, otherInfo), constrained by whichOid */
977 unsigned coin = genRand(1, 2);
978 switch(coin) {
979 case 1:
980 /* nothing */
981 break;
982 case 2:
983 {
984 /*
985 * CSSMOID_OID_QCS_SYNTAX_V2 --> semanticsInfo
986 * other --> otherInfo
987 */
988 if(whichOid == WHICH_QCS_V2) {
989 CE_SemanticsInformation *si = (CE_SemanticsInformation *)malloc(
990 sizeof(CE_SemanticsInformation));
991 qcs->semanticsInfo = si;
992 memset(si, 0, sizeof(CE_SemanticsInformation));
993
994 /* flip a coin; heads --> semanticsIdentifier */
995 coin = genRand(1, 2);
996 if(coin == 2) {
997 si->semanticsIdentifier = (CSSM_OID *)malloc(sizeof(CSSM_OID));
998 *si->semanticsIdentifier = qcsOids[0];
999 }
1000
1001 /* flip a coin; heads --> nameRegistrationAuthorities */
1002 /* also gen this one if semanticsInfo is empty */
1003 coin = genRand(1, 2);
1004 if((coin == 2) || (si->semanticsIdentifier == NULL)) {
1005 si->nameRegistrationAuthorities = (CE_NameRegistrationAuthorities *)
1006 malloc(sizeof(CE_NameRegistrationAuthorities));
1007 genNamesCreate(si->nameRegistrationAuthorities);
1008 }
1009 }
1010 else {
1011 /* ASN_ANY - just take an encoded NULL */
1012 CSSM_DATA *otherInfo = (CSSM_DATA *)malloc(sizeof(CSSM_DATA));
1013 otherInfo->Data = (uint8 *)malloc(2);
1014 otherInfo->Data[0] = 5;
1015 otherInfo->Data[1] = 0;
1016 otherInfo->Length = 2;
1017 qcs->otherInfo = otherInfo;
1018 }
1019 break;
1020 }
1021 }
1022 }
1023 }
1024
1025 static unsigned qcsCompare(const void *pre, const void *post)
1026 {
1027 CE_QC_Statements *qpre = (CE_QC_Statements *)pre;
1028 CE_QC_Statements *qpost = (CE_QC_Statements *)post;
1029 uint32 numQcs = qpre->numQCStatements;
1030 if(numQcs != qpost->numQCStatements) {
1031 printf("***numQCStatements miscompare\n");
1032 return 1;
1033 }
1034
1035 unsigned rtn = 0;
1036 for(unsigned dex=0; dex<numQcs; dex++) {
1037 CE_QC_Statement *qcsPre = &qpre->qcStatements[dex];
1038 CE_QC_Statement *qcsPost = &qpost->qcStatements[dex];
1039 if(compCssmData(qcsPre->statementId, qcsPost->statementId,
1040 "CE_QC_Statement.statementId")) {
1041 rtn++;
1042 }
1043 if(qcsPre->semanticsInfo) {
1044 if(qcsPost->semanticsInfo == NULL) {
1045 printf("***semanticsInfo in pre but not in post\n");
1046 rtn++;
1047 }
1048 else {
1049 CE_SemanticsInformation *siPre = qcsPre->semanticsInfo;
1050 CE_SemanticsInformation *siPost = qcsPost->semanticsInfo;
1051 if((siPre->semanticsIdentifier == NULL) != (siPost->semanticsIdentifier == NULL)) {
1052 printf("***mismatch in presence of semanticsIdentifier\n");
1053 rtn++;
1054 }
1055 else if(siPre->semanticsIdentifier) {
1056 if(compCssmData(*siPre->semanticsIdentifier, *siPost->semanticsIdentifier,
1057 "CE_SemanticsInformation.semanticsIdentifier")) {
1058 rtn++;
1059 }
1060 }
1061 if((siPre->nameRegistrationAuthorities == NULL) !=
1062 (siPost->nameRegistrationAuthorities == NULL)) {
1063 printf("***mismatch in presence of nameRegistrationAuthorities\n");
1064 rtn++;
1065 }
1066 else if(siPre->nameRegistrationAuthorities) {
1067 rtn += genNamesCompare(siPre->nameRegistrationAuthorities,
1068 siPost->nameRegistrationAuthorities);
1069 }
1070 }
1071 }
1072 else if(qcsPost->semanticsInfo != NULL) {
1073 printf("***semanticsInfo in post but not in pre\n");
1074 rtn++;
1075 }
1076 if(qcsPre->otherInfo) {
1077 if(qcsPost->otherInfo == NULL) {
1078 printf("***otherInfo in pre but not in post\n");
1079 rtn++;
1080 }
1081 else {
1082 if(compCssmData(*qcsPre->otherInfo, *qcsPre->otherInfo,
1083 "CE_QC_Statement.otherInfo")) {
1084 rtn++;
1085 }
1086 }
1087 }
1088 else if(qcsPost->otherInfo != NULL) {
1089 printf("***otherInfo in post but not in pre\n");
1090 rtn++;
1091 }
1092 }
1093 return rtn;
1094 }
1095
1096 static void qcsFree(void *arg)
1097 {
1098 CE_QC_Statements *qcss = (CE_QC_Statements *)arg;
1099 uint32 numQcs = qcss->numQCStatements;
1100 for(unsigned dex=0; dex<numQcs; dex++) {
1101 CE_QC_Statement *qcs = &qcss->qcStatements[dex];
1102 if(qcs->semanticsInfo) {
1103 CE_SemanticsInformation *si = qcs->semanticsInfo;
1104 if(si->semanticsIdentifier) {
1105 free(si->semanticsIdentifier);
1106 }
1107 if(si->nameRegistrationAuthorities) {
1108 genNamesFree(si->nameRegistrationAuthorities);
1109 free(si->nameRegistrationAuthorities);
1110 }
1111 free(qcs->semanticsInfo);
1112 }
1113 if(qcs->otherInfo) {
1114 free(qcs->otherInfo->Data);
1115 free(qcs->otherInfo);
1116 }
1117 }
1118 free(qcss->qcStatements);
1119 }
1120
1121 #pragma mark --- test definitions ---
1122
1123 /*
1124 * Define one extension test.
1125 */
1126
1127 /*
1128 * Cook up this extension with random, reasonable values.
1129 * Incoming pointer refers to extension-specific C struct, mallocd
1130 * and zeroed by main test routine.
1131 */
1132 typedef void (*extenCreateFcn)(void *arg);
1133
1134 /*
1135 * Compare two instances of this extension. Return number of
1136 * compare errors.
1137 */
1138 typedef unsigned (*extenCompareFcn)(
1139 const void *preEncode,
1140 const void *postEncode);
1141
1142 /*
1143 * Free struct components mallocd in extenCreateFcn. Do not free
1144 * the outer struct.
1145 */
1146 typedef void (*extenFreeFcn)(void *arg);
1147
1148 typedef struct {
1149 /* three extension-specific functions */
1150 extenCreateFcn createFcn;
1151 extenCompareFcn compareFcn;
1152 extenFreeFcn freeFcn;
1153
1154 /* size of C struct passed to all three functions */
1155 unsigned extenSize;
1156
1157 /* the OID for this extension */
1158 CSSM_OID extenOid;
1159
1160 /* description for error logging and blob writing */
1161 const char *extenDescr;
1162
1163 /* command-line letter for this one */
1164 char extenLetter;
1165
1166 } ExtenTest;
1167
1168 /* empty freeFcn means no extension-specific resources to free */
1169 #define NO_FREE NULL
1170
1171 static ExtenTest extenTests[] = {
1172 { kuCreate, kuCompare, NO_FREE,
1173 sizeof(CE_KeyUsage), CSSMOID_KeyUsage,
1174 "KeyUsage", 'k' },
1175 { bcCreate, bcCompare, NO_FREE,
1176 sizeof(CE_BasicConstraints), CSSMOID_BasicConstraints,
1177 "BasicConstraints", 'b' },
1178 { ekuCreate, ekuCompare, NO_FREE,
1179 sizeof(CE_ExtendedKeyUsage), CSSMOID_ExtendedKeyUsage,
1180 "ExtendedKeyUsage", 'x' },
1181 { skidCreate, skidCompare, skidFree,
1182 sizeof(CSSM_DATA), CSSMOID_SubjectKeyIdentifier,
1183 "SubjectKeyID", 's' },
1184 { authKeyIdCreate, authKeyIdCompare, authKeyIdFree,
1185 sizeof(CE_AuthorityKeyID), CSSMOID_AuthorityKeyIdentifier,
1186 "AuthorityKeyID", 'a' },
1187 { genNamesCreate, genNamesCompare, genNamesFree,
1188 sizeof(CE_GeneralNames), CSSMOID_SubjectAltName,
1189 "SubjectAltName", 't' },
1190 { genNamesCreate, genNamesCompare, genNamesFree,
1191 sizeof(CE_GeneralNames), CSSMOID_IssuerAltName,
1192 "IssuerAltName", 'i' },
1193 { nctCreate, nctCompare, NO_FREE,
1194 sizeof(CE_NetscapeCertType), CSSMOID_NetscapeCertType,
1195 "NetscapeCertType", 'n' },
1196 { cdpCreate, cdpCompare, cdpFree,
1197 sizeof(CE_CRLDistPointsSyntax), CSSMOID_CrlDistributionPoints,
1198 "CRLDistPoints", 'p' },
1199 { cpCreate, cpCompare, cpFree,
1200 sizeof(CE_CertPolicies), CSSMOID_CertificatePolicies,
1201 "CertPolicies", 'c' },
1202 { aiaCreate, aiaCompare, aiaFree,
1203 sizeof(CE_AuthorityInfoAccess), CSSMOID_AuthorityInfoAccess,
1204 "AuthorityInfoAccess", 'A' },
1205 { aiaCreate, aiaCompare, aiaFree,
1206 sizeof(CE_AuthorityInfoAccess), CSSMOID_SubjectInfoAccess,
1207 "SubjectInfoAccess", 'S' },
1208 { qcsCreate, qcsCompare, qcsFree,
1209 sizeof(CE_QC_Statements), CSSMOID_QC_Statements,
1210 "QualifiedCertStatements", 'q' },
1211 };
1212
1213 #define NUM_EXTEN_TESTS (sizeof(extenTests) / sizeof(ExtenTest))
1214
1215 static void printExten(
1216 CSSM_X509_EXTENSION &extn,
1217 bool preEncode,
1218 OidParser &parser)
1219 {
1220 CSSM_FIELD field;
1221 field.FieldOid = extn.extnId;
1222 field.FieldValue.Data = (uint8 *)&extn;
1223 field.FieldValue.Length = sizeof(CSSM_X509_EXTENSION);
1224 printf("=== %s:\n", preEncode ? "PRE-ENCODE" : "POST-DECODE" );
1225 printCertField(field, parser, CSSM_TRUE);
1226 }
1227
1228 static int doTest(
1229 CSSM_CL_HANDLE clHand,
1230 CSSM_CSP_HANDLE cspHand,
1231 ExtenTest &extenTest,
1232 bool writeBlobs,
1233 const char *constFileName, // all blobs to this file if non-NULL
1234 bool displayExtens,
1235 OidParser &parser)
1236 {
1237 /*
1238 * 1. Cook up a random and reasonable instance of the C struct
1239 * associated with this extension.
1240 */
1241 void *preEncode = CSSM_MALLOC(extenTest.extenSize);
1242 memset(preEncode, 0, extenTest.extenSize);
1243 extenTest.createFcn(preEncode);
1244
1245 /*
1246 * Cook up the associated CSSM_X509_EXTENSION.
1247 */
1248 CSSM_X509_EXTENSION extnPre;
1249
1250 extnPre.extnId = extenTest.extenOid;
1251 extnPre.critical = randBool();
1252 extnPre.format = CSSM_X509_DATAFORMAT_PARSED;
1253 extnPre.value.parsedValue = preEncode;
1254 extnPre.BERvalue.Data = NULL;
1255 extnPre.BERvalue.Length = 0;
1256
1257 /* encode the extension in a TBSCert */
1258 CSSM_DATA_PTR rawCert = CB_MakeCertTemplate(clHand,
1259 0x12345678, // serial number
1260 dummyName,
1261 dummyName,
1262 notBefore,
1263 notAfter,
1264 &subjPubKey,
1265 SIG_ALG,
1266 NULL, // subjUniqueId
1267 NULL, // issuerUniqueId
1268 &extnPre, // extensions
1269 1); // numExtensions
1270 if(rawCert == NULL) {
1271 printf("Error generating template; aborting.\n");
1272 /* show what we tried to encode */
1273 printExten(extnPre, true, parser);
1274 return 1;
1275 }
1276
1277 /* sign the cert */
1278 CSSM_DATA signedCert = {0, NULL};
1279 CSSM_CC_HANDLE sigHand;
1280 CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
1281 SIG_ALG,
1282 NULL, // no passphrase for now
1283 &subjPrivKey,
1284 &sigHand);
1285 if(crtn) {
1286 printError("CreateSignatureContext", crtn);
1287 return 1;
1288 }
1289
1290 crtn = CSSM_CL_CertSign(clHand,
1291 sigHand,
1292 rawCert, // CertToBeSigned
1293 NULL, // SignScope per spec
1294 0, // ScopeSize per spec
1295 &signedCert);
1296 if(crtn) {
1297 printError("CSSM_CL_CertSign", crtn);
1298 /* show what we tried to encode */
1299 printExten(extnPre, true, parser);
1300 return 1;
1301 }
1302 CSSM_DeleteContext(sigHand);
1303
1304 if(writeBlobs) {
1305 char fileName[200];
1306 if(constFileName) {
1307 strcpy(fileName, constFileName);
1308 }
1309 else {
1310 sprintf(fileName, "%scert.der", extenTest.extenDescr);
1311 }
1312 writeFile(fileName, signedCert.Data, signedCert.Length);
1313 printf("...wrote %lu bytes to %s\n", signedCert.Length, fileName);
1314 }
1315
1316 /* snag the same extension from the encoded cert */
1317 CSSM_DATA_PTR postField;
1318 CSSM_HANDLE resultHand;
1319 uint32 numFields;
1320
1321 crtn = CSSM_CL_CertGetFirstFieldValue(clHand,
1322 &signedCert,
1323 &extenTest.extenOid,
1324 &resultHand,
1325 &numFields,
1326 &postField);
1327 if(crtn) {
1328 printf("****Extension field not found on decode for %s\n",
1329 extenTest.extenDescr);
1330 printError("CSSM_CL_CertGetFirstFieldValue", crtn);
1331
1332 /* show what we tried to encode and decode */
1333 printExten(extnPre, true, parser);
1334 return 1;
1335 }
1336
1337 if(numFields != 1) {
1338 printf("****GetFirstFieldValue: expect 1 value, got %u\n",
1339 (unsigned)numFields);
1340 return 1;
1341 }
1342 CSSM_CL_CertAbortQuery(clHand, resultHand);
1343
1344 /* verify the fields we generated */
1345 CSSM_X509_EXTENSION *extnPost = (CSSM_X509_EXTENSION *)postField->Data;
1346 if((extnPost == NULL) ||
1347 (postField->Length != sizeof(CSSM_X509_EXTENSION))) {
1348 printf("***Malformed CSSM_X509_EXTENSION (1) after decode\n");
1349 return 1;
1350 }
1351 int rtn = 0;
1352 rtn += compBool(extnPre.critical, extnPost->critical,
1353 "CSSM_X509_EXTENSION.critical");
1354 rtn += compCssmData(extnPre.extnId, extnPost->extnId,
1355 "CSSM_X509_EXTENSION.extnId");
1356
1357 if(extnPost->format != CSSM_X509_DATAFORMAT_PARSED) {
1358 printf("***Expected CSSM_X509_DATAFORMAT_PARSED (%x(x), got %x(x)\n",
1359 CSSM_X509_DATAFORMAT_PARSED, extnPost->format);
1360 }
1361 if(extnPost->value.parsedValue == NULL) {
1362 printf("***no parsedValue pointer!\n");
1363 return 1;
1364 }
1365
1366 /* down to extension-specific compare */
1367 rtn += extenTest.compareFcn(preEncode, extnPost->value.parsedValue);
1368
1369 if(rtn) {
1370 /* print preencode only on error */
1371 printExten(extnPre, true, parser);
1372 }
1373 if(displayExtens || rtn) {
1374 printExten(*extnPost, false, parser);
1375 }
1376
1377 /* free the allocated data */
1378 if(extenTest.freeFcn) {
1379 extenTest.freeFcn(preEncode);
1380 }
1381 CSSM_CL_FreeFieldValue(clHand, &extenTest.extenOid, postField);
1382 CSSM_FREE(rawCert->Data);
1383 CSSM_FREE(rawCert);
1384 CSSM_FREE(signedCert.Data);
1385 CSSM_FREE(preEncode);
1386 return rtn;
1387 }
1388
1389 static void doPause(bool pause)
1390 {
1391 if(!pause) {
1392 return;
1393 }
1394 fpurge(stdin);
1395 printf("CR to continue ");
1396 getchar();
1397 }
1398
1399 int main(int argc, char **argv)
1400 {
1401 CSSM_CL_HANDLE clHand;
1402 CSSM_CSP_HANDLE cspHand;
1403 CSSM_RETURN crtn;
1404 int arg;
1405 int rtn;
1406 OidParser parser;
1407 char *argp;
1408 unsigned i;
1409
1410 /* user-specificied params */
1411 unsigned minExtenNum = 0;
1412 unsigned maxExtenNum = NUM_EXTEN_TESTS-1;
1413 bool writeBlobs = false;
1414 bool displayExtens = false;
1415 bool quiet = false;
1416 unsigned loops = LOOPS_DEF;
1417 bool pauseLoop = false;
1418 bool pauseCert = false;
1419 const char *constFileName = NULL;
1420
1421 for(arg=1; arg<argc; arg++) {
1422 argp = argv[arg];
1423 switch(argp[0]) {
1424 case 'w':
1425 writeBlobs = true;
1426 break;
1427 case 'd':
1428 displayExtens = true;
1429 break;
1430 case 'q':
1431 quiet = true;
1432 break;
1433 case 'p':
1434 pauseLoop = true;
1435 break;
1436 case 'P':
1437 pauseCert = true;
1438 break;
1439 case 'l':
1440 loops = atoi(&argp[2]);
1441 break;
1442 case 'f':
1443 constFileName = &argp[2];
1444 break;
1445 case 'e':
1446 if(argp[1] != '=') {
1447 usage(argv);
1448 }
1449 /* scan thru test array looking for epecified extension */
1450 for(i=0; i<NUM_EXTEN_TESTS; i++) {
1451 if(extenTests[i].extenLetter == argp[2]) {
1452 minExtenNum = maxExtenNum = i;
1453 break;
1454 }
1455 }
1456 if(i == NUM_EXTEN_TESTS) {
1457 usage(argv);
1458 }
1459 break;
1460 default:
1461 usage(argv);
1462 }
1463 }
1464
1465
1466 /* common setup */
1467 clHand = clStartup();
1468 if(clHand == 0) {
1469 return 0;
1470 }
1471 cspHand = cspStartup();
1472 if(cspHand == 0) {
1473 return 0;
1474 }
1475
1476 printf("Starting extenTest; args: ");
1477 for(i=1; i<(unsigned)argc; i++) {
1478 printf("%s ", argv[i]);
1479 }
1480 printf("\n");
1481
1482 /* one common key pair - we're definitely not testing this */
1483 crtn = cspGenKeyPair(cspHand,
1484 KEY_ALG,
1485 SUBJ_KEY_LABEL,
1486 strlen(SUBJ_KEY_LABEL),
1487 KEY_SIZE_BITS,
1488 &subjPubKey,
1489 CSSM_FALSE, // pubIsRef - should work both ways, but not yet
1490 CSSM_KEYUSE_VERIFY,
1491 CSSM_KEYBLOB_RAW_FORMAT_NONE,
1492 &subjPrivKey,
1493 CSSM_TRUE, // privIsRef - doesn't matter
1494 CSSM_KEYUSE_SIGN,
1495 CSSM_KEYBLOB_RAW_FORMAT_NONE,
1496 CSSM_FALSE);
1497 if(crtn) {
1498 exit(1);
1499 }
1500
1501 /* common issuer/subject - not testing this */
1502 dummyName = CB_BuildX509Name(dummyRdn, NUM_DUMMY_NAMES);
1503 if(dummyName == NULL) {
1504 printf("CB_BuildX509Name failure");
1505 exit(1);
1506 }
1507
1508 /* not before/after in generalized time format */
1509 notBefore = CB_BuildX509Time(0);
1510 notAfter = CB_BuildX509Time(10000);
1511
1512 for(unsigned loop=0; loop<loops; loop++) {
1513 if(!quiet) {
1514 printf("...loop %u\n", loop);
1515 }
1516 for(unsigned extenDex=minExtenNum; extenDex<=maxExtenNum; extenDex++) {
1517 rtn = doTest(clHand, cspHand, extenTests[extenDex],
1518 writeBlobs, constFileName, displayExtens, parser);
1519 if(rtn) {
1520 break;
1521 }
1522 doPause(pauseCert);
1523 }
1524 if(rtn) {
1525 break;
1526 }
1527 doPause(pauseLoop);
1528 }
1529
1530 if(rtn) {
1531 printf("***%s FAILED\n", argv[0]);
1532 }
1533 else if(!quiet) {
1534 printf("...%s passed\n", argv[0]);
1535 }
1536
1537
1538 /* cleanup */
1539 CB_FreeX509Name(dummyName);
1540 CB_FreeX509Time(notBefore);
1541 CB_FreeX509Time(notAfter);
1542 CSSM_ModuleDetach(cspHand);
1543 CSSM_ModuleDetach(clHand);
1544 return 0;
1545 }
1546