1/*
2 * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
11 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
14 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/*
18 * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 *    notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 *    notice, this list of conditions and the following disclaimer in the
27 *    documentation and/or other materials provided with the distribution.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41/* $Id: pkcs11-keygen.c,v 1.9 2009/10/26 23:36:53 each Exp $ */
42
43/* pkcs11-keygen - pkcs11 rsa key generator
44*
45* create RSASHA1 key in the keystore of an SCA6000
46* The calculation of key tag is left to the script
47* that converts the key into a DNSKEY RR and inserts
48* it into a zone file.
49*
50* usage:
51* pkcs11-keygen [-P] [-m module] [-s slot] [-e] -b keysize
52*               -l label [-i id] [-p pin]
53*
54*/
55
56/*! \file */
57
58#include <config.h>
59
60#include <stdio.h>
61#include <stdlib.h>
62#include <fcntl.h>
63#include <errno.h>
64#include <string.h>
65#include <sys/types.h>
66#include "cryptoki.h"
67
68#ifdef WIN32
69#include "win32.c"
70#else
71#ifndef FORCE_STATIC_PROVIDER
72#include "unix.c"
73#endif
74#endif
75
76#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
77#define getpassphrase(x)	getpass(x)
78#endif
79
80/* Define static key template values */
81static CK_BBOOL truevalue = TRUE;
82static CK_BBOOL falsevalue = FALSE;
83
84int
85main(int argc, char *argv[])
86{
87	CK_RV rv;
88	CK_SLOT_ID slot = 0;
89	CK_MECHANISM genmech;
90	CK_SESSION_HANDLE hSession;
91	CK_UTF8CHAR *pin = NULL;
92	CK_ULONG modulusbits = 0;
93	CK_CHAR *label = NULL;
94	CK_OBJECT_HANDLE privatekey, publickey;
95	CK_BYTE public_exponent[5];
96	CK_ULONG expsize = 3;
97	int error = 0;
98	int c, errflg = 0;
99	int hide = 1;
100	int idlen = 0;
101	unsigned long id = 0;
102	CK_BYTE idbuf[4];
103	CK_ULONG ulObjectCount;
104	/* Set search template */
105	CK_ATTRIBUTE search_template[] = {
106		{CKA_LABEL, NULL_PTR, 0}
107	};
108	CK_ATTRIBUTE publickey_template[] = {
109		{CKA_LABEL, NULL_PTR, 0},
110		{CKA_VERIFY, &truevalue, sizeof(truevalue)},
111		{CKA_TOKEN, &truevalue, sizeof(truevalue)},
112		{CKA_MODULUS_BITS, &modulusbits, sizeof(modulusbits)},
113		{CKA_PUBLIC_EXPONENT, &public_exponent, expsize},
114		{CKA_ID, &idbuf, idlen}
115	};
116	CK_ULONG publickey_attrcnt = 6;
117	CK_ATTRIBUTE privatekey_template[] = {
118		{CKA_LABEL, NULL_PTR, 0},
119		{CKA_SIGN, &truevalue, sizeof(truevalue)},
120		{CKA_TOKEN, &truevalue, sizeof(truevalue)},
121		{CKA_PRIVATE, &truevalue, sizeof(truevalue)},
122		{CKA_SENSITIVE, &truevalue, sizeof(truevalue)},
123		{CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue)},
124		{CKA_ID, &idbuf, idlen}
125	};
126	CK_ULONG privatekey_attrcnt = 7;
127	char *pk11_provider;
128	extern char *optarg;
129	extern int optopt;
130
131	pk11_provider = getenv("PKCS11_PROVIDER");
132	if (pk11_provider != NULL)
133		pk11_libname = pk11_provider;
134
135	while ((c = getopt(argc, argv, ":Pm:s:b:ei:l:p:")) != -1) {
136		switch (c) {
137		case 'P':
138			hide = 0;
139			break;
140		case 'm':
141			pk11_libname = optarg;
142			break;
143		case 's':
144			slot = atoi(optarg);
145			break;
146		case 'e':
147			expsize = 5;
148			break;
149		case 'b':
150			modulusbits = atoi(optarg);
151			break;
152		case 'l':
153			label = (CK_CHAR *)optarg;
154			break;
155		case 'i':
156			id = strtoul(optarg, NULL, 0);
157			idlen = 4;
158			break;
159		case 'p':
160			pin = (CK_UTF8CHAR *)optarg;
161			break;
162		case ':':
163			fprintf(stderr,
164				"Option -%c requires an operand\n",
165				optopt);
166			errflg++;
167			break;
168		case '?':
169		default:
170			fprintf(stderr, "Unrecognised option: -%c\n", optopt);
171			errflg++;
172		}
173	}
174
175	if (errflg || !modulusbits || (label == NULL)) {
176		fprintf(stderr, "Usage:\n");
177		fprintf(stderr, "\tpkcs11-keygen -b keysize -l label\n");
178		fprintf(stderr, "\t              [-P] [-m module] "
179				"[-s slot] [-e] [-i id] [-p PIN]\n");
180		exit(2);
181	}
182
183	search_template[0].pValue = label;
184	search_template[0].ulValueLen = strlen((char *)label);
185	publickey_template[0].pValue = label;
186	publickey_template[0].ulValueLen = strlen((char *)label);
187	privatekey_template[0].pValue = label;
188	privatekey_template[0].ulValueLen = strlen((char *)label);
189
190	/* Set public exponent to F4 or F5 */
191	public_exponent[0] = 0x01;
192	public_exponent[1] = 0x00;
193	if (expsize == 3)
194		public_exponent[2] = 0x01;
195	else {
196		publickey_template[4].ulValueLen = expsize;
197		public_exponent[2] = 0x00;
198		public_exponent[3] = 0x00;
199		public_exponent[4] = 0x01;
200	}
201
202	/* Set up mechanism for generating key pair */
203	genmech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
204	genmech.pParameter = NULL_PTR;
205	genmech.ulParameterLen = 0;
206
207	if (idlen == 0) {
208		publickey_attrcnt--;
209		privatekey_attrcnt--;
210	} else if (id <= 0xffff) {
211		idlen = 2;
212		publickey_template[5].ulValueLen = idlen;
213		privatekey_template[6].ulValueLen = idlen;
214		idbuf[0] = (CK_BYTE)(id >> 8);
215		idbuf[1] = (CK_BYTE)id;
216	} else {
217		idbuf[0] = (CK_BYTE)(id >> 24);
218		idbuf[1] = (CK_BYTE)(id >> 16);
219		idbuf[2] = (CK_BYTE)(id >> 8);
220		idbuf[3] = (CK_BYTE)id;
221	}
222
223	/* Initialize the CRYPTOKI library */
224	rv = C_Initialize(NULL_PTR);
225
226	if (rv != CKR_OK) {
227		if (rv == 0xfe)
228			fprintf(stderr,
229				"Can't load or link module \"%s\"\n",
230				pk11_libname);
231		else
232			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
233		exit(1);
234	}
235
236	/* Open a session on the slot found */
237	rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION,
238			   NULL_PTR, NULL_PTR, &hSession);
239
240	if (rv != CKR_OK) {
241		fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv);
242		error = 1;
243		goto exit_program;
244	}
245
246	/* Login to the Token (Keystore) */
247	if (pin == NULL)
248		pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
249
250	rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
251	memset(pin, 0, strlen((char *)pin));
252	if (rv != CKR_OK) {
253		fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv);
254		error = 1;
255		goto exit_session;
256	}
257
258	/* check if a key with the same id already exists */
259	rv = C_FindObjectsInit(hSession, search_template, 1);
260	if (rv != CKR_OK) {
261		fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv);
262		error = 1;
263		goto exit_session;
264	}
265	rv = C_FindObjects(hSession, &privatekey, 1, &ulObjectCount);
266	if (rv != CKR_OK) {
267		fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv);
268		error = 1;
269		goto exit_search;
270	}
271	if (ulObjectCount != 0) {
272		fprintf(stderr, "Key already exists.\n");
273		error = 1;
274		goto exit_search;
275	}
276
277	/* Set attributes if the key is not to be hidden */
278	if (!hide) {
279		privatekey_template[4].pValue = &falsevalue;
280		privatekey_template[5].pValue = &truevalue;
281	}
282
283	/* Generate Key pair for signing/verifying */
284	rv = C_GenerateKeyPair(hSession, &genmech,
285			       publickey_template, publickey_attrcnt,
286			       privatekey_template, privatekey_attrcnt,
287			       &publickey, &privatekey);
288
289	if (rv != CKR_OK) {
290		fprintf(stderr, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv);
291		error = 1;
292	}
293
294 exit_search:
295	rv = C_FindObjectsFinal(hSession);
296	if (rv != CKR_OK) {
297		fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv);
298		error = 1;
299	}
300
301 exit_session:
302	(void)C_CloseSession(hSession);
303
304 exit_program:
305	(void)C_Finalize(NULL_PTR);
306
307	exit(error);
308}
309