]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/sslSubjName/sslSubjName.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / sslSubjName / sslSubjName.cpp
1 /* Copyright (c) 2002-2004,2006,2008 Apple Inc.
2 *
3 * sslSubjName.c
4 *
5 * Verify comparision of app-specified host name vs. various
6 * forms of hostname in a cert.
7 *
8 */
9
10 #include <utilLib/common.h>
11 #include <utilLib/cspwrap.h>
12 #include <clAppUtils/clutils.h>
13 #include <clAppUtils/certVerify.h>
14 #include <clAppUtils/BlobList.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <Security/cssm.h>
19 #include <Security/x509defs.h>
20 #include <Security/oidsattr.h>
21 #include <Security/oidscert.h>
22 #include <Security/oidsalg.h>
23 #include <Security/certextensions.h>
24 #include <Security/cssmapple.h>
25 #include <string.h>
26 #include <security_cdsa_utils/cuFileIo.h>
27
28 /* key labels */
29 #define SUBJ_KEY_LABEL "subjectKey"
30 #define ROOT_KEY_LABEL "rootKey"
31
32 /* key and signature algorithm - shouldn't matter for this test */
33 #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
34 #define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA
35 #define KEY_ALG_DEFAULT CSSM_ALGID_RSA
36
37 #define KEY_SIZE_DEFAULT 512
38
39 #define CERT_FILE "sslCert.cer"
40
41 static void usage(char **argv)
42 {
43 printf("Usage: %s [options]\n", argv[0]);
44 printf("Options:\n");
45 printf(" w(write certs)\n");
46 printf(" q(uiet)\n");
47 printf(" v(erbose)\n");
48 exit(1);
49 }
50
51 /*
52 * RDN components for root, subject
53 */
54 CSSM_APPLE_TP_NAME_OID rootRdn[] =
55 {
56 { "Apple Computer", &CSSMOID_OrganizationName },
57 { "The Big Cheese", &CSSMOID_Title }
58 };
59 #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
60
61 #define SUBJ_COMMON_NAME "something.org"
62
63 CSSM_APPLE_TP_NAME_OID subjRdn[] =
64 {
65 { "Apple Computer", &CSSMOID_OrganizationName },
66 /* overridden when creating the cert */
67 { NULL, &CSSMOID_CommonName }
68 };
69 #define SUBJ_COMMON_NAME_DEX 1
70
71 #define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
72
73
74 /*
75 * Test cases
76 */
77 typedef struct {
78 /* test description */
79 const char *testDesc;
80
81 /* host names for leaf cert - zero or one of these */
82 const char *certDnsName;
83 const char *certIpAddr;
84
85 /* subject common name */
86 const char *commonName;
87
88 /* host name for CertGroupVerify */
89 const char *vfyHostName;
90
91 /* expected error - NULL or e.g. "CSSMERR_APPLETP_CRL_NOT_TRUSTED" */
92 const char *expectErrStr;
93
94 /* one optional per-cert error string */
95 const char *certErrorStr;
96
97 } SSN_TestCase;
98
99 SSN_TestCase testCases[] =
100 {
101 {
102 "DNS Name foo.bar, vfyName foo.bar",
103 "foo.bar", NULL, SUBJ_COMMON_NAME, "foo.bar",
104 NULL,
105 NULL
106 },
107 {
108 "DNS Name foo.bar, vfyName something.org, expect fail due to "
109 "DNS present",
110 "foo.bar", NULL, SUBJ_COMMON_NAME, "something.org",
111 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
112 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
113 },
114 {
115 "DNS Name foo.bar, vfyName foo.foo.bar, expect fail",
116 "foo.bar", NULL, SUBJ_COMMON_NAME, "foo.foo.bar",
117 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
118 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
119 },
120 {
121 "IP Name 1.0.5.8, vfyName 1.0.5.8",
122 NULL, "1.0.5.8", SUBJ_COMMON_NAME, "1.0.5.8",
123 NULL,
124 NULL
125 },
126 {
127 "IP Name 1.0.5.8, vfyName 1.00.5.008",
128 NULL, "1.0.5.8", SUBJ_COMMON_NAME, "1.00.5.008",
129 NULL,
130 NULL
131 },
132 {
133 "IP Name 1.0.5.8, vfyName something.org",
134 NULL, "1.0.5.8", SUBJ_COMMON_NAME, "something.org",
135 NULL,
136 NULL
137 },
138 {
139 "IP Name 1.0.5.8, vfyName 2.0.5.8, expect fail",
140 NULL, "1.0.5.8", SUBJ_COMMON_NAME, "2.0.5.8",
141 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
142 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
143 },
144 {
145 "DNS Name *.foo.bar, vfyName bar.foo.bar",
146 "*.foo.bar", NULL, SUBJ_COMMON_NAME, "bar.foo.bar",
147 NULL,
148 NULL
149 },
150 {
151 "DNS Name *.foo.bar, vfyName foo.bar, expect fail",
152 "*.foo.bar", NULL, SUBJ_COMMON_NAME, "foo.bar",
153 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
154 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
155 },
156 {
157 "DNS Name *foo.bar, vfyName barfoo.bar",
158 "*foo.bar", NULL, SUBJ_COMMON_NAME, "barfoo.bar",
159 NULL,
160 NULL
161 },
162 {
163 "DNS Name *foo*.bar, vfyName barfoo.bar",
164 "*foo*.bar", NULL, SUBJ_COMMON_NAME, "barfoo.bar",
165 NULL,
166 NULL
167 },
168 {
169 "DNS Name *foo*.bar, vfyName foobar.bar",
170 "*foo*.bar", NULL, SUBJ_COMMON_NAME, "foobar.bar",
171 NULL,
172 NULL
173 },
174 {
175 "DNS Name *foo*.bar, vfyName foo.bar",
176 "*foo*.bar", NULL, SUBJ_COMMON_NAME, "foo.bar",
177 NULL,
178 NULL
179 },
180 {
181 "DNS Name *foo.bar, vfyName bar.foo.bar, should fail",
182 "*foo.bar", NULL, SUBJ_COMMON_NAME, "bar.foo.bar",
183 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
184 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
185 },
186 {
187 "DNS Name *foo.bar, vfyName foobar.bar, should fail",
188 "*foo.bar", NULL, SUBJ_COMMON_NAME, "foobar.bar",
189 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
190 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
191 },
192 {
193 "No DNS or IP name, commonName = vfyName = 1.0.5.8",
194 NULL, NULL, "1.0.5.8", "1.0.5.8",
195 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
196 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
197 },
198 };
199
200 #define NUM_TEST_CASES (sizeof(testCases) / sizeof(SSN_TestCase))
201
202 /*
203 * Convert a string containing a dotted IP address to 4 bytes.
204 * Returns nonzero on error.
205 * FIXME - should handle 16-byte IP addresses.
206 */
207 static int convertIp(
208 const char *str,
209 uint8 *buf)
210 {
211 char cbuf[4];
212 for(unsigned dex=0; dex<3; dex++) {
213 char *nextDot = strchr(str, '.');
214 if(nextDot == NULL) {
215 return 1;
216 }
217 memset(cbuf, 0, sizeof(cbuf));
218 memmove(cbuf, str, nextDot - str);
219 *buf = atoi(cbuf);
220 buf++; // next out char
221 str = nextDot + 1; // next in char after dot
222
223 }
224 /* str points to last char */
225 if(str == NULL) {
226 return 1;
227 }
228 *buf = atoi(str);
229 return 0;
230 }
231
232 /*
233 * Generate a pair of certs.
234 */
235 static CSSM_RETURN genCerts(
236 CSSM_CL_HANDLE clHand,
237 CSSM_CSP_HANDLE cspHand,
238 CSSM_TP_HANDLE tpHand,
239 CSSM_KEY_PTR rootPrivKey,
240 CSSM_KEY_PTR rootPubKey,
241 CSSM_KEY_PTR subjPubKey,
242 /* one of these goes into leaf's subjectAltName */
243 const char *subjIpAddr,
244 const char *subjDnsName,
245 const char *commonName,
246 CSSM_DATA &rootCert, // RETURNED
247 CSSM_DATA &subjCert) // RETURNED
248
249 {
250 CSSM_DATA refId;
251 // mallocd by CSSM_TP_SubmitCredRequest
252 CSSM_RETURN crtn;
253 CSSM_APPLE_TP_CERT_REQUEST certReq;
254 CSSM_TP_REQUEST_SET reqSet;
255 sint32 estTime;
256 CSSM_BOOL confirmRequired;
257 CSSM_TP_RESULT_SET_PTR resultSet;
258 CSSM_ENCODED_CERT *encCert;
259 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext;
260 CSSM_FIELD policyId;
261 CE_GeneralNames genNames;
262 CE_GeneralName genName;
263 uint8 ipNameBuf[4];
264 /*
265 * Two extensions. Subject has two (KeyUsage and possibly
266 * subjectAltName); root has KeyUsage and BasicConstraints.
267 */
268 CE_DataAndType rootExts[2];
269 CE_DataAndType leafExts[2];
270 unsigned numLeafExts;
271
272 if(subjIpAddr && subjDnsName) {
273 printf("***Max of one of {subjIpAddr, subjDnsName} at a "
274 "time, please.\n");
275 exit(1);
276 }
277 if(subjIpAddr) {
278 if(convertIp(subjIpAddr, ipNameBuf)) {
279 printf("**Malformed IP address. Aborting.\n");
280 exit(1);
281 }
282 }
283
284 /* A KeyUsage extension for both certs */
285 rootExts[0].type = DT_KeyUsage;
286 rootExts[0].critical = CSSM_FALSE;
287 rootExts[0].extension.keyUsage =
288 CE_KU_DigitalSignature | CE_KU_KeyCertSign;
289
290 leafExts[0].type = DT_KeyUsage;
291 leafExts[0].critical = CSSM_FALSE;
292 leafExts[0].extension.keyUsage = CE_KU_DigitalSignature;
293
294 /* BasicConstraints for root only */
295 rootExts[1].type = DT_BasicConstraints;
296 rootExts[1].critical = CSSM_TRUE;
297 rootExts[1].extension.basicConstraints.cA = CSSM_TRUE;
298 rootExts[1].extension.basicConstraints.pathLenConstraintPresent =
299 CSSM_TRUE;
300 rootExts[1].extension.basicConstraints.pathLenConstraint = 2;
301
302 /* possible subjectAltName for leaf */
303 numLeafExts = 1;
304 if(subjIpAddr || subjDnsName) {
305 numLeafExts++;
306 leafExts[1].type = DT_SubjectAltName;
307 leafExts[1].critical = CSSM_TRUE;
308
309 genName.berEncoded = CSSM_FALSE;
310 if(subjIpAddr) {
311 genName.name.Data = (uint8 *)ipNameBuf;
312 genName.name.Length = 4;
313 genName.nameType = GNT_IPAddress;
314 }
315 else {
316 genName.name.Data = (uint8 *)subjDnsName;
317 genName.nameType = GNT_DNSName;
318 genName.name.Length = strlen(subjDnsName);
319 }
320 genNames.numNames = 1;
321 genNames.generalName = &genName;
322 leafExts[1].extension.subjectAltName = genNames;
323 }
324
325 /* certReq for root */
326 memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST));
327 certReq.cspHand = cspHand;
328 certReq.clHand = clHand;
329 certReq.serialNumber = 0x12345678;
330 certReq.numSubjectNames = NUM_ROOT_NAMES;
331 certReq.subjectNames = rootRdn;
332 certReq.numIssuerNames = 0;
333 certReq.issuerNames = NULL;
334 certReq.certPublicKey = rootPubKey;
335 certReq.issuerPrivateKey = rootPrivKey;
336 certReq.signatureAlg = SIG_ALG_DEFAULT;
337 certReq.signatureOid = SIG_OID_DEFAULT;
338 certReq.notBefore = 0; // now
339 certReq.notAfter = 10000; // seconds from now
340 certReq.numExtensions = 2;
341 certReq.extensions = rootExts;
342
343 reqSet.NumberOfRequests = 1;
344 reqSet.Requests = &certReq;
345
346 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
347 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
348 memset(&policyId, 0, sizeof(CSSM_FIELD));
349 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
350 CallerAuthContext.Policy.NumberOfPolicyIds = 1;
351 CallerAuthContext.Policy.PolicyIds = &policyId;
352
353 /* generate root cert */
354 crtn = CSSM_TP_SubmitCredRequest(tpHand,
355 NULL, // PreferredAuthority
356 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
357 &reqSet,
358 &CallerAuthContext,
359 &estTime,
360 &refId);
361 if(crtn) {
362 printError("CSSM_TP_SubmitCredRequest", crtn);
363 return crtn;
364 }
365 crtn = CSSM_TP_RetrieveCredResult(tpHand,
366 &refId,
367 NULL, // CallerAuthCredentials
368 &estTime,
369 &confirmRequired,
370 &resultSet);
371 if(crtn) {
372 printError("CSSM_TP_RetrieveCredResult", crtn);
373 return crtn;
374 }
375 if(resultSet == NULL) {
376 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
377 return crtn;
378 }
379 encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
380 rootCert = encCert->CertBlob;
381
382 /* now a subject cert signed by the root cert */
383 certReq.serialNumber = 0x8765;
384 certReq.numSubjectNames = NUM_SUBJ_NAMES;
385 subjRdn[SUBJ_COMMON_NAME_DEX].string = commonName;
386 certReq.subjectNames = subjRdn;
387 certReq.numIssuerNames = NUM_ROOT_NAMES;
388 certReq.issuerNames = rootRdn;
389 certReq.certPublicKey = subjPubKey;
390 certReq.issuerPrivateKey = rootPrivKey;
391 certReq.numExtensions = numLeafExts;
392 certReq.extensions = leafExts;
393
394 crtn = CSSM_TP_SubmitCredRequest(tpHand,
395 NULL, // PreferredAuthority
396 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
397 &reqSet,
398 &CallerAuthContext,
399 &estTime,
400 &refId);
401 if(crtn) {
402 printError("CSSM_TP_SubmitCredRequest (2)", crtn);
403 return crtn;
404 }
405 crtn = CSSM_TP_RetrieveCredResult(tpHand,
406 &refId,
407 NULL, // CallerAuthCredentials
408 &estTime,
409 &confirmRequired,
410 &resultSet); // leaks.....
411 if(crtn) {
412 printError("CSSM_TP_RetrieveCredResult (2)", crtn);
413 return crtn;
414 }
415 if(resultSet == NULL) {
416 printf("***CSSM_TP_RetrieveCredResult (2) returned NULL "
417 "result set.\n");
418 return crtn;
419 }
420 encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
421 subjCert = encCert->CertBlob;
422
423 return CSSM_OK;
424 }
425
426 int main(int argc, char **argv)
427 {
428 CSSM_CL_HANDLE clHand; // CL handle
429 CSSM_CSP_HANDLE cspHand; // CSP handle
430 CSSM_TP_HANDLE tpHand; // TP handle
431 CSSM_DATA rootCert;
432 CSSM_DATA subjCert;
433 CSSM_KEY subjPubKey; // subject's RSA public key blob
434 CSSM_KEY subjPrivKey; // subject's RSA private key - ref format
435 CSSM_KEY rootPubKey; // root's RSA public key blob
436 CSSM_KEY rootPrivKey; // root's RSA private key - ref format
437 CSSM_RETURN crtn = CSSM_OK;
438 int vfyRtn = 0;
439 int arg;
440 SSN_TestCase *testCase;
441 unsigned testNum;
442
443 CSSM_BOOL quiet = CSSM_FALSE;
444 CSSM_BOOL verbose = CSSM_FALSE;
445 CSSM_BOOL writeCerts = CSSM_FALSE;
446
447 for(arg=1; arg<argc; arg++) {
448 char *argp = argv[arg];
449 switch(argp[0]) {
450 case 'q':
451 quiet = CSSM_TRUE;
452 break;
453 case 'v':
454 verbose = CSSM_TRUE;
455 break;
456 case 'w':
457 writeCerts = CSSM_TRUE;
458 break;
459 default:
460 usage(argv);
461 }
462 }
463
464 testStartBanner("sslSubjName", argc, argv);
465
466 /* connect to CL, TP, and CSP */
467 clHand = clStartup();
468 if(clHand == 0) {
469 return 0;
470 }
471 tpHand = tpStartup();
472 if(tpHand == 0) {
473 return 0;
474 }
475 cspHand = cspStartup();
476 if(cspHand == 0) {
477 return 0;
478 }
479
480 /* subsequent errors to abort: to detach */
481
482 /* cook up an RSA key pair for the subject */
483 crtn = cspGenKeyPair(cspHand,
484 KEY_ALG_DEFAULT,
485 SUBJ_KEY_LABEL,
486 strlen(SUBJ_KEY_LABEL),
487 KEY_SIZE_DEFAULT,
488 &subjPubKey,
489 CSSM_FALSE, // pubIsRef
490 CSSM_KEYUSE_VERIFY,
491 CSSM_KEYBLOB_RAW_FORMAT_NONE,
492 &subjPrivKey,
493 CSSM_TRUE, // privIsRef - doesn't matter
494 CSSM_KEYUSE_SIGN,
495 CSSM_KEYBLOB_RAW_FORMAT_NONE,
496 CSSM_FALSE);
497 if(crtn) {
498 return crtn;
499 }
500
501 /* and the root */
502 crtn = cspGenKeyPair(cspHand,
503 KEY_ALG_DEFAULT,
504 ROOT_KEY_LABEL,
505 strlen(ROOT_KEY_LABEL),
506 KEY_SIZE_DEFAULT,
507 &rootPubKey,
508 CSSM_FALSE, // pubIsRef
509 CSSM_KEYUSE_VERIFY,
510 CSSM_KEYBLOB_RAW_FORMAT_NONE,
511 &rootPrivKey,
512 CSSM_TRUE, // privIsRef - doesn't matter
513 CSSM_KEYUSE_SIGN,
514 CSSM_KEYBLOB_RAW_FORMAT_NONE,
515 CSSM_FALSE);
516 if(crtn) {
517 goto abort;
518 }
519
520 for(testNum=0; testNum<NUM_TEST_CASES; testNum++) {
521 testCase = &testCases[testNum];
522 if(!quiet) {
523 printf("%s\n", testCase->testDesc);
524 }
525 crtn = genCerts(clHand, cspHand, tpHand,
526 &rootPrivKey, &rootPubKey, &subjPubKey,
527 testCase->certIpAddr, testCase->certDnsName, testCase->commonName,
528 rootCert, subjCert);
529 BlobList leaf;
530 BlobList root;
531 /* BlobList uses regular free() on the referent of the blobs */
532 leaf.addBlob(subjCert, CSSM_TRUE);
533 root.addBlob(rootCert, CSSM_TRUE);
534 if(crtn) {
535 if(testError(quiet)) {
536 break;
537 }
538 }
539 if(writeCerts) {
540 if(writeFile(CERT_FILE, subjCert.Data, subjCert.Length)) {
541 printf("***Error writing cert to %s\n", CERT_FILE);
542 }
543 else {
544 printf("...wrote %lu bytes to %s\n", subjCert.Length, CERT_FILE);
545 }
546 }
547 vfyRtn = certVerifySimple(tpHand, clHand, cspHand,
548 leaf, root,
549 CSSM_FALSE, // useSystemAnchors
550 CSSM_FALSE, // leafCertIsCA
551 CSSM_FALSE, // allow expired root
552 CVP_SSL,
553 testCase->vfyHostName,
554 CSSM_FALSE, // sslClient
555 NULL,
556 NULL,
557 testCase->expectErrStr,
558 testCase->certErrorStr ? 1 : 0,
559 testCase->certErrorStr ? (const char **)&testCase->certErrorStr :
560 NULL,
561 0, NULL, // certStatus
562 CSSM_FALSE, // trustSettings
563 quiet,
564 verbose);
565 if(vfyRtn) {
566 if(testError(quiet)) {
567 break;
568 }
569 }
570 /* cert data freed by ~BlobList */
571 }
572
573 /* free keys */
574 cspFreeKey(cspHand, &rootPubKey);
575 cspFreeKey(cspHand, &rootPrivKey);
576 cspFreeKey(cspHand, &subjPubKey);
577 cspFreeKey(cspHand, &subjPrivKey);
578
579 abort:
580 if(cspHand != 0) {
581 CSSM_ModuleDetach(cspHand);
582 }
583 if(clHand != 0) {
584 CSSM_ModuleDetach(clHand);
585 }
586 if(tpHand != 0) {
587 CSSM_ModuleDetach(tpHand);
588 }
589 if(!vfyRtn && !crtn && !quiet) {
590 printf("...test passed\n");
591 }
592 return 0;
593 }
594
595