some updates for the blinding code; summary:
authorNils Larsch <nils@openssl.org>
Tue, 26 Apr 2005 22:31:48 +0000 (22:31 +0000)
committerNils Larsch <nils@openssl.org>
Tue, 26 Apr 2005 22:31:48 +0000 (22:31 +0000)
- possibility of re-creation of the blinding parameters after a
  fixed number of uses (suggested by Bodo)
- calculatition of the rsa::e in case it's absent and p and q
  are present (see bug report #785)
- improve the performance when if one rsa structure is shared by
  more than a thread (see bug report #555)
- fix the problem described in bug report #827
- hide the definition ot the BN_BLINDING structure in bn_blind.c

CHANGES
crypto/bn/bn.h
crypto/bn/bn_blind.c
crypto/bn/bn_err.c
crypto/rsa/rsa.h
crypto/rsa/rsa_eay.c
crypto/rsa/rsa_err.c
crypto/rsa/rsa_lib.c
util/libeay.num

diff --git a/CHANGES b/CHANGES
index f75ddd9..90b64f4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,18 @@
 
  Changes between 0.9.7g and 0.9.8  [xx XXX xxxx]
 
+  *) Add new functionality to the bn blinding code:
+     - automatic re-creation of the BN_BLINDING parameters after
+       a fixed number of uses (currently 32)
+     - add new function for parameter creation
+     - introduce flags to control the update behaviour of the
+       BN_BLINDING parameters
+     - hide BN_BLINDING structure
+     Add a second BN_BLINDING slot to the RSA structure to improve
+     performance when a single RSA object is shared among several
+     threads.
+     [Nils Larsch]
+
   *) Add support for DTLS.
      [Nagendra Modadugu <nagendra@cs.stanford.edu> and Ben Laurie]
 
index 5f57eb8..1c75fd0 100644 (file)
@@ -274,16 +274,6 @@ struct bignum_st
        int flags;
        };
 
-struct bn_blinding_st
-       {
-       int init;
-       BIGNUM *A;
-       BIGNUM *Ai;
-       BIGNUM *mod; /* just a reference */
-       unsigned long thread_id; /* added in OpenSSL 0.9.6j and 0.9.7b;
-                                 * used only by crypto/rsa/rsa_eay.c, rsa_lib.c */
-       };
-
 /* Used for montgomery multiplication */
 struct bn_mont_ctx_st
        {
@@ -521,11 +511,26 @@ void BN_MONT_CTX_free(BN_MONT_CTX *mont);
 int BN_MONT_CTX_set(BN_MONT_CTX *mont,const BIGNUM *mod,BN_CTX *ctx);
 BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to,BN_MONT_CTX *from);
 
-BN_BLINDING *BN_BLINDING_new(BIGNUM *A,BIGNUM *Ai,BIGNUM *mod);
+/* BN_BLINDING flags */
+#define        BN_BLINDING_NO_UPDATE   0x00000001
+#define        BN_BLINDING_NO_RECREATE 0x00000002
+
+BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod);
 void BN_BLINDING_free(BN_BLINDING *b);
 int BN_BLINDING_update(BN_BLINDING *b,BN_CTX *ctx);
-int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *r, BN_CTX *ctx);
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
 int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *);
+void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long);
+unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
+void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
+BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
+       const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
+       int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
+       BN_MONT_CTX *m_ctx);
 
 #ifndef OPENSSL_NO_DEPRECATED
 void BN_set_params(int mul,int high,int low,int mont);
@@ -727,6 +732,7 @@ void ERR_load_BN_strings(void);
 /* Function codes. */
 #define BN_F_BNRAND                                     114
 #define BN_F_BN_BLINDING_CONVERT                        100
+#define BN_F_BN_BLINDING_CREATE_PARAM                   133
 #define BN_F_BN_BLINDING_INVERT                                 101
 #define BN_F_BN_BLINDING_NEW                            102
 #define BN_F_BN_BLINDING_UPDATE                                 103
index 011d37f..1f41740 100644 (file)
@@ -1,4 +1,57 @@
 /* crypto/bn/bn_blind.c */
+/* ====================================================================
+ * Copyright (c) 1998-2005 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
+ *    openssl-core@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).
+ *
+ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 #include "cryptlib.h"
 #include "bn_lcl.h"
 
-BN_BLINDING *BN_BLINDING_new(BIGNUM *A, BIGNUM *Ai, BIGNUM *mod)
+#define BN_BLINDING_COUNTER    32
+
+struct bn_blinding_st
+       {
+       BIGNUM *A;
+       BIGNUM *Ai;
+       BIGNUM *e;
+       BIGNUM *mod; /* just a reference */
+       unsigned long thread_id; /* added in OpenSSL 0.9.6j and 0.9.7b;
+                                 * used only by crypto/rsa/rsa_eay.c, rsa_lib.c */
+       unsigned int  counter;
+       unsigned long flags;
+       BN_MONT_CTX *m_ctx;
+       int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+                         const BIGNUM *m, BN_CTX *ctx,
+                         BN_MONT_CTX *m_ctx);
+       };
+
+BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod)
        {
        BN_BLINDING *ret=NULL;
 
-       bn_check_top(Ai);
        bn_check_top(mod);
 
        if ((ret=(BN_BLINDING *)OPENSSL_malloc(sizeof(BN_BLINDING))) == NULL)
@@ -73,11 +143,16 @@ BN_BLINDING *BN_BLINDING_new(BIGNUM *A, BIGNUM *Ai, BIGNUM *mod)
                return(NULL);
                }
        memset(ret,0,sizeof(BN_BLINDING));
-       if ((ret->A=BN_new()) == NULL) goto err;
-       if ((ret->Ai=BN_new()) == NULL) goto err;
-       if (!BN_copy(ret->A,A)) goto err;
-       if (!BN_copy(ret->Ai,Ai)) goto err;
-       ret->mod=mod;
+       if (A != NULL)
+               {
+               if ((ret->A  = BN_dup(A))  == NULL) goto err;
+               }
+       if (Ai != NULL)
+               {
+               if ((ret->Ai = BN_dup(Ai)) == NULL) goto err;
+               }
+       ret->mod = mod;
+       ret->counter = BN_BLINDING_COUNTER;
        return(ret);
 err:
        if (ret != NULL) BN_BLINDING_free(ret);
@@ -91,6 +166,7 @@ void BN_BLINDING_free(BN_BLINDING *r)
 
        if (r->A  != NULL) BN_free(r->A );
        if (r->Ai != NULL) BN_free(r->Ai);
+       if (r->e  != NULL) BN_free(r->e );
        OPENSSL_free(r);
        }
 
@@ -103,16 +179,33 @@ int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx)
                BNerr(BN_F_BN_BLINDING_UPDATE,BN_R_NOT_INITIALIZED);
                goto err;
                }
-               
-       if (!BN_mod_mul(b->A,b->A,b->A,b->mod,ctx)) goto err;
-       if (!BN_mod_mul(b->Ai,b->Ai,b->Ai,b->mod,ctx)) goto err;
+
+       if (--(b->counter) == 0 && b->e != NULL &&
+               !(b->flags & BN_BLINDING_NO_RECREATE))
+               {
+               /* re-create blinding parameters */
+               if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL))
+                       goto err;
+               }
+       else if (!(b->flags & BN_BLINDING_NO_UPDATE))
+               {
+               if (!BN_mod_mul(b->A,b->A,b->A,b->mod,ctx)) goto err;
+               if (!BN_mod_mul(b->Ai,b->Ai,b->Ai,b->mod,ctx)) goto err;
+               }
 
        ret=1;
 err:
+       if (b->counter == 0)
+               b->counter = BN_BLINDING_COUNTER;
        return(ret);
        }
 
 int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
+       {
+       return BN_BLINDING_convert_ex(n, NULL, b, ctx);
+       }
+
+int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx)
        {
        bn_check_top(n);
 
@@ -121,10 +214,19 @@ int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
                BNerr(BN_F_BN_BLINDING_CONVERT,BN_R_NOT_INITIALIZED);
                return(0);
                }
-       return(BN_mod_mul(n,n,b->A,b->mod,ctx));
+
+       if (r != NULL)
+               BN_copy(r, b->Ai);
+
+       return BN_mod_mul(n,n,b->A,b->mod,ctx);
        }
 
 int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
+       {
+       return BN_BLINDING_invert_ex(n, NULL, b, ctx);
+       }
+
+int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx)
        {
        int ret;
 
@@ -134,7 +236,13 @@ int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
                BNerr(BN_F_BN_BLINDING_INVERT,BN_R_NOT_INITIALIZED);
                return(0);
                }
-       if ((ret=BN_mod_mul(n,n,b->Ai,b->mod,ctx)) >= 0)
+
+       if (r != NULL)
+               ret = BN_mod_mul(n, n, r, b->mod, ctx);
+       else
+               ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx);
+
+       if (ret >= 0)
                {
                if (!BN_BLINDING_update(b,ctx))
                        return(0);
@@ -143,3 +251,105 @@ int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx)
        return(ret);
        }
 
+unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *b)
+       {
+       return b->thread_id;
+       }
+
+void BN_BLINDING_set_thread_id(BN_BLINDING *b, unsigned long n)
+       {
+       b->thread_id = n;
+       }
+
+unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b)
+       {
+       return b->flags;
+       }
+
+void BN_BLINDING_set_flags(BN_BLINDING *b, unsigned long flags)
+       {
+       b->flags = flags;
+       }
+
+BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
+       const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
+       int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
+       BN_MONT_CTX *m_ctx)
+{
+       int    retry_counter = 32;
+       BIGNUM *a, *ai;
+       BN_BLINDING *ret = NULL;
+
+       if (b == NULL)
+               ret = BN_BLINDING_new(NULL, NULL, m);
+       else
+               ret = b;
+
+       if (ret == NULL)
+               goto err;
+
+       if (ret->A  == NULL && (ret->A  = BN_new()) == NULL)
+               goto err;
+       if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL)
+               goto err;
+
+       if (e != NULL)
+               {
+               if (ret->e != NULL)
+                       BN_free(ret->e);
+               ret->e = BN_dup(e);
+               }
+       if (ret->e == NULL)
+               goto err;
+
+       if (bn_mod_exp != NULL)
+               ret->bn_mod_exp = bn_mod_exp;
+       if (m_ctx != NULL)
+               ret->m_ctx = m_ctx;
+
+       do {
+               if (!BN_rand_range(ret->A, ret->mod)) goto err;
+               if (BN_mod_inverse(ret->Ai, ret->A, ret->mod, ctx) == NULL)
+                       {
+                       /* this should almost never happen for good RSA keys */
+                       unsigned long error = ERR_peek_last_error();
+                       if (ERR_GET_REASON(error) == BN_R_NO_INVERSE)
+                               {
+                               if (retry_counter-- == 0)
+                               {
+                                       BNerr(BN_F_BN_BLINDING_CREATE_PARAM,
+                                               BN_R_TOO_MANY_ITERATIONS);
+                                       goto err;
+                               }
+                               ERR_clear_error();
+                               }
+                       else
+                               goto err;
+                       }
+               else
+                       break;
+       } while (1);
+
+       if (ret->bn_mod_exp != NULL && ret->m_ctx != NULL)
+               {
+               if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->m_ctx))
+                       goto err;
+               }
+       else
+               {
+               if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx))
+                       goto err;
+               }
+
+       return ret;
+err:
+       if (b == NULL && ret != NULL)
+               {
+               BN_BLINDING_free(ret);
+               ret = NULL;
+               }
+
+       return ret;
+}
+
index 42db405..37aa709 100644 (file)
@@ -72,6 +72,7 @@ static ERR_STRING_DATA BN_str_functs[]=
        {
 {ERR_FUNC(BN_F_BNRAND),        "BNRAND"},
 {ERR_FUNC(BN_F_BN_BLINDING_CONVERT),   "BN_BLINDING_convert"},
+{ERR_FUNC(BN_F_BN_BLINDING_CREATE_PARAM),      "BN_BLINDING_create_param"},
 {ERR_FUNC(BN_F_BN_BLINDING_INVERT),    "BN_BLINDING_invert"},
 {ERR_FUNC(BN_F_BN_BLINDING_NEW),       "BN_BLINDING_new"},
 {ERR_FUNC(BN_F_BN_BLINDING_UPDATE),    "BN_BLINDING_update"},
index 4bfd51a..4e28bbc 100644 (file)
@@ -156,6 +156,7 @@ struct rsa_st
         * NULL */
        char *bignum_data;
        BN_BLINDING *blinding;
+       BN_BLINDING *mt_blinding;
        };
 
 #define RSA_3  0x3L
@@ -279,6 +280,7 @@ int RSA_verify_ASN1_OCTET_STRING(int type,
 
 int RSA_blinding_on(RSA *rsa, BN_CTX *ctx);
 void RSA_blinding_off(RSA *rsa);
+BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *ctx);
 
 int RSA_padding_add_PKCS1_type_1(unsigned char *to,int tlen,
        const unsigned char *f,int fl);
@@ -341,6 +343,7 @@ void ERR_load_RSA_strings(void);
 #define RSA_F_RSA_PADDING_CHECK_SSLV23                  114
 #define RSA_F_RSA_PRINT                                         115
 #define RSA_F_RSA_PRINT_FP                              116
+#define RSA_F_RSA_SETUP_BLINDING                        125
 #define RSA_F_RSA_SIGN                                  117
 #define RSA_F_RSA_SIGN_ASN1_OCTET_STRING                118
 #define RSA_F_RSA_VERIFY                                119
@@ -367,6 +370,7 @@ void ERR_load_RSA_strings(void);
 #define RSA_R_INVALID_MESSAGE_LENGTH                    131
 #define RSA_R_IQMP_NOT_INVERSE_OF_Q                     126
 #define RSA_R_KEY_SIZE_TOO_SMALL                        120
+#define RSA_R_NO_PUBLIC_EXPONENT                        133
 #define RSA_R_NULL_BEFORE_BLOCK_MISSING                         113
 #define RSA_R_N_DOES_NOT_EQUAL_P_Q                      127
 #define RSA_R_OAEP_DECODING_ERROR                       121
index 3ee753e..6bf681f 100644 (file)
@@ -212,64 +212,78 @@ err:
        return(r);
        }
 
-static int rsa_eay_blinding(RSA *rsa, BN_CTX *ctx)
-       {
-       int ret = 1;
-       CRYPTO_w_lock(CRYPTO_LOCK_RSA);
-       /* Check again inside the lock - the macro's check is racey */
-       if(rsa->blinding == NULL)
-               ret = RSA_blinding_on(rsa, ctx);
-       CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
-       return ret;
-       }
+static BN_BLINDING *rsa_get_blinding(RSA *rsa, BIGNUM **r, int *local, BN_CTX *ctx)
+{
+       BN_BLINDING *ret;
 
-#define BLINDING_HELPER(rsa, ctx, err_instr) \
-       do { \
-               if((!((rsa)->flags & RSA_FLAG_NO_BLINDING)) && \
-                   ((rsa)->blinding == NULL) && \
-                   !rsa_eay_blinding(rsa, ctx)) \
-                       err_instr \
-       } while(0)
+       if (rsa->blinding == NULL)
+               {
+               if (rsa->blinding == NULL)
+                       {
+                       CRYPTO_w_lock(CRYPTO_LOCK_RSA);
+                       if (rsa->blinding == NULL)
+                               rsa->blinding = RSA_setup_blinding(rsa, ctx);
+                       CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
+                       }
+               }
 
-static BN_BLINDING *setup_blinding(RSA *rsa, BN_CTX *ctx)
-       {
-       BIGNUM *A, *Ai;
-       BN_BLINDING *ret = NULL;
+       ret = rsa->blinding;
+       if (ret == NULL)
+               return NULL;
 
-       /* added in OpenSSL 0.9.6j and 0.9.7b */
+       if (BN_BLINDING_get_thread_id(ret) != CRYPTO_thread_id())
+               {
+               *local = 0;
+               if (rsa->mt_blinding == NULL)
+                       {
+                       CRYPTO_w_lock(CRYPTO_LOCK_RSA);
+                       if (rsa->mt_blinding == NULL)
+                               rsa->mt_blinding = RSA_setup_blinding(rsa, ctx);
+                       CRYPTO_w_unlock(CRYPTO_LOCK_RSA);
+                       }
+               ret = rsa->mt_blinding;
+               }
+       else
+               *local = 1;
 
-       /* NB: similar code appears in RSA_blinding_on (rsa_lib.c);
-        * this should be placed in a new function of its own, but for reasons
-        * of binary compatibility can't */
+       return ret;
+}
 
-       BN_CTX_start(ctx);
-       A = BN_CTX_get(ctx);
-       if ((RAND_status() == 0) && rsa->d != NULL && rsa->d->d != NULL)
+static int rsa_blinding_convert(BN_BLINDING *b, int local, BIGNUM *f,
+       BIGNUM *r, BN_CTX *ctx)
+{
+       if (local)
+               return BN_BLINDING_convert_ex(f, NULL, b, ctx);
+       else
                {
-               /* if PRNG is not properly seeded, resort to secret exponent as unpredictable seed */
-               RAND_add(rsa->d->d, rsa->d->dmax * sizeof rsa->d->d[0], 0.0);
-               if (!BN_pseudo_rand_range(A,rsa->n)) goto err;
-               }
+               int ret;
+               CRYPTO_w_lock(CRYPTO_LOCK_RSA_BLINDING);
+               ret = BN_BLINDING_convert_ex(f, r, b, ctx);
+               CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
+               return ret;
+               }
+}
+
+static int rsa_blinding_invert(BN_BLINDING *b, int local, BIGNUM *f,
+       BIGNUM *r, BN_CTX *ctx)
+{
+       if (local)
+               return BN_BLINDING_invert_ex(f, NULL, b, ctx);
        else
                {
-               if (!BN_rand_range(A,rsa->n)) goto err;
+               int ret;
+               CRYPTO_r_lock(CRYPTO_LOCK_RSA_BLINDING);
+               ret = BN_BLINDING_invert_ex(f, r, b, ctx);
+               CRYPTO_r_unlock(CRYPTO_LOCK_RSA_BLINDING);
+               return ret;
                }
-       if ((Ai=BN_mod_inverse(NULL,A,rsa->n,ctx)) == NULL) goto err;
-
-       if (!rsa->meth->bn_mod_exp(A,A,rsa->e,rsa->n,ctx,rsa->_method_mod_n))
-               goto err;
-       ret = BN_BLINDING_new(A,Ai,rsa->n);
-       BN_free(Ai);
-err:
-       BN_CTX_end(ctx);
-       return ret;
-       }
+}
 
 /* signing */
 static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
             unsigned char *to, RSA *rsa, int padding)
        {
-       BIGNUM *f,*ret;
+       BIGNUM *f, *ret, *br;
        int i,j,k,num=0,r= -1;
        unsigned char *buf=NULL;
        BN_CTX *ctx=NULL;
@@ -278,9 +292,10 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
 
        if ((ctx=BN_CTX_new()) == NULL) goto err;
        BN_CTX_start(ctx);
-       f = BN_CTX_get(ctx);
+       f   = BN_CTX_get(ctx);
+       br  = BN_CTX_get(ctx);
        ret = BN_CTX_get(ctx);
-       num=BN_num_bytes(rsa->n);
+       num = BN_num_bytes(rsa->n);
        buf = OPENSSL_malloc(num);
        if(!f || !ret || !buf)
                {
@@ -312,17 +327,9 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
                goto err;
                }
 
-       BLINDING_HELPER(rsa, ctx, goto err;);
-       blinding = rsa->blinding;
-       
-       /* Now unless blinding is disabled, 'blinding' is non-NULL.
-        * But the BN_BLINDING object may be owned by some other thread
-        * (we don't want to keep it constant and we don't want to use
-        * lots of locking to avoid race conditions, so only a single
-        * thread can use it; other threads have to use local blinding
-        * factors) */
        if (!(rsa->flags & RSA_FLAG_NO_BLINDING))
                {
+               blinding = rsa_get_blinding(rsa, &br, &local_blinding, ctx);
                if (blinding == NULL)
                        {
                        RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
@@ -331,20 +338,8 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
                }
        
        if (blinding != NULL)
-               {
-               if (blinding->thread_id != CRYPTO_thread_id())
-                       {
-                       /* we need a local one-time blinding factor */
-
-                       blinding = setup_blinding(rsa, ctx);
-                       if (blinding == NULL)
-                               goto err;
-                       local_blinding = 1;
-                       }
-               }
-
-       if (blinding)
-               if (!BN_BLINDING_convert(f, blinding, ctx)) goto err;
+               if (!rsa_blinding_convert(blinding, local_blinding, f, br, ctx))
+                       goto err;
 
        if ( (rsa->flags & RSA_FLAG_EXT_PKEY) ||
                ((rsa->p != NULL) &&
@@ -361,7 +356,8 @@ static int RSA_eay_private_encrypt(int flen, const unsigned char *from,
                }
 
        if (blinding)
-               if (!BN_BLINDING_invert(ret, blinding, ctx)) goto err;
+               if (!rsa_blinding_invert(blinding, local_blinding, ret, br, ctx))
+                       goto err;
 
        /* put in leading 0 bytes if the number is less than the
         * length of the modulus */
@@ -377,8 +373,6 @@ err:
                BN_CTX_end(ctx);
                BN_CTX_free(ctx);
                }
-       if (local_blinding)
-               BN_BLINDING_free(blinding);
        if (buf != NULL)
                {
                OPENSSL_cleanse(buf,num);
@@ -390,7 +384,7 @@ err:
 static int RSA_eay_private_decrypt(int flen, const unsigned char *from,
             unsigned char *to, RSA *rsa, int padding)
        {
-       BIGNUM *f,*ret;
+       BIGNUM *f, *ret, *br;
        int j,num=0,r= -1;
        unsigned char *p;
        unsigned char *buf=NULL;
@@ -400,9 +394,10 @@ static int RSA_eay_private_decrypt(int flen, const unsigned char *from,
 
        if((ctx = BN_CTX_new()) == NULL) goto err;
        BN_CTX_start(ctx);
-       f = BN_CTX_get(ctx);
+       f   = BN_CTX_get(ctx);
+       br  = BN_CTX_get(ctx);
        ret = BN_CTX_get(ctx);
-       num=BN_num_bytes(rsa->n);
+       num = BN_num_bytes(rsa->n);
        buf = OPENSSL_malloc(num);
        if(!f || !ret || !buf)
                {
@@ -427,39 +422,19 @@ static int RSA_eay_private_decrypt(int flen, const unsigned char *from,
                goto err;
                }
 
-       BLINDING_HELPER(rsa, ctx, goto err;);
-       blinding = rsa->blinding;
-       
-       /* Now unless blinding is disabled, 'blinding' is non-NULL.
-        * But the BN_BLINDING object may be owned by some other thread
-        * (we don't want to keep it constant and we don't want to use
-        * lots of locking to avoid race conditions, so only a single
-        * thread can use it; other threads have to use local blinding
-        * factors) */
        if (!(rsa->flags & RSA_FLAG_NO_BLINDING))
                {
+               blinding = rsa_get_blinding(rsa, &br, &local_blinding, ctx);
                if (blinding == NULL)
                        {
-                       RSAerr(RSA_F_RSA_EAY_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR);
+                       RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
                        goto err;
                        }
                }
        
        if (blinding != NULL)
-               {
-               if (blinding->thread_id != CRYPTO_thread_id())
-                       {
-                       /* we need a local one-time blinding factor */
-
-                       blinding = setup_blinding(rsa, ctx);
-                       if (blinding == NULL)
-                               goto err;
-                       local_blinding = 1;
-                       }
-               }
-
-       if (blinding)
-               if (!BN_BLINDING_convert(f, blinding, ctx)) goto err;
+               if (!rsa_blinding_convert(blinding, local_blinding, f, br, ctx))
+                       goto err;
 
        /* do the decrypt */
        if ( (rsa->flags & RSA_FLAG_EXT_PKEY) ||
@@ -478,7 +453,8 @@ static int RSA_eay_private_decrypt(int flen, const unsigned char *from,
                }
 
        if (blinding)
-               if (!BN_BLINDING_invert(ret, blinding, ctx)) goto err;
+               if (!rsa_blinding_invert(blinding, local_blinding, ret, br, ctx))
+                       goto err;
 
        p=buf;
        j=BN_bn2bin(ret,p); /* j is only used with no-padding mode */
@@ -512,8 +488,6 @@ err:
                BN_CTX_end(ctx);
                BN_CTX_free(ctx);
                }
-       if (local_blinding)
-               BN_BLINDING_free(blinding);
        if (buf != NULL)
                {
                OPENSSL_cleanse(buf,num);
index 07ef9df..6641e61 100644 (file)
@@ -91,6 +91,7 @@ static ERR_STRING_DATA RSA_str_functs[]=
 {ERR_FUNC(RSA_F_RSA_PADDING_CHECK_SSLV23),     "RSA_padding_check_SSLv23"},
 {ERR_FUNC(RSA_F_RSA_PRINT),    "RSA_print"},
 {ERR_FUNC(RSA_F_RSA_PRINT_FP), "RSA_print_fp"},
+{ERR_FUNC(RSA_F_RSA_SETUP_BLINDING),   "RSA_setup_blinding"},
 {ERR_FUNC(RSA_F_RSA_SIGN),     "RSA_sign"},
 {ERR_FUNC(RSA_F_RSA_SIGN_ASN1_OCTET_STRING),   "RSA_sign_ASN1_OCTET_STRING"},
 {ERR_FUNC(RSA_F_RSA_VERIFY),   "RSA_verify"},
@@ -120,6 +121,7 @@ static ERR_STRING_DATA RSA_str_reasons[]=
 {ERR_REASON(RSA_R_INVALID_MESSAGE_LENGTH),"invalid message length"},
 {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) ,"iqmp not inverse of q"},
 {ERR_REASON(RSA_R_KEY_SIZE_TOO_SMALL)    ,"key size too small"},
+{ERR_REASON(RSA_R_NO_PUBLIC_EXPONENT)    ,"no public exponent"},
 {ERR_REASON(RSA_R_NULL_BEFORE_BLOCK_MISSING),"null before block missing"},
 {ERR_REASON(RSA_R_N_DOES_NOT_EQUAL_P_Q)  ,"n does not equal p q"},
 {ERR_REASON(RSA_R_OAEP_DECODING_ERROR)   ,"oaep decoding error"},
index cba2dd6..0447fd5 100644 (file)
@@ -179,6 +179,7 @@ RSA *RSA_new_method(ENGINE *engine)
        ret->_method_mod_p=NULL;
        ret->_method_mod_q=NULL;
        ret->blinding=NULL;
+       ret->mt_blinding=NULL;
        ret->bignum_data=NULL;
        ret->flags=ret->meth->flags;
        CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, ret, &ret->ex_data);
@@ -232,6 +233,7 @@ void RSA_free(RSA *r)
        if (r->dmq1 != NULL) BN_clear_free(r->dmq1);
        if (r->iqmp != NULL) BN_clear_free(r->iqmp);
        if (r->blinding != NULL) BN_BLINDING_free(r->blinding);
+       if (r->mt_blinding != NULL) BN_BLINDING_free(r->mt_blinding);
        if (r->bignum_data != NULL) OPENSSL_free_locked(r->bignum_data);
        OPENSSL_free(r);
        }
@@ -314,59 +316,100 @@ void RSA_blinding_off(RSA *rsa)
        rsa->flags |= RSA_FLAG_NO_BLINDING;
        }
 
-int RSA_blinding_on(RSA *rsa, BN_CTX *p_ctx)
+int RSA_blinding_on(RSA *rsa, BN_CTX *ctx)
        {
-       BIGNUM *A,*Ai = NULL;
-       BN_CTX *ctx;
        int ret=0;
 
-       if (p_ctx == NULL)
+       if (rsa->blinding != NULL)
+               RSA_blinding_off(rsa);
+
+       rsa->blinding = RSA_setup_blinding(rsa, ctx);
+       if (rsa->blinding == NULL)
+               goto err;
+
+       rsa->flags |= RSA_FLAG_BLINDING;
+       rsa->flags &= ~RSA_FLAG_NO_BLINDING;
+       ret=1;
+err:
+       return(ret);
+       }
+
+static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p,
+       const BIGNUM *q, BN_CTX *ctx)
+{
+       BIGNUM *ret = NULL, *r0, *r1, *r2;
+
+       if (d == NULL || p == NULL || q == NULL)
+               return NULL;
+
+       BN_CTX_start(ctx);
+       r0 = BN_CTX_get(ctx);
+       r1 = BN_CTX_get(ctx);
+       r2 = BN_CTX_get(ctx);
+       if (r2 == NULL)
+               goto err;
+
+       if (!BN_sub(r1, p, BN_value_one())) goto err;
+       if (!BN_sub(r2, q, BN_value_one())) goto err;
+       if (!BN_mul(r0, r1, r2, ctx)) goto err;
+
+       ret = BN_mod_inverse(NULL, d, r0, ctx);
+err:
+       BN_CTX_end(ctx);
+       return ret;
+}
+
+BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *in_ctx)
+{
+       BIGNUM *e;
+       BN_CTX *ctx;
+       BN_BLINDING *ret = NULL;
+
+       if (in_ctx == NULL)
                {
-               if ((ctx=BN_CTX_new()) == NULL) goto err;
+               if ((ctx = BN_CTX_new()) == NULL) return 0;
                }
        else
-               ctx=p_ctx;
+               ctx = in_ctx;
 
-       /* XXXXX: Shouldn't this be RSA_blinding_off(rsa)? */
-       if (rsa->blinding != NULL)
+       BN_CTX_start(ctx);
+       e  = BN_CTX_get(ctx);
+       if (e == NULL)
                {
-               BN_BLINDING_free(rsa->blinding);
-               rsa->blinding = NULL;
+               RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_MALLOC_FAILURE);
+               goto err;
                }
 
-       /* NB: similar code appears in setup_blinding (rsa_eay.c);
-        * this should be placed in a new function of its own, but for reasons
-        * of binary compatibility can't */
-
-       BN_CTX_start(ctx);
-       A = BN_CTX_get(ctx);
-       if ((RAND_status() == 0) && rsa->d != NULL && rsa->d->d != NULL)
+       if (rsa->e == NULL)
                {
-               /* if PRNG is not properly seeded, resort to secret exponent as unpredictable seed */
-               RAND_add(rsa->d->d, rsa->d->dmax * sizeof rsa->d->d[0], 0.0);
-               if (!BN_pseudo_rand_range(A,rsa->n)) goto err;
+               e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx);
+               if (e == NULL)
+                       {
+                       RSAerr(RSA_F_RSA_SETUP_BLINDING, RSA_R_NO_PUBLIC_EXPONENT);
+                       goto err;
+                       }
                }
        else
+               e = rsa->e;
+
+       
+       if ((RAND_status() == 0) && rsa->d != NULL && rsa->d->d != NULL)
                {
-               if (!BN_rand_range(A,rsa->n)) goto err;
+               /* if PRNG is not properly seeded, resort to secret
+                * exponent as unpredictable seed */
+               RAND_add(rsa->d->d, rsa->d->dmax * sizeof rsa->d->d[0], 0.0);
                }
-       if ((Ai=BN_mod_inverse(NULL,A,rsa->n,ctx)) == NULL) goto err;
 
-       if (!rsa->meth->bn_mod_exp(A,A,rsa->e,rsa->n,ctx,rsa->_method_mod_n))
-               goto err;
-       if ((rsa->blinding=BN_BLINDING_new(A,Ai,rsa->n)) == NULL) goto err;
-       /* to make things thread-safe without excessive locking,
-        * rsa->blinding will be used just by the current thread: */
-       rsa->blinding->thread_id = CRYPTO_thread_id();
-       rsa->flags |= RSA_FLAG_BLINDING;
-       rsa->flags &= ~RSA_FLAG_NO_BLINDING;
-       ret=1;
+       ret = BN_BLINDING_create_param(NULL, e, rsa->n, ctx,
+                       rsa->meth->bn_mod_exp, rsa->_method_mod_n);
+       BN_BLINDING_set_thread_id(ret, CRYPTO_thread_id());
 err:
-       if (Ai != NULL) BN_free(Ai);
        BN_CTX_end(ctx);
-       if (ctx != p_ctx) BN_CTX_free(ctx);
-       return(ret);
-       }
+       if (in_ctx == NULL)
+               BN_CTX_free(ctx);
+
+       return ret;
+}
 
 int RSA_memory_lock(RSA *r)
        {
index d589dd3..b9485ab 100755 (executable)
@@ -3305,3 +3305,11 @@ BN_set_negative                         3704     EXIST::FUNCTION:
 BIO_new_dgram                           3705   EXIST::FUNCTION:
 BIO_s_datagram                          3706   EXIST::FUNCTION:DGRAM
 BIO_dgram_non_fatal_error               3707   EXIST::FUNCTION:
+RSA_setup_blinding                      3708   EXIST::FUNCTION:RSA
+BN_BLINDING_set_thread_id               3709   EXIST::FUNCTION:
+BN_BLINDING_convert_ex                  3710   EXIST::FUNCTION:
+BN_BLINDING_create_param                3711   EXIST::FUNCTION:
+BN_BLINDING_set_flags                   3712   EXIST::FUNCTION:
+BN_BLINDING_invert_ex                   3713   EXIST::FUNCTION:
+BN_BLINDING_get_thread_id               3714   EXIST::FUNCTION:
+BN_BLINDING_get_flags                   3715   EXIST::FUNCTION: