1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 /*
13  * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /* genrsa [-m module] [-s $slot] [-p pin] [-t] [-b bits] [-n count] */
37 
38 /*! \file */
39 
40 #include <config.h>
41 
42 #include <stdio.h>
43 #include <inttypes.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 
49 #include <isc/commandline.h>
50 #include <isc/print.h>
51 #include <isc/result.h>
52 #include <isc/types.h>
53 #include <isc/util.h>
54 
55 #include <pk11/pk11.h>
56 #include <pk11/result.h>
57 
58 #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
59 #define getpassphrase(x)	getpass(x)
60 #endif
61 
62 #ifndef HAVE_CLOCK_GETTIME
63 
64 #include <sys/time.h>
65 
66 #ifndef CLOCK_REALTIME
67 #define CLOCK_REALTIME 0
68 #endif
69 
70 static int clock_gettime(int32_t id, struct timespec *tp);
71 
72 static int
clock_gettime(int32_t id,struct timespec * tp)73 clock_gettime(int32_t id, struct timespec *tp)
74 {
75 	struct timeval tv;
76 	int result;
77 
78 	UNUSED(id);
79 
80 	result = gettimeofday(&tv, NULL);
81 	if (result == 0) {
82 		tp->tv_sec = tv.tv_sec;
83 		tp->tv_nsec = (long) tv.tv_usec * 1000;
84 	}
85 	return (result);
86 }
87 #endif
88 
89 static CK_BBOOL truevalue = TRUE;
90 static CK_BBOOL falsevalue = FALSE;
91 
92 int
main(int argc,char * argv[])93 main(int argc, char *argv[]) {
94 	isc_result_t result;
95 	CK_RV rv;
96 	CK_SLOT_ID slot = 0;
97 	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
98 	CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 };
99 	CK_OBJECT_HANDLE *pubKey;
100 	CK_OBJECT_HANDLE *privKey;
101 	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
102 	CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY;
103 	CK_KEY_TYPE kType = CKK_RSA;
104 	CK_ULONG bits = 1024;
105 	CK_BYTE exponent[] = { 0x01, 0x00, 0x01 };
106 	CK_ATTRIBUTE pubTemplate[] =
107 	{
108 		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
109 		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
110 		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
111 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
112 		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
113 		{ CKA_MODULUS_BITS, &bits, (CK_ULONG) sizeof(bits) },
114 		{ CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) }
115 	};
116 	CK_ATTRIBUTE privTemplate[] =
117 	{
118 		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
119 		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
120 		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
121 		{ CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) },
122 		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
123 	};
124 	pk11_context_t pctx;
125 	pk11_optype_t op_type = OP_RSA;
126 	char *lib_name = NULL;
127 	char *pin = NULL;
128 	int error = 0;
129 	int c, errflg = 0;
130 	int ontoken  = 0;
131 	unsigned int count = 1000;
132 	unsigned int i;
133 	struct timespec starttime;
134 	struct timespec endtime;
135 
136 	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tb:n:")) != -1) {
137 		switch (c) {
138 		case 'm':
139 			lib_name = isc_commandline_argument;
140 			break;
141 		case 's':
142 			slot = atoi(isc_commandline_argument);
143 			op_type = OP_ANY;
144 			break;
145 		case 'p':
146 			pin = isc_commandline_argument;
147 			break;
148 		case 't':
149 			ontoken = 1;
150 			break;
151 		case 'b':
152 			bits = (CK_ULONG)atoi(isc_commandline_argument);
153 			break;
154 		case 'n':
155 			count = atoi(isc_commandline_argument);
156 			break;
157 		case ':':
158 			fprintf(stderr,
159 				"Option -%c requires an operand\n",
160 				isc_commandline_option);
161 			errflg++;
162 			break;
163 		case '?':
164 		default:
165 			fprintf(stderr, "Unrecognised option: -%c\n",
166 				isc_commandline_option);
167 			errflg++;
168 		}
169 	}
170 
171 	if (errflg) {
172 		fprintf(stderr, "Usage:\n");
173 		fprintf(stderr,
174 			"\tgenrsa [-m module] [-s slot] [-p pin] "
175 			"[-t] [-b bits] [-n count]\n");
176 		exit(1);
177 	}
178 
179 	pk11_result_register();
180 
181 	/* Allocate handles */
182 	pubKey = (CK_SESSION_HANDLE *)
183 		malloc(count * sizeof(CK_SESSION_HANDLE));
184 	if (pubKey == NULL) {
185 		perror("malloc");
186 		exit(1);
187 	}
188 	privKey = (CK_SESSION_HANDLE *)
189 		malloc(count * sizeof(CK_SESSION_HANDLE));
190 	if (privKey == NULL) {
191 		free(pubKey);
192 		perror("malloc");
193 		exit(1);
194 	}
195 	for (i = 0; i < count; i++) {
196 		pubKey[i] = CK_INVALID_HANDLE;
197 		privKey[i] = CK_INVALID_HANDLE;
198 	}
199 
200 	/* Initialize the CRYPTOKI library */
201 	if (lib_name != NULL)
202 		pk11_set_lib_name(lib_name);
203 
204 	if (pin == NULL)
205 		pin = getpassphrase("Enter Pin: ");
206 
207 	result = pk11_get_session(&pctx, op_type, false, true,
208 				  true, (const char *) pin, slot);
209 	if ((result != ISC_R_SUCCESS) &&
210 	    (result != PK11_R_NORANDOMSERVICE) &&
211 	    (result != PK11_R_NODIGESTSERVICE) &&
212 	    (result != PK11_R_NOAESSERVICE)) {
213 		fprintf(stderr, "Error initializing PKCS#11: %s\n",
214 			isc_result_totext(result));
215 		exit(1);
216 	}
217 
218 	if (pin != NULL)
219 		memset(pin, 0, strlen((char *)pin));
220 
221 	hSession = pctx.session;
222 
223 	if (ontoken) {
224 		pubTemplate[2].pValue = &truevalue;
225 		privTemplate[2].pValue = &truevalue;
226 	}
227 
228 	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
229 		perror("clock_gettime(start)");
230 		goto exit_keys;
231 	}
232 
233 	for (i = 0; i < count; i++) {
234 		rv = pkcs_C_GenerateKeyPair(hSession, &mech,
235 				       pubTemplate, 7,
236 				       privTemplate, 5,
237 				       &pubKey[i], &privKey[i]);
238 		if (rv != CKR_OK) {
239 			fprintf(stderr,
240 				"C_GenerateKeyPair[%u]: Error = 0x%.8lX\n",
241 				i, rv);
242 			error = 1;
243 			if (i == 0)
244 				goto exit_keys;
245 			break;
246 		}
247 	}
248 
249 	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
250 		perror("clock_gettime(end)");
251 		goto exit_keys;
252 	}
253 
254 	endtime.tv_sec -= starttime.tv_sec;
255 	endtime.tv_nsec -= starttime.tv_nsec;
256 	while (endtime.tv_nsec < 0) {
257 		endtime.tv_sec -= 1;
258 		endtime.tv_nsec += 1000000000;
259 	}
260 	printf("%u generated RSA in %ld.%09lds\n", i,
261 	       endtime.tv_sec, endtime.tv_nsec);
262 	if (i > 0)
263 		printf("%g generated RSA/s\n",
264 		       1024 * i / ((double) endtime.tv_sec +
265 				   (double) endtime.tv_nsec / 1000000000.));
266 
267     exit_keys:
268 	for (i = 0; i < count; i++) {
269 		/* Destroy keys */
270 		if (pubKey[i] == CK_INVALID_HANDLE)
271 			goto destroy_priv;
272 		rv = pkcs_C_DestroyObject(hSession, pubKey[i]);
273 		if ((rv != CKR_OK) && !errflg) {
274 			fprintf(stderr,
275 				"C_DestroyObject[pub%u]: Error = 0x%.8lX\n",
276 				i, rv);
277 			errflg = 1;
278 		}
279 	    destroy_priv:
280 		if (privKey[i] == CK_INVALID_HANDLE)
281 			continue;
282 		rv = pkcs_C_DestroyObject(hSession, privKey[i]);
283 		if ((rv != CKR_OK) && !errflg) {
284 			fprintf(stderr,
285 				"C_DestroyObject[priv%u]: Error = 0x%.8lX\n",
286 				i, rv);
287 			errflg = 1;
288 		}
289 	}
290 
291 	free(pubKey);
292 	free(privKey);
293 
294 	pk11_return_session(&pctx);
295 	(void) pk11_finalize();
296 
297 	exit(error);
298 }
299