1 /*	$NetBSD: pkcs11-keygen.c,v 1.7 2014/12/10 04:37:52 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2009,2012 Internet Systems Consortium, Inc. ("ISC")
5  *
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.
9  *
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.
17  */
18 
19 /*
20  * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
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.
30  *
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.
41  */
42 
43 /* pkcs11-keygen - PKCS#11 key generator
44  *
45  * Create a key in the keystore of an HSM
46  *
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.
50  *
51  * usage:
52  * pkcs11-keygen [-P] [-m module] [-s slot] [-e] [-b keysize]
53  *               [-i id] [-p pin] -l label
54  *
55  */
56 
57 /*! \file */
58 
59 #include <config.h>
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <fcntl.h>
64 #include <errno.h>
65 #include <string.h>
66 #include <sys/types.h>
67 
68 #include <isc/commandline.h>
69 #include <isc/result.h>
70 #include <isc/types.h>
71 
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>
77 
78 #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
79 #define getpassphrase(x)	getpass(x)
80 #endif
81 
82 /* Define static key template values */
83 static CK_BBOOL truevalue = TRUE;
84 static CK_BBOOL falsevalue = FALSE;
85 
86 /* Key class: RSA, ECC, DSA, DH, or unknown */
87 typedef enum {
88 	key_unknown,
89 	key_rsa,
90 	key_dsa,
91 	key_dh,
92 	key_ecc
93 } key_class_t;
94 
95 /*
96  * Private key template: usable for most key classes without
97  * modificaton; override CKA_SIGN with CKA_DERIVE for DH
98  */
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
106 #define PRIVATE_ID 6
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}
116 };
117 
118 /*
119  * Public key template for RSA keys
120  */
121 #define RSA_LABEL 0
122 #define RSA_VERIFY 1
123 #define RSA_TOKEN 2
124 #define RSA_PRIVATE 3
125 #define RSA_MODULUS_BITS 4
126 #define RSA_PUBLIC_EXPONENT 5
127 #define RSA_ID 6
128 #define RSA_ATTRS 7
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}
137 };
138 
139 /*
140  * Public key template for ECC keys
141  */
142 #define ECC_LABEL 0
143 #define ECC_VERIFY 1
144 #define ECC_TOKEN 2
145 #define ECC_PRIVATE 3
146 #define ECC_PARAMS 4
147 #define ECC_ID 5
148 #define ECC_ATTRS 6
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}
156 };
157 
158 /*
159  * Public key template for DSA keys
160  */
161 #define DSA_LABEL 0
162 #define DSA_VERIFY 1
163 #define DSA_TOKEN 2
164 #define DSA_PRIVATE 3
165 #define DSA_PRIME 4
166 #define DSA_SUBPRIME 5
167 #define DSA_BASE 6
168 #define DSA_ID 7
169 #define DSA_ATTRS 8
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}
179 };
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},
188 };
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)},
195 };
196 
197 /*
198  * Public key template for DH keys
199  */
200 #define DH_LABEL 0
201 #define DH_VERIFY 1
202 #define DH_TOKEN 2
203 #define DH_PRIVATE 3
204 #define DH_PRIME 4
205 #define DH_BASE 5
206 #define DH_ID 6
207 #define DH_ATTRS 7
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}
216 };
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},
223 };
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},
228 };
229 
230 /*
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.
234  */
235 static key_class_t
keyclass_fromtext(const char * name)236 keyclass_fromtext(const char *name) {
237 	if (name == NULL)
238 		return (key_unknown);
239 
240 	if (strncasecmp(name, "rsa", 3) == 0 ||
241 	    strncasecmp(name, "nsec3rsa", 8) == 0)
242 		return (key_rsa);
243 	else if (strncasecmp(name, "dsa", 3) == 0 ||
244 		 strncasecmp(name, "nsec3dsa", 8) == 0)
245 		return (key_dsa);
246 	else if (strcasecmp(name, "dh") == 0)
247 		return (key_dh);
248 	else if (strncasecmp(name, "ecc", 3) == 0 ||
249 		 strncasecmp(name, "ecdsa", 5) == 0)
250 		return (key_ecc);
251 	else
252 		return (key_unknown);
253 }
254 
255 static void
usage(void)256 usage(void) {
257 	fprintf(stderr,
258 		"Usage:\n"
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");
262 	exit(2);
263 }
264 
265 int
main(int argc,char * argv[])266 main(int argc, char *argv[]) {
267 	isc_result_t result;
268 	CK_RV rv;
269 	CK_SLOT_ID slot = 0;
270 	CK_MECHANISM mech, dpmech;
271 	CK_SESSION_HANDLE hSession;
272 	char *lib_name = NULL;
273 	char *pin = NULL;
274 	CK_ULONG bits = 0;
275 	CK_CHAR *label = NULL;
276 	CK_OBJECT_HANDLE privatekey, publickey, domainparams;
277 	CK_BYTE exponent[5];
278 	CK_ULONG expsize = 0;
279 	pk11_context_t pctx;
280 	int error = 0;
281 	int c, errflg = 0;
282 	int hide = 1, special = 0, quiet = 0;
283 	int idlen = 0, id_offset = 0;
284 	unsigned int i;
285 	unsigned long id = 0;
286 	CK_BYTE idbuf[4];
287 	CK_ULONG ulObjectCount;
288 	CK_ATTRIBUTE search_template[] = {
289 		{CKA_LABEL, NULL_PTR, 0}
290 	};
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;
298 
299 #define OPTIONS ":a:b:ei:l:m:Pp:qSs:"
300 	while ((c = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
301 		switch (c) {
302 		case 'a':
303 			keyclass = keyclass_fromtext(isc_commandline_argument);
304 			break;
305 		case 'P':
306 			hide = 0;
307 			break;
308 		case 'm':
309 			lib_name = isc_commandline_argument;
310 			break;
311 		case 's':
312 			slot = atoi(isc_commandline_argument);
313 			break;
314 		case 'e':
315 			expsize = 5;
316 			break;
317 		case 'b':
318 			bits = atoi(isc_commandline_argument);
319 			break;
320 		case 'l':
321 			/* -l option is retained for backward compatibility * */
322 			label = (CK_CHAR *)isc_commandline_argument;
323 			break;
324 		case 'i':
325 			id = strtoul(isc_commandline_argument, NULL, 0);
326 			idlen = 4;
327 			break;
328 		case 'p':
329 			pin = isc_commandline_argument;
330 			break;
331 		case 'q':
332 			quiet = 1;
333 			break;
334 		case 'S':
335 			special = 1;
336 			break;
337 		case ':':
338 			fprintf(stderr,
339 				"Option -%c requires an operand\n",
340 				isc_commandline_option);
341 			errflg++;
342 			break;
343 		case '?':
344 		default:
345 			fprintf(stderr, "Unrecognised option: -%c\n",
346 				isc_commandline_option);
347 			errflg++;
348 		}
349 	}
350 
351 	if (label == NULL && isc_commandline_index < argc)
352 		label = (CK_CHAR *)argv[isc_commandline_index];
353 
354 	if (errflg || (label == NULL))
355 		usage();
356 
357 	if (expsize != 0 && keyclass != key_rsa) {
358 		fprintf(stderr, "The -e option is only compatible "
359 				"with RSA key generation\n");
360 		exit(2);
361 	}
362 
363 	if (special != 0 && keyclass != key_dh) {
364 		fprintf(stderr, "The -S option is only compatible "
365 				"with Diffie-Hellman key generation\n");
366 		exit(2);
367 	}
368 
369 	switch (keyclass) {
370 	case key_rsa:
371 		op_type = OP_RSA;
372 		if (expsize == 0)
373 			expsize = 3;
374 		if (bits == 0)
375 			usage();
376 
377 		mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
378 		mech.pParameter = NULL;
379 		mech.ulParameterLen = 0;
380 
381 		public_template = rsa_template;
382 		public_attrcnt = RSA_ATTRS;
383 		id_offset = RSA_ID;
384 
385 		/* Set public exponent to F4 or F5 */
386 		exponent[0] = 0x01;
387 		exponent[1] = 0x00;
388 		if (expsize == 3)
389 			exponent[2] = 0x01;
390 		else {
391 			exponent[2] = 0x00;
392 			exponent[3] = 0x00;
393 			exponent[4] = 0x01;
394 		}
395 
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;
400 		break;
401 	case key_ecc:
402 		op_type = OP_EC;
403 		if (bits == 0)
404 			bits = 256;
405 		else if (bits != 256 && bits != 384) {
406 			fprintf(stderr, "ECC keys only support bit sizes of "
407 					"256 and 384\n");
408 			exit(2);
409 		}
410 
411 		mech.mechanism = CKM_EC_KEY_PAIR_GEN;
412 		mech.pParameter = NULL;
413 		mech.ulParameterLen = 0;
414 
415 		public_template = ecc_template;
416 		public_attrcnt = ECC_ATTRS;
417 		id_offset = ECC_ID;
418 
419 		if (bits == 256) {
420 			public_template[4].pValue = pk11_ecc_prime256v1;
421 			public_template[4].ulValueLen =
422 				sizeof(pk11_ecc_prime256v1);
423 		} else {
424 			public_template[4].pValue = pk11_ecc_secp384r1;
425 			public_template[4].ulValueLen =
426 				sizeof(pk11_ecc_secp384r1);
427 		}
428 
429 		break;
430 	case key_dsa:
431 		op_type = OP_DSA;
432 		if (bits == 0)
433 			usage();
434 
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;
441 
442 		public_template = dsa_template;
443 		public_attrcnt = DSA_ATTRS;
444 		id_offset = DSA_ID;
445 
446 		domain_template = dsa_domain_template;
447 		domain_attrcnt = DSA_DOMAIN_ATTRS;
448 		param_template = dsa_param_template;
449 		param_attrcnt = DSA_PARAM_ATTRS;
450 
451 		domain_template[DSA_DOMAIN_PRIMEBITS].pValue = &bits;
452 		domain_template[DSA_DOMAIN_PRIMEBITS].ulValueLen = sizeof(bits);
453 		break;
454 	case key_dh:
455 		op_type = OP_DH;
456 		if (special && bits == 0)
457 			bits = 1024;
458 		else if (special &&
459 			 bits != 768 && bits != 1024 && bits != 1536)
460 		{
461 			fprintf(stderr, "When using the special prime (-S) "
462 				"option, only key sizes of\n"
463 				"768, 1024 or 1536 are supported.\n");
464 			exit(2);
465 		} else if (bits == 0)
466 			usage();
467 
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;
474 
475 		/* Override CKA_SIGN attribute */
476 		private_template[PRIVATE_DERIVE].type = CKA_DERIVE;
477 
478 		public_template = dh_template;
479 		public_attrcnt = DH_ATTRS;
480 		id_offset = DH_ID;
481 
482 		domain_template = dh_domain_template;
483 		domain_attrcnt = DH_DOMAIN_ATTRS;
484 		param_template = dh_param_template;
485 		param_attrcnt = DH_PARAM_ATTRS;
486 
487 		domain_template[DH_DOMAIN_PRIMEBITS].pValue = &bits;
488 		domain_template[DH_DOMAIN_PRIMEBITS].ulValueLen = sizeof(bits);
489 		break;
490 	case key_unknown:
491 		usage();
492 	}
493 
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);
500 
501 	if (idlen == 0) {
502 		public_attrcnt--;
503 		private_attrcnt--;
504 	} else {
505 		if (id <= 0xffff) {
506 			idlen = 2;
507 			idbuf[0] = (CK_BYTE)(id >> 8);
508 			idbuf[1] = (CK_BYTE)id;
509 		} else {
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;
514 		}
515 
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;
520 	}
521 
522 	pk11_result_register();
523 
524 	/* Initialize the CRYPTOKI library */
525 	if (lib_name != NULL)
526 		pk11_set_lib_name(lib_name);
527 
528 	if (pin == NULL)
529 		pin = getpassphrase("Enter Pin: ");
530 
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));
542 		exit(1);
543 	}
544 
545 	memset(pin, 0, strlen(pin));
546 
547 	hSession = pctx.session;
548 
549 	/* check if a key with the same id already exists */
550 	rv = pkcs_C_FindObjectsInit(hSession, search_template, 1);
551 	if (rv != CKR_OK) {
552 		fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv);
553 		error = 1;
554 		goto exit_session;
555 	}
556 	rv = pkcs_C_FindObjects(hSession, &privatekey, 1, &ulObjectCount);
557 	if (rv != CKR_OK) {
558 		fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv);
559 		error = 1;
560 		goto exit_search;
561 	}
562 	if (ulObjectCount != 0) {
563 		fprintf(stderr, "Key already exists.\n");
564 		error = 1;
565 		goto exit_search;
566 	}
567 
568 	/* Set attributes if the key is not to be hidden */
569 	if (!hide) {
570 		private_template[4].pValue = &falsevalue;
571 		private_template[5].pValue = &truevalue;
572 	}
573 
574 	if (keyclass == key_rsa || keyclass == key_ecc)
575 		goto generate_keys;
576 
577 	/*
578 	 * Special setup for Diffie-Hellman keys
579 	 */
580 	if (special != 0) {
581 		public_template[DH_BASE].pValue = pk11_dh_bn2;
582 		public_template[DH_BASE].ulValueLen = sizeof(pk11_dh_bn2);
583 		if (bits == 768) {
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);
591 		} else {
592 			public_template[DH_PRIME].pValue = pk11_dh_bn1536;
593 			public_template[DH_PRIME].ulValueLen =
594 				sizeof(pk11_dh_bn1536);
595 		}
596 		param_attrcnt = 0;
597 		goto generate_keys;
598 	}
599 
600 	/* Generate Domain parameters */
601 	rv = pkcs_C_GenerateKey(hSession, &dpmech, domain_template,
602 			   domain_attrcnt, &domainparams);
603 
604 	if (rv != CKR_OK) {
605 		fprintf(stderr,
606 			"C_GenerateKey: Error = 0x%.8lX\n", rv);
607 		error = 1;
608 		goto exit_search;
609 	}
610 
611 	/* Get Domain parameters */
612 	rv = pkcs_C_GetAttributeValue(hSession, domainparams,
613 				 param_template, param_attrcnt);
614 
615 	if (rv != CKR_OK) {
616 		fprintf(stderr,
617 			"C_GetAttributeValue0: Error = 0x%.8lX\n", rv);
618 		error = 1;
619 		goto exit_domain;
620 	}
621 
622 	/* Allocate space for parameter attributes */
623 	for (i = 0; i < param_attrcnt; i++)
624 		param_template[i].pValue = malloc(param_template[i].ulValueLen);
625 
626 	rv = pkcs_C_GetAttributeValue(hSession, domainparams,
627 				 dsa_param_template, DSA_PARAM_ATTRS);
628 
629 	if (rv != CKR_OK) {
630 		fprintf(stderr,
631 			"C_GetAttributeValue1: Error = 0x%.8lX\n", rv);
632 		error = 1;
633 		goto exit_params;
634 	}
635 
636 	switch (keyclass) {
637 	case key_dsa:
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;
650 		break;
651 	case key_dh:
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;
660 	default:
661 		break;
662 	}
663 
664  generate_keys:
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);
670 
671 	if (rv != CKR_OK) {
672 		fprintf(stderr, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv);
673 		error = 1;
674 	 } else if (!quiet)
675 		printf("Key pair generation complete.\n");
676 
677  exit_params:
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);
682 
683  exit_domain:
684 	/* Destroy domain parameters */
685 	if (keyclass == key_dsa || (keyclass == key_dh && !special)) {
686 		rv = pkcs_C_DestroyObject(hSession, domainparams);
687 		if (rv != CKR_OK) {
688 			fprintf(stderr,
689 				"C_DestroyObject: Error = 0x%.8lX\n", rv);
690 			error = 1;
691 		}
692 	}
693 
694  exit_search:
695 	rv = pkcs_C_FindObjectsFinal(hSession);
696 	if (rv != CKR_OK) {
697 		fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv);
698 		error = 1;
699 	}
700 
701  exit_session:
702 	pk11_return_session(&pctx);
703 	(void) pk11_finalize();
704 
705 	exit(error);
706 }
707