/* crypto/engine/hw_ibmca.c */ | |
/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL | |
* project 2000. | |
*/ | |
/* ==================================================================== | |
* Copyright (c) 1999 The OpenSSL Project. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in | |
* the documentation and/or other materials provided with the | |
* distribution. | |
* | |
* 3. All advertising materials mentioning features or use of this | |
* software must display the following acknowledgment: | |
* "This product includes software developed by the OpenSSL Project | |
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
* | |
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
* endorse or promote products derived from this software without | |
* prior written permission. For written permission, please contact | |
* licensing@OpenSSL.org. | |
* | |
* 5. Products derived from this software may not be called "OpenSSL" | |
* nor may "OpenSSL" appear in their names without prior written | |
* permission of the OpenSSL Project. | |
* | |
* 6. Redistributions of any form whatsoever must retain the following | |
* acknowledgment: | |
* "This product includes software developed by the OpenSSL Project | |
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
* OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ==================================================================== | |
* | |
* This product includes cryptographic software written by Eric Young | |
* (eay@cryptsoft.com). This product includes software written by Tim | |
* Hudson (tjh@cryptsoft.com). | |
* | |
*/ | |
/* (C) COPYRIGHT International Business Machines Corp. 2001 */ | |
#include <stdio.h> | |
#include <openssl/crypto.h> | |
#include <openssl/dso.h> | |
#include <openssl/engine.h> | |
#ifndef OPENSSL_NO_HW | |
#ifndef OPENSSL_NO_HW_IBMCA | |
#ifdef FLAT_INC | |
#include "ica_openssl_api.h" | |
#else | |
#include "vendor_defns/ica_openssl_api.h" | |
#endif | |
#define IBMCA_LIB_NAME "ibmca engine" | |
#include "hw_ibmca_err.c" | |
static int ibmca_destroy(ENGINE *e); | |
static int ibmca_init(ENGINE *e); | |
static int ibmca_finish(ENGINE *e); | |
static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); | |
static const char *IBMCA_F1 = "icaOpenAdapter"; | |
static const char *IBMCA_F2 = "icaCloseAdapter"; | |
static const char *IBMCA_F3 = "icaRsaModExpo"; | |
static const char *IBMCA_F4 = "icaRandomNumberGenerate"; | |
static const char *IBMCA_F5 = "icaRsaCrt"; | |
ICA_ADAPTER_HANDLE handle=0; | |
/* BIGNUM stuff */ | |
static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *m, BN_CTX *ctx); | |
static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, | |
const BIGNUM *iqmp, BN_CTX *ctx); | |
#ifndef OPENSSL_NO_RSA | |
/* RSA stuff */ | |
static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa); | |
#endif | |
/* This function is aliased to mod_exp (with the mont stuff dropped). */ | |
static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); | |
#ifndef OPENSSL_NO_DSA | |
/* DSA stuff */ | |
static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, | |
BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, | |
BN_CTX *ctx, BN_MONT_CTX *in_mont); | |
static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, | |
const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, | |
BN_MONT_CTX *m_ctx); | |
#endif | |
#ifndef OPENSSL_NO_DH | |
/* DH stuff */ | |
/* This function is alised to mod_exp (with the DH and mont dropped). */ | |
static int ibmca_mod_exp_dh(const DH *dh, BIGNUM *r, | |
const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); | |
#endif | |
/* RAND stuff */ | |
static int ibmca_rand_bytes(unsigned char *buf, int num); | |
static int ibmca_rand_status(void); | |
/* WJH - check for more commands, like in nuron */ | |
/* The definitions for control commands specific to this engine */ | |
#define IBMCA_CMD_SO_PATH ENGINE_CMD_BASE | |
static const ENGINE_CMD_DEFN ibmca_cmd_defns[] = { | |
{IBMCA_CMD_SO_PATH, | |
"SO_PATH", | |
"Specifies the path to the 'atasi' shared library", | |
ENGINE_CMD_FLAG_STRING}, | |
{0, NULL, NULL, 0} | |
}; | |
#ifndef OPENSSL_NO_RSA | |
/* Our internal RSA_METHOD that we provide pointers to */ | |
static RSA_METHOD ibmca_rsa = | |
{ | |
"Ibmca RSA method", | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
ibmca_rsa_mod_exp, | |
ibmca_mod_exp_mont, | |
NULL, | |
NULL, | |
0, | |
NULL, | |
NULL, | |
NULL | |
}; | |
#endif | |
#ifndef OPENSSL_NO_DSA | |
/* Our internal DSA_METHOD that we provide pointers to */ | |
static DSA_METHOD ibmca_dsa = | |
{ | |
"Ibmca DSA method", | |
NULL, /* dsa_do_sign */ | |
NULL, /* dsa_sign_setup */ | |
NULL, /* dsa_do_verify */ | |
ibmca_dsa_mod_exp, /* dsa_mod_exp */ | |
ibmca_mod_exp_dsa, /* bn_mod_exp */ | |
NULL, /* init */ | |
NULL, /* finish */ | |
0, /* flags */ | |
NULL /* app_data */ | |
}; | |
#endif | |
#ifndef OPENSSL_NO_DH | |
/* Our internal DH_METHOD that we provide pointers to */ | |
static DH_METHOD ibmca_dh = | |
{ | |
"Ibmca DH method", | |
NULL, | |
NULL, | |
ibmca_mod_exp_dh, | |
NULL, | |
NULL, | |
0, | |
NULL | |
}; | |
#endif | |
static RAND_METHOD ibmca_rand = | |
{ | |
/* "IBMCA RAND method", */ | |
NULL, | |
ibmca_rand_bytes, | |
NULL, | |
NULL, | |
ibmca_rand_bytes, | |
ibmca_rand_status, | |
}; | |
/* Constants used when creating the ENGINE */ | |
static const char *engine_ibmca_id = "ibmca"; | |
static const char *engine_ibmca_name = "Ibmca hardware engine support"; | |
/* This internal function is used by ENGINE_ibmca() and possibly by the | |
* "dynamic" ENGINE support too */ | |
static int bind_helper(ENGINE *e) | |
{ | |
#ifndef OPENSSL_NO_RSA | |
const RSA_METHOD *meth1; | |
#endif | |
#ifndef OPENSSL_NO_DSA | |
const DSA_METHOD *meth2; | |
#endif | |
#ifndef OPENSSL_NO_DH | |
const DH_METHOD *meth3; | |
#endif | |
if(!ENGINE_set_id(e, engine_ibmca_id) || | |
!ENGINE_set_name(e, engine_ibmca_name) || | |
#ifndef OPENSSL_NO_RSA | |
!ENGINE_set_RSA(e, &ibmca_rsa) || | |
#endif | |
#ifndef OPENSSL_NO_DSA | |
!ENGINE_set_DSA(e, &ibmca_dsa) || | |
#endif | |
#ifndef OPENSSL_NO_DH | |
!ENGINE_set_DH(e, &ibmca_dh) || | |
#endif | |
!ENGINE_set_RAND(e, &ibmca_rand) || | |
!ENGINE_set_destroy_function(e, ibmca_destroy) || | |
!ENGINE_set_init_function(e, ibmca_init) || | |
!ENGINE_set_finish_function(e, ibmca_finish) || | |
!ENGINE_set_ctrl_function(e, ibmca_ctrl) || | |
!ENGINE_set_cmd_defns(e, ibmca_cmd_defns)) | |
return 0; | |
#ifndef OPENSSL_NO_RSA | |
/* We know that the "PKCS1_SSLeay()" functions hook properly | |
* to the ibmca-specific mod_exp and mod_exp_crt so we use | |
* those functions. NB: We don't use ENGINE_openssl() or | |
* anything "more generic" because something like the RSAref | |
* code may not hook properly, and if you own one of these | |
* cards then you have the right to do RSA operations on it | |
* anyway! */ | |
meth1 = RSA_PKCS1_SSLeay(); | |
ibmca_rsa.rsa_pub_enc = meth1->rsa_pub_enc; | |
ibmca_rsa.rsa_pub_dec = meth1->rsa_pub_dec; | |
ibmca_rsa.rsa_priv_enc = meth1->rsa_priv_enc; | |
ibmca_rsa.rsa_priv_dec = meth1->rsa_priv_dec; | |
#endif | |
#ifndef OPENSSL_NO_DSA | |
/* Use the DSA_OpenSSL() method and just hook the mod_exp-ish | |
* bits. */ | |
meth2 = DSA_OpenSSL(); | |
ibmca_dsa.dsa_do_sign = meth2->dsa_do_sign; | |
ibmca_dsa.dsa_sign_setup = meth2->dsa_sign_setup; | |
ibmca_dsa.dsa_do_verify = meth2->dsa_do_verify; | |
#endif | |
#ifndef OPENSSL_NO_DH | |
/* Much the same for Diffie-Hellman */ | |
meth3 = DH_OpenSSL(); | |
ibmca_dh.generate_key = meth3->generate_key; | |
ibmca_dh.compute_key = meth3->compute_key; | |
#endif | |
/* Ensure the ibmca error handling is set up */ | |
ERR_load_IBMCA_strings(); | |
return 1; | |
} | |
static ENGINE *engine_ibmca(void) | |
{ | |
ENGINE *ret = ENGINE_new(); | |
if(!ret) | |
return NULL; | |
if(!bind_helper(ret)) | |
{ | |
ENGINE_free(ret); | |
return NULL; | |
} | |
return ret; | |
} | |
void ENGINE_load_ibmca(void) | |
{ | |
/* Copied from eng_[openssl|dyn].c */ | |
ENGINE *toadd = engine_ibmca(); | |
if(!toadd) return; | |
ENGINE_add(toadd); | |
ENGINE_free(toadd); | |
ERR_clear_error(); | |
} | |
/* Destructor (complements the "ENGINE_ibmca()" constructor) */ | |
static int ibmca_destroy(ENGINE *e) | |
{ | |
/* Unload the ibmca error strings so any error state including our | |
* functs or reasons won't lead to a segfault (they simply get displayed | |
* without corresponding string data because none will be found). */ | |
ERR_unload_IBMCA_strings(); | |
return 1; | |
} | |
/* This is a process-global DSO handle used for loading and unloading | |
* the Ibmca library. NB: This is only set (or unset) during an | |
* init() or finish() call (reference counts permitting) and they're | |
* operating with global locks, so this should be thread-safe | |
* implicitly. */ | |
static DSO *ibmca_dso = NULL; | |
/* These are the function pointers that are (un)set when the library has | |
* successfully (un)loaded. */ | |
static unsigned int (ICA_CALL *p_icaOpenAdapter)(); | |
static unsigned int (ICA_CALL *p_icaCloseAdapter)(); | |
static unsigned int (ICA_CALL *p_icaRsaModExpo)(); | |
static unsigned int (ICA_CALL *p_icaRandomNumberGenerate)(); | |
static unsigned int (ICA_CALL *p_icaRsaCrt)(); | |
/* utility function to obtain a context */ | |
static int get_context(ICA_ADAPTER_HANDLE *p_handle) | |
{ | |
unsigned int status=0; | |
status = p_icaOpenAdapter(0, p_handle); | |
if(status != 0) | |
return 0; | |
return 1; | |
} | |
/* similarly to release one. */ | |
static void release_context(ICA_ADAPTER_HANDLE handle) | |
{ | |
p_icaCloseAdapter(handle); | |
} | |
/* (de)initialisation functions. */ | |
static int ibmca_init(ENGINE *e) | |
{ | |
void (*p1)(); | |
void (*p2)(); | |
void (*p3)(); | |
void (*p4)(); | |
void (*p5)(); | |
if(ibmca_dso != NULL) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_ALREADY_LOADED); | |
goto err; | |
} | |
/* Attempt to load libatasi.so/atasi.dll/whatever. Needs to be | |
* changed unfortunately because the Ibmca drivers don't have | |
* standard library names that can be platform-translated well. */ | |
/* TODO: Work out how to actually map to the names the Ibmca | |
* drivers really use - for now a symbollic link needs to be | |
* created on the host system from libatasi.so to atasi.so on | |
* unix variants. */ | |
/* WJH XXX check name translation */ | |
ibmca_dso = DSO_load(NULL, IBMCA_LIBNAME, NULL, | |
/* DSO_FLAG_NAME_TRANSLATION */ 0); | |
if(ibmca_dso == NULL) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE); | |
goto err; | |
} | |
if(!(p1 = DSO_bind_func( | |
ibmca_dso, IBMCA_F1)) || | |
!(p2 = DSO_bind_func( | |
ibmca_dso, IBMCA_F2)) || | |
!(p3 = DSO_bind_func( | |
ibmca_dso, IBMCA_F3)) || | |
!(p4 = DSO_bind_func( | |
ibmca_dso, IBMCA_F4)) || | |
!(p5 = DSO_bind_func( | |
ibmca_dso, IBMCA_F5))) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_DSO_FAILURE); | |
goto err; | |
} | |
/* Copy the pointers */ | |
p_icaOpenAdapter = (unsigned int (ICA_CALL *)())p1; | |
p_icaCloseAdapter = (unsigned int (ICA_CALL *)())p2; | |
p_icaRsaModExpo = (unsigned int (ICA_CALL *)())p3; | |
p_icaRandomNumberGenerate = (unsigned int (ICA_CALL *)())p4; | |
p_icaRsaCrt = (unsigned int (ICA_CALL *)())p5; | |
if(!get_context(&handle)) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_INIT,IBMCA_R_UNIT_FAILURE); | |
goto err; | |
} | |
return 1; | |
err: | |
if(ibmca_dso) | |
DSO_free(ibmca_dso); | |
p_icaOpenAdapter = NULL; | |
p_icaCloseAdapter = NULL; | |
p_icaRsaModExpo = NULL; | |
p_icaRandomNumberGenerate = NULL; | |
return 0; | |
} | |
static int ibmca_finish(ENGINE *e) | |
{ | |
if(ibmca_dso == NULL) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_NOT_LOADED); | |
return 0; | |
} | |
release_context(handle); | |
if(!DSO_free(ibmca_dso)) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_FINISH,IBMCA_R_DSO_FAILURE); | |
return 0; | |
} | |
ibmca_dso = NULL; | |
return 1; | |
} | |
static int ibmca_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) | |
{ | |
int initialised = ((ibmca_dso == NULL) ? 0 : 1); | |
switch(cmd) | |
{ | |
case IBMCA_CMD_SO_PATH: | |
if(p == NULL) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_CTRL,ERR_R_PASSED_NULL_PARAMETER); | |
return 0; | |
} | |
if(initialised) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_ALREADY_LOADED); | |
return 0; | |
} | |
IBMCA_LIBNAME = (const char *)p; | |
return 1; | |
default: | |
break; | |
} | |
IBMCAerr(IBMCA_F_IBMCA_CTRL,IBMCA_R_CTRL_COMMAND_NOT_IMPLEMENTED); | |
return 0; | |
} | |
static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *m, BN_CTX *ctx) | |
{ | |
/* I need somewhere to store temporary serialised values for | |
* use with the Ibmca API calls. A neat cheat - I'll use | |
* BIGNUMs from the BN_CTX but access their arrays directly as | |
* byte arrays <grin>. This way I don't have to clean anything | |
* up. */ | |
BIGNUM *argument=NULL; | |
BIGNUM *result=NULL; | |
BIGNUM *key=NULL; | |
int to_return; | |
int inLen, outLen, tmpLen; | |
ICA_KEY_RSA_MODEXPO *publKey=NULL; | |
unsigned int rc; | |
to_return = 0; /* expect failure */ | |
if(!ibmca_dso) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_NOT_LOADED); | |
goto err; | |
} | |
/* Prepare the params */ | |
BN_CTX_start(ctx); | |
argument = BN_CTX_get(ctx); | |
result = BN_CTX_get(ctx); | |
key = BN_CTX_get(ctx); | |
if( !argument || !result || !key) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_CTX_FULL); | |
goto err; | |
} | |
if(!bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top) || | |
!bn_wexpand(key, sizeof(*publKey)/BN_BYTES)) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_EXPAND_FAIL); | |
goto err; | |
} | |
publKey = (ICA_KEY_RSA_MODEXPO *)key->d; | |
if (publKey == NULL) | |
{ | |
goto err; | |
} | |
memset(publKey, 0, sizeof(ICA_KEY_RSA_MODEXPO)); | |
publKey->keyType = CORRECT_ENDIANNESS(ME_KEY_TYPE); | |
publKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_MODEXPO)); | |
publKey->expOffset = (char *) publKey->keyRecord - (char *) publKey; | |
/* A quirk of the card: the exponent length has to be the same | |
as the modulus (key) length */ | |
outLen = BN_num_bytes(m); | |
/* check for modulus length SAB*/ | |
if (outLen > 256 ) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_MEXP_LENGTH_TO_LARGE); | |
goto err; | |
} | |
/* check for modulus length SAB*/ | |
publKey->expLength = publKey->nLength = outLen; | |
/* SAB Check for underflow condition | |
the size of the exponent is less than the size of the parameter | |
then we have a big problem and will underflow the keyRecord | |
buffer. Bad stuff could happen then | |
*/ | |
if (outLen < BN_num_bytes(p)){ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_UNDERFLOW_KEYRECORD); | |
goto err; | |
} | |
/* SAB End check for underflow */ | |
BN_bn2bin(p, &publKey->keyRecord[publKey->expLength - | |
BN_num_bytes(p)]); | |
BN_bn2bin(m, &publKey->keyRecord[publKey->expLength]); | |
publKey->modulusBitLength = CORRECT_ENDIANNESS(publKey->nLength * 8); | |
publKey->nOffset = CORRECT_ENDIANNESS(publKey->expOffset + | |
publKey->expLength); | |
publKey->expOffset = CORRECT_ENDIANNESS((char *) publKey->keyRecord - | |
(char *) publKey); | |
tmpLen = outLen; | |
publKey->expLength = publKey->nLength = CORRECT_ENDIANNESS(tmpLen); | |
/* Prepare the argument */ | |
memset(argument->d, 0, outLen); | |
BN_bn2bin(a, (unsigned char *)argument->d + outLen - | |
BN_num_bytes(a)); | |
inLen = outLen; | |
/* Perform the operation */ | |
if( (rc = p_icaRsaModExpo(handle, inLen,(unsigned char *)argument->d, | |
publKey, &outLen, (unsigned char *)result->d)) | |
!=0 ) | |
{ | |
printf("rc = %d\n", rc); | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_REQUEST_FAILED); | |
goto err; | |
} | |
/* Convert the response */ | |
BN_bin2bn((unsigned char *)result->d, outLen, r); | |
to_return = 1; | |
err: | |
BN_CTX_end(ctx); | |
return to_return; | |
} | |
#ifndef OPENSSL_NO_RSA | |
static int ibmca_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa) | |
{ | |
BN_CTX *ctx; | |
int to_return = 0; | |
if((ctx = BN_CTX_new()) == NULL) | |
goto err; | |
if(!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) | |
{ | |
if(!rsa->d || !rsa->n) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_RSA_MOD_EXP, | |
IBMCA_R_MISSING_KEY_COMPONENTS); | |
goto err; | |
} | |
to_return = ibmca_mod_exp(r0, I, rsa->d, rsa->n, ctx); | |
} | |
else | |
{ | |
to_return = ibmca_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1, | |
rsa->dmq1, rsa->iqmp, ctx); | |
} | |
err: | |
if(ctx) | |
BN_CTX_free(ctx); | |
return to_return; | |
} | |
#endif | |
/* Ein kleines chinesisches "Restessen" */ | |
static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *q, const BIGNUM *dmp1, | |
const BIGNUM *dmq1, const BIGNUM *iqmp, BN_CTX *ctx) | |
{ | |
BIGNUM *argument = NULL; | |
BIGNUM *result = NULL; | |
BIGNUM *key = NULL; | |
int to_return = 0; /* expect failure */ | |
char *pkey=NULL; | |
ICA_KEY_RSA_CRT *privKey=NULL; | |
int inLen, outLen; | |
int rc; | |
unsigned int offset, pSize, qSize; | |
/* SAB New variables */ | |
unsigned int keyRecordSize; | |
unsigned int pbytes = BN_num_bytes(p); | |
unsigned int qbytes = BN_num_bytes(q); | |
unsigned int dmp1bytes = BN_num_bytes(dmp1); | |
unsigned int dmq1bytes = BN_num_bytes(dmq1); | |
unsigned int iqmpbytes = BN_num_bytes(iqmp); | |
/* Prepare the params */ | |
BN_CTX_start(ctx); | |
argument = BN_CTX_get(ctx); | |
result = BN_CTX_get(ctx); | |
key = BN_CTX_get(ctx); | |
if(!argument || !result || !key) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_CTX_FULL); | |
goto err; | |
} | |
if(!bn_wexpand(argument, p->top + q->top) || | |
!bn_wexpand(result, p->top + q->top) || | |
!bn_wexpand(key, sizeof(*privKey)/BN_BYTES )) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_EXPAND_FAIL); | |
goto err; | |
} | |
privKey = (ICA_KEY_RSA_CRT *)key->d; | |
/* SAB Add check for total size in bytes of the parms does not exceed | |
the buffer space we have | |
do this first | |
*/ | |
keyRecordSize = pbytes+qbytes+dmp1bytes+dmq1bytes+iqmpbytes; | |
if ( keyRecordSize > sizeof(privKey->keyRecord )) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); | |
goto err; | |
} | |
if ( (qbytes + dmq1bytes) > 256 ){ | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); | |
goto err; | |
} | |
if ( pbytes + dmp1bytes > 256 ) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); | |
goto err; | |
} | |
/* end SAB additions */ | |
memset(privKey, 0, sizeof(ICA_KEY_RSA_CRT)); | |
privKey->keyType = CORRECT_ENDIANNESS(CRT_KEY_TYPE); | |
privKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_CRT)); | |
privKey->modulusBitLength = | |
CORRECT_ENDIANNESS(BN_num_bytes(q) * 2 * 8); | |
/* | |
* p,dp & qInv are 1 QWORD Larger | |
*/ | |
privKey->pLength = CORRECT_ENDIANNESS(BN_num_bytes(p)+8); | |
privKey->qLength = CORRECT_ENDIANNESS(BN_num_bytes(q)); | |
privKey->dpLength = CORRECT_ENDIANNESS(BN_num_bytes(dmp1)+8); | |
privKey->dqLength = CORRECT_ENDIANNESS(BN_num_bytes(dmq1)); | |
privKey->qInvLength = CORRECT_ENDIANNESS(BN_num_bytes(iqmp)+8); | |
offset = (char *) privKey->keyRecord | |
- (char *) privKey; | |
qSize = BN_num_bytes(q); | |
pSize = qSize + 8; /* 1 QWORD larger */ | |
/* SAB probably aittle redundant, but we'll verify that each of the | |
components which make up a key record sent ot the card does not exceed | |
the space that is allocated for it. this handles the case where even if | |
the total length does not exceed keyrecord zied, if the operands are funny sized | |
they could cause potential side affects on either the card or the result */ | |
if ( (pbytes > pSize) || (dmp1bytes > pSize) || | |
(iqmpbytes > pSize) || ( qbytes >qSize) || | |
(dmq1bytes > qSize) ) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); | |
goto err; | |
} | |
privKey->dpOffset = CORRECT_ENDIANNESS(offset); | |
offset += pSize; | |
privKey->dqOffset = CORRECT_ENDIANNESS(offset); | |
offset += qSize; | |
privKey->pOffset = CORRECT_ENDIANNESS(offset); | |
offset += pSize; | |
privKey->qOffset = CORRECT_ENDIANNESS(offset); | |
offset += qSize; | |
privKey->qInvOffset = CORRECT_ENDIANNESS(offset); | |
pkey = (char *) privKey->keyRecord; | |
/* SAB first check that we don;t under flow the buffer */ | |
if ( pSize < pbytes ) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION); | |
goto err; | |
} | |
/* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */ | |
pkey += pSize - BN_num_bytes(dmp1); | |
BN_bn2bin(dmp1, pkey); | |
pkey += BN_num_bytes(dmp1); /* move the pointer */ | |
BN_bn2bin(dmq1, pkey); /* Copy over dmq1 */ | |
pkey += qSize; /* move pointer */ | |
pkey += pSize - BN_num_bytes(p); /* set up for zero padding of next field */ | |
BN_bn2bin(p, pkey); | |
pkey += BN_num_bytes(p); /* increment pointer by number of bytes moved */ | |
BN_bn2bin(q, pkey); | |
pkey += qSize ; /* move the pointer */ | |
pkey += pSize - BN_num_bytes(iqmp); /* Adjust for padding */ | |
BN_bn2bin(iqmp, pkey); | |
/* Prepare the argument and response */ | |
outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2; /* Correct endianess is used | |
because the fields were converted above */ | |
if (outLen > 256) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OUTLEN_TO_LARGE); | |
goto err; | |
} | |
/* SAB check for underflow here on the argeument */ | |
if ( outLen < BN_num_bytes(a)) { | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_UNDERFLOW_CONDITION); | |
goto err; | |
} | |
BN_bn2bin(a, (unsigned char *)argument->d + outLen - | |
BN_num_bytes(a)); | |
inLen = outLen; | |
memset(result->d, 0, outLen); | |
/* Perform the operation */ | |
if ( (rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d, | |
privKey, &outLen, (unsigned char *)result->d)) != 0) | |
{ | |
printf("rc = %d\n", rc); | |
IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_REQUEST_FAILED); | |
goto err; | |
} | |
/* Convert the response */ | |
BN_bin2bn((unsigned char *)result->d, outLen, r); | |
to_return = 1; | |
err: | |
BN_CTX_end(ctx); | |
return to_return; | |
} | |
#ifndef OPENSSL_NO_DSA | |
/* This code was liberated and adapted from the commented-out code in | |
* dsa_ossl.c. Because of the unoptimised form of the Ibmca acceleration | |
* (it doesn't have a CRT form for RSA), this function means that an | |
* Ibmca system running with a DSA server certificate can handshake | |
* around 5 or 6 times faster/more than an equivalent system running with | |
* RSA. Just check out the "signs" statistics from the RSA and DSA parts | |
* of "openssl speed -engine ibmca dsa1024 rsa1024". */ | |
static int ibmca_dsa_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, | |
BIGNUM *p1, BIGNUM *a2, BIGNUM *p2, BIGNUM *m, | |
BN_CTX *ctx, BN_MONT_CTX *in_mont) | |
{ | |
BIGNUM t; | |
int to_return = 0; | |
BN_init(&t); | |
/* let rr = a1 ^ p1 mod m */ | |
if (!ibmca_mod_exp(rr,a1,p1,m,ctx)) goto end; | |
/* let t = a2 ^ p2 mod m */ | |
if (!ibmca_mod_exp(&t,a2,p2,m,ctx)) goto end; | |
/* let rr = rr * t mod m */ | |
if (!BN_mod_mul(rr,rr,&t,m,ctx)) goto end; | |
to_return = 1; | |
end: | |
BN_free(&t); | |
return to_return; | |
} | |
static int ibmca_mod_exp_dsa(DSA *dsa, BIGNUM *r, BIGNUM *a, | |
const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, | |
BN_MONT_CTX *m_ctx) | |
{ | |
return ibmca_mod_exp(r, a, p, m, ctx); | |
} | |
#endif | |
/* This function is aliased to mod_exp (with the mont stuff dropped). */ | |
static int ibmca_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) | |
{ | |
return ibmca_mod_exp(r, a, p, m, ctx); | |
} | |
#ifndef OPENSSL_NO_DH | |
/* This function is aliased to mod_exp (with the dh and mont dropped). */ | |
static int ibmca_mod_exp_dh(DH const *dh, BIGNUM *r, | |
const BIGNUM *a, const BIGNUM *p, | |
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) | |
{ | |
return ibmca_mod_exp(r, a, p, m, ctx); | |
} | |
#endif | |
/* Random bytes are good */ | |
static int ibmca_rand_bytes(unsigned char *buf, int num) | |
{ | |
int to_return = 0; /* assume failure */ | |
unsigned int ret; | |
if(handle == 0) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_NOT_INITIALISED); | |
goto err; | |
} | |
ret = p_icaRandomNumberGenerate(handle, num, buf); | |
if (ret < 0) | |
{ | |
IBMCAerr(IBMCA_F_IBMCA_RAND_BYTES,IBMCA_R_REQUEST_FAILED); | |
goto err; | |
} | |
to_return = 1; | |
err: | |
return to_return; | |
} | |
static int ibmca_rand_status(void) | |
{ | |
return 1; | |
} | |
/* This stuff is needed if this ENGINE is being compiled into a self-contained | |
* shared-library. */ | |
#ifdef ENGINE_DYNAMIC_SUPPORT | |
static int bind_fn(ENGINE *e, const char *id) | |
{ | |
if(id && (strcmp(id, engine_ibmca_id) != 0)) /* WJH XXX */ | |
return 0; | |
if(!bind_helper(e)) | |
return 0; | |
return 1; | |
} | |
IMPLEMENT_DYNAMIC_CHECK_FN() | |
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn) | |
#endif /* ENGINE_DYNAMIC_SUPPORT */ | |
#endif /* !OPENSSL_NO_HW_IBMCA */ | |
#endif /* !OPENSSL_NO_HW */ |