1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*
15  * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /* privrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */
39 
40 /*! \file */
41 
42 #include <inttypes.h>
43 #include <stdio.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 #ifndef HAVE_CLOCK_GETTIME
59 
60 #include <sys/time.h>
61 
62 #ifndef CLOCK_REALTIME
63 #define CLOCK_REALTIME 0
64 #endif /* ifndef CLOCK_REALTIME */
65 
66 static int
67 clock_gettime(int32_t id, struct timespec *tp);
68 
69 static int
clock_gettime(int32_t id,struct timespec * tp)70 clock_gettime(int32_t id, struct timespec *tp) {
71 	struct timeval tv;
72 	int result;
73 
74 	UNUSED(id);
75 
76 	result = gettimeofday(&tv, NULL);
77 	if (result == 0) {
78 		tp->tv_sec = tv.tv_sec;
79 		tp->tv_nsec = (long)tv.tv_usec * 1000;
80 	}
81 	return (result);
82 }
83 #endif /* ifndef HAVE_CLOCK_GETTIME */
84 
85 CK_BYTE modulus[] = {
86 	0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, 0x44, 0x82, 0x20, 0x78,
87 	0x43, 0x7f, 0x5f, 0x3b, 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90,
88 	0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, 0x16, 0x1c, 0x56, 0xf8,
89 	0xc1, 0x06, 0x2f, 0x96, 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5,
90 	0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, 0x9f, 0xdc, 0x36, 0xcb,
91 	0xad, 0x56, 0xf4, 0xbd, 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08,
92 	0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, 0xca, 0x4e, 0x72, 0xeb,
93 	0xfb, 0x2c, 0xf1, 0x45, 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7,
94 	0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, 0x49, 0xdd, 0x8a, 0x3c,
95 	0x3c, 0xf7, 0xa1, 0x5d, 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f,
96 	0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, 0xbf
97 };
98 CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 };
99 CK_BYTE privexp[] = {
100 	0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02, 0xb8, 0xf1, 0xd6, 0x92,
101 	0x03, 0xee, 0x50, 0x33, 0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e,
102 	0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63, 0x9f, 0x91, 0xe6, 0x3f,
103 	0x44, 0xb8, 0x77, 0x1b, 0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d,
104 	0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e, 0x34, 0xa8, 0x40, 0xea,
105 	0x51, 0x72, 0x8a, 0xea, 0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c,
106 	0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7, 0x19, 0xce, 0x89, 0x08,
107 	0x87, 0x14, 0xef, 0xcc, 0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd,
108 	0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f, 0x26, 0xac, 0x2e, 0x52,
109 	0x02, 0x07, 0xfb, 0x1d, 0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52,
110 	0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c, 0x41
111 };
112 CK_BYTE prime1[] = { 0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde, 0xc2, 0x74,
113 		     0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58, 0xcd, 0xe9, 0x8e, 0x97,
114 		     0xbe, 0xfe, 0xe8, 0x6f, 0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56,
115 		     0x84, 0x36, 0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5,
116 		     0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1, 0xeb, 0xed,
117 		     0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed, 0x17, 0x7c, 0xd3, 0xa6,
118 		     0x35, 0x6e, 0xa6, 0xd8, 0x21 };
119 CK_BYTE prime2[] = { 0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9, 0x09, 0xeb,
120 		     0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa, 0xfa, 0x3c, 0x61, 0x7e,
121 		     0xc1, 0xf8, 0x8c, 0x5e, 0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f,
122 		     0x4f, 0xab, 0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21,
123 		     0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88, 0xe6, 0xf8,
124 		     0xbe, 0x61, 0x38, 0x99, 0xca, 0x36, 0x0d, 0x3e, 0x42, 0x0f,
125 		     0x63, 0x4d, 0x73, 0xf0, 0xdf };
126 CK_BYTE exp_1[] = { 0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35, 0xfe, 0x2b,
127 		    0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13, 0x26, 0x04, 0xe4, 0x18,
128 		    0x9d, 0x76, 0x92, 0x9a, 0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b,
129 		    0x53, 0x2f, 0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21,
130 		    0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42, 0xbd, 0x80,
131 		    0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f, 0x85, 0xf0, 0x9c, 0x55,
132 		    0x60, 0xb4, 0x9e, 0xc1 };
133 CK_BYTE exp_2[] = { 0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c, 0x6d, 0xde,
134 		    0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb, 0xb5, 0x54, 0x85, 0x59,
135 		    0xcf, 0x7a, 0x56, 0xdb, 0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc,
136 		    0xc3, 0xb9, 0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24,
137 		    0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a, 0x16, 0x52,
138 		    0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c, 0x5a, 0xa4, 0xc4, 0x66,
139 		    0x27, 0xe0, 0x96, 0x64, 0x7f };
140 CK_BYTE coeff[] = { 0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b, 0x99, 0xd7,
141 		    0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94, 0x9d, 0x56, 0x0a, 0x05,
142 		    0x55, 0x7d, 0x93, 0x04, 0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3,
143 		    0xf1, 0xd5, 0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9,
144 		    0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5, 0xcc, 0x1b,
145 		    0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67, 0x0c, 0x00, 0x09, 0x56,
146 		    0x8c, 0x33, 0x57, 0xf9, 0x8c };
147 
148 char label[16];
149 
150 static CK_BBOOL truevalue = TRUE;
151 static CK_BBOOL falsevalue = FALSE;
152 
153 int
main(int argc,char * argv[])154 main(int argc, char *argv[]) {
155 	isc_result_t result;
156 	CK_RV rv;
157 	CK_SLOT_ID slot = 0;
158 	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
159 	CK_OBJECT_HANDLE *hKey;
160 	CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY;
161 	CK_KEY_TYPE kType = CKK_RSA;
162 	CK_ATTRIBUTE kTemplate[] = {
163 		{ CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) },
164 		{ CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) },
165 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
166 		{ CKA_PRIVATE, &truevalue, (CK_ULONG)sizeof(truevalue) },
167 		{ CKA_LABEL, (CK_BYTE_PTR)label, (CK_ULONG)sizeof(label) },
168 		{ CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) },
169 		{ CKA_MODULUS, modulus, (CK_ULONG)sizeof(modulus) },
170 		{ CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG)sizeof(pubexp) },
171 		{ CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG)sizeof(privexp) },
172 		{ CKA_PRIME_1, prime1, (CK_ULONG)sizeof(prime1) },
173 		{ CKA_PRIME_2, prime2, (CK_ULONG)sizeof(prime2) },
174 		{ CKA_EXPONENT_1, exp_1, (CK_ULONG)sizeof(exp_1) },
175 		{ CKA_EXPONENT_2, exp_2, (CK_ULONG)sizeof(exp_2) },
176 		{ CKA_COEFFICIENT, coeff, (CK_ULONG)sizeof(coeff) }
177 	};
178 	pk11_context_t pctx;
179 	pk11_optype_t op_type = OP_RSA;
180 	char *lib_name = NULL;
181 	char *pin = NULL;
182 	int error = 0;
183 	int c, errflg = 0;
184 	int ontoken = 0;
185 	unsigned int count = 1000;
186 	unsigned int i;
187 	struct timespec starttime;
188 	struct timespec endtime;
189 
190 	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
191 		switch (c) {
192 		case 'm':
193 			lib_name = isc_commandline_argument;
194 			break;
195 		case 's':
196 			slot = atoi(isc_commandline_argument);
197 			op_type = OP_ANY;
198 			break;
199 		case 'p':
200 			pin = isc_commandline_argument;
201 			break;
202 		case 't':
203 			ontoken = 1;
204 			break;
205 		case 'n':
206 			count = atoi(isc_commandline_argument);
207 			break;
208 		case ':':
209 			fprintf(stderr, "Option -%c requires an operand\n",
210 				isc_commandline_option);
211 			errflg++;
212 			break;
213 		case '?':
214 		default:
215 			fprintf(stderr, "Unrecognised option: -%c\n",
216 				isc_commandline_option);
217 			errflg++;
218 		}
219 	}
220 
221 	if (errflg) {
222 		fprintf(stderr, "Usage:\n");
223 		fprintf(stderr, "\tprivrsa [-m module] [-s slot] [-p pin] "
224 				"[-t] [-n count]\n");
225 		exit(1);
226 	}
227 
228 	pk11_result_register();
229 
230 	/* Allocate handles */
231 	hKey = (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE));
232 	if (hKey == NULL) {
233 		perror("malloc");
234 		exit(1);
235 	}
236 	for (i = 0; i < count; i++)
237 		hKey[i] = CK_INVALID_HANDLE;
238 
239 	/* Initialize the CRYPTOKI library */
240 	if (lib_name != NULL) {
241 		pk11_set_lib_name(lib_name);
242 	}
243 
244 	if (pin == NULL) {
245 		pin = getpass("Enter Pin: ");
246 	}
247 
248 	result = pk11_get_session(&pctx, op_type, false, true, true,
249 				  (const char *)pin, slot);
250 	if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) &&
251 	    (result != PK11_R_NODIGESTSERVICE) &&
252 	    (result != PK11_R_NOAESSERVICE))
253 	{
254 		fprintf(stderr, "Error initializing PKCS#11: %s\n",
255 			isc_result_totext(result));
256 		free(hKey);
257 		exit(1);
258 	}
259 
260 	if (pin != NULL) {
261 		memset(pin, 0, strlen((char *)pin));
262 	}
263 
264 	hSession = pctx.session;
265 
266 	if (ontoken) {
267 		kTemplate[2].pValue = &truevalue;
268 	}
269 
270 	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
271 		perror("clock_gettime(start)");
272 		goto exit_objects;
273 	}
274 
275 	for (i = 0; i < count; i++) {
276 		(void)snprintf(label, sizeof(label), "obj%u", i);
277 		kTemplate[4].ulValueLen = strlen(label);
278 		rv = pkcs_C_CreateObject(hSession, kTemplate, 14, &hKey[i]);
279 		if (rv != CKR_OK) {
280 			fprintf(stderr, "C_CreateObject[%u]: Error = 0x%.8lX\n",
281 				i, rv);
282 			error = 1;
283 			if (i == 0) {
284 				goto exit_objects;
285 			}
286 			break;
287 		}
288 	}
289 
290 	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
291 		perror("clock_gettime(end)");
292 		goto exit_objects;
293 	}
294 
295 	endtime.tv_sec -= starttime.tv_sec;
296 	endtime.tv_nsec -= starttime.tv_nsec;
297 	while (endtime.tv_nsec < 0) {
298 		endtime.tv_sec -= 1;
299 		endtime.tv_nsec += 1000000000;
300 	}
301 	printf("%u private RSA keys in %ld.%09lds\n", i, endtime.tv_sec,
302 	       endtime.tv_nsec);
303 	if (i > 0) {
304 		printf("%g private RSA keys/s\n",
305 		       1024 * i /
306 			       ((double)endtime.tv_sec +
307 				(double)endtime.tv_nsec / 1000000000.));
308 	}
309 
310 exit_objects:
311 	for (i = 0; i < count; i++) {
312 		/* Destroy objects */
313 		if (hKey[i] == CK_INVALID_HANDLE) {
314 			continue;
315 		}
316 		rv = pkcs_C_DestroyObject(hSession, hKey[i]);
317 		if ((rv != CKR_OK) && !errflg) {
318 			fprintf(stderr,
319 				"C_DestroyObject[%u]: Error = 0x%.8lX\n", i,
320 				rv);
321 			errflg = 1;
322 		}
323 	}
324 
325 	free(hKey);
326 
327 	pk11_return_session(&pctx);
328 	(void)pk11_finalize();
329 
330 	exit(error);
331 }
332