1 /* Copyright (c) 1998,2003,2005-2006,2008 Apple Inc.
5 * Create two certs - a root, and a subject cert signed by the root. Includes
6 * extension construction. Verify certs every which way, including various expected
11 * 31 Aug 2000 Doug Mitchell at Apple
13 * 20 Jul 1998 Doug Mitchell at NeXT
17 #include <utilLib/common.h>
18 #include <utilLib/cspwrap.h>
19 #include <security_cdsa_utils/cuFileIo.h>
20 #include <clAppUtils/CertBuilderApp.h>
21 #include <clAppUtils/clutils.h>
25 #include <Security/cssm.h>
26 #include <Security/x509defs.h>
27 #include <Security/oidsattr.h>
28 #include <Security/oidscert.h>
29 #include <Security/oidsalg.h>
30 #include <Security/certextensions.h>
31 #include <Security/cssmapple.h>
34 #define SUBJ_KEY_LABEL "subjectKey"
35 #define ROOT_KEY_LABEL "rootKey"
36 /* default key and signature algorithm */
37 #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
38 #define KEY_ALG_DEFAULT CSSM_ALGID_RSA
40 /* for write certs/components option */
41 #define ROOT_CERT_FILE_NAME "ssRootCert.der"
42 #define ROOT_TBS_FILE_NAME "ssRootTBS.der"
43 #define SUBJ_CERT_FILE_NAME "ssSubjCert.der"
44 #define SUBJ_TBS_FILE_NAME "ssSubjTBS.der"
45 #define ROOT_PRIV_KEY_FILE "ssRootPriv.der"
46 #define SUBJ_PRIV_KEY_FILE "ssSubjPriv.der"
48 static void usage(char **argv
)
50 printf("Usage: %s [options]\n", argv
[0]);
52 printf(" w[rite certs and components]\n");
53 printf(" a=alg where alg is s(RSA/SHA1), m(RSA/MD5), f(FEE/MD5), F(FEE/SHA1),\n");
54 printf(" 2(RSA/SHA224), 6(RSA/SHA256), 3(RSA/SHA384) 5=RSA/SHA512,\n");
55 printf(" e(ECDSA), E(ANSI/ECDSA), 7(ECDSA/SHA256), 8(ECDSA/SHA384), 9(ECDSA/SHA512)\n");
56 printf(" k=keySizeInBits\n");
61 * RDN components for root, subject
63 CB_NameOid rootRdn
[] =
65 { "Apple Computer", &CSSMOID_OrganizationName
},
66 { "The Big Cheese", &CSSMOID_Title
}
68 #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CB_NameOid))
70 CB_NameOid subjRdn
[] =
72 /* note extra space for normalize test */
73 { "Apple Computer", &CSSMOID_OrganizationName
},
74 { "Doug Mitchell", &CSSMOID_CommonName
}
76 #define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CB_NameOid))
78 static CSSM_BOOL
compareKeyData(const CSSM_KEY
*key1
, const CSSM_KEY
*key2
);
79 static CSSM_RETURN
verifyCert(CSSM_CL_HANDLE clHand
,
80 CSSM_CSP_HANDLE cspHand
,
82 CSSM_DATA_PTR signerCert
,
84 CSSM_ALGORITHMS sigAlg
,
85 CSSM_RETURN expectResult
,
86 const char *opString
);
89 int main(int argc
, char **argv
)
91 CSSM_CL_HANDLE clHand
; // CL handle
92 CSSM_X509_NAME
*subjName
;
93 CSSM_X509_NAME
*rootName
;
94 CSSM_X509_TIME
*notBefore
; // UTC-style "not before" time
95 CSSM_X509_TIME
*notAfter
; // UTC-style "not after" time
96 CSSM_DATA_PTR rawCert
; // from CSSM_CL_CertCreateTemplate
97 CSSM_DATA signedRootCert
; // from CSSM_CL_CertSign
98 CSSM_DATA signedSubjCert
; // from CSSM_CL_CertSign
99 CSSM_CSP_HANDLE cspHand
; // CSP handle
100 CSSM_KEY subjPubKey
; // subject's RSA public key blob
101 CSSM_KEY subjPrivKey
; // subject's RSA private key - ref format
102 CSSM_KEY rootPubKey
; // root's RSA public key blob
103 CSSM_KEY rootPrivKey
; // root's RSA private key - ref format
105 CSSM_KEY_PTR extractRootKey
; // from CSSM_CL_CertGetKeyInfo()
106 CSSM_KEY_PTR extractSubjKey
; // ditto
107 CSSM_CC_HANDLE signContext
; // for signing/verifying the cert
110 unsigned errorCount
= 0;
112 /* user-spec'd variables */
113 CSSM_BOOL writeBlobs
= CSSM_FALSE
;
114 CSSM_ALGORITHMS keyAlg
= KEY_ALG_DEFAULT
;
115 CSSM_ALGORITHMS sigAlg
= SIG_ALG_DEFAULT
;
116 uint32 keySizeInBits
= CSP_KEY_SIZE_DEFAULT
;
119 * Two extensions. Subject has one (KeyUsage); root has KeyUsage and
122 CSSM_X509_EXTENSION exts
[2];
123 CE_KeyUsage keyUsage
;
124 CE_BasicConstraints bc
;
126 for(arg
=1; arg
<argc
; arg
++) {
127 switch(argv
[arg
][0]) {
129 writeBlobs
= CSSM_TRUE
;
132 if((argv
[arg
][1] == '\0') || (argv
[arg
][2] == '\0')) {
135 switch(argv
[arg
][2]) {
137 keyAlg
= CSSM_ALGID_RSA
;
138 sigAlg
= CSSM_ALGID_SHA1WithRSA
;
141 keyAlg
= CSSM_ALGID_RSA
;
142 sigAlg
= CSSM_ALGID_MD5WithRSA
;
145 keyAlg
= CSSM_ALGID_FEE
;
146 sigAlg
= CSSM_ALGID_FEE_MD5
;
149 keyAlg
= CSSM_ALGID_FEE
;
150 sigAlg
= CSSM_ALGID_FEE_SHA1
;
153 keyAlg
= CSSM_ALGID_FEE
;
154 sigAlg
= CSSM_ALGID_SHA1WithECDSA
;
157 keyAlg
= CSSM_ALGID_ECDSA
;
158 sigAlg
= CSSM_ALGID_SHA1WithECDSA
;
161 keyAlg
= CSSM_ALGID_ECDSA
;
162 sigAlg
= CSSM_ALGID_SHA256WithECDSA
;
165 keyAlg
= CSSM_ALGID_ECDSA
;
166 sigAlg
= CSSM_ALGID_SHA384WithECDSA
;
169 keyAlg
= CSSM_ALGID_ECDSA
;
170 sigAlg
= CSSM_ALGID_SHA512WithECDSA
;
173 keyAlg
= CSSM_ALGID_RSA
;
174 sigAlg
= CSSM_ALGID_SHA224WithRSA
;
177 keyAlg
= CSSM_ALGID_RSA
;
178 sigAlg
= CSSM_ALGID_SHA256WithRSA
;
181 keyAlg
= CSSM_ALGID_RSA
;
182 sigAlg
= CSSM_ALGID_SHA384WithRSA
;
185 keyAlg
= CSSM_ALGID_RSA
;
186 sigAlg
= CSSM_ALGID_SHA512WithRSA
;
193 keySizeInBits
= atoi(&argv
[arg
][2]);
200 /* connect to CL and CSP */
201 clHand
= clStartup();
205 cspHand
= cspStartup();
210 /* subsequent errors to abort: to detach */
212 /* cook up an RSA key pair for the subject */
213 crtn
= cspGenKeyPair(cspHand
,
216 strlen(SUBJ_KEY_LABEL
),
219 CSSM_FALSE
, // pubIsRef - should work both ways, but not yet
221 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
223 CSSM_FALSE
, // privIsRef
225 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
232 writeFile(SUBJ_PRIV_KEY_FILE
, subjPrivKey
.KeyData
.Data
,
233 subjPrivKey
.KeyData
.Length
);
234 printf("...wrote %lu bytes to %s\n", subjPrivKey
.KeyData
.Length
,
239 crtn
= cspGenKeyPair(cspHand
,
242 strlen(ROOT_KEY_LABEL
),
245 CSSM_FALSE
, // pubIsRef - should work both ways, but not yet
247 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
249 CSSM_FALSE
, // privIsRef
251 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
258 writeFile(ROOT_PRIV_KEY_FILE
, rootPrivKey
.KeyData
.Data
,
259 rootPrivKey
.KeyData
.Length
);
260 printf("...wrote %lu bytes to %s\n", rootPrivKey
.KeyData
.Length
,
264 if(compareKeyData(&rootPubKey
, &subjPubKey
)) {
265 printf("**WARNING: Identical root and subj keys!\n");
269 * Cook up various cert fields.
270 * First, the RDNs for subject and issuer.
272 rootName
= CB_BuildX509Name(rootRdn
, NUM_ROOT_NAMES
);
273 subjName
= CB_BuildX509Name(subjRdn
, NUM_SUBJ_NAMES
);
274 if((rootName
== NULL
) || (subjName
== NULL
)) {
275 printf("CB_BuildX509Name failure");
280 /* not before/after in generalized time format */
281 notBefore
= CB_BuildX509Time(0);
282 notAfter
= CB_BuildX509Time(10000);
284 /* A KeyUsage extension for both certs */
285 exts
[0].extnId
= CSSMOID_KeyUsage
;
286 exts
[0].critical
= CSSM_FALSE
;
287 exts
[0].format
= CSSM_X509_DATAFORMAT_PARSED
;
288 keyUsage
= CE_KU_DigitalSignature
| CE_KU_KeyCertSign
|
289 CE_KU_KeyEncipherment
| CE_KU_DataEncipherment
;
290 exts
[0].value
.parsedValue
= &keyUsage
;
291 exts
[0].BERvalue
.Data
= NULL
;
292 exts
[0].BERvalue
.Length
= 0;
294 /* BasicConstraints for root only */
295 exts
[1].extnId
= CSSMOID_BasicConstraints
;
296 exts
[1].critical
= CSSM_TRUE
;
297 exts
[1].format
= CSSM_X509_DATAFORMAT_PARSED
;
299 bc
.pathLenConstraintPresent
= CSSM_TRUE
;
300 bc
.pathLenConstraint
= 2;
301 exts
[1].value
.parsedValue
= &bc
;
302 exts
[1].BERvalue
.Data
= NULL
;
303 exts
[1].BERvalue
.Length
= 0;
305 /* cook up root cert */
306 printf("Creating root cert...\n");
307 rawCert
= CB_MakeCertTemplate(clHand
,
308 0x12345678, // serial number
315 NULL
, // subjUniqueId
316 NULL
, // issuerUniqueId
320 if(rawCert
== NULL
) {
325 writeFile(ROOT_TBS_FILE_NAME
, rawCert
->Data
, rawCert
->Length
);
326 printf("...wrote %lu bytes to %s\n", rawCert
->Length
, ROOT_TBS_FILE_NAME
);
329 /* Self-sign; this is a root cert */
330 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
336 printError("CSSM_CSP_CreateSignatureContext", crtn
);
340 signedRootCert
.Data
= NULL
;
341 signedRootCert
.Length
= 0;
342 crtn
= CSSM_CL_CertSign(clHand
,
344 rawCert
, // CertToBeSigned
349 printError("CSSM_CL_CertSign", crtn
);
353 crtn
= CSSM_DeleteContext(signContext
);
355 printError("CSSM_DeleteContext", crtn
);
359 appFreeCssmData(rawCert
, CSSM_TRUE
);
361 writeFile(ROOT_CERT_FILE_NAME
, signedRootCert
.Data
, signedRootCert
.Length
);
362 printf("...wrote %lu bytes to %s\n", signedRootCert
.Length
,
363 ROOT_CERT_FILE_NAME
);
366 /* now a subject cert signed by the root cert */
367 printf("Creating subject cert...\n");
368 rawCert
= CB_MakeCertTemplate(clHand
,
369 0x8765, // serial number
376 NULL
, // subjUniqueId
377 NULL
, // issuerUniqueId
380 if(rawCert
== NULL
) {
385 writeFile(SUBJ_TBS_FILE_NAME
, rawCert
->Data
, rawCert
->Length
);
386 printf("...wrote %lu bytes to %s\n", rawCert
->Length
, SUBJ_TBS_FILE_NAME
);
390 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
396 printError("CSSM_CSP_CreateSignatureContext", crtn
);
400 signedSubjCert
.Data
= NULL
;
401 signedSubjCert
.Length
= 0;
402 crtn
= CSSM_CL_CertSign(clHand
,
404 rawCert
, // CertToBeSigned
409 printError("CSSM_CL_CertSign", crtn
);
413 crtn
= CSSM_DeleteContext(signContext
);
415 printError("CSSM_DeleteContext", crtn
);
419 appFreeCssmData(rawCert
, CSSM_TRUE
);
421 writeFile(SUBJ_CERT_FILE_NAME
, signedSubjCert
.Data
, signedSubjCert
.Length
);
422 printf("...wrote %lu bytes to %s\n", signedSubjCert
.Length
,
423 SUBJ_CERT_FILE_NAME
);
426 /* Free the stuff we allocd to get here */
427 CB_FreeX509Name(rootName
);
428 CB_FreeX509Name(subjName
);
429 CB_FreeX509Time(notBefore
);
430 CB_FreeX509Time(notAfter
);
433 * Extract public keys from the two certs, verify.
435 crtn
= CSSM_CL_CertGetKeyInfo(clHand
, &signedSubjCert
, &extractSubjKey
);
437 printError("CSSM_CL_CertGetKeyInfo", crtn
);
440 /* compare key data - header is different.
441 * Known header differences:
442 * -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for
444 * -- Format. rootPubKey : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE)
445 * extractRootKey : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1)
446 * -- KeyAttr. rootPubKey : 0x20 (CSSM_KEYATTR_EXTRACTABLE)
447 * extractRootKey : 0x0
449 if(!compareKeyData(extractSubjKey
, &subjPubKey
)) {
450 printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n");
452 if(extractSubjKey
->KeyHeader
.LogicalKeySizeInBits
!=
453 subjPubKey
.KeyHeader
.LogicalKeySizeInBits
) {
454 printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n",
455 (unsigned)extractSubjKey
->KeyHeader
.LogicalKeySizeInBits
,
456 (unsigned)subjPubKey
.KeyHeader
.LogicalKeySizeInBits
);
459 crtn
= CSSM_CL_CertGetKeyInfo(clHand
, &signedRootCert
, &extractRootKey
);
461 printError("CSSM_CL_CertGetKeyInfo", crtn
);
464 if(!compareKeyData(extractRootKey
, &rootPubKey
)) {
465 printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n");
472 printf("Verifying certificates...\n");
475 * Verify root cert by root pub key, should succeed.
477 if(verifyCert(clHand
,
484 "Verify(root by root key)")) {
490 * Verify root cert by root cert, should succeed.
492 if(verifyCert(clHand
,
497 CSSM_ALGID_NONE
, // sigAlg not used here
499 "Verify(root by root cert)")) {
506 * Verify subject cert by root pub key, should succeed.
508 if(verifyCert(clHand
,
515 "Verify(subj by root key)")) {
521 * Verify subject cert by root cert, should succeed.
523 if(verifyCert(clHand
,
528 CSSM_ALGID_NONE
, // sigAlg not used here
530 "Verify(subj by root cert)")) {
536 * Verify subject cert by root cert AND key, should succeed.
538 if(verifyCert(clHand
,
545 "Verify(subj by root cert and key)")) {
551 * Verify subject cert by extracted root pub key, should succeed.
553 if(verifyCert(clHand
,
560 "Verify(subj by extracted root key)")) {
566 * Verify subject cert by subject pub key, should fail.
568 if(verifyCert(clHand
,
574 CSSMERR_CL_VERIFICATION_FAILURE
,
575 "Verify(subj by subj key)")) {
581 * Verify subject cert by subject cert, should fail.
583 if(verifyCert(clHand
,
588 CSSM_ALGID_NONE
, // sigAlg not used here
589 CSSMERR_CL_VERIFICATION_FAILURE
,
590 "Verify(subj by subj cert)")) {
596 * Verify erroneous subject cert by root pub key, should fail.
598 badByte
= genRand(1, signedSubjCert
.Length
- 1);
599 signedSubjCert
.Data
[badByte
] ^= 0x55;
600 if(verifyCert(clHand
,
606 CSSMERR_CL_VERIFICATION_FAILURE
,
607 "Verify(bad subj by root key)")) {
613 /* free/delete certs and keys */
614 appFreeCssmData(&signedSubjCert
, CSSM_FALSE
);
615 appFreeCssmData(&signedRootCert
, CSSM_FALSE
);
617 cspFreeKey(cspHand
, &rootPubKey
);
618 cspFreeKey(cspHand
, &subjPubKey
);
620 /* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with
621 * a bogus GUID. This may be a problem with the Apple CSP...
623 cspFreeKey(cspHand, extractRootKey);
624 cspFreeKey(cspHand, extractSubjKey);
626 * do it this way instead...*/
627 CSSM_FREE(extractRootKey
->KeyData
.Data
);
628 CSSM_FREE(extractSubjKey
->KeyData
.Data
);
630 /* need to do this regardless...*/
631 CSSM_FREE(extractRootKey
);
632 CSSM_FREE(extractSubjKey
);
636 CSSM_ModuleDetach(cspHand
);
640 printf("Signer/Subject test failed with %d errors\n", errorCount
);
643 printf("Signer/Subject test succeeded\n");
649 /* compare KeyData for two keys. */
650 static CSSM_BOOL
compareKeyData(const CSSM_KEY
*key1
, const CSSM_KEY
*key2
)
652 if(key1
->KeyData
.Length
!= key2
->KeyData
.Length
) {
655 if(memcmp(key1
->KeyData
.Data
,
657 key1
->KeyData
.Length
)) {
663 /* verify a cert using specified key and/or signerCert */
664 static CSSM_RETURN
verifyCert(CSSM_CL_HANDLE clHand
,
665 CSSM_CSP_HANDLE cspHand
,
667 CSSM_DATA_PTR signerCert
, // optional
668 CSSM_KEY_PTR key
, // ditto, to work spec one, other, or both
669 CSSM_ALGORITHMS sigAlg
, // CSSM_ALGID_SHA1WithRSA, etc.
670 CSSM_RETURN expectResult
,
671 const char *opString
)
674 CSSM_CC_HANDLE signContext
= CSSM_INVALID_HANDLE
;
677 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
683 printf("Failure during %s\n", opString
);
684 printError("CSSM_CSP_CreateSignatureContext", crtn
);
688 crtn
= CSSM_CL_CertVerify(clHand
,
690 cert
, // CertToBeVerified
691 signerCert
, // SignerCert
694 if(crtn
!= expectResult
) {
695 printf("Failure during %s\n", opString
);
696 if(crtn
== CSSM_OK
) {
697 printf("Unexpected CSSM_CL_CertVerify success\n");
699 else if(expectResult
== CSSM_OK
) {
700 printError("CSSM_CL_CertVerify", crtn
);
703 printError("CSSM_CL_CertVerify: expected", expectResult
);
704 printError("CSSM_CL_CertVerify: got ", crtn
);
706 return CSSMERR_CL_VERIFICATION_FAILURE
;
708 if(signContext
!= CSSM_INVALID_HANDLE
) {
709 crtn
= CSSM_DeleteContext(signContext
);
711 printf("Failure during %s\n", opString
);
712 printError("CSSM_DeleteContext", crtn
);