]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/certLabelTest/certLabelTest.cpp
Security-57337.40.85.tar.gz
[apple/security.git] / SecurityTests / clxutils / certLabelTest / certLabelTest.cpp
1 /*
2 * certLabelTest.cpp - test SecCertificateInferLabel(), in particular, Radar
3 * 3529689 (teletex strings) and 4746055 (add Description
4 * in parentheses)
5 */
6
7 #include <stdlib.h>
8 #include <strings.h>
9 #include <stdio.h>
10 #include <unistd.h>
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>
18
19 static void usage(char **argv)
20 {
21 printf("usage: %s [options]\n", argv[0]);
22 printf("Options:\n");
23 printf(" -p -- pause for leaks check\n");
24 printf(" -q -- quiet\n");
25 /* etc. */
26 exit(1);
27 }
28
29 #define KEY_SIZE 1024
30 #define KEY_ALG CSSM_ALGID_RSA
31 #define SIG_ALG CSSM_ALGID_SHA1WithRSA
32 #define CERT_FILE_OUT "/tmp/certLabelTest.cer"
33
34 /*
35 * Here's the definitive string for Radar 3529689.
36 * BER tag = Teletex/T61, encoding = kCFStringEncodingISOLatin1.
37 * I hope Herr Petersen does not mind.
38 */
39 static const unsigned char JurgenPetersen[] =
40 {
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
44 };
45
46 /*
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 *
50 * and size_t.
51 */
52 typedef struct {
53 const void *nameVal;
54 CSSM_SIZE nameLen;
55 const CSSM_OID *oid;
56 CSSM_BER_TAG berTag;
57 } NameOid;
58
59 /*
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.
62 */
63 static CSSM_X509_NAME *buildX509Name(
64 const NameOid *nameArray,
65 unsigned numNames)
66 {
67 CSSM_X509_NAME *top = (CSSM_X509_NAME *)appMalloc(sizeof(CSSM_X509_NAME), 0);
68 if(top == NULL) {
69 return NULL;
70 }
71 top->numberOfRDNs = numNames;
72 top->RelativeDistinguishedName =
73 (CSSM_X509_RDN_PTR)appMalloc(sizeof(CSSM_X509_RDN) * numNames, 0);
74 if(top->RelativeDistinguishedName == NULL) {
75 return NULL;
76 }
77 CSSM_X509_RDN_PTR rdn;
78 const NameOid *nameOid;
79 unsigned nameDex;
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;
87 if(atvp == NULL) {
88 return NULL;
89 }
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);
95 }
96 return top;
97 }
98
99 /* just make these static and reuse them */
100 static CSSM_X509_TIME *notBefore;
101 static CSSM_X509_TIME *notAfter;
102
103 /*
104 * Core test routine.
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
110 */
111 static int doTest(
112 const char *testName,
113 bool quiet,
114 CSSM_CSP_HANDLE cspHand,
115 CSSM_CL_HANDLE clHand,
116 CSSM_KEY_PTR privKey,
117 CSSM_KEY_PTR pubKey,
118
119 /* input names - one or two */
120 const void *name1Val,
121 CSSM_SIZE name1Len,
122 CSSM_BER_TAG berTag1,
123 const CSSM_OID *name1Oid,
124 const void *name2Val, // optional
125 CSSM_SIZE name2Len,
126 CSSM_BER_TAG berTag2,
127 const CSSM_OID *name2Oid,
128
129 /* expected label */
130 CFStringRef expectedLabel,
131 bool labelIsCommonName)
132 {
133 if(!quiet) {
134 printf("...%s\n", testName);
135 }
136
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;
141
142 CSSM_X509_NAME *name = buildX509Name(nameArray, numNames);
143 if(name == NULL) {
144 printf("***buildX509Name screwup\n");
145 return -1;
146 }
147
148 /* build the cert template */
149 CSSM_DATA_PTR certTemp = CB_MakeCertTemplate(
150 clHand, 0x123456,
151 name, name,
152 notBefore, notAfter,
153 pubKey, SIG_ALG,
154 NULL, NULL, // subject/issuer UniqueID
155 NULL, 0); // extensions
156 if(certTemp == NULL) {
157 printf("***CB_MakeCertTemplate screwup\n");
158 return -1;
159 }
160
161 /* sign the cert */
162 CSSM_DATA signedCert = {0, NULL};
163 CSSM_CC_HANDLE sigHand;
164 CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
165 SIG_ALG,
166 NULL, // no passphrase for now
167 privKey,
168 &sigHand);
169 if(crtn) {
170 /* should never happen */
171 cssmPerror("CSSM_CSP_CreateSignatureContext", crtn);
172 return 1;
173 }
174 crtn = CSSM_CL_CertSign(clHand,
175 sigHand,
176 certTemp, // CertToBeSigned
177 NULL, // SignScope per spec
178 0, // ScopeSize per spec
179 &signedCert);
180 if(crtn) {
181 cssmPerror("CSSM_CL_CertSign", crtn);
182 return 1;
183 }
184 CSSM_DeleteContext(sigHand);
185 CSSM_FREE(certTemp->Data);
186 CSSM_FREE(certTemp);
187
188 /*
189 * OK, we have a signed cert.
190 * Turn it into a SecCertificateRef and get the inferred label.
191 */
192 OSStatus ortn;
193 SecCertificateRef certRef;
194 ortn = SecCertificateCreateFromData(&signedCert,
195 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
196 &certRef);
197 if(ortn) {
198 cssmPerror("SecCertificateCreateFromData", ortn);
199 return -1;
200 }
201 CFStringRef inferredLabel;
202 ortn = SecCertificateInferLabel(certRef, &inferredLabel);
203 if(ortn) {
204 cssmPerror("SecCertificateCreateFromData", ortn);
205 return -1;
206 }
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);
216 }
217 else {
218 fprintf(stderr, "...write %lu bytes to %s\n", (unsigned long)signedCert.Length,
219 CERT_FILE_OUT);
220 }
221 return -1;
222 }
223
224 if(labelIsCommonName) {
225 CFStringRef commonName = NULL;
226 ortn = SecCertificateCopyCommonName(certRef, &commonName);
227 if(ortn) {
228 cssmPerror("SecCertificateCopyCommonName", ortn);
229 return -1;
230 }
231 res = CFStringCompare(inferredLabel, commonName, 0);
232 if(res != kCFCompareEqualTo) {
233 printf("*** CommonName miscompare in test '%s' ***\n", testName);
234 printf("Common Name : '");
235 CFShow(commonName);
236 printf("'\n");
237 printf("inferred label : '");
238 CFShow(inferredLabel);
239 printf("'\n");
240 if(writeFile(CERT_FILE_OUT, signedCert.Data, signedCert.Length)) {
241 printf("***Error writing cert to %s\n", CERT_FILE_OUT);
242 }
243 else {
244 printf("...write %lu bytes to %s\n", (unsigned long)signedCert.Length,
245 CERT_FILE_OUT);
246 }
247 return -1;
248 }
249 CFRelease(commonName);
250 }
251 CFRelease(certRef);
252 CSSM_FREE(signedCert.Data);
253 CB_FreeX509Name(name);
254 CFRelease(inferredLabel);
255 return 0;
256 }
257
258 int main(int argc, char **argv)
259 {
260 bool quiet = false;
261 bool doPause = false;
262
263 int arg;
264 while ((arg = getopt(argc, argv, "pqh")) != -1) {
265 switch (arg) {
266 case 'q':
267 quiet = true;
268 break;
269 case 'p':
270 doPause = true;
271 break;
272 case 'h':
273 usage(argv);
274 }
275 }
276 if(optind != argc) {
277 usage(argv);
278 }
279
280 testStartBanner("certLabelTest", argc, argv);
281
282 CSSM_CL_HANDLE clHand = clStartup();
283 CSSM_CSP_HANDLE cspHand = cspStartup();
284
285 /* create a key pair */
286 CSSM_RETURN crtn;
287 CSSM_KEY pubKey;
288 CSSM_KEY privKey;
289
290 crtn = cspGenKeyPair(cspHand, KEY_ALG,
291 "someLabel", 8,
292 KEY_SIZE,
293 &pubKey, CSSM_FALSE, CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE,
294 &privKey, CSSM_FALSE, CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE,
295 CSSM_FALSE);
296 if(crtn) {
297 printf("***Error generating RSA key pair. Aborting.\n");
298 exit(1);
299 }
300
301 /* common params, reused for each test */
302 notBefore = CB_BuildX509Time(0);
303 notAfter = CB_BuildX509Time(100000);
304
305 /*
306 * Grind thru test cases.
307 */
308 int ourRtn;
309
310 /* very basic */
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);
316 if(ourRtn) {
317 exit(1);
318 }
319
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);
326 if(ourRtn) {
327 exit(1);
328 }
329
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);
336 if(ourRtn) {
337 exit(1);
338 }
339
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);
346 if(ourRtn) {
347 exit(1);
348 }
349
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);
356 if(ourRtn) {
357 exit(1);
358 }
359
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);
367 if(ourRtn) {
368 exit(1);
369 }
370
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,
378 t61Str, true);
379 if(ourRtn) {
380 exit(1);
381 }
382
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");
388 exit(1);
389 }
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,
395 t61Str, true);
396 if(ourRtn) {
397 exit(1);
398 }
399 CFRelease(unicodeStr);
400
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,
410 combo, false);
411 if(ourRtn) {
412 exit(1);
413 }
414 CFRelease(combo);
415 CFRelease(t61Str);
416
417 if(doPause) {
418 fpurge(stdin);
419 printf("Pausing for leaks testing; CR to continue: ");
420 getchar();
421 }
422 if(!quiet) {
423 printf("...success\n");
424 }
425 return 0;
426 }