hw_ibmca.c revision 296465
1/* crypto/engine/hw_ibmca.c */ 2/* 3 * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project 4 * 2000. 5 */ 6/* ==================================================================== 7 * Copyright (c) 1999 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/* (C) COPYRIGHT International Business Machines Corp. 2001 */ 61 62#include <stdio.h> 63#include <openssl/crypto.h> 64#include <openssl/dso.h> 65#include <openssl/engine.h> 66 67#ifndef OPENSSL_NO_HW 68# ifndef OPENSSL_NO_HW_IBMCA 69 70# ifdef FLAT_INC 71# include "ica_openssl_api.h" 72# else 73# include "vendor_defns/ica_openssl_api.h" 74# endif 75 76# define IBMCA_LIB_NAME "ibmca engine" 77# include "hw_ibmca_err.c" 78 79static int ibmca_destroy(ENGINE *e); 80static int ibmca_init(ENGINE *e); 81static int ibmca_finish(ENGINE *e); 82static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) ()); 83 84static const char *IBMCA_F1 = "icaOpenAdapter"; 85static const char *IBMCA_F2 = "icaCloseAdapter"; 86static const char *IBMCA_F3 = "icaRsaModExpo"; 87static const char *IBMCA_F4 = "icaRandomNumberGenerate"; 88static const char *IBMCA_F5 = "icaRsaCrt"; 89 90ICA_ADAPTER_HANDLE handle = 0; 91 92/* BIGNUM stuff */ 93static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 94 const BIGNUM *m, BN_CTX *ctx); 95 96static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 97 const BIGNUM *q, const BIGNUM *dmp1, 98 const BIGNUM *dmq1, const BIGNUM *iqmp, 99 BN_CTX *ctx); 100 101# ifndef OPENSSL_NO_RSA 102/* RSA stuff */ 103static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); 104# endif 105 106/* This function is aliased to mod_exp (with the mont stuff dropped). */ 107static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 108 const BIGNUM *m, BN_CTX *ctx, 109 BN_MONT_CTX *m_ctx); 110 111# ifndef OPENSSL_NO_DSA 112/* DSA stuff */ 113static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, 114 BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, 115 BN_CTX *ctx, BN_MONT_CTX *in_mont); 116static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, 117 const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, 118 BN_MONT_CTX *m_ctx); 119# endif 120 121# ifndef OPENSSL_NO_DH 122/* DH stuff */ 123/* This function is alised to mod_exp (with the DH and mont dropped). */ 124static int ibmca_mod_exp_dh(const DH *dh, BIGNUM *r, 125 const BIGNUM *a, const BIGNUM *p, 126 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); 127# endif 128 129/* RAND stuff */ 130static int ibmca_rand_bytes(unsigned char *buf, int num); 131static int ibmca_rand_status(void); 132 133/* WJH - check for more commands, like in nuron */ 134 135/* The definitions for control commands specific to this engine */ 136# define IBMCA_CMD_SO_PATH ENGINE_CMD_BASE 137static const ENGINE_CMD_DEFN ibmca_cmd_defns[] = { 138 {IBMCA_CMD_SO_PATH, 139 "SO_PATH", 140 "Specifies the path to the 'atasi' shared library", 141 ENGINE_CMD_FLAG_STRING}, 142 {0, NULL, NULL, 0} 143}; 144 145# ifndef OPENSSL_NO_RSA 146/* Our internal RSA_METHOD that we provide pointers to */ 147static RSA_METHOD ibmca_rsa = { 148 "Ibmca RSA method", 149 NULL, 150 NULL, 151 NULL, 152 NULL, 153 ibmca_rsa_mod_exp, 154 ibmca_mod_exp_mont, 155 NULL, 156 NULL, 157 0, 158 NULL, 159 NULL, 160 NULL 161}; 162# endif 163 164# ifndef OPENSSL_NO_DSA 165/* Our internal DSA_METHOD that we provide pointers to */ 166static DSA_METHOD ibmca_dsa = { 167 "Ibmca DSA method", 168 NULL, /* dsa_do_sign */ 169 NULL, /* dsa_sign_setup */ 170 NULL, /* dsa_do_verify */ 171 ibmca_dsa_mod_exp, /* dsa_mod_exp */ 172 ibmca_mod_exp_dsa, /* bn_mod_exp */ 173 NULL, /* init */ 174 NULL, /* finish */ 175 0, /* flags */ 176 NULL /* app_data */ 177}; 178# endif 179 180# ifndef OPENSSL_NO_DH 181/* Our internal DH_METHOD that we provide pointers to */ 182static DH_METHOD ibmca_dh = { 183 "Ibmca DH method", 184 NULL, 185 NULL, 186 ibmca_mod_exp_dh, 187 NULL, 188 NULL, 189 0, 190 NULL 191}; 192# endif 193 194static RAND_METHOD ibmca_rand = { 195 /* "IBMCA RAND method", */ 196 NULL, 197 ibmca_rand_bytes, 198 NULL, 199 NULL, 200 ibmca_rand_bytes, 201 ibmca_rand_status, 202}; 203 204/* Constants used when creating the ENGINE */ 205static const char *engine_ibmca_id = "ibmca"; 206static const char *engine_ibmca_name = "Ibmca hardware engine support"; 207 208/* 209 * This internal function is used by ENGINE_ibmca() and possibly by the 210 * "dynamic" ENGINE support too 211 */ 212static int bind_helper(ENGINE *e) 213{ 214# ifndef OPENSSL_NO_RSA 215 const RSA_METHOD *meth1; 216# endif 217# ifndef OPENSSL_NO_DSA 218 const DSA_METHOD *meth2; 219# endif 220# ifndef OPENSSL_NO_DH 221 const DH_METHOD *meth3; 222# endif 223 if (!ENGINE_set_id(e, engine_ibmca_id) || 224 !ENGINE_set_name(e, engine_ibmca_name) || 225# ifndef OPENSSL_NO_RSA 226 !ENGINE_set_RSA(e, &ibmca_rsa) || 227# endif 228# ifndef OPENSSL_NO_DSA 229 !ENGINE_set_DSA(e, &ibmca_dsa) || 230# endif 231# ifndef OPENSSL_NO_DH 232 !ENGINE_set_DH(e, &ibmca_dh) || 233# endif 234 !ENGINE_set_RAND(e, &ibmca_rand) || 235 !ENGINE_set_destroy_function(e, ibmca_destroy) || 236 !ENGINE_set_init_function(e, ibmca_init) || 237 !ENGINE_set_finish_function(e, ibmca_finish) || 238 !ENGINE_set_ctrl_function(e, ibmca_ctrl) || 239 !ENGINE_set_cmd_defns(e, ibmca_cmd_defns)) 240 return 0; 241 242# ifndef OPENSSL_NO_RSA 243 /* 244 * We know that the "PKCS1_SSLeay()" functions hook properly to the 245 * ibmca-specific mod_exp and mod_exp_crt so we use those functions. NB: 246 * We don't use ENGINE_openssl() or anything "more generic" because 247 * something like the RSAref code may not hook properly, and if you own 248 * one of these cards then you have the right to do RSA operations on it 249 * anyway! 250 */ 251 meth1 = RSA_PKCS1_SSLeay(); 252 ibmca_rsa.rsa_pub_enc = meth1->rsa_pub_enc; 253 ibmca_rsa.rsa_pub_dec = meth1->rsa_pub_dec; 254 ibmca_rsa.rsa_priv_enc = meth1->rsa_priv_enc; 255 ibmca_rsa.rsa_priv_dec = meth1->rsa_priv_dec; 256# endif 257 258# ifndef OPENSSL_NO_DSA 259 /* 260 * Use the DSA_OpenSSL() method and just hook the mod_exp-ish bits. 261 */ 262 meth2 = DSA_OpenSSL(); 263 ibmca_dsa.dsa_do_sign = meth2->dsa_do_sign; 264 ibmca_dsa.dsa_sign_setup = meth2->dsa_sign_setup; 265 ibmca_dsa.dsa_do_verify = meth2->dsa_do_verify; 266# endif 267 268# ifndef OPENSSL_NO_DH 269 /* Much the same for Diffie-Hellman */ 270 meth3 = DH_OpenSSL(); 271 ibmca_dh.generate_key = meth3->generate_key; 272 ibmca_dh.compute_key = meth3->compute_key; 273# endif 274 275 /* Ensure the ibmca error handling is set up */ 276 ERR_load_IBMCA_strings(); 277 return 1; 278} 279 280static ENGINE *engine_ibmca(void) 281{ 282 ENGINE *ret = ENGINE_new(); 283 if (!ret) 284 return NULL; 285 if (!bind_helper(ret)) { 286 ENGINE_free(ret); 287 return NULL; 288 } 289 return ret; 290} 291 292# ifdef ENGINE_DYNAMIC_SUPPORT 293static 294# endif 295void ENGINE_load_ibmca(void) 296{ 297 /* Copied from eng_[openssl|dyn].c */ 298 ENGINE *toadd = engine_ibmca(); 299 if (!toadd) 300 return; 301 ENGINE_add(toadd); 302 ENGINE_free(toadd); 303 ERR_clear_error(); 304} 305 306/* Destructor (complements the "ENGINE_ibmca()" constructor) */ 307static int ibmca_destroy(ENGINE *e) 308{ 309 /* 310 * Unload the ibmca error strings so any error state including our functs 311 * or reasons won't lead to a segfault (they simply get displayed without 312 * corresponding string data because none will be found). 313 */ 314 ERR_unload_IBMCA_strings(); 315 return 1; 316} 317 318/* 319 * This is a process-global DSO handle used for loading and unloading the 320 * Ibmca library. NB: This is only set (or unset) during an init() or 321 * finish() call (reference counts permitting) and they're operating with 322 * global locks, so this should be thread-safe implicitly. 323 */ 324 325static DSO *ibmca_dso = NULL; 326 327/* 328 * These are the function pointers that are (un)set when the library has 329 * successfully (un)loaded. 330 */ 331 332static unsigned int (ICA_CALL * p_icaOpenAdapter) (); 333static unsigned int (ICA_CALL * p_icaCloseAdapter) (); 334static unsigned int (ICA_CALL * p_icaRsaModExpo) (); 335static unsigned int (ICA_CALL * p_icaRandomNumberGenerate) (); 336static unsigned int (ICA_CALL * p_icaRsaCrt) (); 337 338/* utility function to obtain a context */ 339static int get_context(ICA_ADAPTER_HANDLE * p_handle) 340{ 341 unsigned int status = 0; 342 343 status = p_icaOpenAdapter(0, p_handle); 344 if (status != 0) 345 return 0; 346 return 1; 347} 348 349/* similarly to release one. */ 350static void release_context(ICA_ADAPTER_HANDLE handle) 351{ 352 p_icaCloseAdapter(handle); 353} 354 355/* (de)initialisation functions. */ 356static int ibmca_init(ENGINE *e) 357{ 358 359 void (*p1) (); 360 void (*p2) (); 361 void (*p3) (); 362 void (*p4) (); 363 void (*p5) (); 364 365 if (ibmca_dso != NULL) { 366 IBMCAerr(IBMCA_F_IBMCA_INIT, IBMCA_R_ALREADY_LOADED); 367 goto err; 368 } 369 /* 370 * Attempt to load libatasi.so/atasi.dll/whatever. Needs to be changed 371 * unfortunately because the Ibmca drivers don't have standard library 372 * names that can be platform-translated well. 373 */ 374 /* 375 * TODO: Work out how to actually map to the names the Ibmca drivers 376 * really use - for now a symbollic link needs to be created on the host 377 * system from libatasi.so to atasi.so on unix variants. 378 */ 379 380 /* WJH XXX check name translation */ 381 382 ibmca_dso = DSO_load(NULL, IBMCA_LIBNAME, NULL, 383 /* 384 * DSO_FLAG_NAME_TRANSLATION 385 */ 0); 386 if (ibmca_dso == NULL) { 387 IBMCAerr(IBMCA_F_IBMCA_INIT, IBMCA_R_DSO_FAILURE); 388 goto err; 389 } 390 391 if (!(p1 = DSO_bind_func(ibmca_dso, IBMCA_F1)) || 392 !(p2 = DSO_bind_func(ibmca_dso, IBMCA_F2)) || 393 !(p3 = DSO_bind_func(ibmca_dso, IBMCA_F3)) || 394 !(p4 = DSO_bind_func(ibmca_dso, IBMCA_F4)) || 395 !(p5 = DSO_bind_func(ibmca_dso, IBMCA_F5))) { 396 IBMCAerr(IBMCA_F_IBMCA_INIT, IBMCA_R_DSO_FAILURE); 397 goto err; 398 } 399 400 /* Copy the pointers */ 401 402 p_icaOpenAdapter = (unsigned int (ICA_CALL *) ())p1; 403 p_icaCloseAdapter = (unsigned int (ICA_CALL *) ())p2; 404 p_icaRsaModExpo = (unsigned int (ICA_CALL *) ())p3; 405 p_icaRandomNumberGenerate = (unsigned int (ICA_CALL *) ())p4; 406 p_icaRsaCrt = (unsigned int (ICA_CALL *) ())p5; 407 408 if (!get_context(&handle)) { 409 IBMCAerr(IBMCA_F_IBMCA_INIT, IBMCA_R_UNIT_FAILURE); 410 goto err; 411 } 412 413 return 1; 414 err: 415 if (ibmca_dso) 416 DSO_free(ibmca_dso); 417 418 p_icaOpenAdapter = NULL; 419 p_icaCloseAdapter = NULL; 420 p_icaRsaModExpo = NULL; 421 p_icaRandomNumberGenerate = NULL; 422 423 return 0; 424} 425 426static int ibmca_finish(ENGINE *e) 427{ 428 if (ibmca_dso == NULL) { 429 IBMCAerr(IBMCA_F_IBMCA_FINISH, IBMCA_R_NOT_LOADED); 430 return 0; 431 } 432 release_context(handle); 433 if (!DSO_free(ibmca_dso)) { 434 IBMCAerr(IBMCA_F_IBMCA_FINISH, IBMCA_R_DSO_FAILURE); 435 return 0; 436 } 437 ibmca_dso = NULL; 438 439 return 1; 440} 441 442static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) ()) 443{ 444 int initialised = ((ibmca_dso == NULL) ? 0 : 1); 445 switch (cmd) { 446 case IBMCA_CMD_SO_PATH: 447 if (p == NULL) { 448 IBMCAerr(IBMCA_F_IBMCA_CTRL, ERR_R_PASSED_NULL_PARAMETER); 449 return 0; 450 } 451 if (initialised) { 452 IBMCAerr(IBMCA_F_IBMCA_CTRL, IBMCA_R_ALREADY_LOADED); 453 return 0; 454 } 455 IBMCA_LIBNAME = (const char *)p; 456 return 1; 457 default: 458 break; 459 } 460 IBMCAerr(IBMCA_F_IBMCA_CTRL, IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED); 461 return 0; 462} 463 464static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 465 const BIGNUM *m, BN_CTX *ctx) 466{ 467 /* 468 * I need somewhere to store temporary serialised values for use with the 469 * Ibmca API calls. A neat cheat - I'll use BIGNUMs from the BN_CTX but 470 * access their arrays directly as byte arrays <grin>. This way I don't 471 * have to clean anything up. 472 */ 473 474 BIGNUM *argument = NULL; 475 BIGNUM *result = NULL; 476 BIGNUM *key = NULL; 477 int to_return; 478 int inLen, outLen, tmpLen; 479 480 ICA_KEY_RSA_MODEXPO *publKey = NULL; 481 unsigned int rc; 482 483 to_return = 0; /* expect failure */ 484 485 if (!ibmca_dso) { 486 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP, IBMCA_R_NOT_LOADED); 487 goto err; 488 } 489 /* Prepare the params */ 490 BN_CTX_start(ctx); 491 argument = BN_CTX_get(ctx); 492 result = BN_CTX_get(ctx); 493 key = BN_CTX_get(ctx); 494 495 if (!argument || !result || !key) { 496 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP, IBMCA_R_BN_CTX_FULL); 497 goto err; 498 } 499 500 if (!bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top) || 501 !bn_wexpand(key, sizeof(*publKey) / BN_BYTES)) { 502 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP, IBMCA_R_BN_EXPAND_FAIL); 503 goto err; 504 } 505 506 publKey = (ICA_KEY_RSA_MODEXPO *)key->d; 507 508 if (publKey == NULL) { 509 goto err; 510 } 511 memset(publKey, 0, sizeof(ICA_KEY_RSA_MODEXPO)); 512 513 publKey->keyType = CORRECT_ENDIANNESS(ME_KEY_TYPE); 514 publKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_MODEXPO)); 515 publKey->expOffset = (char *)publKey->keyRecord - (char *)publKey; 516 517 /* 518 * A quirk of the card: the exponent length has to be the same as the 519 * modulus (key) length 520 */ 521 522 outLen = BN_num_bytes(m); 523 524/* check for modulus length SAB*/ 525 if (outLen > 256) { 526 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP, IBMCA_R_MEXP_LENGTH_TO_LARGE); 527 goto err; 528 } 529/* check for modulus length SAB*/ 530 531 publKey->expLength = publKey->nLength = outLen; 532 /* 533 * SAB Check for underflow condition the size of the exponent is less 534 * than the size of the parameter then we have a big problem and will 535 * underflow the keyRecord buffer. Bad stuff could happen then 536 */ 537 if (outLen < BN_num_bytes(p)) { 538 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP, IBMCA_R_UNDERFLOW_KEYRECORD); 539 goto err; 540 } 541/* SAB End check for underflow */ 542 543 BN_bn2bin(p, &publKey->keyRecord[publKey->expLength - BN_num_bytes(p)]); 544 BN_bn2bin(m, &publKey->keyRecord[publKey->expLength]); 545 546 publKey->modulusBitLength = CORRECT_ENDIANNESS(publKey->nLength * 8); 547 publKey->nOffset = CORRECT_ENDIANNESS(publKey->expOffset + 548 publKey->expLength); 549 550 publKey->expOffset = CORRECT_ENDIANNESS((char *)publKey->keyRecord - 551 (char *)publKey); 552 553 tmpLen = outLen; 554 publKey->expLength = publKey->nLength = CORRECT_ENDIANNESS(tmpLen); 555 556 /* Prepare the argument */ 557 558 memset(argument->d, 0, outLen); 559 BN_bn2bin(a, (unsigned char *)argument->d + outLen - BN_num_bytes(a)); 560 561 inLen = outLen; 562 563 /* Perform the operation */ 564 565 if ((rc = p_icaRsaModExpo(handle, inLen, (unsigned char *)argument->d, 566 publKey, &outLen, (unsigned char *)result->d)) 567 != 0) { 568 printf("rc = %d\n", rc); 569 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP, IBMCA_R_REQUEST_FAILED); 570 goto err; 571 } 572 573 /* Convert the response */ 574 BN_bin2bn((unsigned char *)result->d, outLen, r); 575 to_return = 1; 576 err: 577 BN_CTX_end(ctx); 578 return to_return; 579} 580 581# ifndef OPENSSL_NO_RSA 582static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) 583{ 584 BN_CTX *ctx; 585 int to_return = 0; 586 587 if ((ctx = BN_CTX_new()) == NULL) 588 goto err; 589 if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) { 590 if (!rsa->d || !rsa->n) { 591 IBMCAerr(IBMCA_F_IBMCA_RSA_MOD_EXP, 592 IBMCA_R_MISSING_KEY_COMPONENTS); 593 goto err; 594 } 595 to_return = ibmca_mod_exp(r0, I, rsa->d, rsa->n, ctx); 596 } else { 597 to_return = ibmca_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1, 598 rsa->dmq1, rsa->iqmp, ctx); 599 } 600 err: 601 if (ctx) 602 BN_CTX_free(ctx); 603 return to_return; 604} 605# endif 606 607/* Ein kleines chinesisches "Restessen" */ 608static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 609 const BIGNUM *q, const BIGNUM *dmp1, 610 const BIGNUM *dmq1, const BIGNUM *iqmp, 611 BN_CTX *ctx) 612{ 613 614 BIGNUM *argument = NULL; 615 BIGNUM *result = NULL; 616 BIGNUM *key = NULL; 617 618 int to_return = 0; /* expect failure */ 619 620 char *pkey = NULL; 621 ICA_KEY_RSA_CRT *privKey = NULL; 622 int inLen, outLen; 623 624 int rc; 625 unsigned int offset, pSize, qSize; 626/* SAB New variables */ 627 unsigned int keyRecordSize; 628 unsigned int pbytes = BN_num_bytes(p); 629 unsigned int qbytes = BN_num_bytes(q); 630 unsigned int dmp1bytes = BN_num_bytes(dmp1); 631 unsigned int dmq1bytes = BN_num_bytes(dmq1); 632 unsigned int iqmpbytes = BN_num_bytes(iqmp); 633 634 /* Prepare the params */ 635 636 BN_CTX_start(ctx); 637 argument = BN_CTX_get(ctx); 638 result = BN_CTX_get(ctx); 639 key = BN_CTX_get(ctx); 640 641 if (!argument || !result || !key) { 642 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_BN_CTX_FULL); 643 goto err; 644 } 645 646 if (!bn_wexpand(argument, p->top + q->top) || 647 !bn_wexpand(result, p->top + q->top) || 648 !bn_wexpand(key, sizeof(*privKey) / BN_BYTES)) { 649 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_BN_EXPAND_FAIL); 650 goto err; 651 } 652 653 privKey = (ICA_KEY_RSA_CRT *)key->d; 654 /* 655 * SAB Add check for total size in bytes of the parms does not exceed the 656 * buffer space we have do this first 657 */ 658 keyRecordSize = pbytes + qbytes + dmp1bytes + dmq1bytes + iqmpbytes; 659 if (keyRecordSize > sizeof(privKey->keyRecord)) { 660 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); 661 goto err; 662 } 663 664 if ((qbytes + dmq1bytes) > 256) { 665 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); 666 goto err; 667 } 668 669 if (pbytes + dmp1bytes > 256) { 670 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); 671 goto err; 672 } 673 674/* end SAB additions */ 675 676 memset(privKey, 0, sizeof(ICA_KEY_RSA_CRT)); 677 privKey->keyType = CORRECT_ENDIANNESS(CRT_KEY_TYPE); 678 privKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_CRT)); 679 privKey->modulusBitLength = CORRECT_ENDIANNESS(BN_num_bytes(q) * 2 * 8); 680 681 /* 682 * p,dp & qInv are 1 QWORD Larger 683 */ 684 privKey->pLength = CORRECT_ENDIANNESS(BN_num_bytes(p) + 8); 685 privKey->qLength = CORRECT_ENDIANNESS(BN_num_bytes(q)); 686 privKey->dpLength = CORRECT_ENDIANNESS(BN_num_bytes(dmp1) + 8); 687 privKey->dqLength = CORRECT_ENDIANNESS(BN_num_bytes(dmq1)); 688 privKey->qInvLength = CORRECT_ENDIANNESS(BN_num_bytes(iqmp) + 8); 689 690 offset = (char *)privKey->keyRecord - (char *)privKey; 691 692 qSize = BN_num_bytes(q); 693 pSize = qSize + 8; /* 1 QWORD larger */ 694 695 /* 696 * SAB probably aittle redundant, but we'll verify that each of the 697 * components which make up a key record sent ot the card does not exceed 698 * the space that is allocated for it. this handles the case where even 699 * if the total length does not exceed keyrecord zied, if the operands are 700 * funny sized they could cause potential side affects on either the card 701 * or the result 702 */ 703 704 if ((pbytes > pSize) || (dmp1bytes > pSize) || 705 (iqmpbytes > pSize) || (qbytes > qSize) || (dmq1bytes > qSize)) { 706 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); 707 goto err; 708 709 } 710 711 privKey->dpOffset = CORRECT_ENDIANNESS(offset); 712 713 offset += pSize; 714 privKey->dqOffset = CORRECT_ENDIANNESS(offset); 715 716 offset += qSize; 717 privKey->pOffset = CORRECT_ENDIANNESS(offset); 718 719 offset += pSize; 720 privKey->qOffset = CORRECT_ENDIANNESS(offset); 721 722 offset += qSize; 723 privKey->qInvOffset = CORRECT_ENDIANNESS(offset); 724 725 pkey = (char *)privKey->keyRecord; 726 727/* SAB first check that we don;t under flow the buffer */ 728 if (pSize < pbytes) { 729 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION); 730 goto err; 731 } 732 733 /* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */ 734 pkey += pSize - BN_num_bytes(dmp1); 735 BN_bn2bin(dmp1, pkey); 736 pkey += BN_num_bytes(dmp1); /* move the pointer */ 737 738 BN_bn2bin(dmq1, pkey); /* Copy over dmq1 */ 739 740 pkey += qSize; /* move pointer */ 741 /* set up for zero padding of next field */ 742 pkey += pSize - BN_num_bytes(p); 743 744 BN_bn2bin(p, pkey); 745 /* increment pointer by number of bytes moved */ 746 pkey += BN_num_bytes(p); 747 748 BN_bn2bin(q, pkey); 749 pkey += qSize; /* move the pointer */ 750 pkey += pSize - BN_num_bytes(iqmp); /* Adjust for padding */ 751 BN_bn2bin(iqmp, pkey); 752 753 /* Prepare the argument and response */ 754 755 /* 756 * Correct endianess is used because the fields were converted above 757 */ 758 outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2; 759 760 if (outLen > 256) { 761 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OUTLEN_TO_LARGE); 762 goto err; 763 } 764 765 /* SAB check for underflow here on the argeument */ 766 if (outLen < BN_num_bytes(a)) { 767 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION); 768 goto err; 769 } 770 771 BN_bn2bin(a, (unsigned char *)argument->d + outLen - BN_num_bytes(a)); 772 inLen = outLen; 773 774 memset(result->d, 0, outLen); 775 776 /* Perform the operation */ 777 778 if ((rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d, 779 privKey, &outLen, (unsigned char *)result->d)) != 0) 780 { 781 printf("rc = %d\n", rc); 782 IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_REQUEST_FAILED); 783 goto err; 784 } 785 786 /* Convert the response */ 787 788 BN_bin2bn((unsigned char *)result->d, outLen, r); 789 to_return = 1; 790 791 err: 792 BN_CTX_end(ctx); 793 return to_return; 794 795} 796 797# ifndef OPENSSL_NO_DSA 798/* 799 * This code was liberated and adapted from the commented-out code in 800 * dsa_ossl.c. Because of the unoptimised form of the Ibmca acceleration (it 801 * doesn't have a CRT form for RSA), this function means that an Ibmca system 802 * running with a DSA server certificate can handshake around 5 or 6 times 803 * faster/more than an equivalent system running with RSA. Just check out the 804 * "signs" statistics from the RSA and DSA parts of "openssl speed -engine 805 * ibmca dsa1024 rsa1024". 806 */ 807static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, 808 BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, 809 BN_CTX *ctx, BN_MONT_CTX *in_mont) 810{ 811 BIGNUM t; 812 int to_return = 0; 813 814 BN_init(&t); 815 /* let rr = a1 ^ p1 mod m */ 816 if (!ibmca_mod_exp(rr, a1, p1, m, ctx)) 817 goto end; 818 /* let t = a2 ^ p2 mod m */ 819 if (!ibmca_mod_exp(&t, a2, p2, m, ctx)) 820 goto end; 821 /* let rr = rr * t mod m */ 822 if (!BN_mod_mul(rr, rr, &t, m, ctx)) 823 goto end; 824 to_return = 1; 825 end: 826 BN_free(&t); 827 return to_return; 828} 829 830static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, 831 const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, 832 BN_MONT_CTX *m_ctx) 833{ 834 return ibmca_mod_exp(r, a, p, m, ctx); 835} 836# endif 837 838/* This function is aliased to mod_exp (with the mont stuff dropped). */ 839static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 840 const BIGNUM *m, BN_CTX *ctx, 841 BN_MONT_CTX *m_ctx) 842{ 843 return ibmca_mod_exp(r, a, p, m, ctx); 844} 845 846# ifndef OPENSSL_NO_DH 847/* This function is aliased to mod_exp (with the dh and mont dropped). */ 848static int ibmca_mod_exp_dh(DH const *dh, BIGNUM *r, 849 const BIGNUM *a, const BIGNUM *p, 850 const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) 851{ 852 return ibmca_mod_exp(r, a, p, m, ctx); 853} 854# endif 855 856/* Random bytes are good */ 857static int ibmca_rand_bytes(unsigned char *buf, int num) 858{ 859 int to_return = 0; /* assume failure */ 860 unsigned int ret; 861 862 if (handle == 0) { 863 IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES, IBMCA_R_NOT_INITIALISED); 864 goto err; 865 } 866 867 ret = p_icaRandomNumberGenerate(handle, num, buf); 868 if (ret < 0) { 869 IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES, IBMCA_R_REQUEST_FAILED); 870 goto err; 871 } 872 to_return = 1; 873 err: 874 return to_return; 875} 876 877static int ibmca_rand_status(void) 878{ 879 return 1; 880} 881 882/* 883 * This stuff is needed if this ENGINE is being compiled into a 884 * self-contained shared-library. 885 */ 886# ifdef ENGINE_DYNAMIC_SUPPORT 887static int bind_fn(ENGINE *e, const char *id) 888{ 889 if (id && (strcmp(id, engine_ibmca_id) != 0)) /* WJH XXX */ 890 return 0; 891 if (!bind_helper(e)) 892 return 0; 893 return 1; 894} 895 896IMPLEMENT_DYNAMIC_CHECK_FN() 897 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) 898# endif /* ENGINE_DYNAMIC_SUPPORT */ 899# endif /* !OPENSSL_NO_HW_IBMCA */ 900#endif /* !OPENSSL_NO_HW */ 901