Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP4:GA
Botan
CVE-2015-7827+CVE-2016-2849.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2015-7827+CVE-2016-2849.patch of Package Botan
commit bcf13fa153a11b3e0ad54e2af6962441cea3adf1 Author: Jack Lloyd <lloyd@randombit.net> Date: Sat Apr 23 07:01:19 2016 -0400 Fixes for CVE-2015-7827 and CVE-2016-2849 diff --git a/src/math/mp/mp_asm.cpp b/src/math/mp/mp_asm.cpp index 3ba52c4b1..523f9390f 100644 --- a/src/math/mp/mp_asm.cpp +++ b/src/math/mp/mp_asm.cpp @@ -9,6 +9,7 @@ #include <botan/internal/mp_asm.h> #include <botan/internal/mp_asmi.h> #include <botan/internal/mp_core.h> +#include <botan/internal/ct_utils.h> #include <botan/exceptn.h> #include <botan/mem_ops.h> @@ -17,6 +18,76 @@ namespace Botan { extern "C" { /* +* If cond == 0, does nothing. +* If cond > 0, swaps x[0:size] with y[0:size] +* Runs in constant time +*/ +void bigint_cnd_swap(word cnd, word x[], word y[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + for(size_t i = 0; i != size; ++i) + { + word a = x[i]; + word b = y[i]; + x[i] = CT::select(mask, b, a); + y[i] = CT::select(mask, a, b); + } + } + +/* +* If cond > 0 adds x[0:size] to y[0:size] and returns carry +* Runs in constant time +*/ +word bigint_cnd_add(word cnd, word x[], const word y[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + word carry = 0; + for(size_t i = 0; i != size; ++i) + { + /* + Here we are relying on asm version of word_add being + a single addcl or equivalent. Fix this. + */ + const word z = word_add(x[i], y[i], &carry); + x[i] = CT::select(mask, z, x[i]); + } + + return carry & mask; + } + +/* +* If cond > 0 subs x[0:size] to y[0:size] and returns borrow +* Runs in constant time +*/ +word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + word carry = 0; + for(size_t i = 0; i != size; ++i) + { + const word z = word_sub(x[i], y[i], &carry); + x[i] = CT::select(mask, z, x[i]); + } + + return carry & mask; + } + +void bigint_cnd_abs(word cnd, word x[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + word carry = mask & 1; + for(size_t i = 0; i != size; ++i) + { + const word z = word_add(~x[i], 0, &carry); + x[i] = CT::select(mask, z, x[i]); + } + } + +/* * Two Operand Addition, No Carry */ word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) diff --git a/src/math/mp/mp_core.h b/src/math/mp/mp_core.h index 82bdbad53..ac3ef6cad 100644 --- a/src/math/mp/mp_core.h +++ b/src/math/mp/mp_core.h @@ -20,6 +20,32 @@ const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS; extern "C" { /* +* If cond == 0, does nothing. +* If cond > 0, swaps x[0:size] with y[0:size] +* Runs in constant time +*/ +void bigint_cnd_swap(word cnd, word x[], word y[], size_t size); + +/* +* If cond > 0 adds x[0:size] to y[0:size] and returns carry +* Runs in constant time +*/ +word bigint_cnd_add(word cnd, word x[], const word y[], size_t size); + +/* +* If cond > 0 subs x[0:size] to y[0:size] and returns borrow +* Runs in constant time +*/ +word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size); + +/* +* 2s complement absolute value +* If cond > 0 sets x to ~x + 1 +* Runs in constant time +*/ +void bigint_cnd_abs(word cnd, word x[], size_t size); + +/* * Addition/Subtraction Operations */ void bigint_add2(word x[], size_t x_size, diff --git a/src/math/numbertheory/numthry.cpp b/src/math/numbertheory/numthry.cpp index 535ca6772..4ffb9aff5 100644 --- a/src/math/numbertheory/numthry.cpp +++ b/src/math/numbertheory/numthry.cpp @@ -7,6 +7,7 @@ #include <botan/numthry.h> #include <botan/reducer.h> +#include <botan/internal/mp_core.h> #include <botan/internal/bit_ops.h> #include <algorithm> @@ -196,6 +197,117 @@ BigInt lcm(const BigInt& a, const BigInt& b) return ((a * b) / gcd(a, b)); } +namespace { + +BigInt ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) + { + if(n.is_negative() || mod.is_negative()) + throw Invalid_Argument("ct_inverse_mod_odd_modulus: arguments must be non-negative"); + if(mod < 3 || mod.is_even()) + throw Invalid_Argument("Bad modulus to ct_inverse_mod_odd_modulus"); + + /* + This uses a modular inversion algorithm designed by Niels Möller + and implemented in Nettle. The same algorithm was later also + adapted to GMP in mpn_sec_invert. + + It can be easily implemented in a way that does not depend on + secret branches or memory lookups, providing resistance against + some forms of side channel attack. + + There is also a description of the algorithm in Appendix 5 of "Fast + Software Polynomial Multiplication on ARM Processors using the NEON Engine" + by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo + Dahab in LNCS 8182 + http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf + + Thanks to Niels for creating the algorithm, explaining some things + about it, and the reference to the paper. + */ + + // todo allow this to be pre-calculated and passed in as arg + BigInt mp1o2 = (mod + 1) >> 1; + + const size_t mod_words = mod.sig_words(); + + BigInt a = n; + BigInt b = mod; + BigInt u = 1, v = 0; + + a.grow_to(mod_words); + u.grow_to(mod_words); + v.grow_to(mod_words); + mp1o2.grow_to(mod_words); + + SecureVector<word>& a_w = a.get_reg(); + SecureVector<word>& b_w = b.get_reg(); + SecureVector<word>& u_w = u.get_reg(); + SecureVector<word>& v_w = v.get_reg(); + + // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n + size_t bits = 2 * mod.bits(); + + while(bits--) + { +#if 1 + const word odd = a.is_odd(); + a -= odd * b; + const word underflow = a.is_negative(); + b += a * underflow; + a.set_sign(BigInt::Positive); + + a >>= 1; + + if(underflow) + { + std::swap(u, v); + } + + u -= odd * v; + u += u.is_negative() * mod; + + const word odd_u = u.is_odd(); + + u >>= 1; + u += mp1o2 * odd_u; +#else + const word odd_a = a_w[0] & 1; + + //if(odd_a) a -= b + word underflow = bigint_cnd_sub(odd_a, a_w.begin(), b_w.begin(), mod_words); + + //if(underflow) { b -= a; a = abs(a); swap(u, v); } + bigint_cnd_add(underflow, b_w.begin(), a_w.begin(), mod_words); + bigint_cnd_abs(underflow, a_w.begin(), mod_words); + bigint_cnd_swap(underflow, u_w.begin(), v_w.begin(), mod_words); + + // a >>= 1 + bigint_shr1(a_w.begin(), mod_words, 0, 1); + + //if(odd_a) u -= v; + word borrow = bigint_cnd_sub(odd_a, u_w.begin(), v_w.begin(), mod_words); + + // if(borrow) u += p + bigint_cnd_add(borrow, u_w.begin(), mod.data(), mod_words); + + const word odd_u = u_w[0] & 1; + + // u >>= 1 + bigint_shr1(u_w.begin(), mod_words, 0, 1); + + //if(odd_u) u += mp1o2; + bigint_cnd_add(odd_u, u_w.begin(), mp1o2.data(), mod_words); +#endif + } + + if(b != 1) + return 0; + + return v; + } + +} + /* * Find the Modular Inverse */ @@ -209,6 +321,9 @@ BigInt inverse_mod(const BigInt& n, const BigInt& mod) if(n.is_zero() || (n.is_even() && mod.is_even())) return 0; + if(mod.is_odd()) + return ct_inverse_mod_odd_modulus(n % mod, mod); + BigInt x = mod, y = n, u = mod, v = n; BigInt A = 1, B = 0, C = 0, D = 1; diff --git a/src/pk_pad/eme_pkcs/eme_pkcs.cpp b/src/pk_pad/eme_pkcs/eme_pkcs.cpp index c4d6838b1..7f0393ed8 100644 --- a/src/pk_pad/eme_pkcs/eme_pkcs.cpp +++ b/src/pk_pad/eme_pkcs/eme_pkcs.cpp @@ -6,6 +6,7 @@ */ #include <botan/eme_pkcs.h> +#include <botan/internal/ct_utils.h> namespace Botan { @@ -40,20 +41,31 @@ SecureVector<byte> EME_PKCS1v15::pad(const byte in[], size_t inlen, SecureVector<byte> EME_PKCS1v15::unpad(const byte in[], size_t inlen, size_t key_len) const { - if(inlen != key_len / 8 || inlen < 10 || in[0] != 0x02) - throw Decoding_Error("PKCS1::unpad"); - - size_t seperator = 0; - for(size_t j = 0; j != inlen; ++j) - if(in[j] == 0) - { - seperator = j; - break; - } - if(seperator < 9) - throw Decoding_Error("PKCS1::unpad"); - - return SecureVector<byte>(in + seperator + 1, inlen - seperator - 1); + + byte bad_input_m = 0; + byte seen_zero_m = 0; + size_t delim_idx = 0; + + bad_input_m |= ~CT::is_equal<byte>(in[0], 2); + + for(size_t i = 1; i < inlen; ++i) + { + const byte is_zero_m = CT::is_zero<byte>(in[i]); + + delim_idx += CT::select<byte>(~seen_zero_m, 1, 0); + + bad_input_m |= is_zero_m & CT::expand_mask<byte>(i < 9); + seen_zero_m |= is_zero_m; + } + + bad_input_m |= ~seen_zero_m; + bad_input_m |= CT::is_less<size_t>(delim_idx, 8); + + SecureVector<byte> output(&in[delim_idx + 1], inlen - (delim_idx + 1)); + + if(bad_input_m) + throw Decoding_Error("EME_PKCS1v15::unpad invalid ciphertext"); + return output; } /* diff --git a/src/utils/ct_utils.h b/src/utils/ct_utils.h new file mode 100644 index 000000000..0eab90636 --- /dev/null +++ b/src/utils/ct_utils.h @@ -0,0 +1,137 @@ +/* +* Functions for constant time operations on data and testing of +* constant time annotations using valgrind. +* +* For more information about constant time programming see +* Wagner, Molnar, et al "The Program Counter Security Model" +* +* (C) 2010 Falko Strenzke +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TIMING_ATTACK_CM_H__ +#define BOTAN_TIMING_ATTACK_CM_H__ + +#include <botan/secmem.h> +#include <vector> + +namespace Botan { + +namespace CT { + +/* +* T should be an unsigned machine integer type +* Expand to a mask used for other operations +* @param in an integer +* @return If n is zero, returns zero. Otherwise +* returns a T with all bits set for use as a mask with +* select. +*/ +template<typename T> +inline T expand_mask(T x) + { + T r = x; + // First fold r down to a single bit + for(size_t i = 1; i != sizeof(T)*8; i *= 2) + r |= r >> i; + r &= 1; + r = ~(r - 1); + return r; + } + +template<typename T> +inline T select(T mask, T from0, T from1) + { + return (from0 & mask) | (from1 & ~mask); + } + +template<typename PredT, typename ValT> +inline ValT val_or_zero(PredT pred_val, ValT val) + { + return select(CT::expand_mask<ValT>(pred_val), val, static_cast<ValT>(0)); + } + +template<typename T> +inline T is_zero(T x) + { + return ~expand_mask(x); + } + +template<typename T> +inline T is_equal(T x, T y) + { + return is_zero(x ^ y); + } + +template<typename T> +inline T is_less(T x, T y) + { + /* + This expands to a constant time sequence with GCC 5.2.0 on x86-64 + but something more complicated may be needed for portable const time. + */ + return expand_mask<T>(x < y); + } + +template<typename T> +inline T is_lte(T x, T y) + { + return expand_mask<T>(x <= y); + } + +template<typename T> +inline void conditional_copy_mem(T value, + T* to, + const T* from0, + const T* from1, + size_t elems) + { + const T mask = CT::expand_mask(value); + + for(size_t i = 0; i != elems; ++i) + { + to[i] = CT::select(mask, from0[i], from1[i]); + } + } + +template<typename T> +inline void cond_zero_mem(T cond, + T* array, + size_t elems) + { + const T mask = CT::expand_mask(cond); + const T zero(0); + + for(size_t i = 0; i != elems; ++i) + { + array[i] = CT::select(mask, zero, array[i]); + } + } + +template<typename T> +inline T expand_top_bit(T a) + { + return expand_mask<T>(a >> (sizeof(T)*8-1)); + } + +template<typename T> +inline T max(T a, T b) + { + const T a_larger = b - a; // negative if a is larger + return select(expand_top_bit(a), a, b); + } + +template<typename T> +inline T min(T a, T b) + { + const T a_larger = b - a; // negative if a is larger + return select(expand_top_bit(b), b, a); + } + +} + +} + +#endif diff --git a/src/utils/info.txt b/src/utils/info.txt index fcf16bd5a..57b6a2740 100644 --- a/src/utils/info.txt +++ b/src/utils/info.txt @@ -16,6 +16,7 @@ version.cpp <header:internal> assert.h bit_ops.h +ct_utils.h mlock.h prefetch.h rounding.h
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