e_nuron.c revision 302408
1/* crypto/engine/hw_nuron.c */ 2/* 3 * Written by Ben Laurie for the OpenSSL Project, leaning heavily on Geoff 4 * Thorpe's Atalla implementation. 5 */ 6/* ==================================================================== 7 * Copyright (c) 2000-2001 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This product includes cryptographic software written by Eric Young 55 * (eay@cryptsoft.com). This product includes software written by Tim 56 * Hudson (tjh@cryptsoft.com). 57 * 58 */ 59 60#include <stdio.h> 61#include <string.h> 62#include <openssl/crypto.h> 63#include <openssl/buffer.h> 64#include <openssl/dso.h> 65#include <openssl/engine.h> 66#ifndef OPENSSL_NO_RSA 67# include <openssl/rsa.h> 68#endif 69#ifndef OPENSSL_NO_DSA 70# include <openssl/dsa.h> 71#endif 72#ifndef OPENSSL_NO_DH 73# include <openssl/dh.h> 74#endif 75#include <openssl/bn.h> 76 77#ifndef OPENSSL_NO_HW 78# ifndef OPENSSL_NO_HW_NURON 79 80# define NURON_LIB_NAME "nuron engine" 81# include "e_nuron_err.c" 82 83static const char *NURON_LIBNAME = NULL; 84static const char *get_NURON_LIBNAME(void) 85{ 86 if (NURON_LIBNAME) 87 return NURON_LIBNAME; 88 return "nuronssl"; 89} 90 91static void free_NURON_LIBNAME(void) 92{ 93 if (NURON_LIBNAME) 94 OPENSSL_free((void *)NURON_LIBNAME); 95 NURON_LIBNAME = NULL; 96} 97 98static long set_NURON_LIBNAME(const char *name) 99{ 100 free_NURON_LIBNAME(); 101 return (((NURON_LIBNAME = BUF_strdup(name)) != NULL) ? 1 : 0); 102} 103 104static const char *NURON_F1 = "nuron_mod_exp"; 105 106/* The definitions for control commands specific to this engine */ 107# define NURON_CMD_SO_PATH ENGINE_CMD_BASE 108static const ENGINE_CMD_DEFN nuron_cmd_defns[] = { 109 {NURON_CMD_SO_PATH, 110 "SO_PATH", 111 "Specifies the path to the 'nuronssl' shared library", 112 ENGINE_CMD_FLAG_STRING}, 113 {0, NULL, NULL, 0} 114}; 115 116typedef int tfnModExp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 117 const BIGNUM *m); 118static tfnModExp *pfnModExp = NULL; 119 120static DSO *pvDSOHandle = NULL; 121 122static int nuron_destroy(ENGINE *e) 123{ 124 free_NURON_LIBNAME(); 125 ERR_unload_NURON_strings(); 126 return 1; 127} 128 129static int nuron_init(ENGINE *e) 130{ 131 if (pvDSOHandle != NULL) { 132 NURONerr(NURON_F_NURON_INIT, NURON_R_ALREADY_LOADED); 133 return 0; 134 } 135 136 pvDSOHandle = DSO_load(NULL, get_NURON_LIBNAME(), NULL, 137 DSO_FLAG_NAME_TRANSLATION_EXT_ONLY); 138 if (!pvDSOHandle) { 139 NURONerr(NURON_F_NURON_INIT, NURON_R_DSO_NOT_FOUND); 140 return 0; 141 } 142 143 pfnModExp = (tfnModExp *) DSO_bind_func(pvDSOHandle, NURON_F1); 144 if (!pfnModExp) { 145 NURONerr(NURON_F_NURON_INIT, NURON_R_DSO_FUNCTION_NOT_FOUND); 146 return 0; 147 } 148 149 return 1; 150} 151 152static int nuron_finish(ENGINE *e) 153{ 154 free_NURON_LIBNAME(); 155 if (pvDSOHandle == NULL) { 156 NURONerr(NURON_F_NURON_FINISH, NURON_R_NOT_LOADED); 157 return 0; 158 } 159 if (!DSO_free(pvDSOHandle)) { 160 NURONerr(NURON_F_NURON_FINISH, NURON_R_DSO_FAILURE); 161 return 0; 162 } 163 pvDSOHandle = NULL; 164 pfnModExp = NULL; 165 return 1; 166} 167 168static int nuron_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 169{ 170 int initialised = ((pvDSOHandle == NULL) ? 0 : 1); 171 switch (cmd) { 172 case NURON_CMD_SO_PATH: 173 if (p == NULL) { 174 NURONerr(NURON_F_NURON_CTRL, ERR_R_PASSED_NULL_PARAMETER); 175 return 0; 176 } 177 if (initialised) { 178 NURONerr(NURON_F_NURON_CTRL, NURON_R_ALREADY_LOADED); 179 return 0; 180 } 181 return set_NURON_LIBNAME((const char *)p); 182 default: 183 break; 184 } 185 NURONerr(NURON_F_NURON_CTRL, NURON_R_CTRL_COMMAND_NOT_IMPLEMENTED); 186 return 0; 187} 188 189static int nuron_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 190 const BIGNUM *m, BN_CTX *ctx) 191{ 192 if (!pvDSOHandle) { 193 NURONerr(NURON_F_NURON_MOD_EXP, NURON_R_NOT_LOADED); 194 return 0; 195 } 196 return pfnModExp(r, a, p, m); 197} 198 199# ifndef OPENSSL_NO_RSA 200static int nuron_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, 201 BN_CTX *ctx) 202{ 203 return nuron_mod_exp(r0, I, rsa->d, rsa->n, ctx); 204} 205# endif 206 207# ifndef OPENSSL_NO_DSA 208/* 209 * This code was liberated and adapted from the commented-out code in 210 * dsa_ossl.c. Because of the unoptimised form of the Atalla acceleration (it 211 * doesn't have a CRT form for RSA), this function means that an Atalla 212 * system running with a DSA server certificate can handshake around 5 or 6 213 * times faster/more than an equivalent system running with RSA. Just check 214 * out the "signs" statistics from the RSA and DSA parts of "openssl speed 215 * -engine atalla dsa1024 rsa1024". 216 */ 217static int nuron_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, 218 BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, 219 BN_CTX *ctx, BN_MONT_CTX *in_mont) 220{ 221 BIGNUM t; 222 int to_return = 0; 223 224 BN_init(&t); 225 /* let rr = a1 ^ p1 mod m */ 226 if (!nuron_mod_exp(rr, a1, p1, m, ctx)) 227 goto end; 228 /* let t = a2 ^ p2 mod m */ 229 if (!nuron_mod_exp(&t, a2, p2, m, ctx)) 230 goto end; 231 /* let rr = rr * t mod m */ 232 if (!BN_mod_mul(rr, rr, &t, m, ctx)) 233 goto end; 234 to_return = 1; 235 end: 236 BN_free(&t); 237 return to_return; 238} 239 240static int nuron_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, 241 const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, 242 BN_MONT_CTX *m_ctx) 243{ 244 return nuron_mod_exp(r, a, p, m, ctx); 245} 246# endif 247 248/* This function is aliased to mod_exp (with the mont stuff dropped). */ 249# ifndef OPENSSL_NO_RSA 250static int nuron_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 251 const BIGNUM *m, BN_CTX *ctx, 252 BN_MONT_CTX *m_ctx) 253{ 254 return nuron_mod_exp(r, a, p, m, ctx); 255} 256# endif 257 258# ifndef OPENSSL_NO_DH 259/* This function is aliased to mod_exp (with the dh and mont dropped). */ 260static int nuron_mod_exp_dh(const DH *dh, BIGNUM *r, 261 const BIGNUM *a, const BIGNUM *p, 262 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) 263{ 264 return nuron_mod_exp(r, a, p, m, ctx); 265} 266# endif 267 268# ifndef OPENSSL_NO_RSA 269static RSA_METHOD nuron_rsa = { 270 "Nuron RSA method", 271 NULL, 272 NULL, 273 NULL, 274 NULL, 275 nuron_rsa_mod_exp, 276 nuron_mod_exp_mont, 277 NULL, 278 NULL, 279 0, 280 NULL, 281 NULL, 282 NULL, 283 NULL 284}; 285# endif 286 287# ifndef OPENSSL_NO_DSA 288static DSA_METHOD nuron_dsa = { 289 "Nuron DSA method", 290 NULL, /* dsa_do_sign */ 291 NULL, /* dsa_sign_setup */ 292 NULL, /* dsa_do_verify */ 293 nuron_dsa_mod_exp, /* dsa_mod_exp */ 294 nuron_mod_exp_dsa, /* bn_mod_exp */ 295 NULL, /* init */ 296 NULL, /* finish */ 297 0, /* flags */ 298 NULL, /* app_data */ 299 NULL, /* dsa_paramgen */ 300 NULL /* dsa_keygen */ 301}; 302# endif 303 304# ifndef OPENSSL_NO_DH 305static DH_METHOD nuron_dh = { 306 "Nuron DH method", 307 NULL, 308 NULL, 309 nuron_mod_exp_dh, 310 NULL, 311 NULL, 312 0, 313 NULL, 314 NULL 315}; 316# endif 317 318/* Constants used when creating the ENGINE */ 319static const char *engine_nuron_id = "nuron"; 320static const char *engine_nuron_name = "Nuron hardware engine support"; 321 322/* 323 * This internal function is used by ENGINE_nuron() and possibly by the 324 * "dynamic" ENGINE support too 325 */ 326static int bind_helper(ENGINE *e) 327{ 328# ifndef OPENSSL_NO_RSA 329 const RSA_METHOD *meth1; 330# endif 331# ifndef OPENSSL_NO_DSA 332 const DSA_METHOD *meth2; 333# endif 334# ifndef OPENSSL_NO_DH 335 const DH_METHOD *meth3; 336# endif 337 if (!ENGINE_set_id(e, engine_nuron_id) || 338 !ENGINE_set_name(e, engine_nuron_name) || 339# ifndef OPENSSL_NO_RSA 340 !ENGINE_set_RSA(e, &nuron_rsa) || 341# endif 342# ifndef OPENSSL_NO_DSA 343 !ENGINE_set_DSA(e, &nuron_dsa) || 344# endif 345# ifndef OPENSSL_NO_DH 346 !ENGINE_set_DH(e, &nuron_dh) || 347# endif 348 !ENGINE_set_destroy_function(e, nuron_destroy) || 349 !ENGINE_set_init_function(e, nuron_init) || 350 !ENGINE_set_finish_function(e, nuron_finish) || 351 !ENGINE_set_ctrl_function(e, nuron_ctrl) || 352 !ENGINE_set_cmd_defns(e, nuron_cmd_defns)) 353 return 0; 354 355# ifndef OPENSSL_NO_RSA 356 /* 357 * We know that the "PKCS1_SSLeay()" functions hook properly to the 358 * nuron-specific mod_exp and mod_exp_crt so we use those functions. NB: 359 * We don't use ENGINE_openssl() or anything "more generic" because 360 * something like the RSAref code may not hook properly, and if you own 361 * one of these cards then you have the right to do RSA operations on it 362 * anyway! 363 */ 364 meth1 = RSA_PKCS1_SSLeay(); 365 nuron_rsa.rsa_pub_enc = meth1->rsa_pub_enc; 366 nuron_rsa.rsa_pub_dec = meth1->rsa_pub_dec; 367 nuron_rsa.rsa_priv_enc = meth1->rsa_priv_enc; 368 nuron_rsa.rsa_priv_dec = meth1->rsa_priv_dec; 369# endif 370 371# ifndef OPENSSL_NO_DSA 372 /* 373 * Use the DSA_OpenSSL() method and just hook the mod_exp-ish bits. 374 */ 375 meth2 = DSA_OpenSSL(); 376 nuron_dsa.dsa_do_sign = meth2->dsa_do_sign; 377 nuron_dsa.dsa_sign_setup = meth2->dsa_sign_setup; 378 nuron_dsa.dsa_do_verify = meth2->dsa_do_verify; 379# endif 380 381# ifndef OPENSSL_NO_DH 382 /* Much the same for Diffie-Hellman */ 383 meth3 = DH_OpenSSL(); 384 nuron_dh.generate_key = meth3->generate_key; 385 nuron_dh.compute_key = meth3->compute_key; 386# endif 387 388 /* Ensure the nuron error handling is set up */ 389 ERR_load_NURON_strings(); 390 return 1; 391} 392 393# ifdef OPENSSL_NO_DYNAMIC_ENGINE 394static ENGINE *engine_nuron(void) 395{ 396 ENGINE *ret = ENGINE_new(); 397 if (!ret) 398 return NULL; 399 if (!bind_helper(ret)) { 400 ENGINE_free(ret); 401 return NULL; 402 } 403 return ret; 404} 405 406void ENGINE_load_nuron(void) 407{ 408 /* Copied from eng_[openssl|dyn].c */ 409 ENGINE *toadd = engine_nuron(); 410 if (!toadd) 411 return; 412 ENGINE_add(toadd); 413 ENGINE_free(toadd); 414 ERR_clear_error(); 415} 416# endif 417 418/* 419 * This stuff is needed if this ENGINE is being compiled into a 420 * self-contained shared-library. 421 */ 422# ifndef OPENSSL_NO_DYNAMIC_ENGINE 423static int bind_fn(ENGINE *e, const char *id) 424{ 425 if (id && (strcmp(id, engine_nuron_id) != 0)) 426 return 0; 427 if (!bind_helper(e)) 428 return 0; 429 return 1; 430} 431 432IMPLEMENT_DYNAMIC_CHECK_FN() 433 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) 434# endif /* OPENSSL_NO_DYNAMIC_ENGINE */ 435# endif /* !OPENSSL_NO_HW_NURON */ 436#endif /* !OPENSSL_NO_HW */ 437