1 /* $NetBSD: pkcs11-keygen.c,v 1.7 2014/12/10 04:37:52 christos Exp $ */
4 * Copyright (C) 2009,2012 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
13 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Portions copyright (c) 2008 Nominet UK. All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 /* pkcs11-keygen - PKCS#11 key generator
45 * Create a key in the keystore of an HSM
47 * The calculation of key tag is left to the script
48 * that converts the key into a DNSKEY RR and inserts
49 * it into a zone file.
52 * pkcs11-keygen [-P] [-m module] [-s slot] [-e] [-b keysize]
53 * [-i id] [-p pin] -l label
66 #include <sys/types.h>
68 #include <isc/commandline.h>
69 #include <isc/result.h>
70 #include <isc/types.h>
72 #include <pk11/pk11.h>
73 #include <pk11/result.h>
74 #define WANT_DH_PRIMES
75 #define WANT_ECC_CURVES
76 #include <pk11/constants.h>
78 #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
79 #define getpassphrase(x) getpass(x)
82 /* Define static key template values */
83 static CK_BBOOL truevalue
= TRUE
;
84 static CK_BBOOL falsevalue
= FALSE
;
86 /* Key class: RSA, ECC, DSA, DH, or unknown */
96 * Private key template: usable for most key classes without
97 * modificaton; override CKA_SIGN with CKA_DERIVE for DH
99 #define PRIVATE_LABEL 0
100 #define PRIVATE_SIGN 1
101 #define PRIVATE_DERIVE 1
102 #define PRIVATE_TOKEN 2
103 #define PRIVATE_PRIVATE 3
104 #define PRIVATE_SENSITIVE 4
105 #define PRIVATE_EXTRACTABLE 5
107 #define PRIVATE_ATTRS 7
108 static CK_ATTRIBUTE private_template
[] = {
109 {CKA_LABEL
, NULL_PTR
, 0},
110 {CKA_SIGN
, &truevalue
, sizeof(truevalue
)},
111 {CKA_TOKEN
, &truevalue
, sizeof(truevalue
)},
112 {CKA_PRIVATE
, &truevalue
, sizeof(truevalue
)},
113 {CKA_SENSITIVE
, &truevalue
, sizeof(truevalue
)},
114 {CKA_EXTRACTABLE
, &falsevalue
, sizeof(falsevalue
)},
115 {CKA_ID
, NULL_PTR
, 0}
119 * Public key template for RSA keys
124 #define RSA_PRIVATE 3
125 #define RSA_MODULUS_BITS 4
126 #define RSA_PUBLIC_EXPONENT 5
129 static CK_ATTRIBUTE rsa_template
[] = {
130 {CKA_LABEL
, NULL_PTR
, 0},
131 {CKA_VERIFY
, &truevalue
, sizeof(truevalue
)},
132 {CKA_TOKEN
, &truevalue
, sizeof(truevalue
)},
133 {CKA_PRIVATE
, &falsevalue
, sizeof(falsevalue
)},
134 {CKA_MODULUS_BITS
, NULL_PTR
, 0},
135 {CKA_PUBLIC_EXPONENT
, NULL_PTR
, 0},
136 {CKA_ID
, NULL_PTR
, 0}
140 * Public key template for ECC keys
145 #define ECC_PRIVATE 3
149 static CK_ATTRIBUTE ecc_template
[] = {
150 {CKA_LABEL
, NULL_PTR
, 0},
151 {CKA_VERIFY
, &truevalue
, sizeof(truevalue
)},
152 {CKA_TOKEN
, &truevalue
, sizeof(truevalue
)},
153 {CKA_PRIVATE
, &falsevalue
, sizeof(falsevalue
)},
154 {CKA_EC_PARAMS
, NULL_PTR
, 0},
155 {CKA_ID
, NULL_PTR
, 0}
159 * Public key template for DSA keys
164 #define DSA_PRIVATE 3
166 #define DSA_SUBPRIME 5
170 static CK_ATTRIBUTE dsa_template
[] = {
171 {CKA_LABEL
, NULL_PTR
, 0},
172 {CKA_VERIFY
, &truevalue
, sizeof(truevalue
)},
173 {CKA_TOKEN
, &truevalue
, sizeof(truevalue
)},
174 {CKA_PRIVATE
, &falsevalue
, sizeof(falsevalue
)},
175 {CKA_PRIME
, NULL_PTR
, 0},
176 {CKA_SUBPRIME
, NULL_PTR
, 0},
177 {CKA_BASE
, NULL_PTR
, 0},
178 {CKA_ID
, NULL_PTR
, 0}
180 #define DSA_PARAM_PRIME 0
181 #define DSA_PARAM_SUBPRIME 1
182 #define DSA_PARAM_BASE 2
183 #define DSA_PARAM_ATTRS 3
184 static CK_ATTRIBUTE dsa_param_template
[] = {
185 {CKA_PRIME
, NULL_PTR
, 0},
186 {CKA_SUBPRIME
, NULL_PTR
, 0},
187 {CKA_BASE
, NULL_PTR
, 0},
189 #define DSA_DOMAIN_PRIMEBITS 0
190 #define DSA_DOMAIN_PRIVATE 1
191 #define DSA_DOMAIN_ATTRS 2
192 static CK_ATTRIBUTE dsa_domain_template
[] = {
193 {CKA_PRIME_BITS
, NULL_PTR
, 0},
194 {CKA_PRIVATE
, &falsevalue
, sizeof(falsevalue
)},
198 * Public key template for DH keys
208 static CK_ATTRIBUTE dh_template
[] = {
209 {CKA_LABEL
, NULL_PTR
, 0},
210 {CKA_VERIFY
, &truevalue
, sizeof(truevalue
)},
211 {CKA_TOKEN
, &truevalue
, sizeof(truevalue
)},
212 {CKA_PRIVATE
, &falsevalue
, sizeof(falsevalue
)},
213 {CKA_PRIME
, NULL_PTR
, 0},
214 {CKA_BASE
, NULL_PTR
, 0},
215 {CKA_ID
, NULL_PTR
, 0}
217 #define DH_PARAM_PRIME 0
218 #define DH_PARAM_BASE 1
219 #define DH_PARAM_ATTRS 2
220 static CK_ATTRIBUTE dh_param_template
[] = {
221 {CKA_PRIME
, NULL_PTR
, 0},
222 {CKA_BASE
, NULL_PTR
, 0},
224 #define DH_DOMAIN_PRIMEBITS 0
225 #define DH_DOMAIN_ATTRS 1
226 static CK_ATTRIBUTE dh_domain_template
[] = {
227 {CKA_PRIME_BITS
, NULL_PTR
, 0},
231 * Convert from text to key class. Accepts the names of DNSSEC
232 * signing algorithms, so e.g., ECDSAP256SHA256 maps to ECC and
233 * NSEC3RSASHA1 maps to RSA.
236 keyclass_fromtext(const char *name
) {
238 return (key_unknown
);
240 if (strncasecmp(name
, "rsa", 3) == 0 ||
241 strncasecmp(name
, "nsec3rsa", 8) == 0)
243 else if (strncasecmp(name
, "dsa", 3) == 0 ||
244 strncasecmp(name
, "nsec3dsa", 8) == 0)
246 else if (strcasecmp(name
, "dh") == 0)
248 else if (strncasecmp(name
, "ecc", 3) == 0 ||
249 strncasecmp(name
, "ecdsa", 5) == 0)
252 return (key_unknown
);
259 "\tpkcs11-keygen -a algorithm -b keysize -l label\n"
260 "\t [-P] [-m module] "
261 "[-s slot] [-e] [-S] [-i id] [-p PIN]\n");
266 main(int argc
, char *argv
[]) {
270 CK_MECHANISM mech
, dpmech
;
271 CK_SESSION_HANDLE hSession
;
272 char *lib_name
= NULL
;
275 CK_CHAR
*label
= NULL
;
276 CK_OBJECT_HANDLE privatekey
, publickey
, domainparams
;
278 CK_ULONG expsize
= 0;
282 int hide
= 1, special
= 0, quiet
= 0;
283 int idlen
= 0, id_offset
= 0;
285 unsigned long id
= 0;
287 CK_ULONG ulObjectCount
;
288 CK_ATTRIBUTE search_template
[] = {
289 {CKA_LABEL
, NULL_PTR
, 0}
291 CK_ATTRIBUTE
*public_template
= NULL
;
292 CK_ATTRIBUTE
*domain_template
= NULL
;
293 CK_ATTRIBUTE
*param_template
= NULL
;
294 CK_ULONG public_attrcnt
= 0, private_attrcnt
= PRIVATE_ATTRS
;
295 CK_ULONG domain_attrcnt
= 0, param_attrcnt
= 0;
296 key_class_t keyclass
= key_rsa
;
297 pk11_optype_t op_type
= OP_ANY
;
299 #define OPTIONS ":a:b:ei:l:m:Pp:qSs:"
300 while ((c
= isc_commandline_parse(argc
, argv
, OPTIONS
)) != -1) {
303 keyclass
= keyclass_fromtext(isc_commandline_argument
);
309 lib_name
= isc_commandline_argument
;
312 slot
= atoi(isc_commandline_argument
);
318 bits
= atoi(isc_commandline_argument
);
321 /* -l option is retained for backward compatibility * */
322 label
= (CK_CHAR
*)isc_commandline_argument
;
325 id
= strtoul(isc_commandline_argument
, NULL
, 0);
329 pin
= isc_commandline_argument
;
339 "Option -%c requires an operand\n",
340 isc_commandline_option
);
345 fprintf(stderr
, "Unrecognised option: -%c\n",
346 isc_commandline_option
);
351 if (label
== NULL
&& isc_commandline_index
< argc
)
352 label
= (CK_CHAR
*)argv
[isc_commandline_index
];
354 if (errflg
|| (label
== NULL
))
357 if (expsize
!= 0 && keyclass
!= key_rsa
) {
358 fprintf(stderr
, "The -e option is only compatible "
359 "with RSA key generation\n");
363 if (special
!= 0 && keyclass
!= key_dh
) {
364 fprintf(stderr
, "The -S option is only compatible "
365 "with Diffie-Hellman key generation\n");
377 mech
.mechanism
= CKM_RSA_PKCS_KEY_PAIR_GEN
;
378 mech
.pParameter
= NULL
;
379 mech
.ulParameterLen
= 0;
381 public_template
= rsa_template
;
382 public_attrcnt
= RSA_ATTRS
;
385 /* Set public exponent to F4 or F5 */
396 public_template
[RSA_MODULUS_BITS
].pValue
= &bits
;
397 public_template
[RSA_MODULUS_BITS
].ulValueLen
= sizeof(bits
);
398 public_template
[RSA_PUBLIC_EXPONENT
].pValue
= &exponent
;
399 public_template
[RSA_PUBLIC_EXPONENT
].ulValueLen
= expsize
;
405 else if (bits
!= 256 && bits
!= 384) {
406 fprintf(stderr
, "ECC keys only support bit sizes of "
411 mech
.mechanism
= CKM_EC_KEY_PAIR_GEN
;
412 mech
.pParameter
= NULL
;
413 mech
.ulParameterLen
= 0;
415 public_template
= ecc_template
;
416 public_attrcnt
= ECC_ATTRS
;
420 public_template
[4].pValue
= pk11_ecc_prime256v1
;
421 public_template
[4].ulValueLen
=
422 sizeof(pk11_ecc_prime256v1
);
424 public_template
[4].pValue
= pk11_ecc_secp384r1
;
425 public_template
[4].ulValueLen
=
426 sizeof(pk11_ecc_secp384r1
);
435 dpmech
.mechanism
= CKM_DSA_PARAMETER_GEN
;
436 dpmech
.pParameter
= NULL
;
437 dpmech
.ulParameterLen
= 0;
438 mech
.mechanism
= CKM_DSA_KEY_PAIR_GEN
;
439 mech
.pParameter
= NULL
;
440 mech
.ulParameterLen
= 0;
442 public_template
= dsa_template
;
443 public_attrcnt
= DSA_ATTRS
;
446 domain_template
= dsa_domain_template
;
447 domain_attrcnt
= DSA_DOMAIN_ATTRS
;
448 param_template
= dsa_param_template
;
449 param_attrcnt
= DSA_PARAM_ATTRS
;
451 domain_template
[DSA_DOMAIN_PRIMEBITS
].pValue
= &bits
;
452 domain_template
[DSA_DOMAIN_PRIMEBITS
].ulValueLen
= sizeof(bits
);
456 if (special
&& bits
== 0)
459 bits
!= 768 && bits
!= 1024 && bits
!= 1536)
461 fprintf(stderr
, "When using the special prime (-S) "
462 "option, only key sizes of\n"
463 "768, 1024 or 1536 are supported.\n");
465 } else if (bits
== 0)
468 dpmech
.mechanism
= CKM_DH_PKCS_PARAMETER_GEN
;
469 dpmech
.pParameter
= NULL
;
470 dpmech
.ulParameterLen
= 0;
471 mech
.mechanism
= CKM_DH_PKCS_KEY_PAIR_GEN
;
472 mech
.pParameter
= NULL
;
473 mech
.ulParameterLen
= 0;
475 /* Override CKA_SIGN attribute */
476 private_template
[PRIVATE_DERIVE
].type
= CKA_DERIVE
;
478 public_template
= dh_template
;
479 public_attrcnt
= DH_ATTRS
;
482 domain_template
= dh_domain_template
;
483 domain_attrcnt
= DH_DOMAIN_ATTRS
;
484 param_template
= dh_param_template
;
485 param_attrcnt
= DH_PARAM_ATTRS
;
487 domain_template
[DH_DOMAIN_PRIMEBITS
].pValue
= &bits
;
488 domain_template
[DH_DOMAIN_PRIMEBITS
].ulValueLen
= sizeof(bits
);
494 search_template
[0].pValue
= label
;
495 search_template
[0].ulValueLen
= strlen((char *)label
);
496 public_template
[0].pValue
= label
;
497 public_template
[0].ulValueLen
= strlen((char *)label
);
498 private_template
[0].pValue
= label
;
499 private_template
[0].ulValueLen
= strlen((char *)label
);
507 idbuf
[0] = (CK_BYTE
)(id
>> 8);
508 idbuf
[1] = (CK_BYTE
)id
;
510 idbuf
[0] = (CK_BYTE
)(id
>> 24);
511 idbuf
[1] = (CK_BYTE
)(id
>> 16);
512 idbuf
[2] = (CK_BYTE
)(id
>> 8);
513 idbuf
[3] = (CK_BYTE
)id
;
516 public_template
[id_offset
].pValue
= idbuf
;
517 public_template
[id_offset
].ulValueLen
= idlen
;
518 private_template
[PRIVATE_ID
].pValue
= idbuf
;
519 private_template
[PRIVATE_ID
].ulValueLen
= idlen
;
522 pk11_result_register();
524 /* Initialize the CRYPTOKI library */
525 if (lib_name
!= NULL
)
526 pk11_set_lib_name(lib_name
);
529 pin
= getpassphrase("Enter Pin: ");
531 result
= pk11_get_session(&pctx
, op_type
, ISC_FALSE
, ISC_TRUE
,
532 ISC_TRUE
, (const char *) pin
, slot
);
533 if (result
== PK11_R_NORANDOMSERVICE
||
534 result
== PK11_R_NODIGESTSERVICE
||
535 result
== PK11_R_NOAESSERVICE
) {
536 fprintf(stderr
, "Warning: %s\n", isc_result_totext(result
));
537 fprintf(stderr
, "This HSM will not work with BIND 9 "
538 "using native PKCS#11.\n");
539 } else if (result
!= ISC_R_SUCCESS
) {
540 fprintf(stderr
, "Unrecoverable error initializing "
541 "PKCS#11: %s\n", isc_result_totext(result
));
545 memset(pin
, 0, strlen(pin
));
547 hSession
= pctx
.session
;
549 /* check if a key with the same id already exists */
550 rv
= pkcs_C_FindObjectsInit(hSession
, search_template
, 1);
552 fprintf(stderr
, "C_FindObjectsInit: Error = 0x%.8lX\n", rv
);
556 rv
= pkcs_C_FindObjects(hSession
, &privatekey
, 1, &ulObjectCount
);
558 fprintf(stderr
, "C_FindObjects: Error = 0x%.8lX\n", rv
);
562 if (ulObjectCount
!= 0) {
563 fprintf(stderr
, "Key already exists.\n");
568 /* Set attributes if the key is not to be hidden */
570 private_template
[4].pValue
= &falsevalue
;
571 private_template
[5].pValue
= &truevalue
;
574 if (keyclass
== key_rsa
|| keyclass
== key_ecc
)
578 * Special setup for Diffie-Hellman keys
581 public_template
[DH_BASE
].pValue
= pk11_dh_bn2
;
582 public_template
[DH_BASE
].ulValueLen
= sizeof(pk11_dh_bn2
);
584 public_template
[DH_PRIME
].pValue
= pk11_dh_bn768
;
585 public_template
[DH_PRIME
].ulValueLen
=
586 sizeof(pk11_dh_bn768
);
587 } else if (bits
== 1024) {
588 public_template
[DH_PRIME
].pValue
= pk11_dh_bn1024
;
589 public_template
[DH_PRIME
].ulValueLen
=
590 sizeof(pk11_dh_bn1024
);
592 public_template
[DH_PRIME
].pValue
= pk11_dh_bn1536
;
593 public_template
[DH_PRIME
].ulValueLen
=
594 sizeof(pk11_dh_bn1536
);
600 /* Generate Domain parameters */
601 rv
= pkcs_C_GenerateKey(hSession
, &dpmech
, domain_template
,
602 domain_attrcnt
, &domainparams
);
606 "C_GenerateKey: Error = 0x%.8lX\n", rv
);
611 /* Get Domain parameters */
612 rv
= pkcs_C_GetAttributeValue(hSession
, domainparams
,
613 param_template
, param_attrcnt
);
617 "C_GetAttributeValue0: Error = 0x%.8lX\n", rv
);
622 /* Allocate space for parameter attributes */
623 for (i
= 0; i
< param_attrcnt
; i
++)
624 param_template
[i
].pValue
= malloc(param_template
[i
].ulValueLen
);
626 rv
= pkcs_C_GetAttributeValue(hSession
, domainparams
,
627 dsa_param_template
, DSA_PARAM_ATTRS
);
631 "C_GetAttributeValue1: Error = 0x%.8lX\n", rv
);
638 public_template
[DSA_PRIME
].pValue
=
639 param_template
[DSA_PARAM_PRIME
].pValue
;
640 public_template
[DSA_PRIME
].ulValueLen
=
641 param_template
[DSA_PARAM_PRIME
].ulValueLen
;
642 public_template
[DSA_SUBPRIME
].pValue
=
643 param_template
[DSA_PARAM_SUBPRIME
].pValue
;
644 public_template
[DSA_SUBPRIME
].ulValueLen
=
645 param_template
[DSA_PARAM_SUBPRIME
].ulValueLen
;
646 public_template
[DSA_BASE
].pValue
=
647 param_template
[DSA_PARAM_BASE
].pValue
;
648 public_template
[DSA_BASE
].ulValueLen
=
649 param_template
[DSA_PARAM_BASE
].ulValueLen
;
652 public_template
[DH_PRIME
].pValue
=
653 param_template
[DH_PARAM_PRIME
].pValue
;
654 public_template
[DH_PRIME
].ulValueLen
=
655 param_template
[DH_PARAM_PRIME
].ulValueLen
;
656 public_template
[DH_BASE
].pValue
=
657 param_template
[DH_PARAM_BASE
].pValue
;
658 public_template
[DH_BASE
].ulValueLen
=
659 param_template
[DH_PARAM_BASE
].ulValueLen
;
665 /* Generate Key pair for signing/verifying */
666 rv
= pkcs_C_GenerateKeyPair(hSession
, &mech
,
667 public_template
, public_attrcnt
,
668 private_template
, private_attrcnt
,
669 &publickey
, &privatekey
);
672 fprintf(stderr
, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv
);
675 printf("Key pair generation complete.\n");
678 /* Free parameter attributes */
679 if (keyclass
== key_dsa
|| keyclass
== key_dh
)
680 for (i
= 0; i
< param_attrcnt
; i
++)
681 free(param_template
[i
].pValue
);
684 /* Destroy domain parameters */
685 if (keyclass
== key_dsa
|| (keyclass
== key_dh
&& !special
)) {
686 rv
= pkcs_C_DestroyObject(hSession
, domainparams
);
689 "C_DestroyObject: Error = 0x%.8lX\n", rv
);
695 rv
= pkcs_C_FindObjectsFinal(hSession
);
697 fprintf(stderr
, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv
);
702 pk11_return_session(&pctx
);
703 (void) pk11_finalize();