1 /* Copyright (c) 2002-2004,2006,2008 Apple Inc.
5 * Verify comparision of app-specified host name vs. various
6 * forms of hostname in a cert.
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>
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>
26 #include <security_cdsa_utils/cuFileIo.h>
29 #define SUBJ_KEY_LABEL "subjectKey"
30 #define ROOT_KEY_LABEL "rootKey"
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
37 #define KEY_SIZE_DEFAULT 512
39 #define CERT_FILE "sslCert.cer"
41 static void usage(char **argv
)
43 printf("Usage: %s [options]\n", argv
[0]);
45 printf(" w(write certs)\n");
47 printf(" v(erbose)\n");
52 * RDN components for root, subject
54 CSSM_APPLE_TP_NAME_OID rootRdn
[] =
56 { "Apple Computer", &CSSMOID_OrganizationName
},
57 { "The Big Cheese", &CSSMOID_Title
}
59 #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
61 #define SUBJ_COMMON_NAME "something.org"
63 CSSM_APPLE_TP_NAME_OID subjRdn
[] =
65 { "Apple Computer", &CSSMOID_OrganizationName
},
66 /* overridden when creating the cert */
67 { NULL
, &CSSMOID_CommonName
}
69 #define SUBJ_COMMON_NAME_DEX 1
71 #define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
78 /* test description */
81 /* host names for leaf cert - zero or one of these */
82 const char *certDnsName
;
83 const char *certIpAddr
;
85 /* subject common name */
86 const char *commonName
;
88 /* host name for CertGroupVerify */
89 const char *vfyHostName
;
91 /* expected error - NULL or e.g. "CSSMERR_APPLETP_CRL_NOT_TRUSTED" */
92 const char *expectErrStr
;
94 /* one optional per-cert error string */
95 const char *certErrorStr
;
99 SSN_TestCase testCases
[] =
102 "DNS Name foo.bar, vfyName foo.bar",
103 "foo.bar", NULL
, SUBJ_COMMON_NAME
, "foo.bar",
108 "DNS Name foo.bar, vfyName something.org, expect fail due to "
110 "foo.bar", NULL
, SUBJ_COMMON_NAME
, "something.org",
111 "CSSMERR_APPLETP_HOSTNAME_MISMATCH",
112 "0:CSSMERR_APPLETP_HOSTNAME_MISMATCH"
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"
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",
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",
133 "IP Name 1.0.5.8, vfyName something.org",
134 NULL
, "1.0.5.8", SUBJ_COMMON_NAME
, "something.org",
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"
145 "DNS Name *.foo.bar, vfyName bar.foo.bar",
146 "*.foo.bar", NULL
, SUBJ_COMMON_NAME
, "bar.foo.bar",
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"
157 "DNS Name *foo.bar, vfyName barfoo.bar",
158 "*foo.bar", NULL
, SUBJ_COMMON_NAME
, "barfoo.bar",
163 "DNS Name *foo*.bar, vfyName barfoo.bar",
164 "*foo*.bar", NULL
, SUBJ_COMMON_NAME
, "barfoo.bar",
169 "DNS Name *foo*.bar, vfyName foobar.bar",
170 "*foo*.bar", NULL
, SUBJ_COMMON_NAME
, "foobar.bar",
175 "DNS Name *foo*.bar, vfyName foo.bar",
176 "*foo*.bar", NULL
, SUBJ_COMMON_NAME
, "foo.bar",
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"
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"
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"
200 #define NUM_TEST_CASES (sizeof(testCases) / sizeof(SSN_TestCase))
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.
207 static int convertIp(
212 for(unsigned dex
=0; dex
<3; dex
++) {
213 char *nextDot
= strchr(str
, '.');
214 if(nextDot
== NULL
) {
217 memset(cbuf
, 0, sizeof(cbuf
));
218 memmove(cbuf
, str
, nextDot
- str
);
220 buf
++; // next out char
221 str
= nextDot
+ 1; // next in char after dot
224 /* str points to last char */
233 * Generate a pair of certs.
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
251 // mallocd by CSSM_TP_SubmitCredRequest
253 CSSM_APPLE_TP_CERT_REQUEST certReq
;
254 CSSM_TP_REQUEST_SET reqSet
;
256 CSSM_BOOL confirmRequired
;
257 CSSM_TP_RESULT_SET_PTR resultSet
;
258 CSSM_ENCODED_CERT
*encCert
;
259 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext
;
261 CE_GeneralNames genNames
;
262 CE_GeneralName genName
;
265 * Two extensions. Subject has two (KeyUsage and possibly
266 * subjectAltName); root has KeyUsage and BasicConstraints.
268 CE_DataAndType rootExts
[2];
269 CE_DataAndType leafExts
[2];
270 unsigned numLeafExts
;
272 if(subjIpAddr
&& subjDnsName
) {
273 printf("***Max of one of {subjIpAddr, subjDnsName} at a "
278 if(convertIp(subjIpAddr
, ipNameBuf
)) {
279 printf("**Malformed IP address. Aborting.\n");
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
;
290 leafExts
[0].type
= DT_KeyUsage
;
291 leafExts
[0].critical
= CSSM_FALSE
;
292 leafExts
[0].extension
.keyUsage
= CE_KU_DigitalSignature
;
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
=
300 rootExts
[1].extension
.basicConstraints
.pathLenConstraint
= 2;
302 /* possible subjectAltName for leaf */
304 if(subjIpAddr
|| subjDnsName
) {
306 leafExts
[1].type
= DT_SubjectAltName
;
307 leafExts
[1].critical
= CSSM_TRUE
;
309 genName
.berEncoded
= CSSM_FALSE
;
311 genName
.name
.Data
= (uint8
*)ipNameBuf
;
312 genName
.name
.Length
= 4;
313 genName
.nameType
= GNT_IPAddress
;
316 genName
.name
.Data
= (uint8
*)subjDnsName
;
317 genName
.nameType
= GNT_DNSName
;
318 genName
.name
.Length
= strlen(subjDnsName
);
320 genNames
.numNames
= 1;
321 genNames
.generalName
= &genName
;
322 leafExts
[1].extension
.subjectAltName
= genNames
;
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
;
343 reqSet
.NumberOfRequests
= 1;
344 reqSet
.Requests
= &certReq
;
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
;
353 /* generate root cert */
354 crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
355 NULL
, // PreferredAuthority
356 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
362 printError("CSSM_TP_SubmitCredRequest", crtn
);
365 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
367 NULL
, // CallerAuthCredentials
372 printError("CSSM_TP_RetrieveCredResult", crtn
);
375 if(resultSet
== NULL
) {
376 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
379 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
380 rootCert
= encCert
->CertBlob
;
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
;
394 crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
395 NULL
, // PreferredAuthority
396 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
402 printError("CSSM_TP_SubmitCredRequest (2)", crtn
);
405 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
407 NULL
, // CallerAuthCredentials
410 &resultSet
); // leaks.....
412 printError("CSSM_TP_RetrieveCredResult (2)", crtn
);
415 if(resultSet
== NULL
) {
416 printf("***CSSM_TP_RetrieveCredResult (2) returned NULL "
420 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
421 subjCert
= encCert
->CertBlob
;
426 int main(int argc
, char **argv
)
428 CSSM_CL_HANDLE clHand
; // CL handle
429 CSSM_CSP_HANDLE cspHand
; // CSP handle
430 CSSM_TP_HANDLE tpHand
; // TP handle
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
;
440 SSN_TestCase
*testCase
;
443 CSSM_BOOL quiet
= CSSM_FALSE
;
444 CSSM_BOOL verbose
= CSSM_FALSE
;
445 CSSM_BOOL writeCerts
= CSSM_FALSE
;
447 for(arg
=1; arg
<argc
; arg
++) {
448 char *argp
= argv
[arg
];
457 writeCerts
= CSSM_TRUE
;
464 testStartBanner("sslSubjName", argc
, argv
);
466 /* connect to CL, TP, and CSP */
467 clHand
= clStartup();
471 tpHand
= tpStartup();
475 cspHand
= cspStartup();
480 /* subsequent errors to abort: to detach */
482 /* cook up an RSA key pair for the subject */
483 crtn
= cspGenKeyPair(cspHand
,
486 strlen(SUBJ_KEY_LABEL
),
489 CSSM_FALSE
, // pubIsRef
491 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
493 CSSM_TRUE
, // privIsRef - doesn't matter
495 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
502 crtn
= cspGenKeyPair(cspHand
,
505 strlen(ROOT_KEY_LABEL
),
508 CSSM_FALSE
, // pubIsRef
510 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
512 CSSM_TRUE
, // privIsRef - doesn't matter
514 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
520 for(testNum
=0; testNum
<NUM_TEST_CASES
; testNum
++) {
521 testCase
= &testCases
[testNum
];
523 printf("%s\n", testCase
->testDesc
);
525 crtn
= genCerts(clHand
, cspHand
, tpHand
,
526 &rootPrivKey
, &rootPubKey
, &subjPubKey
,
527 testCase
->certIpAddr
, testCase
->certDnsName
, testCase
->commonName
,
531 /* BlobList uses regular free() on the referent of the blobs */
532 leaf
.addBlob(subjCert
, CSSM_TRUE
);
533 root
.addBlob(rootCert
, CSSM_TRUE
);
535 if(testError(quiet
)) {
540 if(writeFile(CERT_FILE
, subjCert
.Data
, subjCert
.Length
)) {
541 printf("***Error writing cert to %s\n", CERT_FILE
);
544 printf("...wrote %lu bytes to %s\n", subjCert
.Length
, CERT_FILE
);
547 vfyRtn
= certVerifySimple(tpHand
, clHand
, cspHand
,
549 CSSM_FALSE
, // useSystemAnchors
550 CSSM_FALSE
, // leafCertIsCA
551 CSSM_FALSE
, // allow expired root
553 testCase
->vfyHostName
,
554 CSSM_FALSE
, // sslClient
557 testCase
->expectErrStr
,
558 testCase
->certErrorStr
? 1 : 0,
559 testCase
->certErrorStr
? (const char **)&testCase
->certErrorStr
:
561 0, NULL
, // certStatus
562 CSSM_FALSE
, // trustSettings
566 if(testError(quiet
)) {
570 /* cert data freed by ~BlobList */
574 cspFreeKey(cspHand
, &rootPubKey
);
575 cspFreeKey(cspHand
, &rootPrivKey
);
576 cspFreeKey(cspHand
, &subjPubKey
);
577 cspFreeKey(cspHand
, &subjPrivKey
);
581 CSSM_ModuleDetach(cspHand
);
584 CSSM_ModuleDetach(clHand
);
587 CSSM_ModuleDetach(tpHand
);
589 if(!vfyRtn
&& !crtn
&& !quiet
) {
590 printf("...test passed\n");