1/*	$NetBSD: pkcs11-keygen.c,v 1.2.6.1 2012/06/05 21:15:30 bouyer Exp $	*/
2
3/*
4 * Copyright (C) 2009  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/* Id: pkcs11-keygen.c,v 1.9 2009/10/26 23:36:53 each Exp  */
44
45/* pkcs11-keygen - pkcs11 rsa key generator
46*
47* create RSASHA1 key in the keystore of an SCA6000
48* The calculation of key tag is left to the script
49* that converts the key into a DNSKEY RR and inserts
50* it into a zone file.
51*
52* usage:
53* pkcs11-keygen [-P] [-m module] [-s slot] [-e] -b keysize
54*               -l label [-i id] [-p pin]
55*
56*/
57
58/*! \file */
59
60#include <config.h>
61
62#include <stdio.h>
63#include <stdlib.h>
64#include <fcntl.h>
65#include <errno.h>
66#include <string.h>
67#include <sys/types.h>
68#include "cryptoki.h"
69
70#ifdef WIN32
71#include "win32.c"
72#else
73#ifndef FORCE_STATIC_PROVIDER
74#include "unix.c"
75#endif
76#endif
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 */
83static CK_BBOOL truevalue = TRUE;
84static CK_BBOOL falsevalue = FALSE;
85
86int
87main(int argc, char *argv[])
88{
89	CK_RV rv;
90	CK_SLOT_ID slot = 0;
91	CK_MECHANISM genmech;
92	CK_SESSION_HANDLE hSession;
93	CK_UTF8CHAR *pin = NULL;
94	CK_ULONG modulusbits = 0;
95	CK_CHAR *label = NULL;
96	CK_OBJECT_HANDLE privatekey, publickey;
97	CK_BYTE public_exponent[5];
98	CK_ULONG expsize = 3;
99	int error = 0;
100	int c, errflg = 0;
101	int hide = 1;
102	int idlen = 0;
103	unsigned long id = 0;
104	CK_BYTE idbuf[4];
105	CK_ULONG ulObjectCount;
106	/* Set search template */
107	CK_ATTRIBUTE search_template[] = {
108		{CKA_LABEL, NULL_PTR, 0}
109	};
110	CK_ATTRIBUTE publickey_template[] = {
111		{CKA_LABEL, NULL_PTR, 0},
112		{CKA_VERIFY, &truevalue, sizeof(truevalue)},
113		{CKA_TOKEN, &truevalue, sizeof(truevalue)},
114		{CKA_MODULUS_BITS, &modulusbits, sizeof(modulusbits)},
115		{CKA_PUBLIC_EXPONENT, &public_exponent, expsize},
116		{CKA_ID, &idbuf, idlen}
117	};
118	CK_ULONG publickey_attrcnt = 6;
119	CK_ATTRIBUTE privatekey_template[] = {
120		{CKA_LABEL, NULL_PTR, 0},
121		{CKA_SIGN, &truevalue, sizeof(truevalue)},
122		{CKA_TOKEN, &truevalue, sizeof(truevalue)},
123		{CKA_PRIVATE, &truevalue, sizeof(truevalue)},
124		{CKA_SENSITIVE, &truevalue, sizeof(truevalue)},
125		{CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue)},
126		{CKA_ID, &idbuf, idlen}
127	};
128	CK_ULONG privatekey_attrcnt = 7;
129	char *pk11_provider;
130	extern char *optarg;
131	extern int optopt;
132
133	pk11_provider = getenv("PKCS11_PROVIDER");
134	if (pk11_provider != NULL)
135		pk11_libname = pk11_provider;
136
137	while ((c = getopt(argc, argv, ":Pm:s:b:ei:l:p:")) != -1) {
138		switch (c) {
139		case 'P':
140			hide = 0;
141			break;
142		case 'm':
143			pk11_libname = optarg;
144			break;
145		case 's':
146			slot = atoi(optarg);
147			break;
148		case 'e':
149			expsize = 5;
150			break;
151		case 'b':
152			modulusbits = atoi(optarg);
153			break;
154		case 'l':
155			label = (CK_CHAR *)optarg;
156			break;
157		case 'i':
158			id = strtoul(optarg, NULL, 0);
159			idlen = 4;
160			break;
161		case 'p':
162			pin = (CK_UTF8CHAR *)optarg;
163			break;
164		case ':':
165			fprintf(stderr,
166				"Option -%c requires an operand\n",
167				optopt);
168			errflg++;
169			break;
170		case '?':
171		default:
172			fprintf(stderr, "Unrecognised option: -%c\n", optopt);
173			errflg++;
174		}
175	}
176
177	if (errflg || !modulusbits || (label == NULL)) {
178		fprintf(stderr, "Usage:\n");
179		fprintf(stderr, "\tpkcs11-keygen -b keysize -l label\n");
180		fprintf(stderr, "\t              [-P] [-m module] "
181				"[-s slot] [-e] [-i id] [-p PIN]\n");
182		exit(2);
183	}
184
185	search_template[0].pValue = label;
186	search_template[0].ulValueLen = strlen((char *)label);
187	publickey_template[0].pValue = label;
188	publickey_template[0].ulValueLen = strlen((char *)label);
189	privatekey_template[0].pValue = label;
190	privatekey_template[0].ulValueLen = strlen((char *)label);
191
192	/* Set public exponent to F4 or F5 */
193	public_exponent[0] = 0x01;
194	public_exponent[1] = 0x00;
195	if (expsize == 3)
196		public_exponent[2] = 0x01;
197	else {
198		publickey_template[4].ulValueLen = expsize;
199		public_exponent[2] = 0x00;
200		public_exponent[3] = 0x00;
201		public_exponent[4] = 0x01;
202	}
203
204	/* Set up mechanism for generating key pair */
205	genmech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
206	genmech.pParameter = NULL_PTR;
207	genmech.ulParameterLen = 0;
208
209	if (idlen == 0) {
210		publickey_attrcnt--;
211		privatekey_attrcnt--;
212	} else if (id <= 0xffff) {
213		idlen = 2;
214		publickey_template[5].ulValueLen = idlen;
215		privatekey_template[6].ulValueLen = idlen;
216		idbuf[0] = (CK_BYTE)(id >> 8);
217		idbuf[1] = (CK_BYTE)id;
218	} else {
219		idbuf[0] = (CK_BYTE)(id >> 24);
220		idbuf[1] = (CK_BYTE)(id >> 16);
221		idbuf[2] = (CK_BYTE)(id >> 8);
222		idbuf[3] = (CK_BYTE)id;
223	}
224
225	/* Initialize the CRYPTOKI library */
226	rv = C_Initialize(NULL_PTR);
227
228	if (rv != CKR_OK) {
229		if (rv == 0xfe)
230			fprintf(stderr,
231				"Can't load or link module \"%s\"\n",
232				pk11_libname);
233		else
234			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
235		exit(1);
236	}
237
238	/* Open a session on the slot found */
239	rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION,
240			   NULL_PTR, NULL_PTR, &hSession);
241
242	if (rv != CKR_OK) {
243		fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv);
244		error = 1;
245		goto exit_program;
246	}
247
248	/* Login to the Token (Keystore) */
249	if (pin == NULL)
250		pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
251
252	rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
253	memset(pin, 0, strlen((char *)pin));
254	if (rv != CKR_OK) {
255		fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv);
256		error = 1;
257		goto exit_session;
258	}
259
260	/* check if a key with the same id already exists */
261	rv = C_FindObjectsInit(hSession, search_template, 1);
262	if (rv != CKR_OK) {
263		fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv);
264		error = 1;
265		goto exit_session;
266	}
267	rv = C_FindObjects(hSession, &privatekey, 1, &ulObjectCount);
268	if (rv != CKR_OK) {
269		fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv);
270		error = 1;
271		goto exit_search;
272	}
273	if (ulObjectCount != 0) {
274		fprintf(stderr, "Key already exists.\n");
275		error = 1;
276		goto exit_search;
277	}
278
279	/* Set attributes if the key is not to be hidden */
280	if (!hide) {
281		privatekey_template[4].pValue = &falsevalue;
282		privatekey_template[5].pValue = &truevalue;
283	}
284
285	/* Generate Key pair for signing/verifying */
286	rv = C_GenerateKeyPair(hSession, &genmech,
287			       publickey_template, publickey_attrcnt,
288			       privatekey_template, privatekey_attrcnt,
289			       &publickey, &privatekey);
290
291	if (rv != CKR_OK) {
292		fprintf(stderr, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv);
293		error = 1;
294	}
295
296 exit_search:
297	rv = C_FindObjectsFinal(hSession);
298	if (rv != CKR_OK) {
299		fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv);
300		error = 1;
301	}
302
303 exit_session:
304	(void)C_CloseSession(hSession);
305
306 exit_program:
307	(void)C_Finalize(NULL_PTR);
308
309	exit(error);
310}
311