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