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 /* signrsa [-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 CK_BYTE buf[1024];
149 CK_BYTE sig[128];
150 
151 static CK_BBOOL truevalue = TRUE;
152 static CK_BBOOL falsevalue = FALSE;
153 
154 int
main(int argc,char * argv[])155 main(int argc, char *argv[]) {
156 	isc_result_t result;
157 	CK_RV rv;
158 	CK_SLOT_ID slot = 0;
159 	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
160 	CK_ULONG len;
161 	CK_ULONG slen;
162 	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
163 	CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY;
164 	CK_KEY_TYPE kType = CKK_RSA;
165 	CK_ATTRIBUTE kTemplate[] = {
166 		{ CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) },
167 		{ CKA_KEY_TYPE, &kType, (CK_ULONG)sizeof(kType) },
168 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
169 		{ CKA_PRIVATE, &truevalue, (CK_ULONG)sizeof(truevalue) },
170 		{ CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) },
171 		{ CKA_MODULUS, modulus, (CK_ULONG)sizeof(modulus) },
172 		{ CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG)sizeof(pubexp) },
173 		{ CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG)sizeof(privexp) },
174 		{ CKA_PRIME_1, prime1, (CK_ULONG)sizeof(prime1) },
175 		{ CKA_PRIME_2, prime2, (CK_ULONG)sizeof(prime2) },
176 		{ CKA_EXPONENT_1, exp_1, (CK_ULONG)sizeof(exp_1) },
177 		{ CKA_EXPONENT_2, exp_2, (CK_ULONG)sizeof(exp_2) },
178 		{ CKA_COEFFICIENT, coeff, (CK_ULONG)sizeof(coeff) }
179 	};
180 	CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 };
181 	pk11_context_t pctx;
182 	pk11_optype_t op_type = OP_RSA;
183 	char *lib_name = NULL;
184 	char *pin = NULL;
185 	int error = 0;
186 	int c, errflg = 0;
187 	int ontoken = 0;
188 	unsigned int count = 1000;
189 	unsigned int i;
190 	struct timespec starttime;
191 	struct timespec endtime;
192 
193 	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
194 		switch (c) {
195 		case 'm':
196 			lib_name = isc_commandline_argument;
197 			break;
198 		case 's':
199 			slot = atoi(isc_commandline_argument);
200 			op_type = OP_ANY;
201 			break;
202 		case 'p':
203 			pin = isc_commandline_argument;
204 			break;
205 		case 't':
206 			ontoken = 1;
207 			break;
208 		case 'n':
209 			count = atoi(isc_commandline_argument);
210 			break;
211 		case ':':
212 			fprintf(stderr, "Option -%c requires an operand\n",
213 				isc_commandline_option);
214 			errflg++;
215 			break;
216 		case '?':
217 		default:
218 			fprintf(stderr, "Unrecognised option: -%c\n",
219 				isc_commandline_option);
220 			errflg++;
221 		}
222 	}
223 
224 	if (errflg) {
225 		fprintf(stderr, "Usage:\n");
226 		fprintf(stderr, "\tsign [-m module] [-s slot] [-p pin] "
227 				"[-t] [-n count]\n");
228 		exit(1);
229 	}
230 
231 	pk11_result_register();
232 
233 	/* Initialize the CRYPTOKI library */
234 	if (lib_name != NULL) {
235 		pk11_set_lib_name(lib_name);
236 	}
237 
238 	if (pin == NULL) {
239 		pin = getpass("Enter Pin: ");
240 	}
241 
242 	result = pk11_get_session(&pctx, op_type, false, true, true,
243 				  (const char *)pin, slot);
244 	if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) &&
245 	    (result != PK11_R_NODIGESTSERVICE) &&
246 	    (result != PK11_R_NOAESSERVICE))
247 	{
248 		fprintf(stderr, "Error initializing PKCS#11: %s\n",
249 			isc_result_totext(result));
250 		exit(1);
251 	}
252 
253 	if (pin != NULL) {
254 		memset(pin, 0, strlen((char *)pin));
255 	}
256 
257 	hSession = pctx.session;
258 
259 	/* Create the private RSA key */
260 	if (ontoken) {
261 		kTemplate[2].pValue = &truevalue;
262 	}
263 
264 	rv = pkcs_C_CreateObject(hSession, kTemplate, 13, &hKey);
265 	if (rv != CKR_OK) {
266 		fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv);
267 		goto exit_key;
268 	}
269 
270 	/* Randomize the buffer */
271 	len = (CK_ULONG)sizeof(buf);
272 	rv = pkcs_C_GenerateRandom(hSession, buf, len);
273 	if (rv != CKR_OK) {
274 		fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv);
275 		goto exit_key;
276 	}
277 
278 	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
279 		perror("clock_gettime(start)");
280 		goto exit_key;
281 	}
282 
283 	for (i = 0; i < count; i++) {
284 		/* Initialize Sign */
285 		rv = pkcs_C_SignInit(hSession, &mech, hKey);
286 		if (rv != CKR_OK) {
287 			fprintf(stderr, "C_SignInit[%u]: Error = 0x%.8lX\n", i,
288 				rv);
289 			error = 1;
290 			break;
291 		}
292 
293 		/* Perform Sign */
294 		slen = (CK_ULONG)sizeof(sig);
295 		rv = pkcs_C_Sign(hSession, buf, len, sig, &slen);
296 		if (rv != CKR_OK) {
297 			fprintf(stderr, "C_Sign[%u]: Error = 0x%.8lX\n", i, rv);
298 			error = 1;
299 			break;
300 		}
301 	}
302 
303 	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
304 		perror("clock_gettime(end)");
305 		goto exit_key;
306 	}
307 
308 	endtime.tv_sec -= starttime.tv_sec;
309 	endtime.tv_nsec -= starttime.tv_nsec;
310 	while (endtime.tv_nsec < 0) {
311 		endtime.tv_sec -= 1;
312 		endtime.tv_nsec += 1000000000;
313 	}
314 	printf("%u RSA signs in %ld.%09lds\n", i, endtime.tv_sec,
315 	       endtime.tv_nsec);
316 	if (i > 0) {
317 		printf("%g RSA signs/s\n",
318 		       1024 * i /
319 			       ((double)endtime.tv_sec +
320 				(double)endtime.tv_nsec / 1000000000.));
321 	}
322 
323 exit_key:
324 	if (hKey != CK_INVALID_HANDLE) {
325 		rv = pkcs_C_DestroyObject(hSession, hKey);
326 		if (rv != CKR_OK) {
327 			fprintf(stderr, "C_DestroyObject: Error = 0x%.8lX\n",
328 				rv);
329 		}
330 	}
331 
332 	pk11_return_session(&pctx);
333 	(void)pk11_finalize();
334 
335 	exit(error);
336 }
337