2 * certLabelTest.cpp - test SecCertificateInferLabel(), in particular, Radar
3 * 3529689 (teletex strings) and 4746055 (add Description
11 #include <Security/Security.h>
12 #include <Security/SecCertificatePriv.h>
13 #include <clAppUtils/clutils.h>
14 #include <clAppUtils/CertBuilderApp.h>
15 #include <utilLib/common.h>
16 #include <utilLib/cspwrap.h>
17 #include <security_cdsa_utils/cuFileIo.h>
19 static void usage(char **argv
)
21 printf("usage: %s [options]\n", argv
[0]);
23 printf(" -p -- pause for leaks check\n");
24 printf(" -q -- quiet\n");
30 #define KEY_ALG CSSM_ALGID_RSA
31 #define SIG_ALG CSSM_ALGID_SHA1WithRSA
32 #define CERT_FILE_OUT "/tmp/certLabelTest.cer"
35 * Here's the definitive string for Radar 3529689.
36 * BER tag = Teletex/T61, encoding = kCFStringEncodingISOLatin1.
37 * I hope Herr Petersen does not mind.
39 static const unsigned char JurgenPetersen
[] =
41 0x4a, 0xf8, 0x72, 0x67, 0x65, 0x6e, 0x20, 0x4e,
42 0xf8, 0x72, 0x67, 0x61, 0x61, 0x72, 0x64, 0x20,
43 0x50, 0x65, 0x74, 0x65, 0x72, 0x73, 0x65, 0x6e
47 * Name/OID pair used in buildX509Name().
48 * This logic is like the CB_BuildX509Name() code in clAppUtils/CertBuilderApp.cpp,
49 * with the addition of the berTag specification, and data is specified as a void *
60 * Build up a CSSM_X509_NAME from an arbitrary list of name/OID/tag triplets.
61 * We do one a/v pair per RDN.
63 static CSSM_X509_NAME
*buildX509Name(
64 const NameOid
*nameArray
,
67 CSSM_X509_NAME
*top
= (CSSM_X509_NAME
*)appMalloc(sizeof(CSSM_X509_NAME
), 0);
71 top
->numberOfRDNs
= numNames
;
72 top
->RelativeDistinguishedName
=
73 (CSSM_X509_RDN_PTR
)appMalloc(sizeof(CSSM_X509_RDN
) * numNames
, 0);
74 if(top
->RelativeDistinguishedName
== NULL
) {
77 CSSM_X509_RDN_PTR rdn
;
78 const NameOid
*nameOid
;
80 for(nameDex
=0; nameDex
<numNames
; nameDex
++) {
81 rdn
= &top
->RelativeDistinguishedName
[nameDex
];
82 nameOid
= &nameArray
[nameDex
];
83 rdn
->numberOfPairs
= 1;
84 rdn
->AttributeTypeAndValue
= (CSSM_X509_TYPE_VALUE_PAIR_PTR
)
85 appMalloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR
), 0);
86 CSSM_X509_TYPE_VALUE_PAIR_PTR atvp
= rdn
->AttributeTypeAndValue
;
90 appCopyCssmData(nameOid
->oid
, &atvp
->type
);
91 atvp
->valueType
= nameOid
->berTag
;
92 atvp
->value
.Length
= nameOid
->nameLen
;
93 atvp
->value
.Data
= (uint8
*)CSSM_MALLOC(nameOid
->nameLen
);
94 memmove(atvp
->value
.Data
, nameOid
->nameVal
, nameOid
->nameLen
);
99 /* just make these static and reuse them */
100 static CSSM_X509_TIME
*notBefore
;
101 static CSSM_X509_TIME
*notAfter
;
105 * -- build a cert with issuer and subject as per specified name components
106 * -- extract inferred label
107 * -- compare inferred label to expected value
108 * -- if labelIsCommonName true, verify that SecCertificateCopyCommonName() yields
109 * the same string as inferred label
112 const char *testName
,
114 CSSM_CSP_HANDLE cspHand
,
115 CSSM_CL_HANDLE clHand
,
116 CSSM_KEY_PTR privKey
,
119 /* input names - one or two */
120 const void *name1Val
,
122 CSSM_BER_TAG berTag1
,
123 const CSSM_OID
*name1Oid
,
124 const void *name2Val
, // optional
126 CSSM_BER_TAG berTag2
,
127 const CSSM_OID
*name2Oid
,
130 CFStringRef expectedLabel
,
131 bool labelIsCommonName
)
134 printf("...%s\n", testName
);
137 /* build the subject/issuer name */
138 NameOid nameArray
[2] = { {name1Val
, name1Len
, name1Oid
, berTag1
},
139 {name2Val
, name2Len
, name2Oid
, berTag2
} };
140 unsigned numNames
= name2Val
? 2 : 1;
142 CSSM_X509_NAME
*name
= buildX509Name(nameArray
, numNames
);
144 printf("***buildX509Name screwup\n");
148 /* build the cert template */
149 CSSM_DATA_PTR certTemp
= CB_MakeCertTemplate(
154 NULL
, NULL
, // subject/issuer UniqueID
155 NULL
, 0); // extensions
156 if(certTemp
== NULL
) {
157 printf("***CB_MakeCertTemplate screwup\n");
162 CSSM_DATA signedCert
= {0, NULL
};
163 CSSM_CC_HANDLE sigHand
;
164 CSSM_RETURN crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
166 NULL
, // no passphrase for now
170 /* should never happen */
171 cssmPerror("CSSM_CSP_CreateSignatureContext", crtn
);
174 crtn
= CSSM_CL_CertSign(clHand
,
176 certTemp
, // CertToBeSigned
177 NULL
, // SignScope per spec
178 0, // ScopeSize per spec
181 cssmPerror("CSSM_CL_CertSign", crtn
);
184 CSSM_DeleteContext(sigHand
);
185 CSSM_FREE(certTemp
->Data
);
189 * OK, we have a signed cert.
190 * Turn it into a SecCertificateRef and get the inferred label.
193 SecCertificateRef certRef
;
194 ortn
= SecCertificateCreateFromData(&signedCert
,
195 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
198 cssmPerror("SecCertificateCreateFromData", ortn
);
201 CFStringRef inferredLabel
;
202 ortn
= SecCertificateInferLabel(certRef
, &inferredLabel
);
204 cssmPerror("SecCertificateCreateFromData", ortn
);
207 CFComparisonResult res
= CFStringCompare(inferredLabel
, expectedLabel
, 0);
208 if(res
!= kCFCompareEqualTo
) {
209 fprintf(stderr
, "*** label miscompare in test '%s' ***\n", testName
);
210 fprintf(stderr
, "expected label : ");
211 CFShow(expectedLabel
);
212 fprintf(stderr
, "inferred label : ");
213 CFShow(inferredLabel
);
214 if(writeFile(CERT_FILE_OUT
, signedCert
.Data
, signedCert
.Length
)) {
215 fprintf(stderr
, "***Error writing cert to %s\n", CERT_FILE_OUT
);
218 fprintf(stderr
, "...write %lu bytes to %s\n", (unsigned long)signedCert
.Length
,
224 if(labelIsCommonName
) {
225 CFStringRef commonName
= NULL
;
226 ortn
= SecCertificateCopyCommonName(certRef
, &commonName
);
228 cssmPerror("SecCertificateCopyCommonName", ortn
);
231 res
= CFStringCompare(inferredLabel
, commonName
, 0);
232 if(res
!= kCFCompareEqualTo
) {
233 printf("*** CommonName miscompare in test '%s' ***\n", testName
);
234 printf("Common Name : '");
237 printf("inferred label : '");
238 CFShow(inferredLabel
);
240 if(writeFile(CERT_FILE_OUT
, signedCert
.Data
, signedCert
.Length
)) {
241 printf("***Error writing cert to %s\n", CERT_FILE_OUT
);
244 printf("...write %lu bytes to %s\n", (unsigned long)signedCert
.Length
,
249 CFRelease(commonName
);
252 CSSM_FREE(signedCert
.Data
);
253 CB_FreeX509Name(name
);
254 CFRelease(inferredLabel
);
258 int main(int argc
, char **argv
)
261 bool doPause
= false;
264 while ((arg
= getopt(argc
, argv
, "pqh")) != -1) {
280 testStartBanner("certLabelTest", argc
, argv
);
282 CSSM_CL_HANDLE clHand
= clStartup();
283 CSSM_CSP_HANDLE cspHand
= cspStartup();
285 /* create a key pair */
290 crtn
= cspGenKeyPair(cspHand
, KEY_ALG
,
293 &pubKey
, CSSM_FALSE
, CSSM_KEYUSE_ANY
, CSSM_KEYBLOB_RAW_FORMAT_NONE
,
294 &privKey
, CSSM_FALSE
, CSSM_KEYUSE_ANY
, CSSM_KEYBLOB_RAW_FORMAT_NONE
,
297 printf("***Error generating RSA key pair. Aborting.\n");
301 /* common params, reused for each test */
302 notBefore
= CB_BuildX509Time(0);
303 notAfter
= CB_BuildX509Time(100000);
306 * Grind thru test cases.
311 ourRtn
= doTest("simple ASCII common name", quiet
,
312 cspHand
, clHand
, &privKey
, &pubKey
,
313 "Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_CommonName
,
314 NULL
, 0, BER_TAG_UNKNOWN
, NULL
,
315 CFSTR("Simple Name"), true);
320 /* test concatentation of description */
321 ourRtn
= doTest("ASCII common name plus ASCII description", quiet
,
322 cspHand
, clHand
, &privKey
, &pubKey
,
323 "Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_CommonName
,
324 "Description", strlen("Description"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_Description
,
325 CFSTR("Simple Name (Description)"), false);
330 /* basic, specifying UTF8 (should be same as PRINTABLE) */
331 ourRtn
= doTest("simple UTF8 common name", quiet
,
332 cspHand
, clHand
, &privKey
, &pubKey
,
333 "Simple Name", strlen("Simple Name"), BER_TAG_PKIX_UTF8_STRING
, &CSSMOID_CommonName
,
334 NULL
, 0, BER_TAG_UNKNOWN
, NULL
,
335 CFSTR("Simple Name"), true);
340 /* label from org name instead of common name */
341 ourRtn
= doTest("label from OrgName", quiet
,
342 cspHand
, clHand
, &privKey
, &pubKey
,
343 "Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_OrganizationName
,
344 NULL
, 0, BER_TAG_UNKNOWN
, NULL
,
345 CFSTR("Simple Name"), false);
350 /* label from orgUnit name instead of common name */
351 ourRtn
= doTest("label from OrgUnit", quiet
,
352 cspHand
, clHand
, &privKey
, &pubKey
,
353 "Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_OrganizationalUnitName
,
354 NULL
, 0, BER_TAG_UNKNOWN
, NULL
,
355 CFSTR("Simple Name"), false);
360 /* label from orgUnit name, description is ignored (it's only used if the
361 * label comes from CommonName) */
362 ourRtn
= doTest("label from OrgUnit, description is ignored", quiet
,
363 cspHand
, clHand
, &privKey
, &pubKey
,
364 "Simple Name", strlen("Simple Name"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_OrganizationalUnitName
,
365 "Description", strlen("Description"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_Description
,
366 CFSTR("Simple Name"), false);
371 /* Radar 3529689: T61/Teletex, ISOLatin encoding, commonName only */
372 CFStringRef t61Str
= CFStringCreateWithBytes(NULL
, JurgenPetersen
, sizeof(JurgenPetersen
),
373 kCFStringEncodingISOLatin1
, true);
374 ourRtn
= doTest("T61/Teletex name from Radar 3529689", quiet
,
375 cspHand
, clHand
, &privKey
, &pubKey
,
376 JurgenPetersen
, sizeof(JurgenPetersen
), BER_TAG_TELETEX_STRING
, &CSSMOID_CommonName
,
377 NULL
, 0, BER_TAG_UNKNOWN
, NULL
,
383 /* Now convert that ISOLatin into Unicode and try with that */
384 CFDataRef unicodeStr
= CFStringCreateExternalRepresentation(NULL
, t61Str
,
385 kCFStringEncodingUnicode
, 0);
386 if(unicodeStr
== NULL
) {
387 printf("***Error converting to Unicode\n");
390 ourRtn
= doTest("Unicode CommonName", quiet
,
391 cspHand
, clHand
, &privKey
, &pubKey
,
392 CFDataGetBytePtr(unicodeStr
), CFDataGetLength(unicodeStr
),
393 BER_TAG_PKIX_BMP_STRING
, &CSSMOID_CommonName
,
394 NULL
, 0, BER_TAG_UNKNOWN
, NULL
,
399 CFRelease(unicodeStr
);
401 /* Mix up ISOLatin Common Name and ASCII Description to ensure that the encodings
402 * of the two components are handled separately */
403 CFMutableStringRef combo
= CFStringCreateMutable(NULL
, 0);
404 CFStringAppend(combo
, t61Str
);
405 CFStringAppendCString(combo
, " (Description)", kCFStringEncodingASCII
);
406 ourRtn
= doTest("ISOLatin Common Name and ASCII Description", quiet
,
407 cspHand
, clHand
, &privKey
, &pubKey
,
408 JurgenPetersen
, sizeof(JurgenPetersen
), BER_TAG_TELETEX_STRING
, &CSSMOID_CommonName
,
409 "Description", strlen("Description"), BER_TAG_PRINTABLE_STRING
, &CSSMOID_Description
,
419 printf("Pausing for leaks testing; CR to continue: ");
423 printf("...success\n");