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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25 * This file implements the sign CSR operation for this tool.
31 #include <cryptoutil.h>
32 #include <security/cryptoki.h>
38 #define SET_VALUE(f, s) \
41 cryptoerror(LOG_STDERR, \
42 gettext("Failed to set %s: 0x%02x\n"), s, rv); \
48 read_csrdata(KMF_HANDLE_T handle
, char *csrfile
, KMF_CSR_DATA
*csrdata
)
50 KMF_RETURN rv
= KMF_OK
;
51 KMF_ENCODE_FORMAT csrfmt
;
52 KMF_DATA csrfiledata
= { 0, NULL
};
53 KMF_DATA rawcsr
= { 0, NULL
};
55 rv
= kmf_get_file_format(csrfile
, &csrfmt
);
59 rv
= kmf_read_input_file(handle
, csrfile
, &csrfiledata
);
63 if (csrfmt
== KMF_FORMAT_PEM
) {
64 rv
= kmf_pem_to_der(csrfiledata
.Data
, csrfiledata
.Length
,
65 &rawcsr
.Data
, (int *)&rawcsr
.Length
);
69 kmf_free_data(&csrfiledata
);
71 rawcsr
.Data
= csrfiledata
.Data
;
72 rawcsr
.Length
= csrfiledata
.Length
;
75 rv
= kmf_decode_csr(handle
, &rawcsr
, csrdata
);
76 kmf_free_data(&rawcsr
);
82 find_csr_extn(KMF_X509_EXTENSIONS
*extnlist
, KMF_OID
*extoid
,
83 KMF_X509_EXTENSION
*outextn
)
86 KMF_X509_EXTENSION
*eptr
;
87 KMF_RETURN rv
= KMF_OK
;
89 (void) memset(outextn
, 0, sizeof (KMF_X509_EXTENSION
));
90 for (i
= 0; !found
&& i
< extnlist
->numberOfExtensions
; i
++) {
91 eptr
= &extnlist
->extensions
[i
];
92 if (IsEqualOid(extoid
, &eptr
->extnId
)) {
93 rv
= copy_extension_data(outextn
, eptr
);
97 if (found
== 0 || rv
!= KMF_OK
)
104 build_cert_from_csr(KMF_CSR_DATA
*csrdata
,
105 KMF_X509_CERTIFICATE
*signedCert
,
108 char *issuer
, char *subject
,
110 KMF_GENERALNAMECHOICES alttype
,
116 KMF_RETURN rv
= KMF_OK
;
117 KMF_X509_NAME issuerDN
, subjectDN
;
120 * If the CSR is ok, now we can generate the final certificate.
122 (void) memset(signedCert
, 0, sizeof (KMF_X509_CERTIFICATE
));
123 (void) memset(&issuerDN
, 0, sizeof (issuerDN
));
124 (void) memset(&subjectDN
, 0, sizeof (subjectDN
));
126 SET_VALUE(kmf_set_cert_version(signedCert
, 2), "version number");
128 SET_VALUE(kmf_set_cert_serial(signedCert
, serial
), "serial number");
130 SET_VALUE(kmf_set_cert_validity(signedCert
, NULL
, ltime
),
134 if (kmf_dn_parser(issuer
, &issuerDN
) != KMF_OK
) {
135 cryptoerror(LOG_STDERR
,
136 gettext("Issuer name cannot be parsed\n"));
137 return (PK_ERR_USAGE
);
139 SET_VALUE(kmf_set_cert_issuer(signedCert
, &issuerDN
),
143 if (kmf_dn_parser(subject
, &subjectDN
) != KMF_OK
) {
144 cryptoerror(LOG_STDERR
,
145 gettext("Subject name cannot be parsed\n"));
146 return (PK_ERR_USAGE
);
148 SET_VALUE(kmf_set_cert_subject(signedCert
, &subjectDN
),
151 signedCert
->certificate
.subject
= csrdata
->csr
.subject
;
154 signedCert
->certificate
.subjectPublicKeyInfo
=
155 csrdata
->csr
.subjectPublicKeyInfo
;
157 signedCert
->certificate
.extensions
= csrdata
->csr
.extensions
;
159 signedCert
->certificate
.signature
=
160 csrdata
->signature
.algorithmIdentifier
;
163 KMF_X509_EXTENSION extn
;
166 * If the CSR already has KU, merge them.
168 rv
= find_csr_extn(&csrdata
->csr
.extensions
,
169 (KMF_OID
*)&KMFOID_KeyUsage
, &extn
);
171 extn
.critical
|= kucrit
;
172 if (extn
.value
.tagAndValue
->value
.Length
> 1) {
174 extn
.value
.tagAndValue
->value
.Data
[1] << 8;
177 extn
.value
.tagAndValue
->value
.Data
[0];
181 SET_VALUE(kmf_set_cert_ku(signedCert
, kucrit
, kubits
),
185 if (altname
!= NULL
) {
186 SET_VALUE(kmf_set_cert_subject_altname(signedCert
,
187 altcrit
, alttype
, altname
), "subjectAltName");
189 if (ekulist
!= NULL
) {
191 for (i
= 0; rv
== KMF_OK
&& i
< ekulist
->eku_count
; i
++) {
192 SET_VALUE(kmf_add_cert_eku(signedCert
,
193 &ekulist
->ekulist
[i
],
194 ekulist
->critlist
[i
]), "Extended Key Usage");
199 kmf_free_dn(&issuerDN
);
201 kmf_free_dn(&subjectDN
);
207 pk_sign_cert(KMF_HANDLE_T handle
, KMF_X509_CERTIFICATE
*cert
,
208 KMF_KEY_HANDLE
*key
, KMF_OID
*sigoid
, KMF_DATA
*outdata
)
212 KMF_ATTRIBUTE attrlist
[4];
215 kmf_set_attr_at_index(attrlist
, numattr
++, KMF_KEYSTORE_TYPE_ATTR
,
216 &key
->kstype
, sizeof (KMF_KEYSTORE_TYPE
));
218 kmf_set_attr_at_index(attrlist
, numattr
++, KMF_KEY_HANDLE_ATTR
,
219 key
, sizeof (KMF_KEY_HANDLE_ATTR
));
221 /* cert data that is to be signed */
222 kmf_set_attr_at_index(attrlist
, numattr
++, KMF_X509_CERTIFICATE_ATTR
,
223 cert
, sizeof (KMF_X509_CERTIFICATE
));
225 /* output buffer for the signed cert */
226 kmf_set_attr_at_index(attrlist
, numattr
++, KMF_CERT_DATA_ATTR
,
227 outdata
, sizeof (KMF_DATA
));
229 /* Set the signature OID value so KMF knows how to generate the sig */
231 kmf_set_attr_at_index(attrlist
, numattr
++, KMF_OID_ATTR
,
232 sigoid
, sizeof (KMF_OID
));
235 if ((rv
= kmf_sign_cert(handle
, numattr
, attrlist
)) != KMF_OK
) {
236 cryptoerror(LOG_STDERR
,
237 gettext("Failed to sign certificate.\n"));
245 pk_signcsr_files(KMF_HANDLE_T handle
,
253 KMF_GENERALNAMECHOICES alttype
,
259 KMF_ENCODE_FORMAT fmt
)
261 KMF_RETURN rv
= KMF_OK
;
262 KMF_CSR_DATA csrdata
;
263 KMF_ATTRIBUTE attrlist
[16];
264 KMF_X509_CERTIFICATE signedCert
;
265 KMF_KEYSTORE_TYPE kstype
= KMF_KEYSTORE_OPENSSL
;
266 KMF_KEY_CLASS keyclass
= KMF_ASYM_PRI
;
267 KMF_KEY_HANDLE cakey
;
268 KMF_DATA certdata
= { 0, NULL
};
271 (void) memset(&cakey
, 0, sizeof (cakey
));
272 (void) memset(&signedCert
, 0, sizeof (signedCert
));
274 rv
= read_csrdata(handle
, csrfile
, &csrdata
);
276 cryptoerror(LOG_STDERR
,
277 gettext("Error reading CSR data\n"));
281 /* verify the signature first */
283 kmf_set_attr_at_index(attrlist
, numattr
, KMF_CSR_DATA_ATTR
,
284 &csrdata
, sizeof (csrdata
));
287 rv
= kmf_verify_csr(handle
, numattr
, attrlist
);
289 cryptoerror(LOG_STDERR
, gettext("CSR signature "
290 "verification failed.\n"));
294 rv
= build_cert_from_csr(&csrdata
, &signedCert
, serial
, ltime
,
295 issuer
, subject
, altname
, alttype
, altcrit
, kubits
,
302 * Find the signing key.
304 (void) memset(&cakey
, 0, sizeof (cakey
));
307 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYSTORE_TYPE_ATTR
,
308 &kstype
, sizeof (kstype
));
311 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEY_FILENAME_ATTR
,
312 signkey
, strlen(signkey
));
315 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYCLASS_ATTR
,
316 &keyclass
, sizeof (keyclass
));
319 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEY_HANDLE_ATTR
,
320 &cakey
, sizeof (cakey
));
324 kmf_set_attr_at_index(attrlist
, numattr
, KMF_COUNT_ATTR
,
325 &count
, sizeof (count
));
328 rv
= kmf_find_key(handle
, numattr
, attrlist
);
330 cryptoerror(LOG_STDERR
, gettext(
331 "Error finding CA signing key\n"));
335 rv
= pk_sign_cert(handle
, &signedCert
, &cakey
, NULL
, &certdata
);
337 cryptoerror(LOG_STDERR
, gettext(
338 "Error signing certificate.\n"));
342 rv
= kmf_create_cert_file(&certdata
, fmt
, certfile
);
345 kmf_free_signed_csr(&csrdata
);
346 kmf_free_data(&certdata
);
347 kmf_free_kmf_key(handle
, &cakey
);
352 pk_signcsr_pk11_nss(KMF_HANDLE_T handle
,
353 KMF_KEYSTORE_TYPE kstype
,
354 char *dir
, char *prefix
,
355 char *token
, KMF_CREDENTIAL
*cred
,
356 char *signkey
, char *csrfile
,
357 KMF_BIGINT
*serial
, char *certfile
, char *issuer
, char *subject
,
358 char *altname
, KMF_GENERALNAMECHOICES alttype
, int altcrit
,
359 uint16_t kubits
, int kucrit
,
360 EKU_LIST
*ekulist
, uint32_t ltime
,
361 KMF_ENCODE_FORMAT fmt
, int store
, char *outlabel
)
363 KMF_RETURN rv
= KMF_OK
;
364 KMF_DATA outcert
= { 0, NULL
};
365 KMF_CSR_DATA csrdata
= { 0, NULL
};
366 KMF_KEY_HANDLE casignkey
;
367 KMF_KEY_CLASS keyclass
= KMF_ASYM_PRI
;
368 KMF_ATTRIBUTE attrlist
[16];
369 KMF_X509_CERTIFICATE signedCert
;
370 boolean_t token_bool
= B_TRUE
;
371 boolean_t private_bool
= B_TRUE
;
375 (void) memset(&casignkey
, 0, sizeof (KMF_KEY_HANDLE
));
376 (void) memset(&signedCert
, 0, sizeof (signedCert
));
378 rv
= read_csrdata(handle
, csrfile
, &csrdata
);
380 cryptoerror(LOG_STDERR
,
381 gettext("Error reading CSR data\n"));
385 if (kstype
== KMF_KEYSTORE_PK11TOKEN
) {
386 rv
= select_token(handle
, token
, FALSE
);
387 } else if (kstype
== KMF_KEYSTORE_NSS
) {
388 rv
= configure_nss(handle
, dir
, prefix
);
391 /* verify the signature first */
392 kmf_set_attr_at_index(attrlist
, numattr
, KMF_CSR_DATA_ATTR
,
393 &csrdata
, sizeof (csrdata
));
396 rv
= kmf_verify_csr(handle
, numattr
, attrlist
);
398 cryptoerror(LOG_STDERR
, gettext("CSR signature "
399 "verification failed.\n"));
403 rv
= build_cert_from_csr(&csrdata
,
404 &signedCert
, serial
, ltime
,
405 issuer
, subject
, altname
,
406 alttype
, altcrit
, kubits
,
413 * Find the signing key.
416 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYSTORE_TYPE_ATTR
,
417 &kstype
, sizeof (kstype
));
419 if (kstype
== KMF_KEYSTORE_NSS
) {
420 kmf_set_attr_at_index(attrlist
, numattr
, KMF_TOKEN_LABEL_ATTR
,
421 token
, strlen(token
));
425 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYLABEL_ATTR
, signkey
,
429 kmf_set_attr_at_index(attrlist
, numattr
, KMF_PRIVATE_BOOL_ATTR
,
430 &private_bool
, sizeof (private_bool
));
433 kmf_set_attr_at_index(attrlist
, numattr
, KMF_TOKEN_BOOL_ATTR
,
434 &token_bool
, sizeof (token_bool
));
437 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYCLASS_ATTR
,
438 &keyclass
, sizeof (keyclass
));
441 kmf_set_attr_at_index(attrlist
, numattr
, KMF_CREDENTIAL_ATTR
,
442 cred
, sizeof (KMF_CREDENTIAL_ATTR
));
445 kmf_set_attr_at_index(attrlist
, numattr
, KMF_COUNT_ATTR
,
446 &keys
, sizeof (keys
));
449 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEY_HANDLE_ATTR
,
450 &casignkey
, sizeof (casignkey
));
453 rv
= kmf_find_key(handle
, numattr
, attrlist
);
455 cryptoerror(LOG_STDERR
,
456 gettext("Failed to find signing key\n"));
460 * If we found the key, now we can sign the cert.
462 rv
= pk_sign_cert(handle
, &signedCert
, &casignkey
, NULL
,
465 cryptoerror(LOG_STDERR
, gettext(
466 "Error signing certificate.\n"));
471 * Store it on the token if the user asked for it.
475 kmf_set_attr_at_index(attrlist
, numattr
, KMF_KEYSTORE_TYPE_ATTR
,
476 &kstype
, sizeof (kstype
));
479 kmf_set_attr_at_index(attrlist
, numattr
, KMF_CERT_DATA_ATTR
,
480 &outcert
, sizeof (KMF_DATA
));
483 if (outlabel
!= NULL
) {
484 kmf_set_attr_at_index(attrlist
, numattr
,
486 outlabel
, strlen(outlabel
));
490 if (kstype
== KMF_KEYSTORE_NSS
) {
492 kmf_set_attr_at_index(attrlist
, numattr
,
493 KMF_TOKEN_LABEL_ATTR
,
494 token
, strlen(token
));
498 rv
= kmf_store_cert(handle
, numattr
, attrlist
);
500 display_error(handle
, rv
,
501 gettext("Failed to store cert "
502 "on PKCS#11 token.\n"));
504 /* Not fatal, we can still write it to a file. */
507 rv
= kmf_create_cert_file(&outcert
, fmt
, certfile
);
510 kmf_free_signed_csr(&csrdata
);
511 kmf_free_data(&outcert
);
512 kmf_free_kmf_key(handle
, &casignkey
);
518 * sign a CSR and generate an x509v3 certificate file.
521 pk_signcsr(int argc
, char *argv
[])
524 extern int optind_av
;
525 extern char *optarg_av
;
526 char *token_spec
= NULL
;
527 char *subject
= NULL
;
531 char *csrfile
= NULL
;
536 char *storestr
= NULL
;
537 char *altname
= NULL
;
538 char *certfile
= NULL
;
539 char *lifetime
= NULL
;
540 char *signkey
= NULL
;
541 char *outlabel
= NULL
;
542 uint32_t ltime
= 365 * 24 * 60 * 60; /* 1 Year */
545 int altcrit
= 0, kucrit
= 0;
546 KMF_BIGINT serial
= { NULL
, 0 };
547 EKU_LIST
*ekulist
= NULL
;
548 KMF_KEYSTORE_TYPE kstype
= 0;
549 KMF_RETURN rv
= KMF_OK
;
550 KMF_HANDLE_T kmfhandle
= NULL
;
551 KMF_CREDENTIAL tokencred
= { NULL
, 0 };
552 KMF_GENERALNAMECHOICES alttype
= 0;
553 KMF_ENCODE_FORMAT fmt
= KMF_FORMAT_PEM
;
555 /* Parse command line options. Do NOT i18n/l10n. */
556 while ((opt
= getopt_av(argc
, argv
,
557 "k:(keystore)c:(csr)T:(token)d:(dir)"
558 "p:(prefix)S:(serial)s:(subject)a:(altname)"
559 "t:(store)F:(format)K:(keyusage)l:(signkey)"
560 "L:(lifetime)e:(eku)i:(issuer)"
561 "n:(outlabel)o:(outcert)")) != EOF
) {
562 if (EMPTYSTRING(optarg_av
))
563 return (PK_ERR_USAGE
);
567 return (PK_ERR_USAGE
);
568 kstype
= KS2Int(optarg_av
);
570 return (PK_ERR_USAGE
);
573 if (storestr
!= NULL
)
574 return (PK_ERR_USAGE
);
575 storestr
= optarg_av
;
576 store
= yn_to_int(optarg_av
);
578 return (PK_ERR_USAGE
);
582 return (PK_ERR_USAGE
);
587 return (PK_ERR_USAGE
);
592 return (PK_ERR_USAGE
);
597 return (PK_ERR_USAGE
);
602 return (PK_ERR_USAGE
);
607 return (PK_ERR_USAGE
);
612 return (PK_ERR_USAGE
);
615 case 'T': /* token specifier */
617 return (PK_ERR_USAGE
);
618 token_spec
= optarg_av
;
620 case 'l': /* object with specific label */
622 return (PK_ERR_USAGE
);
627 return (PK_ERR_USAGE
);
632 return (PK_ERR_USAGE
);
637 return (PK_ERR_USAGE
);
641 if (certfile
!= NULL
)
642 return (PK_ERR_USAGE
);
643 certfile
= optarg_av
;
646 if (lifetime
!= NULL
)
647 return (PK_ERR_USAGE
);
648 lifetime
= optarg_av
;
651 if (outlabel
!= NULL
)
652 return (PK_ERR_USAGE
);
653 outlabel
= optarg_av
;
656 return (PK_ERR_USAGE
);
659 /* No additional args allowed. */
663 return (PK_ERR_USAGE
);
666 /* Assume keystore = PKCS#11 if not specified. */
668 kstype
= KMF_KEYSTORE_PK11TOKEN
;
670 DIR_OPTION_CHECK(kstype
, dir
);
672 if (signkey
== NULL
) {
673 (void) fprintf(stderr
, gettext("The signing key label "
674 "or filename was not specified\n"));
675 return (PK_ERR_USAGE
);
677 if (csrfile
== NULL
) {
678 (void) fprintf(stderr
, gettext("The CSR filename was not"
680 return (PK_ERR_USAGE
);
682 if (certfile
== NULL
) {
683 (void) fprintf(stderr
, gettext("The output certificate file "
684 "was not specified\n"));
685 return (PK_ERR_USAGE
);
687 if (issuer
== NULL
) {
688 (void) fprintf(stderr
, gettext("The issuer DN "
689 "was not specified\n"));
690 return (PK_ERR_USAGE
);
692 if (lifetime
!= NULL
) {
693 if (Str2Lifetime(lifetime
, <ime
) != 0) {
694 cryptoerror(LOG_STDERR
,
695 gettext("Error parsing lifetime string\n"));
696 return (PK_ERR_USAGE
);
699 if (kstype
== KMF_KEYSTORE_PK11TOKEN
&& EMPTYSTRING(token_spec
)) {
700 token_spec
= PK_DEFAULT_PK11TOKEN
;
701 } else if (kstype
== KMF_KEYSTORE_NSS
&& EMPTYSTRING(token_spec
)) {
702 token_spec
= DEFAULT_NSS_TOKEN
;
705 if (serstr
!= NULL
) {
706 uchar_t
*bytes
= NULL
;
709 rv
= kmf_hexstr_to_bytes((uchar_t
*)serstr
, &bytes
, &bytelen
);
710 if (rv
!= KMF_OK
|| bytes
== NULL
) {
711 (void) fprintf(stderr
, gettext("Serial number "
712 "must be specified as a hex number "
713 "(ex: 0x0102030405ffeeddee)\n"));
714 return (PK_ERR_USAGE
);
717 serial
.len
= bytelen
;
719 (void) fprintf(stderr
, gettext("The serial number was not"
721 return (PK_ERR_USAGE
);
724 if ((kstype
== KMF_KEYSTORE_PK11TOKEN
||
725 kstype
== KMF_KEYSTORE_NSS
)) {
726 /* Need to get password for private key access */
727 (void) get_token_password(kstype
, token_spec
,
731 rv
= verify_keyusage(kustr
, &kubits
, &kucrit
);
733 (void) fprintf(stderr
, gettext("KeyUsage "
734 "must be specified as a comma-separated list. "
735 "See the man page for details.\n"));
740 if (ekustr
!= NULL
) {
741 rv
= verify_ekunames(ekustr
, &ekulist
);
743 (void) fprintf(stderr
, gettext("EKUs must "
744 "be specified as a comma-separated list. "
745 "See the man page for details.\n"));
750 if (altname
!= NULL
) {
752 rv
= verify_altname(altname
, &alttype
, &altcrit
);
754 (void) fprintf(stderr
, gettext("Subject AltName "
755 "must be specified as a name=value pair. "
756 "See the man page for details.\n"));
760 /* advance the altname past the '=' sign */
761 p
= strchr(altname
, '=');
765 if (format
&& (fmt
= Str2Format(format
)) == KMF_FORMAT_UNDEF
) {
766 cryptoerror(LOG_STDERR
,
767 gettext("Error parsing format string (%s).\n"),
769 return (PK_ERR_USAGE
);
772 if ((rv
= kmf_initialize(&kmfhandle
, NULL
, NULL
)) != KMF_OK
) {
776 if (kstype
== KMF_KEYSTORE_PK11TOKEN
) {
777 rv
= pk_signcsr_pk11_nss(kmfhandle
,
778 kstype
, dir
, prefix
, token_spec
, &tokencred
,
779 signkey
, csrfile
, &serial
, certfile
, issuer
, subject
,
780 altname
, alttype
, altcrit
, kubits
, kucrit
,
781 ekulist
, ltime
, fmt
, store
, outlabel
);
783 } else if (kstype
== KMF_KEYSTORE_NSS
) {
785 dir
= PK_DEFAULT_DIRECTORY
;
787 rv
= pk_signcsr_pk11_nss(kmfhandle
,
788 kstype
, dir
, prefix
, token_spec
, &tokencred
,
789 signkey
, csrfile
, &serial
, certfile
, issuer
, subject
,
790 altname
, alttype
, altcrit
, kubits
, kucrit
,
791 ekulist
, ltime
, fmt
, store
, outlabel
);
793 } else if (kstype
== KMF_KEYSTORE_OPENSSL
) {
794 rv
= pk_signcsr_files(kmfhandle
,
795 signkey
, csrfile
, &serial
, certfile
, issuer
, subject
,
796 altname
, alttype
, altcrit
, kubits
, kucrit
,
797 ekulist
, ltime
, fmt
);
802 display_error(kmfhandle
, rv
,
803 gettext("Error listing objects"));
806 if (serial
.val
!= NULL
)
809 if (tokencred
.cred
!= NULL
)
810 free(tokencred
.cred
);
812 free_eku_list(ekulist
);
814 (void) kmf_finalize(kmfhandle
);