1/*	$NetBSD: test_rsa.c,v 1.2 2017/01/28 21:31:47 christos Exp $	*/
2
3/*
4 * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <config.h>
37#include <krb5/roken.h>
38#include <krb5/getarg.h>
39
40#include <engine.h>
41#include <evp.h>
42
43/*
44 *
45 */
46
47static int version_flag;
48static int help_flag;
49static int time_keygen;
50static char *time_key;
51static int key_blinding = 1;
52static char *rsa_key;
53static char *id_flag;
54static int loops = 1;
55
56static struct getargs args[] = {
57    { "loops",		0,	arg_integer,	&loops,
58      "number of loops", 	"loops" },
59    { "id",		0,	arg_string,	&id_flag,
60      "selects the engine id", 	"engine-id" },
61    { "time-keygen",	0,	arg_flag,	&time_keygen,
62      "time rsa generation", NULL },
63    { "time-key",	0,	arg_string,	&time_key,
64      "rsa key file", NULL },
65    { "key-blinding",	0,	arg_negative_flag, &key_blinding,
66      "key blinding", NULL },
67    { "key",	0,	arg_string,	&rsa_key,
68      "rsa key file", NULL },
69    { "version",	0,	arg_flag,	&version_flag,
70      "print version", NULL },
71    { "help",		0,	arg_flag,	&help_flag,
72      NULL, 	NULL }
73};
74
75/*
76 *
77 */
78
79static void
80check_rsa(const unsigned char *in, size_t len, RSA *rsa, int padding)
81{
82    unsigned char *res, *res2;
83    unsigned int len2;
84    int keylen;
85
86    res = malloc(RSA_size(rsa));
87    if (res == NULL)
88	errx(1, "res: ENOMEM");
89
90    res2 = malloc(RSA_size(rsa));
91    if (res2 == NULL)
92	errx(1, "res2: ENOMEM");
93
94    /* signing */
95
96    keylen = RSA_private_encrypt(len, in, res, rsa, padding);
97    if (keylen <= 0)
98	errx(1, "failed to private encrypt: %d %d", (int)len, (int)keylen);
99
100    if (keylen > RSA_size(rsa))
101	errx(1, "keylen > RSA_size(rsa)");
102
103    keylen = RSA_public_decrypt(keylen, res, res2, rsa, padding);
104    if (keylen <= 0)
105	errx(1, "failed to public decrypt: %d", (int)keylen);
106
107    if (keylen != len)
108	errx(1, "output buffer not same length: %d", (int)keylen);
109
110    if (memcmp(res2, in, len) != 0)
111	errx(1, "string not the same after decryption");
112
113    /* encryption */
114
115    keylen = RSA_public_encrypt(len, in, res, rsa, padding);
116    if (keylen <= 0)
117	errx(1, "failed to public encrypt: %d", (int)keylen);
118
119    if (keylen > RSA_size(rsa))
120	errx(1, "keylen > RSA_size(rsa)");
121
122    keylen = RSA_private_decrypt(keylen, res, res2, rsa, padding);
123    if (keylen <= 0)
124	errx(1, "failed to private decrypt: %d", (int)keylen);
125
126    if (keylen != len)
127	errx(1, "output buffer not same length: %d", (int)keylen);
128
129    if (memcmp(res2, in, len) != 0)
130	errx(1, "string not the same after decryption");
131
132    len2 = keylen;
133
134    if (RSA_sign(NID_sha1, in, len, res, &len2, rsa) != 1)
135	errx(1, "RSA_sign failed");
136
137    if (RSA_verify(NID_sha1, in, len, res, len2, rsa) != 1)
138	errx(1, "RSA_verify failed");
139
140    free(res);
141    free(res2);
142}
143
144static int
145cb_func(int a, int b, BN_GENCB *c)
146{
147    return 1;
148}
149
150static RSA *
151read_key(ENGINE *engine, const char *keyfile)
152{
153    unsigned char buf[1024 * 4];
154    const unsigned char *p;
155    size_t size;
156    RSA *rsa;
157    FILE *f;
158
159    f = fopen(keyfile, "rb");
160    if (f == NULL)
161	err(1, "could not open file %s", keyfile);
162    rk_cloexec_file(f);
163
164    size = fread(buf, 1, sizeof(buf), f);
165    fclose(f);
166    if (size == 0)
167	err(1, "failed to read file %s", keyfile);
168    if (size == sizeof(buf))
169	err(1, "key too long in file %s!", keyfile);
170
171    p = buf;
172    rsa = d2i_RSAPrivateKey(NULL, &p, size);
173    if (rsa == NULL)
174	err(1, "failed to parse key in file %s", keyfile);
175
176    RSA_set_method(rsa, ENGINE_get_RSA(engine));
177
178    if (!key_blinding)
179	rsa->flags |= RSA_FLAG_NO_BLINDING;
180
181    return rsa;
182}
183
184/*
185 *
186 */
187
188static void
189usage (int ret)
190{
191    arg_printusage (args,
192		    sizeof(args)/sizeof(*args),
193		    NULL,
194		    "filename.so");
195    exit (ret);
196}
197
198int
199main(int argc, char **argv)
200{
201    ENGINE *engine = NULL;
202    int i, j, idx = 0;
203    RSA *rsa;
204
205    setprogname(argv[0]);
206
207    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx))
208	usage(1);
209
210    if (help_flag)
211	usage(0);
212
213    if(version_flag){
214	print_version(NULL);
215	exit(0);
216    }
217
218    argc -= idx;
219    argv += idx;
220
221    OpenSSL_add_all_algorithms();
222#ifdef OPENSSL
223    ENGINE_load_openssl();
224#endif
225    ENGINE_load_builtin_engines();
226
227    if (argc == 0) {
228	engine = ENGINE_by_id("builtin");
229    } else {
230	engine = ENGINE_by_id(argv[0]);
231	if (engine == NULL)
232	    engine = ENGINE_by_dso(argv[0], id_flag);
233    }
234    if (engine == NULL)
235	errx(1, "ENGINE_by_dso failed");
236
237    if (ENGINE_get_RSA(engine) == NULL)
238	return 77;
239
240    printf("rsa %s\n", ENGINE_get_RSA(engine)->name);
241
242    if (RAND_status() != 1)
243	errx(77, "no functional random device, refusing to run tests");
244
245    if (time_keygen) {
246	struct timeval tv1, tv2;
247	BIGNUM *e;
248
249	rsa = RSA_new_method(engine);
250	if (!key_blinding)
251	    rsa->flags |= RSA_FLAG_NO_BLINDING;
252
253	e = BN_new();
254	BN_set_word(e, 0x10001);
255
256	printf("running keygen with %d loops\n", loops);
257
258	gettimeofday(&tv1, NULL);
259
260	for (i = 0; i < loops; i++) {
261	    rsa = RSA_new_method(engine);
262	    if (RSA_generate_key_ex(rsa, 1024, e, NULL) != 1)
263		errx(1, "RSA_generate_key_ex");
264	    RSA_free(rsa);
265	}
266
267	gettimeofday(&tv2, NULL);
268	timevalsub(&tv2, &tv1);
269
270	printf("time %lu.%06lu\n",
271	       (unsigned long)tv2.tv_sec,
272	       (unsigned long)tv2.tv_usec);
273
274	BN_free(e);
275	ENGINE_finish(engine);
276
277	return 0;
278    }
279
280    if (time_key) {
281	const int size = 20;
282	struct timeval tv1, tv2;
283	unsigned char *p;
284
285	if (strcmp(time_key, "generate") == 0) {
286	    BIGNUM *e;
287
288	    rsa = RSA_new_method(engine);
289	    if (!key_blinding)
290		rsa->flags |= RSA_FLAG_NO_BLINDING;
291
292	    e = BN_new();
293	    BN_set_word(e, 0x10001);
294
295	    if (RSA_generate_key_ex(rsa, 1024, e, NULL) != 1)
296		errx(1, "RSA_generate_key_ex");
297	} else {
298	    rsa = read_key(engine, time_key);
299	}
300
301	p = emalloc(loops * size);
302
303	RAND_bytes(p, loops * size);
304
305	gettimeofday(&tv1, NULL);
306	for (i = 0; i < loops; i++)
307	    check_rsa(p + (i * size), size, rsa, RSA_PKCS1_PADDING);
308	gettimeofday(&tv2, NULL);
309
310	timevalsub(&tv2, &tv1);
311
312	printf("time %lu.%06lu\n",
313	       (unsigned long)tv2.tv_sec,
314	       (unsigned long)tv2.tv_usec);
315
316	RSA_free(rsa);
317	ENGINE_finish(engine);
318
319	return 0;
320    }
321
322    if (rsa_key) {
323	rsa = read_key(engine, rsa_key);
324
325	/*
326	 * Assuming that you use the RSA key in the distribution, this
327	 * test will generate a signature have a starting zero and thus
328	 * will generate a checksum that is 127 byte instead of the
329	 * checksum that is 128 byte (like the key).
330	 */
331	{
332	    const unsigned char sha1[20] = {
333		0x6d, 0x33, 0xf9, 0x40, 0x75, 0x5b, 0x4e, 0xc5, 0x90, 0x35,
334		0x48, 0xab, 0x75, 0x02, 0x09, 0x76, 0x9a, 0xb4, 0x7d, 0x6b
335	    };
336
337	    check_rsa(sha1, sizeof(sha1), rsa, RSA_PKCS1_PADDING);
338	}
339
340	for (i = 0; i < 128; i++) {
341	    unsigned char sha1[20];
342
343	    RAND_bytes(sha1, sizeof(sha1));
344	    check_rsa(sha1, sizeof(sha1), rsa, RSA_PKCS1_PADDING);
345	}
346	for (i = 0; i < 128; i++) {
347	    unsigned char des3[21];
348
349	    RAND_bytes(des3, sizeof(des3));
350	    check_rsa(des3, sizeof(des3), rsa, RSA_PKCS1_PADDING);
351	}
352	for (i = 0; i < 128; i++) {
353	    unsigned char aes[32];
354
355	    RAND_bytes(aes, sizeof(aes));
356	    check_rsa(aes, sizeof(aes), rsa, RSA_PKCS1_PADDING);
357	}
358
359	RSA_free(rsa);
360    }
361
362    for (i = 0; i < loops; i++) {
363	BN_GENCB cb;
364	BIGNUM *e;
365	unsigned int n;
366
367	rsa = RSA_new_method(engine);
368	if (!key_blinding)
369	    rsa->flags |= RSA_FLAG_NO_BLINDING;
370
371	e = BN_new();
372	BN_set_word(e, 0x10001);
373
374	BN_GENCB_set(&cb, cb_func, NULL);
375
376	RAND_bytes(&n, sizeof(n));
377	n &= 0x1ff;
378	n += 1024;
379
380	if (RSA_generate_key_ex(rsa, n, e, &cb) != 1)
381	    errx(1, "RSA_generate_key_ex");
382
383	BN_free(e);
384
385	for (j = 0; j < 8; j++) {
386	    unsigned char sha1[20];
387	    RAND_bytes(sha1, sizeof(sha1));
388	    check_rsa(sha1, sizeof(sha1), rsa, RSA_PKCS1_PADDING);
389	}
390
391	RSA_free(rsa);
392    }
393
394    ENGINE_finish(engine);
395
396    return 0;
397}
398