1 /* Copyright (c) 1998-2003,2005-2006 Apple Computer, Inc.
5 * Create two certs - a root, and a subject cert signed by the root.
6 * Includes subjectAltName extension for leaf cert.
7 * This version uses CSSM_TP_SubmitCredRequest to create the certs.
11 #include <utilLib/common.h>
12 #include <utilLib/cspwrap.h>
13 #include <security_cdsa_utils/cuFileIo.h>
14 #include <clAppUtils/clutils.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>
28 #define SUBJ_KEY_LABEL "subjectKey"
29 #define ROOT_KEY_LABEL "rootKey"
31 /* default key and signature algorithm */
32 #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA
33 #define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA
34 #define KEY_ALG_DEFAULT CSSM_ALGID_RSA
36 /* for write certs option */
37 #define ROOT_CERT_FILE_NAME "ssRootCert.der"
38 #define SUBJ_CERT_FILE_NAME "ssSubjCert.der"
40 /* public key in ref form, TP supports this as of 1/30/02 */
41 #define PUB_KEY_IS_REF CSSM_TRUE
43 static void usage(char **argv
)
45 printf("Usage: %s [options]\n", argv
[0]);
47 printf(" i=IP_Address for subjectAltName\n");
48 printf(" d=dnsName for subjectAltName\n");
49 printf(" k=keySizeInBits\n");
55 * RDN components for root, subject
57 CSSM_APPLE_TP_NAME_OID rootRdn
[] =
59 { "Apple Computer", &CSSMOID_OrganizationName
},
60 { "The Big Cheese", &CSSMOID_Title
}
62 #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
64 CSSM_APPLE_TP_NAME_OID subjRdn
[] =
66 { "Apple Computer", &CSSMOID_OrganizationName
},
67 { "something.org", &CSSMOID_CommonName
}
69 #define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
72 * Convert a string containing a dotted IP address to 4 bytes.
73 * Returns nonzero on error.
80 for(unsigned dex
=0; dex
<3; dex
++) {
81 char *nextDot
= strchr(str
, '.');
85 memmove(cbuf
, str
, nextDot
- str
);
87 buf
++; // next out char
88 str
= nextDot
+ 1; // next in char after dot
91 /* str points to last char */
99 int main(int argc
, char **argv
)
101 CSSM_CL_HANDLE clHand
; // CL handle
102 CSSM_CSP_HANDLE cspHand
; // CSP handle
103 CSSM_TP_HANDLE tpHand
; // TP handle
104 CSSM_DATA signedRootCert
; // from CSSM_CL_CertSign
105 CSSM_DATA signedSubjCert
; // from CSSM_CL_CertSign
106 CSSM_KEY subjPubKey
; // subject's RSA public key blob
107 CSSM_KEY subjPrivKey
; // subject's RSA private key - ref format
108 CSSM_KEY rootPubKey
; // root's RSA public key blob
109 CSSM_KEY rootPrivKey
; // root's RSA private key - ref format
112 unsigned errorCount
= 0;
113 CSSM_DATA refId
; // mallocd by CSSM_TP_SubmitCredRequest
114 CSSM_APPLE_TP_CERT_REQUEST certReq
;
115 CSSM_TP_REQUEST_SET reqSet
;
117 CSSM_BOOL confirmRequired
;
118 CSSM_TP_RESULT_SET_PTR resultSet
;
119 CSSM_ENCODED_CERT
*encCert
;
120 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext
;
122 CE_GeneralNames genNames
;
123 CE_GeneralName genName
;
126 /* user-spec'd variables */
127 CSSM_ALGORITHMS keyAlg
= KEY_ALG_DEFAULT
;
128 CSSM_ALGORITHMS sigAlg
= SIG_ALG_DEFAULT
;
129 CSSM_OID sigOid
= SIG_OID_DEFAULT
;
130 uint32 keySizeInBits
= CSP_KEY_SIZE_DEFAULT
;
131 char *ipAddrs
= NULL
;
132 char *dnsName
= NULL
;
133 CSSM_BOOL quiet
= CSSM_FALSE
;
136 * Two extensions. Subject has two (KeyUsage and possibly
137 * subjectAltName); root has KeyUsage and BasicConstraints.
139 CE_DataAndType rootExts
[2];
140 CE_DataAndType leafExts
[2];
141 unsigned numLeafExts
;
143 for(arg
=1; arg
<argc
; arg
++) {
144 char *argp
= argv
[arg
];
147 keySizeInBits
= atoi(&argp
[2]);
163 if(ipAddrs
&& dnsName
) {
164 printf("Max of one of {ipAddrs, dnsName} at a time, please.\n");
168 if(convertIp(ipAddrs
, ipNameBuf
)) {
169 printf("**Malformed IP address. Aborting.\n");
174 /* connect to CL, TP, and CSP */
175 clHand
= clStartup();
179 tpHand
= tpStartup();
183 cspHand
= cspStartup();
188 /* subsequent errors to abort: to detach */
190 /* cook up an RSA key pair for the subject */
191 crtn
= cspGenKeyPair(cspHand
,
194 strlen(SUBJ_KEY_LABEL
),
200 CSSM_FALSE
, // pubIsRef - should work both ways, but not yet
203 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
205 CSSM_TRUE
, // privIsRef - doesn't matter
207 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
215 crtn
= cspGenKeyPair(cspHand
,
218 strlen(ROOT_KEY_LABEL
),
221 CSSM_FALSE
, // pubIsRef - should work both ways, but not yet
223 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
225 CSSM_TRUE
, // privIsRef - doesn't matter
227 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
234 /* A KeyUsage extension for both certs */
235 rootExts
[0].type
= DT_KeyUsage
;
236 rootExts
[0].critical
= CSSM_FALSE
;
237 rootExts
[0].extension
.keyUsage
=
238 CE_KU_DigitalSignature
| CE_KU_KeyCertSign
;
240 leafExts
[0].type
= DT_KeyUsage
;
241 leafExts
[0].critical
= CSSM_FALSE
;
242 leafExts
[0].extension
.keyUsage
= CE_KU_DigitalSignature
;
244 /* BasicConstraints for root only */
245 rootExts
[1].type
= DT_BasicConstraints
;
246 rootExts
[1].critical
= CSSM_TRUE
;
247 rootExts
[1].extension
.basicConstraints
.cA
= CSSM_TRUE
;
248 rootExts
[1].extension
.basicConstraints
.pathLenConstraintPresent
=
250 rootExts
[1].extension
.basicConstraints
.pathLenConstraint
= 2;
252 /* possible subjectAltName for leaf */
254 if(ipAddrs
|| dnsName
) {
256 leafExts
[1].type
= DT_SubjectAltName
;
257 leafExts
[1].critical
= CSSM_TRUE
;
259 genName
.berEncoded
= CSSM_FALSE
;
261 genName
.name
.Data
= (uint8
*)ipNameBuf
;
262 genName
.name
.Length
= 4;
263 genName
.nameType
= GNT_IPAddress
;
266 genName
.name
.Data
= (uint8
*)dnsName
;
267 genName
.nameType
= GNT_DNSName
;
268 genName
.name
.Length
= strlen(dnsName
);
270 genNames
.numNames
= 1;
271 genNames
.generalName
= &genName
;
272 leafExts
[1].extension
.subjectAltName
= genNames
;
275 /* certReq for root */
276 memset(&certReq
, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST
));
277 certReq
.cspHand
= cspHand
;
278 certReq
.clHand
= clHand
;
279 certReq
.serialNumber
= 0x12345678;
280 certReq
.numSubjectNames
= NUM_ROOT_NAMES
;
281 certReq
.subjectNames
= rootRdn
;
282 certReq
.numIssuerNames
= 0;
283 certReq
.issuerNames
= NULL
;
284 certReq
.certPublicKey
= &rootPubKey
;
285 certReq
.issuerPrivateKey
= &rootPrivKey
;
286 certReq
.signatureAlg
= sigAlg
;
287 certReq
.signatureOid
= sigOid
;
288 certReq
.notBefore
= 0; // now
289 certReq
.notAfter
= 10000; // seconds from now
290 certReq
.numExtensions
= 2;
291 certReq
.extensions
= rootExts
;
293 reqSet
.NumberOfRequests
= 1;
294 reqSet
.Requests
= &certReq
;
296 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
297 memset(&CallerAuthContext
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
298 memset(&policyId
, 0, sizeof(CSSM_FIELD
));
299 policyId
.FieldOid
= CSSMOID_APPLE_TP_LOCAL_CERT_GEN
;
300 CallerAuthContext
.Policy
.NumberOfPolicyIds
= 1;
301 CallerAuthContext
.Policy
.PolicyIds
= &policyId
;
303 /* generate root cert */
304 crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
305 NULL
, // PreferredAuthority
306 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
312 printError("CSSM_TP_SubmitCredRequest", crtn
);
316 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
318 NULL
, // CallerAuthCredentials
323 printError("CSSM_TP_RetrieveCredResult", crtn
);
327 if(resultSet
== NULL
) {
328 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
332 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
333 signedRootCert
= encCert
->CertBlob
;
335 writeFile(ROOT_CERT_FILE_NAME
, signedRootCert
.Data
,
336 signedRootCert
.Length
);
338 printf("...wrote %lu bytes to %s\n", signedRootCert
.Length
,
339 ROOT_CERT_FILE_NAME
);
342 /* now a subject cert signed by the root cert */
343 certReq
.serialNumber
= 0x8765;
344 certReq
.numSubjectNames
= NUM_SUBJ_NAMES
;
345 certReq
.subjectNames
= subjRdn
;
346 certReq
.numIssuerNames
= NUM_ROOT_NAMES
;
347 certReq
.issuerNames
= rootRdn
;
348 certReq
.certPublicKey
= &subjPubKey
;
349 certReq
.issuerPrivateKey
= &rootPrivKey
;
350 certReq
.numExtensions
= numLeafExts
;
351 certReq
.extensions
= leafExts
;
353 crtn
= CSSM_TP_SubmitCredRequest(tpHand
,
354 NULL
, // PreferredAuthority
355 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
,
361 printError("CSSM_TP_SubmitCredRequest (2)", crtn
);
365 crtn
= CSSM_TP_RetrieveCredResult(tpHand
,
367 NULL
, // CallerAuthCredentials
370 &resultSet
); // leaks.....
372 printError("CSSM_TP_RetrieveCredResult (2)", crtn
);
376 if(resultSet
== NULL
) {
377 printf("***CSSM_TP_RetrieveCredResult (2) returned NULL result set.\n");
381 encCert
= (CSSM_ENCODED_CERT
*)resultSet
->Results
;
382 signedSubjCert
= encCert
->CertBlob
;
384 writeFile(SUBJ_CERT_FILE_NAME
, signedSubjCert
.Data
,
385 signedSubjCert
.Length
);
387 printf("...wrote %lu bytes to %s\n", signedSubjCert
.Length
,
388 SUBJ_CERT_FILE_NAME
);
391 /* free/delete certs and keys */
392 appFreeCssmData(&signedSubjCert
, CSSM_FALSE
);
393 appFreeCssmData(&signedRootCert
, CSSM_FALSE
);
395 cspFreeKey(cspHand
, &rootPubKey
);
396 cspFreeKey(cspHand
, &subjPubKey
);
400 CSSM_ModuleDetach(cspHand
);
403 CSSM_ModuleDetach(clHand
);
406 CSSM_ModuleDetach(tpHand
);