2 * extenTestTp - verify encoding and decoding of extensions using
3 * CSSM_TP_SubmitCredRequest() to create the certs.
6 #include <security_cdsa_utils/cuFileIo.h>
7 #include <clAppUtils/CertBuilderApp.h>
8 #include <utilLib/common.h>
9 #include <utilLib/cspwrap.h>
10 #include <clAppUtils/clutils.h>
11 #include <security_cdsa_utils/cuPrintCert.h>
12 #include <security_cdsa_utils/cuOidParser.h>
17 #include <Security/cssm.h>
18 #include <Security/x509defs.h>
19 #include <Security/oidsattr.h>
20 #include <Security/oidscert.h>
21 #include <Security/oidsalg.h>
22 #include <Security/certextensions.h>
23 #include <Security/cssmapple.h>
25 #define KEY_ALG CSSM_ALGID_RSA
26 #define SIG_ALG CSSM_ALGID_SHA1WithRSA
27 #define SIG_OID CSSMOID_SHA1WithRSA
28 #define KEY_SIZE_BITS CSP_RSA_KEY_SIZE_DEFAULT
29 #define SUBJ_KEY_LABEL "subjectKey"
33 static void usage(char **argv
)
35 printf("Usage: %s [options]\n", argv
[0]);
37 printf(" e=extenSpec (default = all)\n");
38 printf(" k keyUsage\n");
39 printf(" b basicConstraints\n");
40 printf(" x extendedKeyUsage\n");
41 printf(" s subjectKeyId\n");
42 printf(" a authorityKeyId\n");
43 printf(" t SubjectAltName\n");
44 printf(" i IssuerAltName\n");
45 printf(" c certPolicies\n");
46 printf(" n netscapeCertType\n");
47 printf(" p CRLDistributionPoints\n");
48 printf(" A AuthorityInfoAccess\n");
49 printf(" S SubjectInfoAccess\n");
50 printf(" w(rite blobs)\n");
51 printf(" f=fileName (default is extension-specific file name)\n");
52 printf(" d(isplay certs)\n");
53 printf(" l=loops (default = %d)\n", LOOPS_DEF
);
54 printf(" p(ause on each loop)\n");
55 printf(" P(ause on each cert)\n");
59 /* subject and issuer - we aren't testing this */
60 CSSM_APPLE_TP_NAME_OID dummyRdn
[] =
62 { "Apple Computer", &CSSMOID_OrganizationName
},
63 { "Doug Mitchell", &CSSMOID_CommonName
}
65 #define NUM_DUMMY_NAMES (sizeof(dummyRdn) / sizeof(CB_NameOid))
68 * Static components we reuse for each encode/decode.
70 static CSSM_KEY subjPrivKey
;
71 static CSSM_KEY subjPubKey
;
73 static CSSM_BOOL
randBool()
75 unsigned r
= genRand(1, 0x10000000);
76 return (r
& 0x1) ? CSSM_TRUE
: CSSM_FALSE
;
79 /* Fill a CSSM_DATA with random data. Its referent is allocd with malloc. */
84 data
->Data
= (uint8
*)malloc(maxLen
);
85 simpleGenData(data
, 1, maxLen
);
89 * Various compare tests
99 printf("***Boolean miscompare on %s\n", desc
);
100 /* in case a CSSM_TRUE isn't exactly right... */
106 printf("*** post value is %d expected %d\n",
107 (int)post
, (int)pre
);
113 static int compCssmData(
118 if(appCompareCssmData(&d1
, &d2
)) {
121 printf("CSSM_DATA miscompare on %s\n", desc
);
125 #pragma mark ----- individual extension tests -----
127 #pragma mark --- CE_KeyUsage ---
128 static void kuCreate(void *arg
)
130 CE_KeyUsage
*ku
= (CE_KeyUsage
*)arg
;
132 /* set two random valid bits */
134 *ku
|= 1 << genRand(7, 15);
135 *ku
|= 1 << genRand(7, 15);
138 static unsigned kuCompare(const void *pre
, const void *post
)
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");
149 #pragma mark --- CE_BasicConstraints ---
150 static void bcCreate(void *arg
)
152 CE_BasicConstraints
*bc
= (CE_BasicConstraints
*)arg
;
154 bc
->pathLenConstraintPresent
= randBool();
155 if(bc
->pathLenConstraintPresent
) {
156 bc
->pathLenConstraint
= genRand(1,10);
160 static unsigned bcCompare(const void *pre
, const void *post
)
162 const CE_BasicConstraints
*bcpre
= (CE_BasicConstraints
*)pre
;
163 const CE_BasicConstraints
*bcpost
= (CE_BasicConstraints
*)post
;
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");
177 #pragma mark --- CE_SubjectKeyID ---
178 static void skidCreate(void *arg
)
180 CSSM_DATA_PTR skid
= (CSSM_DATA_PTR
)arg
;
184 static unsigned skidCompare(const void *pre
, const void *post
)
186 CSSM_DATA_PTR spre
= (CSSM_DATA_PTR
)pre
;
187 CSSM_DATA_PTR spost
= (CSSM_DATA_PTR
)post
;
188 return compCssmData(*spre
, *spost
, "SubjectKeyID");
191 static void skidFree(void *arg
)
193 CSSM_DATA_PTR skid
= (CSSM_DATA_PTR
)arg
;
197 #pragma mark --- CE_NetscapeCertType ---
198 static void nctCreate(void *arg
)
200 CE_NetscapeCertType
*nct
= (CE_NetscapeCertType
*)arg
;
202 /* set two random valid bits */
204 *nct
|= 1 << genRand(8, 15);
205 *nct
|= 1 << genRand(8, 15);
208 static unsigned nctCompare(const void *pre
, const void *post
)
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");
219 #pragma mark --- CE_ExtendedKeyUsage ---
221 /* a static array of meaningless OIDs, use 1.. NUM_SKU_OIDS */
222 CSSM_OID ekuOids
[] = {
225 CSSMOID_HoldInstructionCode
,
226 CSSMOID_InvalidityDate
228 #define NUM_SKU_OIDS 4
230 static void ekuCreate(void *arg
)
232 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)arg
;
233 eku
->numPurposes
= genRand(1, NUM_SKU_OIDS
);
234 eku
->purposes
= ekuOids
;
237 static unsigned ekuCompare(const void *pre
, const void *post
)
239 CE_ExtendedKeyUsage
*ekupre
= (CE_ExtendedKeyUsage
*)pre
;
240 CE_ExtendedKeyUsage
*ekupost
= (CE_ExtendedKeyUsage
*)post
;
242 if(ekupre
->numPurposes
!= ekupost
->numPurposes
) {
243 printf("CE_ExtendedKeyUsage.numPurposes miscompare\n");
247 for(unsigned dex
=0; dex
<ekupre
->numPurposes
; dex
++) {
248 rtn
+= compCssmData(ekupre
->purposes
[dex
],
249 ekupost
->purposes
[dex
], "CE_ExtendedKeyUsage.purposes");
255 #pragma mark --- general purpose X509 name generator ---
257 /* Attr/Value pairs, pick one of NUM_ATTR_STRINGS */
258 static char *attrStrings
[] = {
260 (char *)"anotherName",
261 (char *)"someOtherName"
263 #define NUM_ATTR_STRINGS 3
265 /* A/V type, pick one of NUM_ATTR_TYPES */
266 static CSSM_OID attrTypes
[] = {
269 CSSMOID_OrganizationName
,
272 #define NUM_ATTR_TYPES 4
274 /* A/V tag, pick one of NUM_ATTR_TAGS */
275 static char attrTags
[] = {
276 BER_TAG_PRINTABLE_STRING
,
280 #define NUM_ATTR_TAGS 3
282 static void rdnCreate(
283 CSSM_X509_RDN_PTR rdn
)
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
);
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];
306 static unsigned rdnCompare(
307 CSSM_X509_RDN_PTR rdn1
,
308 CSSM_X509_RDN_PTR rdn2
)
310 if(rdn1
->numberOfPairs
!= rdn2
->numberOfPairs
) {
311 printf("***Mismatch in numberOfPairs\n");
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");
324 if(compCssmData(p1
.type
, p2
.type
, "ATV.type")) {
327 if(compCssmData(p1
.value
, p2
.value
, "ATV.value")) {
335 CSSM_X509_RDN_PTR rdn
)
337 free(rdn
->AttributeTypeAndValue
);
340 static void x509NameCreate(
341 CSSM_X509_NAME_PTR x509Name
)
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
);
350 for(unsigned rdnDex
=0; rdnDex
<numRdns
; rdnDex
++) {
351 CSSM_X509_RDN
&rdn
= x509Name
->RelativeDistinguishedName
[rdnDex
];
356 static unsigned x509NameCompare(
357 const CSSM_X509_NAME_PTR n1
,
358 const CSSM_X509_NAME_PTR n2
)
360 if(n1
->numberOfRDNs
!= n2
->numberOfRDNs
) {
361 printf("***Mismatch in numberOfRDNs\n");
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
);
373 static void x509NameFree(
374 CSSM_X509_NAME_PTR n
)
376 for(unsigned rdnDex
=0; rdnDex
<n
->numberOfRDNs
; rdnDex
++) {
377 CSSM_X509_RDN
&rdn
= n
->RelativeDistinguishedName
[rdnDex
];
380 free(n
->RelativeDistinguishedName
);
383 #pragma mark --- general purpose GeneralNames generator ---
385 #define SOME_URL_1 (char *)"http://foo.bar.com"
386 #define SOME_URL_2 (char *)"http://bar.foo.com"
387 #define SOME_DNS_1 (char *)"Some DNS"
388 #define SOME_DNS_2 (char *)"Another DNS"
389 unsigned char someIpAdr_1
[] = {208, 161, 124, 209 };
390 unsigned char someIpAdr_2
[] = {10, 0, 61, 5};
392 static void genNameCreate(CE_GeneralName
*name
)
394 unsigned type
= genRand(1, 5);
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
);
406 name
->nameType
= GNT_RegisteredID
;
407 name
->berEncoded
= CSSM_FALSE
;
408 appCopyData(CSSMOID_SubjectDirectoryAttributes
.Data
,
409 CSSMOID_SubjectDirectoryAttributes
.Length
,
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
);
421 name
->nameType
= GNT_IPAddress
;
422 name
->berEncoded
= CSSM_FALSE
;
423 usrc
= randBool() ? someIpAdr_1
: someIpAdr_2
;
424 appCopyData(usrc
, 4, &name
->name
);
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
);
438 static void genNamesCreate(void *arg
)
440 CE_GeneralNames
*names
= (CE_GeneralNames
*)arg
;
441 names
->numNames
= genRand(1, 3);
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
));
448 for(unsigned i
=0; i
<names
->numNames
; i
++) {
449 CE_GeneralName
*name
= &names
->generalName
[i
];
454 static unsigned genNameCompare(
455 CE_GeneralName
*npre
,
456 CE_GeneralName
*npost
)
459 if(npre
->nameType
!= npost
->nameType
) {
460 printf("***CE_GeneralName.nameType miscompare\n");
463 if(compBool(npre
->berEncoded
, npost
->berEncoded
,
464 "CE_GeneralName.berEncoded")) {
468 /* nameType-specific compare */
469 switch(npre
->nameType
) {
471 rtn
+= compCssmData(npre
->name
, npost
->name
,
472 "CE_GeneralName.RFC822Name");
475 rtn
+= compCssmData(npre
->name
, npost
->name
,
476 "CE_GeneralName.DNSName");
479 rtn
+= compCssmData(npre
->name
, npost
->name
,
480 "CE_GeneralName.URI");
483 rtn
+= compCssmData(npre
->name
, npost
->name
,
484 "CE_GeneralName.RFIPAddressC822Name");
486 case GNT_RegisteredID
:
487 rtn
+= compCssmData(npre
->name
, npost
->name
,
488 "CE_GeneralName.RegisteredID");
490 case GNT_DirectoryName
:
491 rtn
+= x509NameCompare((CSSM_X509_NAME_PTR
)npre
->name
.Data
,
492 (CSSM_X509_NAME_PTR
)npost
->name
.Data
);
495 printf("****BRRZAP! genNamesCompare needs work\n");
501 static unsigned genNamesCompare(const void *pre
, const void *post
)
503 const CE_GeneralNames
*gnPre
= (CE_GeneralNames
*)pre
;
504 const CE_GeneralNames
*gnPost
= (CE_GeneralNames
*)post
;
507 if((gnPre
== NULL
) || (gnPost
== NULL
)) {
508 printf("***Bad GenNames pointer\n");
511 if(gnPre
->numNames
!= gnPost
->numNames
) {
512 printf("***CE_GeneralNames.numNames miscompare\n");
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
);
524 static void genNameFree(CE_GeneralName
*n
)
526 switch(n
->nameType
) {
527 case GNT_DirectoryName
:
528 x509NameFree((CSSM_X509_NAME_PTR
)n
->name
.Data
);
529 CSSM_FREE(n
->name
.Data
);
532 CSSM_FREE(n
->name
.Data
);
538 static void genNamesFree(void *arg
)
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
];
545 free(gn
->generalName
);
548 #pragma mark --- CE_CRLDistPointsSyntax ---
549 static void cdpCreate(void *arg
)
551 CE_CRLDistPointsSyntax
*cdp
= (CE_CRLDistPointsSyntax
*)arg
;
552 //cdp->numDistPoints = genRand(1,3);
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
);
559 for(unsigned dex
=0; dex
<cdp
->numDistPoints
; dex
++) {
560 CE_CRLDistributionPoint
*pt
= &cdp
->distPoints
[dex
];
562 /* all fields optional */
564 CE_DistributionPointName
*dpn
= pt
->distPointName
=
565 (CE_DistributionPointName
*)malloc(
566 sizeof(CE_DistributionPointName
));
567 memset(dpn
, 0, sizeof(CE_DistributionPointName
));
569 /* CE_DistributionPointName has two flavors */
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
);
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
);
584 } /* creating CE_DistributionPointName */
586 pt
->reasonsPresent
= randBool();
587 if(pt
->reasonsPresent
) {
588 CE_CrlDistReasonFlags
*cdr
= &pt
->reasons
;
589 /* set two random valid bits */
591 *cdr
|= 1 << genRand(0,7);
592 *cdr
|= 1 << genRand(0,7);
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
);
604 static unsigned cdpCompare(const void *pre
, const void *post
)
606 CE_CRLDistPointsSyntax
*cpre
= (CE_CRLDistPointsSyntax
*)pre
;
607 CE_CRLDistPointsSyntax
*cpost
= (CE_CRLDistPointsSyntax
*)post
;
609 if(cpre
->numDistPoints
!= cpost
->numDistPoints
) {
610 printf("***CE_CRLDistPointsSyntax.numDistPoints miscompare\n");
614 for(unsigned dex
=0; dex
<cpre
->numDistPoints
; dex
++) {
615 CE_CRLDistributionPoint
*ptpre
= &cpre
->distPoints
[dex
];
616 CE_CRLDistributionPoint
*ptpost
= &cpost
->distPoints
[dex
];
618 if(ptpre
->distPointName
) {
619 if(ptpost
->distPointName
== NULL
) {
620 printf("***NULL distPointName post decode\n");
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");
631 if(dpnpre
->nameType
== CE_CDNT_FullName
) {
632 rtn
+= genNamesCompare(dpnpre
->dpn
.fullName
, dpnpost
->dpn
.fullName
);
635 rtn
+= rdnCompare(dpnpre
->dpn
.rdn
, dpnpost
->dpn
.rdn
);
639 else if(ptpost
->distPointName
!= NULL
) {
640 printf("***NON NULL distPointName post decode\n");
645 if(ptpre
->reasons
!= ptpost
->reasons
) {
646 printf("***CE_CRLDistributionPoint.reasons miscompare\n");
650 if(ptpre
->crlIssuer
) {
651 if(ptpost
->crlIssuer
== NULL
) {
652 printf("***NULL crlIssuer post decode\n");
656 CE_GeneralNames
*gnpre
= ptpre
->crlIssuer
;
657 CE_GeneralNames
*gnpost
= ptpost
->crlIssuer
;
658 rtn
+= genNamesCompare(gnpre
, gnpost
);
660 else if(ptpost
->crlIssuer
!= NULL
) {
661 printf("***NON NULL crlIssuer post decode\n");
668 static void cdpFree(void *arg
)
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
);
680 rdnFree(dpn
->dpn
.rdn
);
687 genNamesFree(pt
->crlIssuer
);
691 free(cdp
->distPoints
);
694 #pragma mark --- CE_AuthorityKeyID ---
695 static void authKeyIdCreate(void *arg
)
697 CE_AuthorityKeyID
*akid
= (CE_AuthorityKeyID
*)arg
;
699 /* all three fields optional */
701 akid
->keyIdentifierPresent
= randBool();
702 if(akid
->keyIdentifierPresent
) {
703 randData(&akid
->keyIdentifier
, 16);
706 akid
->generalNamesPresent
= randBool();
707 if(akid
->generalNamesPresent
) {
709 (CE_GeneralNames
*)malloc(sizeof(CE_GeneralNames
));
710 memset(akid
->generalNames
, 0, sizeof(CE_GeneralNames
));
711 genNamesCreate(akid
->generalNames
);
714 if(!akid
->keyIdentifierPresent
& !akid
->generalNamesPresent
) {
715 /* force at least one to be present */
716 akid
->serialNumberPresent
= CSSM_TRUE
;
719 akid
->serialNumberPresent
= randBool();
721 if(akid
->serialNumberPresent
) {
722 randData(&akid
->serialNumber
, 16);
727 static unsigned authKeyIdCompare(const void *pre
, const void *post
)
729 CE_AuthorityKeyID
*akpre
= (CE_AuthorityKeyID
*)pre
;
730 CE_AuthorityKeyID
*akpost
= (CE_AuthorityKeyID
*)post
;
733 if(compBool(akpre
->keyIdentifierPresent
, akpost
->keyIdentifierPresent
,
734 "CE_AuthorityKeyID.keyIdentifierPresent")) {
737 else if(akpre
->keyIdentifierPresent
) {
738 rtn
+= compCssmData(akpre
->keyIdentifier
,
739 akpost
->keyIdentifier
, "CE_AuthorityKeyID.keyIdentifier");
742 if(compBool(akpre
->generalNamesPresent
, akpost
->generalNamesPresent
,
743 "CE_AuthorityKeyID.generalNamesPresent")) {
746 else if(akpre
->generalNamesPresent
) {
747 rtn
+= genNamesCompare(akpre
->generalNames
,
748 akpost
->generalNames
);
751 if(compBool(akpre
->serialNumberPresent
, akpost
->serialNumberPresent
,
752 "CE_AuthorityKeyID.serialNumberPresent")) {
755 else if(akpre
->serialNumberPresent
) {
756 rtn
+= compCssmData(akpre
->serialNumber
,
757 akpost
->serialNumber
, "CE_AuthorityKeyID.serialNumber");
762 static void authKeyIdFree(void *arg
)
764 CE_AuthorityKeyID
*akid
= (CE_AuthorityKeyID
*)arg
;
766 if(akid
->keyIdentifier
.Data
) {
767 free(akid
->keyIdentifier
.Data
);
769 if(akid
->generalNames
) {
770 genNamesFree(akid
->generalNames
); // genNamesCreate mallocd
771 free(akid
->generalNames
); // we mallocd
773 if(akid
->serialNumber
.Data
) {
774 free(akid
->serialNumber
.Data
);
778 #pragma mark --- CE_CertPolicies ---
780 /* random OIDs, pick 1..NUM_CP_OIDS */
781 static CSSM_OID cpOids
[] =
783 CSSMOID_EmailAddress
,
784 CSSMOID_UnstructuredName
,
786 CSSMOID_MessageDigest
788 #define NUM_CP_OIDS 4
790 /* CPS strings, pick one of NUM_CPS_STR */
791 static char *someCPSs
[] =
793 (char *)"http://www.apple.com",
794 (char *)"https://cdnow.com",
795 (char *)"ftp:backwards.com"
797 #define NUM_CPS_STR 3
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};
803 static void cpCreate(void *arg
)
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
);
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
*)
821 memset(pi
->policyQualifiers
, 0, len
);
822 for(unsigned cpiDex
=0; cpiDex
<numQual
; cpiDex
++) {
823 CE_PolicyQualifierInfo
*qi
=
824 &pi
->policyQualifiers
[cpiDex
];
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
);
832 qi
->policyQualifierId
= CSSMOID_QT_UNOTICE
;
834 qi
->qualifier
.Data
= someUnotice
;
835 qi
->qualifier
.Length
= 5;
838 qi
->qualifier
.Data
= someOtherData
;
839 qi
->qualifier
.Length
= 4;
846 static unsigned cpCompare(const void *pre
, const void *post
)
848 CE_CertPolicies
*cppre
= (CE_CertPolicies
*)pre
;
849 CE_CertPolicies
*cppost
= (CE_CertPolicies
*)post
;
851 if(cppre
->numPolicies
!= cppost
->numPolicies
) {
852 printf("CE_CertPolicies.numPolicies mismatch\n");
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");
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
,
875 "CE_PolicyQualifierInfo.qualifier");
881 static void cpFree(void *arg
)
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
);
891 #pragma mark --- CE_AuthorityInfoAccess ---
893 /* random OIDs, pick 1..NUM_AI_OIDS */
894 static CSSM_OID aiOids
[] =
897 CSSMOID_AD_CA_ISSUERS
,
898 CSSMOID_AD_TIME_STAMPING
,
899 CSSMOID_AD_CA_REPOSITORY
901 #define NUM_AI_OIDS 4
903 static void aiaCreate(void *arg
)
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
);
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
);
919 static unsigned aiaCompare(const void *pre
, const void *post
)
921 CE_AuthorityInfoAccess
*apre
= (CE_AuthorityInfoAccess
*)pre
;
922 CE_AuthorityInfoAccess
*apost
= (CE_AuthorityInfoAccess
*)post
;
925 if(apre
->numAccessDescriptions
!= apost
->numAccessDescriptions
) {
926 printf("***CE_AuthorityInfoAccess.numAccessDescriptions miscompare\n");
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")) {
936 rtn
+= genNameCompare(&adPre
->accessLocation
, &adPost
->accessLocation
);
941 static void aiaFree(void *arg
)
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
);
948 free(aia
->accessDescriptions
);
951 #pragma mark --- test definitions ---
954 * Define one extension test.
958 * Cook up this extension with random, reasonable values.
959 * Incoming pointer refers to extension-specific C struct, mallocd
960 * and zeroed by main test routine.
962 typedef void (*extenCreateFcn
)(void *arg
);
965 * Compare two instances of this extension. Return number of
968 typedef unsigned (*extenCompareFcn
)(
969 const void *preEncode
,
970 const void *postEncode
);
973 * Free struct components mallocd in extenCreateFcn. Do not free
976 typedef void (*extenFreeFcn
)(void *arg
);
979 /* three extension-specific functions */
980 extenCreateFcn createFcn
;
981 extenCompareFcn compareFcn
;
982 extenFreeFcn freeFcn
;
984 /* size of C struct passed to all three functions */
987 /* the CE_DataType for this extension, used on encode */
988 CE_DataType extenType
;
990 /* the OID for this extension, tested on decode */
993 /* description for error logging and blob writing */
994 const char *extenDescr
;
996 /* command-line letter for this one */
1001 /* empty freeFcn means no extension-specific resources to free */
1002 #define NO_FREE NULL
1004 static ExtenTest extenTests
[] = {
1005 { kuCreate
, kuCompare
, NO_FREE
,
1006 sizeof(CE_KeyUsage
),
1007 DT_KeyUsage
, CSSMOID_KeyUsage
,
1009 { bcCreate
, bcCompare
, NO_FREE
,
1010 sizeof(CE_BasicConstraints
),
1011 DT_BasicConstraints
, CSSMOID_BasicConstraints
,
1012 "BasicConstraints", 'b' },
1013 { ekuCreate
, ekuCompare
, NO_FREE
,
1014 sizeof(CE_ExtendedKeyUsage
),
1015 DT_ExtendedKeyUsage
, CSSMOID_ExtendedKeyUsage
,
1016 "ExtendedKeyUsage", 'x' },
1017 { skidCreate
, skidCompare
, skidFree
,
1019 DT_SubjectKeyID
, CSSMOID_SubjectKeyIdentifier
,
1020 "SubjectKeyID", 's' },
1021 { authKeyIdCreate
, authKeyIdCompare
, authKeyIdFree
,
1022 sizeof(CE_AuthorityKeyID
),
1023 DT_AuthorityKeyID
, CSSMOID_AuthorityKeyIdentifier
,
1024 "AuthorityKeyID", 'a' },
1025 { genNamesCreate
, genNamesCompare
, genNamesFree
,
1026 sizeof(CE_GeneralNames
),
1027 DT_SubjectAltName
, CSSMOID_SubjectAltName
,
1028 "SubjectAltName", 't' },
1029 { genNamesCreate
, genNamesCompare
, genNamesFree
,
1030 sizeof(CE_GeneralNames
),
1031 DT_IssuerAltName
, CSSMOID_IssuerAltName
,
1032 "IssuerAltName", 'i' },
1033 { nctCreate
, nctCompare
, NO_FREE
,
1034 sizeof(CE_NetscapeCertType
),
1035 DT_NetscapeCertType
, CSSMOID_NetscapeCertType
,
1036 "NetscapeCertType", 'n' },
1037 { cdpCreate
, cdpCompare
, cdpFree
,
1038 sizeof(CE_CRLDistPointsSyntax
),
1039 DT_CrlDistributionPoints
, CSSMOID_CrlDistributionPoints
,
1040 "CRLDistPoints", 'p' },
1041 { cpCreate
, cpCompare
, cpFree
,
1042 sizeof(CE_CertPolicies
),
1043 DT_CertPolicies
, CSSMOID_CertificatePolicies
,
1044 "CertPolicies", 'c' },
1045 { aiaCreate
, aiaCompare
, aiaFree
,
1046 sizeof(CE_AuthorityInfoAccess
),
1047 DT_AuthorityInfoAccess
, CSSMOID_AuthorityInfoAccess
,
1048 "AuthorityInfoAccess", 'A' },
1050 /* TP doesn't have this, neither does certextensions.h! */
1051 { aiaCreate
, aiaCompare
, aiaFree
,
1052 sizeof(CE_AuthorityInfoAccess
), CSSMOID_SubjectInfoAccess
,
1053 "SubjectInfoAccess", 'S' },
1057 #define NUM_EXTEN_TESTS (sizeof(extenTests) / sizeof(ExtenTest))
1059 static void printExtenPre(
1060 CE_DataAndType
*extenData
,
1065 CSSM_X509_EXTENSION extn
;
1068 * Convert pre-digested into CSSM_X509_EXTENSION that
1069 * printCertField() can understand
1071 extn
.extnId
= *extenOid
;
1072 extn
.critical
= extenData
->critical
;
1073 extn
.format
= CSSM_X509_DATAFORMAT_PARSED
;
1074 extn
.value
.parsedValue
= &extenData
->extension
;
1075 field
.FieldOid
= *extenOid
;
1076 field
.FieldValue
.Data
= (uint8
*)&extn
;
1077 field
.FieldValue
.Length
= sizeof(CSSM_X509_EXTENSION
);
1078 printf("=== PRE-ENCODE:\n");
1079 printCertField(field
, parser
, CSSM_TRUE
);
1083 static void printExten(
1084 CSSM_X509_EXTENSION
&extn
,
1088 field
.FieldOid
= extn
.extnId
;
1089 field
.FieldValue
.Data
= (uint8
*)&extn
;
1090 field
.FieldValue
.Length
= sizeof(CSSM_X509_EXTENSION
);
1091 printf("=== POST-DECODE:\n");
1092 printCertField(field
, parser
, CSSM_TRUE
);
1096 CSSM_CL_HANDLE clHand
,
1097 CSSM_TP_HANDLE tpHand
,
1098 CSSM_CSP_HANDLE cspHand
,
1099 ExtenTest
&extenTest
,
1101 const char *constFileName
, // all blobs to this file if non-NULL
1105 CSSM_APPLE_TP_CERT_REQUEST certReq
;
1106 CSSM_TP_REQUEST_SET reqSet
;
1108 CSSM_BOOL confirmRequired
;
1109 CSSM_TP_RESULT_SET_PTR resultSet
;
1110 CSSM_ENCODED_CERT
*encCert
;
1111 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext
;
1112 CSSM_FIELD policyId
;
1113 CE_DataAndType extPre
;
1115 CSSM_DATA refId
; // mallocd by CSSM_TP_SubmitCredRequest
1116 CSSM_DATA signedCert
= {0, NULL
};
1118 memset(&certReq
, 0, sizeof(certReq
));
1119 memset(&extPre
, 0, sizeof(extPre
));
1122 * Cook up a random and reasonable instance of the C struct
1123 * associated with this extension.
1125 extenTest
.createFcn(&extPre
.extension
);
1128 * Cook up the associated CSSM_X509_EXTENSION.
1130 extPre
.type
= extenTest
.extenType
;
1131 extPre
.critical
= randBool();
1134 * Now the cert request proper.
1136 certReq
.cspHand
= cspHand
;
1137 certReq
.clHand
= clHand
;
1138 certReq
.serialNumber
= 0x8765;
1139 certReq
.numSubjectNames
= NUM_DUMMY_NAMES
;
1140 certReq
.subjectNames
= dummyRdn
;
1141 certReq
.numIssuerNames
= NUM_DUMMY_NAMES
;
1142 certReq
.issuerNames
= dummyRdn
;
1143 certReq
.certPublicKey
= &subjPubKey
;
1144 certReq
.issuerPrivateKey
= &subjPrivKey
;
1145 certReq
.signatureAlg
= CSSM_ALGID_SHA1WithRSA
;
1146 certReq
.signatureOid
= SIG_OID
;
1147 certReq
.notBefore
= 0; // now
1148 certReq
.notAfter
= 10000; // seconds from now
1149 certReq
.numExtensions
= 1;
1150 certReq
.extensions
= &extPre
;
1152 reqSet
.NumberOfRequests
= 1;
1153 reqSet
.Requests
= &certReq
;
1155 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
1156 memset(&CallerAuthContext
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
1157 memset(&policyId
, 0, sizeof(CSSM_FIELD
));
1158 policyId
.FieldOid
= CSSMOID_APPLE_TP_LOCAL_CERT_GEN
;
1159 CallerAuthContext
.Policy
.NumberOfPolicyIds
= 1;
1160 CallerAuthContext
.Policy
.PolicyIds
= &policyId
;
1163 crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
1164 NULL
, // PreferredAuthority
1165 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
1171 printError("CSSM_TP_SubmitCredRequest", crtn
);
1172 /* show what we tried to encode and decode */
1173 printExtenPre(&extPre
, &extenTest
.extenOid
, parser
);
1176 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
1178 NULL
, // CallerAuthCredentials
1181 &resultSet
); // leaks.....
1183 printError("CSSM_TP_RetrieveCredResult", crtn
);
1184 /* show what we tried to encode and decode */
1185 printExtenPre(&extPre
, &extenTest
.extenOid
, parser
);
1188 if(resultSet
== NULL
) {
1189 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
1190 /* show what we tried to encode and decode */
1191 printExtenPre(&extPre
, &extenTest
.extenOid
, parser
);
1194 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
1195 signedCert
= encCert
->CertBlob
;
1200 strcpy(fileName
, constFileName
);
1203 sprintf(fileName
, "%scert.der", extenTest
.extenDescr
);
1205 writeFile(fileName
, signedCert
.Data
, signedCert
.Length
);
1206 printf("...wrote %lu bytes to %s\n", signedCert
.Length
, fileName
);
1209 /* snag the same extension from the encoded cert */
1210 CSSM_DATA_PTR postField
;
1211 CSSM_HANDLE resultHand
;
1214 crtn
= CSSM_CL_CertGetFirstFieldValue(clHand
,
1216 &extenTest
.extenOid
,
1221 printf("****Extension field not found on decode for %s\n",
1222 extenTest
.extenDescr
);
1223 printError("CSSM_CL_CertGetFirstFieldValue", crtn
);
1225 /* show what we tried to encode and decode */
1226 printExtenPre(&extPre
, &extenTest
.extenOid
, parser
);
1230 if(numFields
!= 1) {
1231 printf("****GetFirstFieldValue: expect 1 value, got %u\n",
1232 (unsigned)numFields
);
1235 CSSM_CL_CertAbortQuery(clHand
, resultHand
);
1237 /* verify the fields we generated */
1238 CSSM_X509_EXTENSION
*extnPost
= (CSSM_X509_EXTENSION
*)postField
->Data
;
1239 if((extnPost
== NULL
) ||
1240 (postField
->Length
!= sizeof(CSSM_X509_EXTENSION
))) {
1241 printf("***Malformed CSSM_X509_EXTENSION (1) after decode\n");
1245 rtn
+= compBool(extPre
.critical
, extnPost
->critical
,
1246 "CSSM_X509_EXTENSION.critical");
1247 rtn
+= compCssmData(extenTest
.extenOid
, extnPost
->extnId
,
1248 "CSSM_X509_EXTENSION.extnId");
1250 if(extnPost
->format
!= CSSM_X509_DATAFORMAT_PARSED
) {
1251 printf("***Expected CSSM_X509_DATAFORMAT_PARSED (%x(x), got %x(x)\n",
1252 CSSM_X509_DATAFORMAT_PARSED
, extnPost
->format
);
1254 if(extnPost
->value
.parsedValue
== NULL
) {
1255 printf("***no parsedValue pointer!\n");
1259 /* down to extension-specific compare */
1260 rtn
+= extenTest
.compareFcn(&extPre
.extension
, extnPost
->value
.parsedValue
);
1263 /* print preencode only on error */
1264 printExtenPre(&extPre
, &extenTest
.extenOid
, parser
);
1266 if(displayExtens
|| rtn
) {
1267 printExten(*extnPost
, parser
);
1270 /* free the allocated data */
1271 if(extenTest
.freeFcn
) {
1272 extenTest
.freeFcn(&extPre
.extension
);
1274 CSSM_CL_FreeFieldValue(clHand
, &extenTest
.extenOid
, postField
);
1275 CSSM_FREE(signedCert
.Data
);
1277 CSSM_FREE(resultSet
);
1281 static void doPause(bool pause
)
1287 printf("CR to continue ");
1291 int main(int argc
, char **argv
)
1293 CSSM_CL_HANDLE clHand
;
1294 CSSM_TP_HANDLE tpHand
;
1295 CSSM_CSP_HANDLE cspHand
;
1303 /* user-specificied params */
1304 unsigned minExtenNum
= 0;
1305 unsigned maxExtenNum
= NUM_EXTEN_TESTS
-1;
1306 bool writeBlobs
= false;
1307 bool displayExtens
= false;
1309 unsigned loops
= LOOPS_DEF
;
1310 bool pauseLoop
= false;
1311 bool pauseCert
= false;
1312 const char *constFileName
= NULL
;
1314 for(arg
=1; arg
<argc
; arg
++) {
1321 displayExtens
= true;
1333 loops
= atoi(&argp
[2]);
1336 constFileName
= &argp
[2];
1339 if(argp
[1] != '=') {
1342 /* scan thru test array looking for epecified extension */
1343 for(i
=0; i
<NUM_EXTEN_TESTS
; i
++) {
1344 if(extenTests
[i
].extenLetter
== argp
[2]) {
1345 minExtenNum
= maxExtenNum
= i
;
1349 if(i
== NUM_EXTEN_TESTS
) {
1360 clHand
= clStartup();
1364 tpHand
= tpStartup();
1368 cspHand
= cspStartup();
1373 printf("Starting extenTestTp; args: ");
1374 for(i
=1; i
<(unsigned)argc
; i
++) {
1375 printf("%s ", argv
[i
]);
1379 /* one common key pair - we're definitely not testing this */
1380 crtn
= cspGenKeyPair(cspHand
,
1383 strlen(SUBJ_KEY_LABEL
),
1386 CSSM_FALSE
, // pubIsRef - should work both ways, but not yet
1388 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
1390 CSSM_TRUE
, // privIsRef - doesn't matter
1392 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
1398 for(unsigned loop
=0; loop
<loops
; loop
++) {
1400 printf("...loop %u\n", loop
);
1402 for(unsigned extenDex
=minExtenNum
; extenDex
<=maxExtenNum
; extenDex
++) {
1403 rtn
= doTest(clHand
, tpHand
, cspHand
, extenTests
[extenDex
],
1404 writeBlobs
, constFileName
, displayExtens
, parser
);
1417 printf("***%s FAILED\n", argv
[0]);
1420 printf("...%s passed\n", argv
[0]);
1425 CSSM_ModuleDetach(cspHand
);
1426 CSSM_ModuleDetach(clHand
);
1427 CSSM_ModuleDetach(tpHand
);