4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
30 #include <cryptoutil.h>
31 #include <security/cryptoki.h>
36 #define SET_VALUE(f, s) \
38 if (kmfrv != KMF_OK) { \
39 cryptoerror(LOG_STDERR, \
40 gettext("Failed to %s: 0x%02\n"), \
46 gencsr_pkcs11(KMF_HANDLE_T kmfhandle
,
47 char *token
, char *subject
, char *altname
,
48 KMF_GENERALNAMECHOICES alttype
, int altcrit
,
49 char *certlabel
, KMF_KEY_ALG keyAlg
,
50 int keylen
, uint16_t kubits
, int kucrit
,
51 KMF_ENCODE_FORMAT fmt
, char *csrfile
,
52 KMF_CREDENTIAL
*tokencred
, EKU_LIST
*ekulist
,
53 KMF_ALGORITHM_INDEX sigAlg
, KMF_OID
*curveoid
)
55 KMF_RETURN kmfrv
= KMF_OK
;
56 KMF_KEY_HANDLE pubk
, prik
;
57 KMF_X509_NAME csrSubject
;
59 KMF_DATA signedCsr
= { 0, NULL
};
61 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_PK11TOKEN
;
63 KMF_ATTRIBUTE attrlist
[16];
65 (void) memset(&csr
, 0, sizeof (csr
));
66 (void) memset(&csrSubject
, 0, sizeof (csrSubject
));
68 /* If the subject name cannot be parsed, flag it now and exit */
69 if ((kmfrv
= kmf_dn_parser(subject
, &csrSubject
)) != KMF_OK
)
72 /* Select a PKCS11 token */
73 kmfrv
= select_token(kmfhandle
, token
, FALSE
);
77 * Share the "genkeypair" routine for creating the keypair.
79 kmfrv
= genkeypair_pkcs11(kmfhandle
, token
, certlabel
,
80 keyAlg
, keylen
, tokencred
, curveoid
, &prik
, &pubk
);
84 SET_VALUE(kmf_set_csr_pubkey(kmfhandle
, &pubk
, &csr
), "keypair");
86 SET_VALUE(kmf_set_csr_version(&csr
, 2), "version number");
88 SET_VALUE(kmf_set_csr_subject(&csr
, &csrSubject
), "subject name");
90 SET_VALUE(kmf_set_csr_sig_alg(&csr
, sigAlg
),
91 "SignatureAlgorithm");
93 if (altname
!= NULL
) {
94 SET_VALUE(kmf_set_csr_subject_altname(&csr
, altname
, altcrit
,
95 alttype
), "SetCSRSubjectAltName");
99 SET_VALUE(kmf_set_csr_ku(&csr
, kucrit
, kubits
),
102 if (ekulist
!= NULL
) {
104 for (i
= 0; kmfrv
== KMF_OK
&& i
< ekulist
->eku_count
; i
++) {
105 SET_VALUE(kmf_add_csr_eku(&csr
,
106 &ekulist
->ekulist
[i
],
107 ekulist
->critlist
[i
]),
108 "Extended Key Usage");
111 if ((kmfrv
= kmf_sign_csr(kmfhandle
, &csr
, &prik
, &signedCsr
)) ==
113 kmfrv
= kmf_create_csr_file(&signedCsr
, fmt
, csrfile
);
117 (void) kmf_free_data(&signedCsr
);
118 (void) kmf_free_signed_csr(&csr
);
120 /* delete the public key */
122 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYSTORE_TYPE_ATTR
,
123 &kstype
, sizeof (kstype
));
126 kmf_set_attr_at_index(attrlist
, numattr
, KMF_PUBKEY_HANDLE_ATTR
,
127 &pubk
, sizeof (KMF_KEY_HANDLE
));
130 if (tokencred
!= NULL
&& tokencred
->cred
!= NULL
) {
131 kmf_set_attr_at_index(attrlist
, numattr
, KMF_CREDENTIAL_ATTR
,
132 tokencred
, sizeof (KMF_CREDENTIAL
));
136 (void) kmf_delete_key_from_keystore(kmfhandle
, numattr
, attrlist
);
139 * If there is an error, then we need to remove the private key
142 if (kmfrv
!= KMF_OK
) {
144 kmf_set_attr_at_index(attrlist
, numattr
,
145 KMF_KEYSTORE_TYPE_ATTR
, &kstype
, sizeof (kstype
));
148 kmf_set_attr_at_index(attrlist
, numattr
,
149 KMF_KEY_HANDLE_ATTR
, &prik
, sizeof (KMF_KEY_HANDLE
));
152 if (tokencred
!= NULL
&& tokencred
->cred
!= NULL
) {
153 kmf_set_attr_at_index(attrlist
, numattr
,
154 KMF_CREDENTIAL_ATTR
, tokencred
,
155 sizeof (KMF_CREDENTIAL
));
159 (void) kmf_delete_key_from_keystore(kmfhandle
, numattr
,
163 (void) kmf_free_kmf_key(kmfhandle
, &prik
);
168 gencsr_file(KMF_HANDLE_T kmfhandle
,
170 int keylen
, KMF_ENCODE_FORMAT fmt
,
171 char *subject
, char *altname
, KMF_GENERALNAMECHOICES alttype
,
172 int altcrit
, uint16_t kubits
, int kucrit
,
173 char *outcsr
, char *outkey
, EKU_LIST
*ekulist
,
174 KMF_ALGORITHM_INDEX sigAlg
)
177 KMF_KEY_HANDLE pubk
, prik
;
178 KMF_X509_NAME csrSubject
;
180 KMF_DATA signedCsr
= { 0, NULL
};
181 char *fullcsrpath
= NULL
;
182 char *fullkeypath
= NULL
;
185 (void) memset(&csr
, 0, sizeof (csr
));
186 (void) memset(&csrSubject
, 0, sizeof (csrSubject
));
188 if (EMPTYSTRING(outcsr
) || EMPTYSTRING(outkey
)) {
189 cryptoerror(LOG_STDERR
,
190 gettext("No output file was specified for "
191 "the csr or key\n"));
192 return (KMF_ERR_BAD_PARAMETER
);
194 fullcsrpath
= strdup(outcsr
);
195 if (verify_file(fullcsrpath
)) {
196 cryptoerror(LOG_STDERR
,
197 gettext("Cannot write the indicated output "
198 "certificate file (%s).\n"), fullcsrpath
);
200 return (PK_ERR_USAGE
);
203 /* If the subject name cannot be parsed, flag it now and exit */
204 if ((kmfrv
= kmf_dn_parser(subject
, &csrSubject
)) != KMF_OK
) {
208 * Share the "genkeypair" routine for creating the keypair.
210 kmfrv
= genkeypair_file(kmfhandle
, keyAlg
, keylen
,
211 fmt
, outkey
, &prik
, &pubk
);
215 SET_VALUE(kmf_set_csr_pubkey(kmfhandle
, &pubk
, &csr
),
218 SET_VALUE(kmf_set_csr_version(&csr
, 2), "SetCSRVersion");
220 SET_VALUE(kmf_set_csr_subject(&csr
, &csrSubject
),
221 "kmf_set_csr_subject");
223 SET_VALUE(kmf_set_csr_sig_alg(&csr
, sigAlg
), "kmf_set_csr_sig_alg");
225 if (altname
!= NULL
) {
226 SET_VALUE(kmf_set_csr_subject_altname(&csr
, altname
, altcrit
,
227 alttype
), "kmf_set_csr_subject_altname");
230 SET_VALUE(kmf_set_csr_ku(&csr
, kucrit
, kubits
),
233 if (ekulist
!= NULL
) {
235 for (i
= 0; kmfrv
== KMF_OK
&& i
< ekulist
->eku_count
; i
++) {
236 SET_VALUE(kmf_add_csr_eku(&csr
,
237 &ekulist
->ekulist
[i
],
238 ekulist
->critlist
[i
]),
239 "Extended Key Usage");
242 if ((kmfrv
= kmf_sign_csr(kmfhandle
, &csr
, &prik
, &signedCsr
)) ==
244 kmfrv
= kmf_create_csr_file(&signedCsr
, fmt
, fullcsrpath
);
251 kmf_free_data(&signedCsr
);
252 kmf_free_kmf_key(kmfhandle
, &prik
);
253 kmf_free_signed_csr(&csr
);
259 gencsr_nss(KMF_HANDLE_T kmfhandle
,
260 char *token
, char *subject
, char *altname
,
261 KMF_GENERALNAMECHOICES alttype
, int altcrit
,
262 char *nickname
, char *dir
, char *prefix
,
263 KMF_KEY_ALG keyAlg
, int keylen
,
264 uint16_t kubits
, int kucrit
,
265 KMF_ENCODE_FORMAT fmt
, char *csrfile
,
266 KMF_CREDENTIAL
*tokencred
, EKU_LIST
*ekulist
,
267 KMF_ALGORITHM_INDEX sigAlg
, KMF_OID
*curveoid
)
270 KMF_KEY_HANDLE pubk
, prik
;
271 KMF_X509_NAME csrSubject
;
273 KMF_DATA signedCsr
= { 0, NULL
};
275 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_NSS
;
277 KMF_ATTRIBUTE attrlist
[16];
280 token
= DEFAULT_NSS_TOKEN
;
282 kmfrv
= configure_nss(kmfhandle
, dir
, prefix
);
286 (void) memset(&csr
, 0, sizeof (csr
));
287 (void) memset(&csrSubject
, 0, sizeof (csrSubject
));
288 (void) memset(&pubk
, 0, sizeof (pubk
));
289 (void) memset(&prik
, 0, sizeof (prik
));
291 /* If the subject name cannot be parsed, flag it now and exit */
292 if ((kmfrv
= kmf_dn_parser(subject
, &csrSubject
)) != KMF_OK
) {
296 kmfrv
= genkeypair_nss(kmfhandle
, token
, nickname
, dir
,
297 prefix
, keyAlg
, keylen
, tokencred
, curveoid
,
302 SET_VALUE(kmf_set_csr_pubkey(kmfhandle
, &pubk
, &csr
),
303 "kmf_set_csr_pubkey");
304 SET_VALUE(kmf_set_csr_version(&csr
, 2), "kmf_set_csr_version");
305 SET_VALUE(kmf_set_csr_subject(&csr
, &csrSubject
),
306 "kmf_set_csr_subject");
307 SET_VALUE(kmf_set_csr_sig_alg(&csr
, sigAlg
), "kmf_set_csr_sig_alg");
309 if (altname
!= NULL
) {
310 SET_VALUE(kmf_set_csr_subject_altname(&csr
, altname
, altcrit
,
311 alttype
), "kmf_set_csr_subject_altname");
314 SET_VALUE(kmf_set_csr_ku(&csr
, kucrit
, kubits
),
317 if (ekulist
!= NULL
) {
319 for (i
= 0; kmfrv
== KMF_OK
&& i
< ekulist
->eku_count
; i
++) {
320 SET_VALUE(kmf_add_csr_eku(&csr
,
321 &ekulist
->ekulist
[i
],
322 ekulist
->critlist
[i
]),
323 "Extended Key Usage");
326 if ((kmfrv
= kmf_sign_csr(kmfhandle
, &csr
, &prik
, &signedCsr
)) ==
328 kmfrv
= kmf_create_csr_file(&signedCsr
, fmt
, csrfile
);
332 (void) kmf_free_data(&signedCsr
);
333 (void) kmf_free_kmf_key(kmfhandle
, &prik
);
337 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYSTORE_TYPE_ATTR
,
338 &kstype
, sizeof (kstype
));
341 kmf_set_attr_at_index(attrlist
, numattr
, KMF_PUBKEY_HANDLE_ATTR
,
342 &pubk
, sizeof (KMF_KEY_HANDLE
));
345 if (tokencred
!= NULL
&& tokencred
->credlen
> 0) {
346 kmf_set_attr_at_index(attrlist
, numattr
, KMF_CREDENTIAL_ATTR
,
347 tokencred
, sizeof (KMF_CREDENTIAL
));
351 if (token
&& strlen(token
)) {
352 kmf_set_attr_at_index(attrlist
, numattr
, KMF_TOKEN_LABEL_ATTR
,
353 token
, strlen(token
));
357 (void) kmf_delete_key_from_keystore(kmfhandle
, numattr
, attrlist
);
359 (void) kmf_free_signed_csr(&csr
);
365 pk_gencsr(int argc
, char *argv
[])
369 extern int optind_av
;
370 extern char *optarg_av
;
371 KMF_KEYSTORE_TYPE kstype
= 0;
372 char *subject
= NULL
;
373 char *tokenname
= NULL
;
376 int keylen
= PK_DEFAULT_KEYLENGTH
;
377 char *certlabel
= NULL
;
381 char *altname
= NULL
;
384 char *hashname
= NULL
;
386 char *keytype
= PK_DEFAULT_KEYTYPE
;
387 KMF_HANDLE_T kmfhandle
= NULL
;
388 KMF_ENCODE_FORMAT fmt
= KMF_FORMAT_ASN1
;
389 KMF_KEY_ALG keyAlg
= KMF_RSA
;
390 KMF_ALGORITHM_INDEX sigAlg
= KMF_ALGID_SHA1WithRSA
;
391 boolean_t interactive
= B_FALSE
;
392 char *subname
= NULL
;
393 KMF_CREDENTIAL tokencred
= { NULL
, 0 };
394 KMF_GENERALNAMECHOICES alttype
= 0;
395 int altcrit
= 0, kucrit
= 0;
396 EKU_LIST
*ekulist
= NULL
;
397 KMF_OID
*curveoid
= NULL
; /* ECC */
398 KMF_OID
*hashoid
= NULL
;
401 while ((opt
= getopt_av(argc
, argv
,
402 "ik:(keystore)s:(subject)n:(nickname)A:(altname)"
403 "u:(keyusage)T:(token)d:(dir)p:(prefix)t:(keytype)"
404 "y:(keylen)l:(label)c:(outcsr)e:(eku)C:(curve)"
405 "K:(outkey)F:(format)E(listcurves)h:(hash)")) != EOF
) {
413 return (PK_ERR_USAGE
);
415 cryptoerror(LOG_STDERR
,
416 gettext("Interactive (-i) and "
417 "subject options are mutually "
419 return (PK_ERR_USAGE
);
421 interactive
= B_TRUE
;
424 kstype
= KS2Int(optarg_av
);
426 return (PK_ERR_USAGE
);
430 return (PK_ERR_USAGE
);
431 else if (interactive
) {
432 cryptoerror(LOG_STDERR
,
433 gettext("Interactive (-i) and "
434 "subject options are mutually "
436 return (PK_ERR_USAGE
);
443 return (PK_ERR_USAGE
);
444 certlabel
= optarg_av
;
448 return (PK_ERR_USAGE
);
449 tokenname
= optarg_av
;
456 return (PK_ERR_USAGE
);
466 if (sscanf(optarg_av
, "%d",
468 cryptoerror(LOG_STDERR
,
469 gettext("Unrecognized "
470 "key length (%s)\n"), optarg_av
);
471 return (PK_ERR_USAGE
);
477 return (PK_ERR_USAGE
);
482 return (PK_ERR_USAGE
);
487 return (PK_ERR_USAGE
);
494 curveoid
= ecc_name_to_oid(optarg_av
);
495 if (curveoid
== NULL
) {
496 cryptoerror(LOG_STDERR
,
497 gettext("Unrecognized ECC "
499 return (PK_ERR_USAGE
);
504 * This argument is only to be used
505 * by itself, no other options should
509 cryptoerror(LOG_STDERR
,
510 gettext("listcurves has no other "
512 return (PK_ERR_USAGE
);
517 hashname
= optarg_av
;
518 hashoid
= ecc_name_to_oid(optarg_av
);
519 if (hashoid
== NULL
) {
520 cryptoerror(LOG_STDERR
,
521 gettext("Unrecognized hash.\n"));
522 return (PK_ERR_USAGE
);
526 cryptoerror(LOG_STDERR
, gettext(
527 "unrecognized gencsr option '%s'\n"),
529 return (PK_ERR_USAGE
);
532 /* No additional args allowed. */
536 return (PK_ERR_USAGE
);
539 /* Assume keystore = PKCS#11 if not specified. */
541 kstype
= KMF_KEYSTORE_PK11TOKEN
;
543 DIR_OPTION_CHECK(kstype
, dir
);
545 if (EMPTYSTRING(outcsr
) && interactive
) {
546 (void) get_filename("CSR", &outcsr
);
548 if (EMPTYSTRING(outcsr
)) {
549 (void) printf(gettext("A filename must be specified to hold"
550 "the final certificate request data.\n"));
551 return (PK_ERR_USAGE
);
554 * verify that the outcsr file does not already exist
555 * and that it can be created.
557 rv
= verify_file(outcsr
);
558 if (rv
== KMF_ERR_OPEN_FILE
) {
559 cryptoerror(LOG_STDERR
,
560 gettext("Warning: file \"%s\" exists, "
561 "will be overwritten."), outcsr
);
562 if (yesno(gettext("Continue with gencsr? "),
563 gettext("Respond with yes or no.\n"), B_FALSE
) == B_FALSE
) {
566 /* remove the file */
567 (void) unlink(outcsr
);
569 } else if (rv
!= KMF_OK
) {
570 cryptoerror(LOG_STDERR
,
571 gettext("Warning: error accessing \"%s\""), outcsr
);
575 if ((kstype
== KMF_KEYSTORE_NSS
|| kstype
== KMF_KEYSTORE_PK11TOKEN
)) {
576 if (EMPTYSTRING(certlabel
) && interactive
)
577 (void) get_certlabel(&certlabel
);
579 if (EMPTYSTRING(certlabel
)) {
580 cryptoerror(LOG_STDERR
, gettext("A label must be "
581 "specified to create a certificate request.\n"));
582 return (PK_ERR_USAGE
);
584 } else if (kstype
== KMF_KEYSTORE_OPENSSL
) {
585 if (EMPTYSTRING(outkey
) && interactive
)
586 (void) get_filename("private key", &outkey
);
588 if (EMPTYSTRING(outkey
)) {
589 cryptoerror(LOG_STDERR
, gettext("A key filename "
590 "must be specified to create a certificate "
592 return (PK_ERR_USAGE
);
596 if (format
&& (fmt
= Str2Format(format
)) == KMF_FORMAT_UNDEF
) {
597 cryptoerror(LOG_STDERR
,
598 gettext("Error parsing format string (%s).\n"), format
);
599 return (PK_ERR_USAGE
);
601 if (format
&& fmt
!= KMF_FORMAT_ASN1
&& fmt
!= KMF_FORMAT_PEM
) {
602 cryptoerror(LOG_STDERR
,
603 gettext("CSR must be DER or PEM format.\n"));
604 return (PK_ERR_USAGE
);
608 * Check the subject name.
609 * If interactive is true, get it now interactively.
612 if (get_subname(&subname
) != KMF_OK
) {
613 cryptoerror(LOG_STDERR
, gettext("Failed to get the "
614 "subject name interactively.\n"));
615 return (PK_ERR_USAGE
);
618 if (EMPTYSTRING(subject
)) {
619 cryptoerror(LOG_STDERR
, gettext("A subject name or "
620 "-i must be specified to create a certificate "
622 return (PK_ERR_USAGE
);
624 subname
= strdup(subject
);
625 if (subname
== NULL
) {
626 cryptoerror(LOG_STDERR
,
627 gettext("Out of memory.\n"));
628 return (PK_ERR_SYSTEM
);
632 if (altname
!= NULL
) {
633 rv
= verify_altname(altname
, &alttype
, &altcrit
);
635 cryptoerror(LOG_STDERR
, gettext("Subject AltName "
636 "must be specified as a name=value pair. "
637 "See the man page for details."));
640 /* advance the altname past the '=' sign */
641 char *p
= strchr(altname
, '=');
648 rv
= verify_keyusage(kustr
, &kubits
, &kucrit
);
650 cryptoerror(LOG_STDERR
, gettext("KeyUsage "
651 "must be specified as a comma-separated list. "
652 "See the man page for details."));
656 if (ekustr
!= NULL
) {
657 rv
= verify_ekunames(ekustr
, &ekulist
);
659 (void) fprintf(stderr
, gettext("EKUs must "
660 "be specified as a comma-separated list. "
661 "See the man page for details.\n"));
666 if ((rv
= Str2KeyType(keytype
, hashoid
, &keyAlg
, &sigAlg
)) != 0) {
667 cryptoerror(LOG_STDERR
,
668 gettext("Unsupported key/hash combination (%s/%s).\n"),
669 keytype
, (hashname
? hashname
: "none"));
672 if (curveoid
!= NULL
&& keyAlg
!= KMF_ECDSA
) {
673 cryptoerror(LOG_STDERR
, gettext("EC curves are only "
674 "valid for EC keytypes.\n"));
675 return (PK_ERR_USAGE
);
677 if (keyAlg
== KMF_ECDSA
&& curveoid
== NULL
) {
678 cryptoerror(LOG_STDERR
, gettext("A curve must be "
679 "specifed when using EC keys.\n"));
680 return (PK_ERR_USAGE
);
682 if (keyAlg
== KMF_ECDSA
&& kstype
== KMF_KEYSTORE_OPENSSL
) {
683 (void) fprintf(stderr
, gettext("ECC certificates are"
684 "only supported with the pkcs11 and nss keystores\n"));
689 /* Adjust default keylength for NSS and DSA */
690 if (keyAlg
== KMF_DSA
&& !y_flag
&& kstype
== KMF_KEYSTORE_NSS
)
693 if (kstype
== KMF_KEYSTORE_NSS
|| kstype
== KMF_KEYSTORE_PK11TOKEN
) {
694 if (tokenname
== NULL
|| !strlen(tokenname
)) {
695 if (kstype
== KMF_KEYSTORE_NSS
) {
696 tokenname
= "internal";
698 tokenname
= PK_DEFAULT_PK11TOKEN
;
702 (void) get_token_password(kstype
, tokenname
, &tokencred
);
705 if ((rv
= kmf_initialize(&kmfhandle
, NULL
, NULL
)) != KMF_OK
) {
706 cryptoerror(LOG_STDERR
, gettext("Error initializing KMF\n"));
707 return (PK_ERR_USAGE
);
711 if (kstype
== KMF_KEYSTORE_NSS
) {
713 dir
= PK_DEFAULT_DIRECTORY
;
715 rv
= gencsr_nss(kmfhandle
,
716 tokenname
, subname
, altname
, alttype
, altcrit
,
717 certlabel
, dir
, prefix
,
718 keyAlg
, keylen
, kubits
, kucrit
,
719 fmt
, outcsr
, &tokencred
, ekulist
,
722 } else if (kstype
== KMF_KEYSTORE_PK11TOKEN
) {
723 rv
= gencsr_pkcs11(kmfhandle
,
724 tokenname
, subname
, altname
, alttype
, altcrit
,
725 certlabel
, keyAlg
, keylen
,
726 kubits
, kucrit
, fmt
, outcsr
, &tokencred
,
727 ekulist
, sigAlg
, curveoid
);
729 } else if (kstype
== KMF_KEYSTORE_OPENSSL
) {
730 rv
= gencsr_file(kmfhandle
,
731 keyAlg
, keylen
, fmt
, subname
, altname
,
732 alttype
, altcrit
, kubits
, kucrit
,
733 outcsr
, outkey
, ekulist
, sigAlg
);
738 display_error(kmfhandle
, rv
,
739 gettext("Error creating CSR or keypair"));
741 if (rv
== KMF_ERR_RDN_PARSER
) {
742 cryptoerror(LOG_STDERR
, gettext("subject or "
743 "issuer name must be in proper DN format.\n"));
748 free_eku_list(ekulist
);
752 free(tokencred
.cred
);
754 (void) kmf_finalize(kmfhandle
);
756 return (PK_ERR_USAGE
);