e_gmp.c revision 280304
1151497Sru/* crypto/engine/e_gmp.c */ 2104862Sru/* 3104862Sru * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project 4104862Sru * 2003. 5104862Sru */ 6104862Sru/* ==================================================================== 7104862Sru * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 8104862Sru * 9104862Sru * Redistribution and use in source and binary forms, with or without 10104862Sru * modification, are permitted provided that the following conditions 11104862Sru * are met: 12104862Sru * 13104862Sru * 1. Redistributions of source code must retain the above copyright 14151497Sru * notice, this list of conditions and the following disclaimer. 15104862Sru * 16104862Sru * 2. Redistributions in binary form must reproduce the above copyright 17151497Sru * notice, this list of conditions and the following disclaimer in 18104862Sru * the documentation and/or other materials provided with the 19151497Sru * distribution. 20104862Sru * 21104862Sru * 3. All advertising materials mentioning features or use of this 22151497Sru * software must display the following acknowledgment: 23151497Sru * "This product includes software developed by the OpenSSL Project 24104862Sru * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25104862Sru * 26104862Sru * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27104862Sru * endorse or promote products derived from this software without 28104862Sru * prior written permission. For written permission, please contact 29104862Sru * licensing@OpenSSL.org. 30104862Sru * 31104862Sru * 5. Products derived from this software may not be called "OpenSSL" 32151497Sru * nor may "OpenSSL" appear in their names without prior written 33104862Sru * permission of the OpenSSL Project. 34151497Sru * 35104862Sru * 6. Redistributions of any form whatsoever must retain the following 36104862Sru * acknowledgment: 37104862Sru * "This product includes software developed by the OpenSSL Project 38104862Sru * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39104862Sru * 40104862Sru * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41104862Sru * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42104862Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43104862Sru * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44104862Sru * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45104862Sru * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46104862Sru * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47104862Sru * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48104862Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49104862Sru * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50104862Sru * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51104862Sru * OF THE POSSIBILITY OF SUCH DAMAGE. 52104862Sru * ==================================================================== 53104862Sru * 54104862Sru * This product includes cryptographic software written by Eric Young 55104862Sru * (eay@cryptsoft.com). This product includes software written by Tim 56104862Sru * Hudson (tjh@cryptsoft.com). 57104862Sru * 58104862Sru */ 59104862Sru 60104862Sru/* 61151497Sru * This engine is not (currently) compiled in by default. Do enable it, 62104862Sru * reconfigure OpenSSL with "enable-gmp -lgmp". The GMP libraries and headers 63104862Sru * must reside in one of the paths searched by the compiler/linker, otherwise 64104862Sru * paths must be specified - eg. try configuring with "enable-gmp 65151497Sru * -I<includepath> -L<libpath> -lgmp". YMMV. 66104862Sru */ 67104862Sru 68104862Sru/*- 69151497Sru * As for what this does - it's a largely unoptimised implementation of an 70104862Sru * ENGINE that uses the GMP library to perform RSA private key operations. To 71151497Sru * obtain more information about what "unoptimised" means, see my original mail 72151497Sru * on the subject (though ignore the build instructions which have since 73151497Sru * changed); 74151497Sru * 75151497Sru * http://www.mail-archive.com/openssl-dev@openssl.org/msg12227.html 76151497Sru * 77151497Sru * On my athlon system at least, it appears the builtin OpenSSL code is now 78151497Sru * slightly faster, which is to say that the RSA-related MPI performance 79151497Sru * between OpenSSL's BIGNUM and GMP's mpz implementations is probably pretty 80104862Sru * balanced for this chip, and so the performance degradation in this ENGINE by 81104862Sru * having to convert to/from GMP formats (and not being able to cache 82104862Sru * montgomery forms) is probably the difference. However, if some unconfirmed 83104862Sru * reports from users is anything to go by, the situation on some other 84104862Sru * chipsets might be a good deal more favourable to the GMP version (eg. PPC). 85104862Sru * Feedback welcome. */ 86104862Sru 87151497Sru#include <stdio.h> 88104862Sru#include <string.h> 89104862Sru#include <openssl/crypto.h> 90104862Sru#include <openssl/buffer.h> 91104862Sru#include <openssl/engine.h> 92104862Sru#ifndef OPENSSL_NO_RSA 93104862Sru# include <openssl/rsa.h> 94104862Sru#endif 95104862Sru#include <openssl/bn.h> 96104862Sru 97104862Sru#ifndef OPENSSL_NO_HW 98104862Sru# ifndef OPENSSL_NO_GMP 99104862Sru 100104862Sru# include <gmp.h> 101104862Sru 102104862Sru# define E_GMP_LIB_NAME "gmp engine" 103104862Sru# include "e_gmp_err.c" 104104862Sru 105104862Srustatic int e_gmp_destroy(ENGINE *e); 106104862Srustatic int e_gmp_init(ENGINE *e); 107104862Srustatic int e_gmp_finish(ENGINE *e); 108104862Srustatic int e_gmp_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)); 109104862Sru 110104862Sru# ifndef OPENSSL_NO_RSA 111104862Sru/* RSA stuff */ 112104862Srustatic int e_gmp_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, 113104862Sru BN_CTX *ctx); 114104862Srustatic int e_gmp_rsa_finish(RSA *r); 115104862Sru# endif 116104862Sru 117104862Sru/* The definitions for control commands specific to this engine */ 118104862Sru/* #define E_GMP_CMD_SO_PATH ENGINE_CMD_BASE */ 119104862Srustatic const ENGINE_CMD_DEFN e_gmp_cmd_defns[] = { 120104862Sru# if 0 121104862Sru {E_GMP_CMD_SO_PATH, 122104862Sru "SO_PATH", 123104862Sru "Specifies the path to the 'e_gmp' shared library", 124104862Sru ENGINE_CMD_FLAG_STRING}, 125104862Sru# endif 126104862Sru {0, NULL, NULL, 0} 127104862Sru}; 128104862Sru 129104862Sru# ifndef OPENSSL_NO_RSA 130104862Sru/* Our internal RSA_METHOD that we provide pointers to */ 131104862Srustatic RSA_METHOD e_gmp_rsa = { 132104862Sru "GMP RSA method", 133104862Sru NULL, 134104862Sru NULL, 135104862Sru NULL, 136104862Sru NULL, 137104862Sru e_gmp_rsa_mod_exp, 138104862Sru NULL, 139104862Sru NULL, 140104862Sru e_gmp_rsa_finish, 141104862Sru /* 142104862Sru * These flags initialise montgomery crud that GMP ignores, however it 143104862Sru * makes sure the public key ops (which are done in openssl) don't seem 144104862Sru * *slower* than usual :-) 145104862Sru */ 146104862Sru RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE, 147104862Sru NULL, 148104862Sru NULL, 149104862Sru NULL 150104862Sru}; 151104862Sru# endif 152104862Sru 153104862Sru/* Constants used when creating the ENGINE */ 154104862Srustatic const char *engine_e_gmp_id = "gmp"; 155104862Srustatic const char *engine_e_gmp_name = "GMP engine support"; 156104862Sru 157151497Sru/* 158104862Sru * This internal function is used by ENGINE_gmp() and possibly by the 159104862Sru * "dynamic" ENGINE support too 160104862Sru */ 161104862Srustatic int bind_helper(ENGINE *e) 162104862Sru{ 163104862Sru# ifndef OPENSSL_NO_RSA 164151497Sru const RSA_METHOD *meth1; 165104862Sru# endif 166104862Sru if (!ENGINE_set_id(e, engine_e_gmp_id) || 167104862Sru !ENGINE_set_name(e, engine_e_gmp_name) || 168104862Sru# ifndef OPENSSL_NO_RSA 169104862Sru !ENGINE_set_RSA(e, &e_gmp_rsa) || 170104862Sru# endif 171104862Sru !ENGINE_set_destroy_function(e, e_gmp_destroy) || 172104862Sru !ENGINE_set_init_function(e, e_gmp_init) || 173104862Sru !ENGINE_set_finish_function(e, e_gmp_finish) || 174104862Sru !ENGINE_set_ctrl_function(e, e_gmp_ctrl) || 175104862Sru !ENGINE_set_cmd_defns(e, e_gmp_cmd_defns)) 176104862Sru return 0; 177104862Sru 178104862Sru# ifndef OPENSSL_NO_RSA 179104862Sru meth1 = RSA_PKCS1_SSLeay(); 180104862Sru e_gmp_rsa.rsa_pub_enc = meth1->rsa_pub_enc; 181104862Sru e_gmp_rsa.rsa_pub_dec = meth1->rsa_pub_dec; 182104862Sru e_gmp_rsa.rsa_priv_enc = meth1->rsa_priv_enc; 183104862Sru e_gmp_rsa.rsa_priv_dec = meth1->rsa_priv_dec; 184104862Sru e_gmp_rsa.bn_mod_exp = meth1->bn_mod_exp; 185104862Sru# endif 186104862Sru 187104862Sru /* Ensure the e_gmp error handling is set up */ 188104862Sru ERR_load_GMP_strings(); 189104862Sru return 1; 190104862Sru} 191104862Sru 192104862Srustatic ENGINE *engine_gmp(void) 193104862Sru{ 194104862Sru ENGINE *ret = ENGINE_new(); 195104862Sru if (!ret) 196104862Sru return NULL; 197104862Sru if (!bind_helper(ret)) { 198104862Sru ENGINE_free(ret); 199104862Sru return NULL; 200104862Sru } 201104862Sru return ret; 202104862Sru} 203104862Sru 204104862Sruvoid ENGINE_load_gmp(void) 205104862Sru{ 206104862Sru /* Copied from eng_[openssl|dyn].c */ 207104862Sru ENGINE *toadd = engine_gmp(); 208104862Sru if (!toadd) 209104862Sru return; 210151497Sru ENGINE_add(toadd); 211104862Sru ENGINE_free(toadd); 212104862Sru ERR_clear_error(); 213104862Sru} 214104862Sru 215104862Sru# ifndef OPENSSL_NO_RSA 216104862Sru/* Used to attach our own key-data to an RSA structure */ 217151497Srustatic int hndidx_rsa = -1; 218104862Sru# endif 219104862Sru 220104862Srustatic int e_gmp_destroy(ENGINE *e) 221104862Sru{ 222104862Sru ERR_unload_GMP_strings(); 223104862Sru return 1; 224104862Sru} 225104862Sru 226151497Sru/* (de)initialisation functions. */ 227151497Srustatic int e_gmp_init(ENGINE *e) 228104862Sru{ 229104862Sru# ifndef OPENSSL_NO_RSA 230104862Sru if (hndidx_rsa == -1) 231104862Sru hndidx_rsa = RSA_get_ex_new_index(0, 232104862Sru "GMP-based RSA key handle", 233104862Sru NULL, NULL, NULL); 234104862Sru# endif 235104862Sru if (hndidx_rsa == -1) 236104862Sru return 0; 237104862Sru return 1; 238104862Sru} 239104862Sru 240104862Srustatic int e_gmp_finish(ENGINE *e) 241104862Sru{ 242104862Sru return 1; 243151497Sru} 244104862Sru 245151497Srustatic int e_gmp_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 246151497Sru{ 247151497Sru int to_return = 1; 248151497Sru 249151497Sru switch (cmd) { 250104862Sru# if 0 251104862Sru case E_GMP_CMD_SO_PATH: 252151497Sru /* ... */ 253151497Sru# endif 254151497Sru /* The command isn't understood by this engine */ 255151497Sru default: 256151497Sru GMPerr(GMP_F_E_GMP_CTRL, GMP_R_CTRL_COMMAND_NOT_IMPLEMENTED); 257151497Sru to_return = 0; 258151497Sru break; 259151497Sru } 260104862Sru 261104862Sru return to_return; 262104862Sru} 263104862Sru 264104862Sru/* 265104862Sru * Most often limb sizes will be the same. If not, we use hex conversion 266104862Sru * which is neat, but extremely inefficient. 267104862Sru */ 268104862Srustatic int bn2gmp(const BIGNUM *bn, mpz_t g) 269104862Sru{ 270151497Sru bn_check_top(bn); 271104862Sru if (((sizeof(bn->d[0]) * 8) == GMP_NUMB_BITS) && 272151497Sru (BN_BITS2 == GMP_NUMB_BITS)) { 273151497Sru /* The common case */ 274151497Sru if (!_mpz_realloc(g, bn->top)) 275151497Sru return 0; 276151497Sru memcpy(&g->_mp_d[0], &bn->d[0], bn->top * sizeof(bn->d[0])); 277151497Sru g->_mp_size = bn->top; 278151497Sru if (bn->neg) 279151497Sru g->_mp_size = -g->_mp_size; 280151497Sru return 1; 281151497Sru } else { 282151497Sru int toret; 283151497Sru char *tmpchar = BN_bn2hex(bn); 284151497Sru if (!tmpchar) 285151497Sru return 0; 286151497Sru toret = (mpz_set_str(g, tmpchar, 16) == 0 ? 1 : 0); 287151497Sru OPENSSL_free(tmpchar); 288151497Sru return toret; 289151497Sru } 290151497Sru} 291151497Sru 292151497Srustatic int gmp2bn(mpz_t g, BIGNUM *bn) 293151497Sru{ 294151497Sru if (((sizeof(bn->d[0]) * 8) == GMP_NUMB_BITS) && 295151497Sru (BN_BITS2 == GMP_NUMB_BITS)) { 296151497Sru /* The common case */ 297151497Sru int s = (g->_mp_size >= 0) ? g->_mp_size : -g->_mp_size; 298151497Sru BN_zero(bn); 299151497Sru if (bn_expand2(bn, s) == NULL) 300151497Sru return 0; 301151497Sru bn->top = s; 302151497Sru memcpy(&bn->d[0], &g->_mp_d[0], s * sizeof(bn->d[0])); 303151497Sru bn_correct_top(bn); 304151497Sru bn->neg = g->_mp_size >= 0 ? 0 : 1; 305151497Sru return 1; 306151497Sru } else { 307151497Sru int toret; 308151497Sru char *tmpchar = OPENSSL_malloc(mpz_sizeinbase(g, 16) + 10); 309151497Sru if (!tmpchar) 310151497Sru return 0; 311151497Sru mpz_get_str(tmpchar, 16, g); 312151497Sru toret = BN_hex2bn(&bn, tmpchar); 313151497Sru OPENSSL_free(tmpchar); 314151497Sru return toret; 315151497Sru } 316151497Sru} 317151497Sru 318151497Sru# ifndef OPENSSL_NO_RSA 319151497Srutypedef struct st_e_gmp_rsa_ctx { 320151497Sru int public_only; 321151497Sru mpz_t n; 322151497Sru mpz_t d; 323151497Sru mpz_t e; 324151497Sru mpz_t p; 325151497Sru mpz_t q; 326151497Sru mpz_t dmp1; 327151497Sru mpz_t dmq1; 328104862Sru mpz_t iqmp; 329104862Sru mpz_t r0, r1, I0, m1; 330104862Sru} E_GMP_RSA_CTX; 331104862Sru 332151497Srustatic E_GMP_RSA_CTX *e_gmp_get_rsa(RSA *rsa) 333151497Sru{ 334104862Sru E_GMP_RSA_CTX *hptr = RSA_get_ex_data(rsa, hndidx_rsa); 335104862Sru if (hptr) 336104862Sru return hptr; 337151497Sru hptr = OPENSSL_malloc(sizeof(E_GMP_RSA_CTX)); 338151497Sru if (!hptr) 339151497Sru return NULL; 340151497Sru /* 341151497Sru * These inits could probably be replaced by more intelligent mpz_init2() 342151497Sru * versions, to reduce malloc-thrashing. 343151497Sru */ 344151497Sru mpz_init(hptr->n); 345151497Sru mpz_init(hptr->d); 346151497Sru mpz_init(hptr->e); 347104862Sru mpz_init(hptr->p); 348104862Sru mpz_init(hptr->q); 349104862Sru mpz_init(hptr->dmp1); 350104862Sru mpz_init(hptr->dmq1); 351104862Sru mpz_init(hptr->iqmp); 352104862Sru mpz_init(hptr->r0); 353104862Sru mpz_init(hptr->r1); 354104862Sru mpz_init(hptr->I0); 355104862Sru mpz_init(hptr->m1); 356104862Sru if (!bn2gmp(rsa->n, hptr->n) || !bn2gmp(rsa->e, hptr->e)) 357104862Sru goto err; 358104862Sru if (!rsa->p || !rsa->q || !rsa->d || !rsa->dmp1 || !rsa->dmq1 359104862Sru || !rsa->iqmp) { 360104862Sru hptr->public_only = 1; 361104862Sru return hptr; 362104862Sru } 363104862Sru if (!bn2gmp(rsa->d, hptr->d) || !bn2gmp(rsa->p, hptr->p) || 364104862Sru !bn2gmp(rsa->q, hptr->q) || !bn2gmp(rsa->dmp1, hptr->dmp1) || 365104862Sru !bn2gmp(rsa->dmq1, hptr->dmq1) || !bn2gmp(rsa->iqmp, hptr->iqmp)) 366104862Sru goto err; 367151497Sru hptr->public_only = 0; 368104862Sru RSA_set_ex_data(rsa, hndidx_rsa, hptr); 369104862Sru return hptr; 370104862Sru err: 371104862Sru mpz_clear(hptr->n); 372104862Sru mpz_clear(hptr->d); 373104862Sru mpz_clear(hptr->e); 374151497Sru mpz_clear(hptr->p); 375104862Sru mpz_clear(hptr->q); 376104862Sru mpz_clear(hptr->dmp1); 377104862Sru mpz_clear(hptr->dmq1); 378104862Sru mpz_clear(hptr->iqmp); 379104862Sru mpz_clear(hptr->r0); 380104862Sru mpz_clear(hptr->r1); 381104862Sru mpz_clear(hptr->I0); 382104862Sru mpz_clear(hptr->m1); 383104862Sru OPENSSL_free(hptr); 384104862Sru return NULL; 385104862Sru} 386104862Sru 387104862Srustatic int e_gmp_rsa_finish(RSA *rsa) 388104862Sru{ 389104862Sru E_GMP_RSA_CTX *hptr = RSA_get_ex_data(rsa, hndidx_rsa); 390104862Sru if (!hptr) 391104862Sru return 0; 392104862Sru mpz_clear(hptr->n); 393104862Sru mpz_clear(hptr->d); 394104862Sru mpz_clear(hptr->e); 395104862Sru mpz_clear(hptr->p); 396151497Sru mpz_clear(hptr->q); 397151497Sru mpz_clear(hptr->dmp1); 398151497Sru mpz_clear(hptr->dmq1); 399151497Sru mpz_clear(hptr->iqmp); 400151497Sru mpz_clear(hptr->r0); 401151497Sru mpz_clear(hptr->r1); 402151497Sru mpz_clear(hptr->I0); 403151497Sru mpz_clear(hptr->m1); 404151497Sru OPENSSL_free(hptr); 405151497Sru RSA_set_ex_data(rsa, hndidx_rsa, NULL); 406151497Sru return 1; 407151497Sru} 408151497Sru 409151497Srustatic int e_gmp_rsa_mod_exp(BIGNUM *r, const BIGNUM *I, RSA *rsa, 410151497Sru BN_CTX *ctx) 411151497Sru{ 412151497Sru E_GMP_RSA_CTX *hptr; 413151497Sru int to_return = 0; 414151497Sru 415151497Sru hptr = e_gmp_get_rsa(rsa); 416151497Sru if (!hptr) { 417151497Sru GMPerr(GMP_F_E_GMP_RSA_MOD_EXP, GMP_R_KEY_CONTEXT_ERROR); 418151497Sru return 0; 419151497Sru } 420151497Sru if (hptr->public_only) { 421151497Sru GMPerr(GMP_F_E_GMP_RSA_MOD_EXP, GMP_R_MISSING_KEY_COMPONENTS); 422151497Sru return 0; 423151497Sru } 424151497Sru 425151497Sru /* ugh!!! */ 426151497Sru if (!bn2gmp(I, hptr->I0)) 427151497Sru return 0; 428151497Sru 429151497Sru /* 430151497Sru * This is basically the CRT logic in crypto/rsa/rsa_eay.c reworded into 431151497Sru * GMP-speak. It may be that GMP's API facilitates cleaner formulations 432151497Sru * of this stuff, eg. better handling of negatives, or functions that 433151497Sru * combine operations. 434151497Sru */ 435151497Sru 436151497Sru mpz_mod(hptr->r1, hptr->I0, hptr->q); 437151497Sru mpz_powm(hptr->m1, hptr->r1, hptr->dmq1, hptr->q); 438151497Sru 439151497Sru mpz_mod(hptr->r1, hptr->I0, hptr->p); 440151497Sru mpz_powm(hptr->r0, hptr->r1, hptr->dmp1, hptr->p); 441104862Sru 442104862Sru mpz_sub(hptr->r0, hptr->r0, hptr->m1); 443104862Sru 444104862Sru if (mpz_sgn(hptr->r0) < 0) 445104862Sru mpz_add(hptr->r0, hptr->r0, hptr->p); 446151497Sru mpz_mul(hptr->r1, hptr->r0, hptr->iqmp); 447104862Sru mpz_mod(hptr->r0, hptr->r1, hptr->p); 448104862Sru 449104862Sru if (mpz_sgn(hptr->r0) < 0) 450104862Sru mpz_add(hptr->r0, hptr->r0, hptr->p); 451104862Sru mpz_mul(hptr->r1, hptr->r0, hptr->q); 452104862Sru mpz_add(hptr->r0, hptr->r1, hptr->m1); 453104862Sru 454104862Sru /* ugh!!! */ 455104862Sru if (gmp2bn(hptr->r0, r)) 456104862Sru to_return = 1; 457104862Sru 458104862Sru return 1; 459104862Sru} 460104862Sru# endif 461104862Sru 462104862Sru# endif /* !OPENSSL_NO_GMP */ 463104862Sru 464104862Sru/* 465104862Sru * This stuff is needed if this ENGINE is being compiled into a 466104862Sru * self-contained shared-library. 467104862Sru */ 468104862Sru# ifndef OPENSSL_NO_DYNAMIC_ENGINE 469104862SruIMPLEMENT_DYNAMIC_CHECK_FN() 470104862Sru# ifndef OPENSSL_NO_GMP 471104862Srustatic int bind_fn(ENGINE *e, const char *id) 472104862Sru{ 473104862Sru if (id && (strcmp(id, engine_e_gmp_id) != 0)) 474104862Sru return 0; 475104862Sru if (!bind_helper(e)) 476104862Sru return 0; 477104862Sru return 1; 478104862Sru} 479104862Sru 480104862SruIMPLEMENT_DYNAMIC_BIND_FN(bind_fn) 481104862Sru# else 482104862SruOPENSSL_EXPORT 483104862Sru int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); 484104862SruOPENSSL_EXPORT 485104862Sru int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) 486104862Sru{ 487104862Sru return 0; 488104862Sru} 489104862Sru# endif 490104862Sru# endif /* !OPENSSL_NO_DYNAMIC_ENGINE */ 491104862Sru 492104862Sru#endif /* !OPENSSL_NO_HW */ 493104862Sru