Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP3:Update
openssl.7904
openssl-add-blinding-to-ecdsa.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File openssl-add-blinding-to-ecdsa.patch of Package openssl.7904
From 949ff36623eafc3523a9f91784992965018ffb05 Mon Sep 17 00:00:00 2001 From: Matt Caswell <matt@openssl.org> Date: Fri, 25 May 2018 12:10:13 +0100 Subject: [PATCH] Add blinding to an ECDSA signature Keegan Ryan (NCC Group) has demonstrated a side channel attack on an ECDSA signature operation. During signing the signer calculates: s:= k^-1 * (m + r * priv_key) mod order The addition operation above provides a sufficient signal for a flush+reload attack to derive the private key given sufficient signature operations. As a mitigation (based on a suggestion from Keegan) we add blinding to the operation so that: s := k^-1 * blind^-1 (blind * m + blind * r * priv_key) mod order Since this attack is a localhost side channel only no CVE is assigned. Reviewed-by: Rich Salz <rsalz@openssl.org> --- CHANGES | 4 +++ crypto/ecdsa/ecdsatest.c | 9 +++++- crypto/ecdsa/ecs_ossl.c | 82 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 16 deletions(-) Index: openssl-1.0.1i/crypto/ecdsa/ecdsatest.c =================================================================== --- openssl-1.0.1i.orig/crypto/ecdsa/ecdsatest.c +++ openssl-1.0.1i/crypto/ecdsa/ecdsatest.c @@ -10,7 +10,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 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 @@ -58,13 +58,13 @@ /* ==================================================================== * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * - * Portions of the attached software ("Contribution") are developed by + * Portions of the attached software ("Contribution") are developed by * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. * * The Contribution is licensed pursuant to the OpenSSL open source * license provided above. * - * The elliptic curve binary polynomial software is originally written by + * The elliptic curve binary polynomial software is originally written by * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. * */ @@ -137,7 +137,7 @@ int restore_rand(void) return 1; } -static int fbytes_counter = 0; +static int fbytes_counter = 0, use_fake = 0; static const char *numbers[10] = { "651056770906015076056810763456358567190100156695615665659", "651056770906015076056810763456358567190100156695615665659", @@ -160,6 +160,11 @@ int fbytes(unsigned char *buf, int num) int ret; BIGNUM *tmp = NULL; + if (use_fake == 0) + return old_rand->bytes(buf, num); + + use_fake = 0; + if (fbytes_counter >= 10) return 0; tmp = BN_new(); @@ -173,7 +178,7 @@ int fbytes(unsigned char *buf, int num) fbytes_counter ++; if (num != BN_num_bytes(tmp) || !BN_bn2bin(tmp, buf)) ret = 0; - else + else ret = 1; if (tmp) BN_free(tmp); @@ -202,11 +207,13 @@ int x9_62_test_internal(BIO *out, int ni /* create the key */ if ((key = EC_KEY_new_by_curve_name(nid)) == NULL) goto x962_int_err; + use_fake = 1; if (!EC_KEY_generate_key(key)) goto x962_int_err; BIO_printf(out, "."); (void)BIO_flush(out); /* create the signature */ + use_fake = 1; signature = ECDSA_do_sign(digest, 20, key); if (signature == NULL) goto x962_int_err; @@ -298,7 +305,7 @@ int test_builtin(BIO *out) unsigned char *raw_buf = NULL; unsigned int sig_len, degree, r_len, s_len, bn_len, buf_len; int nid, ret = 0; - + /* fill digest values with some random data */ if (!RAND_pseudo_bytes(digest, 20) || !RAND_pseudo_bytes(wrong_digest, 20)) @@ -322,7 +329,7 @@ int test_builtin(BIO *out) BIO_printf(out, "malloc error\n"); goto builtin_err; } - + if (!EC_get_builtin_curves(curves, crv_len)) { BIO_printf(out, "unable to get internal curves\n"); @@ -348,7 +355,7 @@ int test_builtin(BIO *out) EC_GROUP_free(group); degree = EC_GROUP_get_degree(EC_KEY_get0_group(eckey)); if (degree < 160) - /* drop the curve */ + /* drop the curve */ { EC_KEY_free(eckey); eckey = NULL; @@ -406,7 +413,7 @@ int test_builtin(BIO *out) BIO_printf(out, "."); (void)BIO_flush(out); /* verify signature with the wrong key */ - if (ECDSA_verify(0, digest, 20, signature, sig_len, + if (ECDSA_verify(0, digest, 20, signature, sig_len, wrong_eckey) == 1) { BIO_printf(out, " failed\n"); @@ -491,7 +498,7 @@ int test_builtin(BIO *out) } BIO_printf(out, "."); (void)BIO_flush(out); - + BIO_printf(out, " ok\n"); /* cleanup */ /* clean bogus errors */ @@ -508,7 +515,7 @@ int test_builtin(BIO *out) raw_buf = NULL; } - ret = 1; + ret = 1; builtin_err: if (eckey) EC_KEY_free(eckey); @@ -532,9 +539,9 @@ int main(void) BIO *out; out = BIO_new_fp(stdout, BIO_NOCLOSE); - + /* enable memory leak checking unless explicitly disabled */ - if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && + if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && (0 == strcmp(getenv("OPENSSL_DEBUG_MEMORY"), "off")))) { CRYPTO_malloc_debug_init(); @@ -557,12 +564,12 @@ int main(void) if (!x9_62_tests(out)) goto err; #endif if (!test_builtin(out)) goto err; - + ret = 0; -err: - if (ret) +err: + if (ret) BIO_printf(out, "\nECDSA test failed\n"); - else + else BIO_printf(out, "\nECDSA test passed\n"); if (ret) ERR_print_errors(out); @@ -573,5 +580,5 @@ err: if (out != NULL) BIO_free(out); return ret; - } + } #endif Index: openssl-1.0.1i/crypto/ecdsa/ecs_ossl.c =================================================================== --- openssl-1.0.1i.orig/crypto/ecdsa/ecs_ossl.c +++ openssl-1.0.1i/crypto/ecdsa/ecs_ossl.c @@ -10,7 +10,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 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 @@ -64,11 +64,11 @@ #include <openssl/fips.h> #endif -static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dlen, +static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dlen, const BIGNUM *, const BIGNUM *, EC_KEY *eckey); -static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, +static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp); -static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len, +static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len, const ECDSA_SIG *sig, EC_KEY *eckey); static ECDSA_METHOD openssl_ecdsa_meth = { @@ -104,7 +104,7 @@ static int ecdsa_sign_setup(EC_KEY *ecke return 0; } - if (ctx_in == NULL) + if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { @@ -134,15 +134,15 @@ static int ecdsa_sign_setup(EC_KEY *ecke ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } - + do { - /* get random k */ + /* get random k */ do if (!BN_rand_range(k, order)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, - ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); + ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } while (BN_is_zero(k)); @@ -194,12 +194,12 @@ static int ecdsa_sign_setup(EC_KEY *ecke if (!BN_mod_inverse(k, k, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); - goto err; + goto err; } /* clear old values if necessary */ if (*rp != NULL) BN_clear_free(*rp); - if (*kinvp != NULL) + if (*kinvp != NULL) BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; @@ -211,11 +211,11 @@ err: if (k != NULL) BN_clear_free(k); if (r != NULL) BN_clear_free(r); } - if (ctx_in == NULL) + if (ctx_in == NULL) BN_CTX_free(ctx); if (order != NULL) BN_free(order); - if (tmp_point != NULL) + if (tmp_point != NULL) EC_POINT_free(tmp_point); if (X) BN_clear_free(X); @@ -223,11 +223,12 @@ err: } -static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len, +static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *eckey) { int ok = 0, i; BIGNUM *kinv=NULL, *s, *m=NULL,*tmp=NULL,*order=NULL; + BIGNUM *blind = NULL, *blindm = NULL; const BIGNUM *ckinv; BN_CTX *ctx = NULL; const EC_GROUP *group; @@ -246,7 +247,7 @@ static ECDSA_SIG *ecdsa_do_sign(const un ecdsa = ecdsa_check(eckey); group = EC_KEY_get0_group(eckey); priv_key = EC_KEY_get0_private_key(eckey); - + if (group == NULL || priv_key == NULL || ecdsa == NULL) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_PASSED_NULL_PARAMETER); @@ -261,9 +262,19 @@ static ECDSA_SIG *ecdsa_do_sign(const un } s = ret->s; - if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL || - (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) - { + ctx = BN_CTX_new(); + if (ctx == NULL) { + ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE); + goto err; + } + + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + m = BN_CTX_get(ctx); + blind = BN_CTX_get(ctx); + blindm = BN_CTX_get(ctx); + if (blindm == NULL) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE); goto err; } @@ -311,16 +322,60 @@ static ECDSA_SIG *ecdsa_do_sign(const un } } - if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) + /* + * The normal signature calculation is: + * + * s := k^-1 * (m + r * priv_key) mod order + * + * We will blind this to protect against side channel attacks + * + * s := k^-1 * blind^-1 * (blind * m + blind * r * priv_key) mod order + */ + + /* Generate a blinding value */ + do { + if (!BN_rand(blind, BN_num_bits(order) - 1, -1, 0)) + goto err; + } while (BN_is_zero(blind)); + BN_set_flags(blind, BN_FLG_CONSTTIME); + BN_set_flags(blindm, BN_FLG_CONSTTIME); + BN_set_flags(tmp, BN_FLG_CONSTTIME); + + /* tmp := blind * priv_key * r mod order */ + if (!BN_mod_mul(tmp, blind, priv_key, order, ctx)) { + ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); + goto err; + } + if (!BN_mod_mul(tmp, tmp, ret->r, order, ctx)) { + ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); + goto err; + } + + /* blindm := blind * m mod order */ + if (!BN_mod_mul(blindm, blind, m, order, ctx)) { + ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); + goto err; + } + + /* s : = (blind * priv_key * r) + (blind * m) mod order */ + if (!BN_mod_add_quick(s, tmp, blindm, order)) { + ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); + goto err; + } + + /* s:= s * blind^-1 mod order */ + if (BN_mod_inverse(blind, blind, order, ctx) == NULL) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } - if (!BN_mod_add_quick(s, tmp, m, order)) + if (!BN_mod_mul(s, s, blind, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } + + /* s := s * k^-1 mod order */ if (!BN_mod_mul(s, s, ckinv, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); @@ -349,15 +404,11 @@ err: ECDSA_SIG_free(ret); ret = NULL; } - if (ctx) + if (ctx != NULL) { + BN_CTX_end(ctx); BN_CTX_free(ctx); - if (m) - BN_clear_free(m); - if (tmp) - BN_clear_free(tmp); - if (order) - BN_free(order); - if (kinv) + } + if (kinv != NULL) BN_clear_free(kinv); return ret; } @@ -395,7 +446,7 @@ static int ecdsa_do_verify(const unsigne return -1; } BN_CTX_start(ctx); - order = BN_CTX_get(ctx); + order = BN_CTX_get(ctx); u1 = BN_CTX_get(ctx); u2 = BN_CTX_get(ctx); m = BN_CTX_get(ctx); @@ -405,14 +456,14 @@ static int ecdsa_do_verify(const unsigne ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); goto err; } - + if (!EC_GROUP_get_order(group, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB); goto err; } - if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || + if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) || BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) { @@ -486,7 +537,7 @@ static int ecdsa_do_verify(const unsigne goto err; } } -#endif +#endif if (!BN_nnmod(u1, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor