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