Commit f11fd3f4 authored by Richard Levitte's avatar Richard Levitte
Browse files

Implement failover for ubsec. Submitted by Subramanian Ramamoorthy

<sram@broadcom.com> with the following comment:

[...] We have implemented failover (ie, if for some reason that the
hardware fails, the implementation detects this failure and performs
this operation as if no hardware is present, ie, in software) for
sometime now and have tested it here with our hardware. [...]

This change was cc:ed to exports@crypto.com
parent 29b108f9
Loading
Loading
Loading
Loading
+229 −40
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@
#include "vendor_defns/hw_ubsec.h"
#endif

#define FAIL_TO_SOFTWARE -15

static int ubsec_destroy(ENGINE *e);
static int ubsec_init(ENGINE *e);
static int ubsec_finish(ENGINE *e);
@@ -184,6 +186,7 @@ static DH_METHOD ubsec_dh =
#define UBSEC_F_UBSEC_RSA_MOD_EXP_CRT		105
#define UBSEC_F_UBSEC_DSA_SIGN			106
#define UBSEC_F_UBSEC_DSA_VERIFY		107
#define UBSEC_F_UBSEC_DH_COMPUTE_KEY		117
/* Error reason codes */
#define UBSEC_R_ALREADY_LOADED			108
#define UBSEC_R_DSO_FAILURE			109
@@ -194,6 +197,7 @@ static DH_METHOD ubsec_dh =
#define UBSEC_R_BN_EXPAND_FAIL			114
#define UBSEC_R_REQUEST_FAILED			115
#define UBSEC_R_MISSING_KEY_COMPONENTS		116

static ERR_STRING_DATA ubsec_str_functs[] =
	{
	/* This first element is changed to match the dynamic 'lib' number */
@@ -361,6 +365,9 @@ static t_UBSEC_dsa_verify_ioctl *p_UBSEC_dsa_verify_ioctl = NULL;
#endif
static t_UBSEC_math_accelerate_ioctl *p_UBSEC_math_accelerate_ioctl = NULL;
static t_UBSEC_rng_ioctl *p_UBSEC_rng_ioctl = NULL;
static t_UBSEC_max_key_len_ioctl *p_UBSEC_max_key_len_ioctl = NULL;

static int max_key_len = 1024;  /* ??? */

/* 
 * These are the static string constants for the DSO file name and the function
@@ -386,6 +393,7 @@ static const char *UBSEC_F10 = "dsa_verify_ioctl";
#endif
static const char *UBSEC_F11 = "math_accelerate_ioctl";
static const char *UBSEC_F12 = "rng_ioctl";
static const char *UBSEC_F13 = "ubsec_max_key_len_ioctl";

/* Destructor (complements the "ENGINE_ubsec()" constructor) */
static int ubsec_destroy(ENGINE *e)
@@ -415,6 +423,7 @@ static int ubsec_init(ENGINE *e)
#endif
	t_UBSEC_math_accelerate_ioctl *p11;
	t_UBSEC_rng_ioctl *p12;
        t_UBSEC_max_key_len_ioctl *p13;
	int fd = 0;

	if(ubsec_dso != NULL)
@@ -453,7 +462,8 @@ static int ubsec_init(ENGINE *e)
#endif
	!(p11 = (t_UBSEC_math_accelerate_ioctl *) 
				DSO_bind_func(ubsec_dso, UBSEC_F11)) ||
	!(p12 = (t_UBSEC_rng_ioctl *) DSO_bind_func(ubsec_dso, UBSEC_F12)))
	!(p12 = (t_UBSEC_rng_ioctl *) DSO_bind_func(ubsec_dso, UBSEC_F12)) ||
        !(p13 = (t_UBSEC_max_key_len_ioctl *) DSO_bind_func(ubsec_dso, UBSEC_F13)))
		{
		UBSECerr(UBSEC_F_UBSEC_INIT, UBSEC_R_DSO_FAILURE);
		goto err;
@@ -478,9 +488,10 @@ static int ubsec_init(ENGINE *e)
#endif
	p_UBSEC_math_accelerate_ioctl = p11;
	p_UBSEC_rng_ioctl = p12;
        p_UBSEC_max_key_len_ioctl = p13;

	/* Perform an open to see if there's actually any unit running. */
	if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) > 0)
	if (((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) > 0) && (p_UBSEC_max_key_len_ioctl(fd, &max_key_len) == 0))
	{
	   p_UBSEC_ubsec_close(fd);
	   return 1;
@@ -511,6 +522,7 @@ err:
#endif
	p_UBSEC_math_accelerate_ioctl = NULL;
	p_UBSEC_rng_ioctl = NULL;
        p_UBSEC_max_key_len_ioctl = NULL;

	return 0;
	}
@@ -546,6 +558,7 @@ static int ubsec_finish(ENGINE *e)
#endif
	p_UBSEC_math_accelerate_ioctl = NULL;
	p_UBSEC_rng_ioctl = NULL;
        p_UBSEC_max_key_len_ioctl = NULL;
	return 1;
	}

@@ -588,9 +601,9 @@ static int ubsec_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,

	/* Check if hardware can't handle this argument. */
	y_len = BN_num_bits(m);
	if (y_len > 1024) {
	if (y_len > max_key_len) {
		UBSECerr(UBSEC_F_UBSEC_MOD_EXP, UBSEC_R_SIZE_TOO_LARGE_OR_TOO_SMALL);
		return 0;
                return BN_mod_exp(r, a, p, m, ctx);
	} 

	if(!bn_wexpand(r, m->top))
@@ -603,7 +616,7 @@ static int ubsec_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) {
		fd = 0;
		UBSECerr(UBSEC_F_UBSEC_INIT, UBSEC_R_UNIT_FAILURE);
		return 0;
                return BN_mod_exp(r, a, p, m, ctx);
	}

	if (p_UBSEC_rsa_mod_exp_ioctl(fd, (unsigned char *)a->d, BN_num_bits(a),
@@ -611,7 +624,9 @@ static int ubsec_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
		BN_num_bits(p), (unsigned char *)r->d, &y_len) != 0)
	{
		UBSECerr(UBSEC_F_UBSEC_MOD_EXP, UBSEC_R_REQUEST_FAILED);
		return 0;
                p_UBSEC_ubsec_close(fd);

                return BN_mod_exp(r, a, p, m, ctx);
	}

	p_UBSEC_ubsec_close(fd);
@@ -635,15 +650,15 @@ static int ubsec_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa)
		goto err;
		}

	to_return = ubsec_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1,
		    rsa->dmq1, rsa->iqmp, ctx);
	if (to_return == FAIL_TO_SOFTWARE)
	{
	  /*
	 * Do in software if argument is too large for hardware.
	   * Do in software as hardware failed.
	   */
	if ((BN_num_bits(rsa->p)+BN_num_bits(rsa->q)) > 1024) {
	   const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
	   to_return = (*meth->rsa_mod_exp)(r0, I, rsa);
	} else {
		to_return = ubsec_mod_exp_crt(r0, I, rsa->p, rsa->q, rsa->dmp1,
			rsa->dmq1, rsa->iqmp, ctx);
	}
err:
	if(ctx)
@@ -664,9 +679,9 @@ static int ubsec_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	y_len = BN_num_bits(p) + BN_num_bits(q);

	/* Check if hardware can't handle this argument. */
	if (y_len > 1024) {
	if (y_len > max_key_len) {
		UBSECerr(UBSEC_F_UBSEC_MOD_EXP, UBSEC_R_SIZE_TOO_LARGE_OR_TOO_SMALL);
		return 0;
		return FAIL_TO_SOFTWARE;
	} 

	if (!bn_wexpand(r, p->top + q->top + 1)) {
@@ -677,7 +692,7 @@ static int ubsec_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) {
		fd = 0;
		UBSECerr(UBSEC_F_UBSEC_INIT, UBSEC_R_UNIT_FAILURE);
		return 0;
		return FAIL_TO_SOFTWARE;
	}

	if (p_UBSEC_rsa_mod_exp_crt_ioctl(fd,
@@ -689,7 +704,8 @@ static int ubsec_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
		(unsigned char *)q->d, BN_num_bits(q),
		(unsigned char *)r->d,  &y_len) != 0) {
		UBSECerr(UBSEC_F_UBSEC_MOD_EXP, UBSEC_R_REQUEST_FAILED);
		return 0;
                p_UBSEC_ubsec_close(fd);
		return FAIL_TO_SOFTWARE;
	}

	p_UBSEC_ubsec_close(fd);
@@ -739,7 +755,7 @@ static int ubsec_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,

#ifndef OPENSSL_NO_RSA
 	/* Do in software if the key is too large for the hardware. */
	if (BN_num_bits(m) > 1024)
	if (BN_num_bits(m) > max_key_len)
                {
		const RSA_METHOD *meth = RSA_PKCS1_SSLeay();
		ret = (*meth->bn_mod_exp)(r, a, p, m, ctx, m_ctx);
@@ -791,9 +807,12 @@ static DSA_SIG *ubsec_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
	} 

	if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) {
                const DSA_METHOD *meth;
		fd = 0;
		UBSECerr(UBSEC_F_UBSEC_INIT, UBSEC_R_UNIT_FAILURE);
		return 0;
                meth = DSA_OpenSSL();
                to_return =  meth->dsa_do_sign(dgst, dlen, dsa);
		goto err;
	}

	if (p_UBSEC_dsa_sign_ioctl(fd, 0, /* compute hash before signing */
@@ -805,7 +824,13 @@ static DSA_SIG *ubsec_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
		(unsigned char *)dsa->priv_key->d, BN_num_bits(dsa->priv_key),
		(unsigned char *)r->d, &r_len,
		(unsigned char *)s->d, &s_len ) != 0) {
                const DSA_METHOD *meth;

		UBSECerr(UBSEC_F_UBSEC_DSA_SIGN, UBSEC_R_REQUEST_FAILED);
                p_UBSEC_ubsec_close(fd);
                meth = DSA_OpenSSL();
                to_return = meth->dsa_do_sign(dgst, dlen, dsa);

		goto err;
	}

@@ -852,9 +877,12 @@ static int ubsec_dsa_verify(const unsigned char *dgst, int dgst_len,
	d_len = p_UBSEC_ubsec_bytes_to_bits((unsigned char *)dgst, dgst_len);

	if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) {
                const DSA_METHOD *meth;
		fd = 0;
		UBSECerr(UBSEC_F_UBSEC_INIT, UBSEC_R_UNIT_FAILURE);
		return 0;
                meth = DSA_OpenSSL();
                to_return = meth->dsa_do_verify(dgst, dgst_len, sig, dsa);
		goto err;
	}

	if (p_UBSEC_dsa_verify_ioctl(fd, 0, /* compute hash before signing */
@@ -866,7 +894,13 @@ static int ubsec_dsa_verify(const unsigned char *dgst, int dgst_len,
		(unsigned char *)sig->r->d, BN_num_bits(sig->r),
		(unsigned char *)sig->s->d, BN_num_bits(sig->s),
		(unsigned char *)v.d, &v_len) != 0) {
                const DSA_METHOD *meth;
		UBSECerr(UBSEC_F_UBSEC_DSA_VERIFY , UBSEC_R_REQUEST_FAILED);
                p_UBSEC_ubsec_close(fd);

                meth = DSA_OpenSSL();
                to_return = meth->dsa_do_verify(dgst, dgst_len, sig, dsa);

		goto err;
	}

@@ -882,21 +916,176 @@ err:
#ifndef OPENSSL_NO_DH
static int ubsec_dh_compute_key (unsigned char *key,const BIGNUM *pub_key,DH *dh)
        {
	return 0;
        int      ret      = -1,
                 k_len,
                 fd;

        k_len = BN_num_bits(dh->p);

        if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0)
                {
                const DH_METHOD *meth;
                ENGINEerr(UBSEC_F_UBSEC_INIT, ENGINE_R_UNIT_FAILURE);
                meth = DH_OpenSSL();
                ret = meth->compute_key(key, pub_key, dh);
                goto err;
                }

        if (p_UBSEC_diffie_hellman_agree_ioctl(fd,
                                               (unsigned char *)dh->priv_key->d, BN_num_bits(dh->priv_key),
                                               (unsigned char *)pub_key->d, BN_num_bits(pub_key),
                                               (unsigned char *)dh->p->d, BN_num_bits(dh->p),
                                               key, &k_len) != 0)
                {
                /* Hardware's a no go, failover to software */
                const DH_METHOD *meth;
                ENGINEerr(UBSEC_F_UBSEC_DH_COMPUTE_KEY, ENGINE_R_REQUEST_FAILED);
                p_UBSEC_ubsec_close(fd);

                meth = DH_OpenSSL();
                ret = meth->compute_key(key, pub_key, dh);

                goto err;
                }

        p_UBSEC_ubsec_close(fd);

        ret = p_UBSEC_ubsec_bits_to_bytes(k_len);
err:
        return ret;
        }

static int ubsec_dh_generate_key (DH *dh)
        {
	return 0;
        int      ret               = 0,
                 random_bits       = 0,
                 pub_key_len       = 0,
                 priv_key_len      = 0,
                 fd;
        BIGNUM   *pub_key          = NULL;
        BIGNUM   *priv_key         = NULL;

        /* 
         *  How many bits should Random x be? dh_key.c
         *  sets the range from 0 to num_bits(modulus) ???
         */

        if (dh->priv_key == NULL)
                {
                priv_key = BN_new();
                if (priv_key == NULL) goto err;
                priv_key_len = BN_num_bits(dh->p);
                bn_wexpand(priv_key, dh->p->top);
                do
                        if (!BN_rand_range(priv_key, dh->p)) goto err;
                while (BN_is_zero(priv_key));
                random_bits = BN_num_bits(priv_key);
                }
        else
                {
                priv_key = dh->priv_key;
                }

        if (dh->pub_key == NULL)
                {
                pub_key = BN_new();
                pub_key_len = BN_num_bits(dh->p);
                bn_wexpand(pub_key, dh->p->top);
                if(pub_key == NULL) goto err;
                }
        else
                {
                pub_key = dh->pub_key;
                }

        if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0)
                {
                const DH_METHOD *meth;
                ENGINEerr(UBSEC_F_UBSEC_INIT, ENGINE_R_UNIT_FAILURE);
                meth = DH_OpenSSL();
                ret = meth->generate_key(dh);
                goto err;
                }

        if (p_UBSEC_diffie_hellman_generate_ioctl(fd,
                                                  (unsigned char *)priv_key->d, &priv_key_len,
                                                  (unsigned char *)pub_key->d,  &pub_key_len,
                                                  (unsigned char *)dh->g->d, BN_num_bits(dh->g),
                                                  (unsigned char *)dh->p->d, BN_num_bits(dh->p),
                                                  0, 0, random_bits) != 0)
                {
                /* Hardware's a no go, failover to software */
                const DH_METHOD *meth;

                ENGINEerr(UBSEC_F_UBSEC_DH_COMPUTE_KEY, ENGINE_R_REQUEST_FAILED);
                p_UBSEC_ubsec_close(fd);

                meth = DH_OpenSSL();
                ret = meth->generate_key(dh);

                goto err;
                }

        p_UBSEC_ubsec_close(fd);

        dh->pub_key = pub_key;
        dh->pub_key->top = (pub_key_len + BN_BITS2-1) / BN_BITS2;
        dh->priv_key = priv_key;
        dh->priv_key->top = (priv_key_len + BN_BITS2-1) / BN_BITS2;

        ret = 1;
err:
        return ret;
        }
#endif

#ifdef NOT_USED
static int ubsec_rand_bytes(unsigned char *buf, int num)
#if NOT_USED
static int ubsec_rand_bytes(unsigned char * buf,
                            int num)
        {
	return 0;
        int      ret      = 0,
                 fd;

        if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0)
                {
                const RAND_METHOD *meth;
                ENGINEerr(UBSEC_F_UBSEC_INIT, ENGINE_R_UNIT_FAILURE);
                num = p_UBSEC_ubsec_bits_to_bytes(num);
                meth = RAND_SSLeay();
                meth->seed(buf, num);
                ret = meth->bytes(buf, num);
                goto err;
                }

        num *= 8; /* bytes to bits */

        if (p_UBSEC_rng_ioctl(fd,
                              UBSEC_RNG_DIRECT,
                              buf,
                              &num) != 0)
                {
                /* Hardware's a no go, failover to software */
                const RAND_METHOD *meth;

                ENGINEerr(UBSEC_F_UBSEC_RNG_BYTES, ENGINE_R_REQUEST_FAILED);
                p_UBSEC_ubsec_close(fd);

                num = p_UBSEC_ubsec_bits_to_bytes(num);
                meth = RAND_SSLeay();
                meth->seed(buf, num);
                ret = meth->bytes(buf, num);

                goto err;
                }

        p_UBSEC_ubsec_close(fd);

        ret = 1;
err:
        return(ret);
        }


static int ubsec_rand_status(void)
	{
	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -97,3 +97,4 @@ typedef int t_UBSEC_math_accelerate_ioctl(int fd, ubsec_MathCommand_t command,
typedef int t_UBSEC_rng_ioctl(int fd, ubsec_RNGCommand_t command,
	unsigned char *Result, int *Result_len);

typedef int t_UBSEC_max_key_len_ioctl(int fd, int *max_key_len);