Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package botan1.10 Hi, I would like to pre-mediate the inclusion of 1.10.4 (e.g. new upstream version). The patch is very small and fixes three issues. Upstream changelog: http://botan.randombit.net/relnotes/1_10_4.html --cut here-- * Avoid a conditional operation in the power mod implementations on if a nibble of the exponent was zero or not. This may help protect against certain forms of side channel attacks. * The SRP6 code was checking for invalid values as specified in RFC 5054, specifically values equal to zero mod p. However SRP would accept negative A/B values, or ones larger than p, neither of which should occur in a normal run of the protocol. These values are now rejected. Credits to Timothy Prepscius for pointing out these values are not normally used and probably signal something fishy. * The return value of version_string is now a compile time constant string, so version information can be more easily extracted from binaries. --cut here-- The first two issues are security issues and the third could be included just for the sake of clarity. $ git diff upstream/1.10.3..upstream/1.10.4 | diffstat botan_version.py | 6 +++--- configure.py | 23 ++++++++++++++--------- doc/log.txt | 18 ++++++++++++++++++ readme.txt | 2 +- src/constructs/srp6/srp6.cpp | 4 ++-- src/math/numbertheory/powm_fw.cpp | 20 ++++++++++++-------- src/math/numbertheory/powm_mnt.cpp | 37 +++++++++++++++++++++++-------------- src/pubkey/dh/dh.cpp | 3 +++ src/utils/version.cpp | 32 +++++++++++++++++--------------- 9 files changed, 93 insertions(+), 52 deletions(-) Attached is the 1.10.3 to 1.10.4 patch (I have tried to dig the individual patches from monotone, but I have discovered that I don't have a time to learn yet another revision system with weird syntax, so unless you force me to do it, I would like to skip this part.) unblock botan1.10/1.10.4-1 -- System Information: Debian Release: 7.0 APT prefers testing APT policy: (500, 'testing') Architecture: amd64 (x86_64) Kernel: Linux 3.2.0-3-amd64 (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash
diff --git a/botan_version.py b/botan_version.py index 1ad9b89..72fda66 100644 --- a/botan_version.py +++ b/botan_version.py @@ -1,9 +1,9 @@ release_major = 1 release_minor = 10 -release_patch = 3 +release_patch = 4 -release_vc_rev = 'mtn:7b193c2f27bc5bdbdd4297c5e53acfe4e4624bdb' +release_vc_rev = 'mtn:d7a8dbe5ea390b354623a869b96f95c4b2a37bae' release_so_abi_rev = 0 -release_datestamp = 20120710 +release_datestamp = 20120107 diff --git a/configure.py b/configure.py index 71d2a3d..b606e06 100755 --- a/configure.py +++ b/configure.py @@ -1780,7 +1780,7 @@ def main(argv = None): gcc_version = stdout.strip() logging.info('Detected gcc version %s' % (gcc_version)) - return gcc_version + return map(int, gcc_version.split('.')[0:2]) except OSError: logging.warning('Could not execute %s for version check' % (gcc_bin)) return None @@ -1792,24 +1792,29 @@ def main(argv = None): gcc_version = get_gcc_version(options.compiler_binary or cc.binary_name) + def gcc_version_matches(matches): + for match in matches.items(): + if gcc_version[0] != match[0]: + continue + + for minor in match[1]: + if minor == gcc_version[1]: + return True + return False + if gcc_version: if not is_64bit_arch(options.arch) and not options.dumb_gcc: - matching_version = '(4\.[01234]\.)|(3\.[34]\.)|(2\.95\.[0-4])' - - if re.search(matching_version, gcc_version): + if gcc_version_matches({ 4 : [0, 1, 2, 3, 4], 3 : [3, 4], 2 : [95] }): options.dumb_gcc = True - versions_without_tr1 = '(4\.0\.)|(3\.[0-4]\.)|(2\.95\.[0-4])' - if options.with_tr1 == None and \ - re.search(versions_without_tr1, gcc_version): + gcc_version_matches({ 4 : [0], 3 : [0,1,2,3,4], 2 : [95] }): logging.info('Disabling TR1 support for this gcc, too old') options.with_tr1 = 'none' - versions_without_visibility = '(3\.[0-4]\.)|(2\.95\.[0-4])' if options.with_visibility == None and \ - re.search(versions_without_visibility, gcc_version): + gcc_version_matches({ 3 : [0,1,2,3,4], 2 : [95] }): logging.info('Disabling DSO visibility support for this gcc, too old') options.with_visibility = False diff --git a/doc/log.txt b/doc/log.txt index 5f95cf4..575f3d4 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -7,6 +7,24 @@ Release Notes Series 1.10 ---------------------------------------- +Version 1.10.4, 2013-01-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Avoid a conditional operation in the power mod implementations on if + a nibble of the exponent was zero or not. This may help protect + against certain forms of side channel attacks. + +* The SRP6 code was checking for invalid values as specified in RFC + 5054, specifically values equal to zero mod p. However SRP would + accept negative A/B values, or ones larger than p, neither of which + should occur in a normal run of the protocol. These values are now + rejected. Credits to Timothy Prepscius for pointing out these values + are not normally used and probably signal something fishy. + +* The return value of version_string is now a compile time constant + string, so version information can be more easily extracted from + binaries. + Version 1.10.3, 2012-07-10 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/readme.txt b/readme.txt index 1044332..792ad25 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -Botan 1.10.3, 2012-07-10 +Botan 1.10.4, 2013-01-07 http://botan.randombit.net/ Botan is a C++ class library for performing a wide variety of diff --git a/src/constructs/srp6/srp6.cpp b/src/constructs/srp6/srp6.cpp index 0dfe210..b1eefa8 100644 --- a/src/constructs/srp6/srp6.cpp +++ b/src/constructs/srp6/srp6.cpp @@ -107,7 +107,7 @@ srp6_client_agree(const std::string& identifier, const size_t p_bytes = group.get_p().bytes(); - if(B % p == 0) + if(B <= 0 || B >= p) throw std::runtime_error("Invalid SRP parameter from server"); BigInt k = hash_seq(hash_id, p_bytes, p, g); @@ -166,7 +166,7 @@ BigInt SRP6_Server_Session::step1(const BigInt& v, SymmetricKey SRP6_Server_Session::step2(const BigInt& A) { - if(A % p == 0) + if(A <= 0 || A >= p) throw std::runtime_error("Invalid SRP parameter from client"); BigInt u = hash_seq(hash_id, p_bytes, A, B); diff --git a/src/math/numbertheory/powm_fw.cpp b/src/math/numbertheory/powm_fw.cpp index 3348e55..8c6d7b6 100644 --- a/src/math/numbertheory/powm_fw.cpp +++ b/src/math/numbertheory/powm_fw.cpp @@ -26,10 +26,12 @@ void Fixed_Window_Exponentiator::set_base(const BigInt& base) { window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints); - g.resize((1 << window_bits) - 1); - g[0] = base; - for(size_t j = 1; j != g.size(); ++j) - g[j] = reducer.multiply(g[j-1], g[0]); + g.resize((1 << window_bits)); + g[0] = 1; + g[1] = base; + + for(size_t i = 2; i != g.size(); ++i) + g[i] = reducer.multiply(g[i-1], g[0]); } /* @@ -40,13 +42,15 @@ BigInt Fixed_Window_Exponentiator::execute() const const size_t exp_nibbles = (exp.bits() + window_bits - 1) / window_bits; BigInt x = 1; - for(size_t j = exp_nibbles; j > 0; --j) + + for(size_t i = exp_nibbles; i > 0; --i) { - for(size_t k = 0; k != window_bits; ++k) + for(size_t j = 0; j != window_bits; ++j) x = reducer.square(x); - if(u32bit nibble = exp.get_substring(window_bits*(j-1), window_bits)) - x = reducer.multiply(x, g[nibble-1]); + const u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits); + + x = reducer.multiply(x, g[nibble]); } return x; } diff --git a/src/math/numbertheory/powm_mnt.cpp b/src/math/numbertheory/powm_mnt.cpp index 8993f4b..884766a 100644 --- a/src/math/numbertheory/powm_mnt.cpp +++ b/src/math/numbertheory/powm_mnt.cpp @@ -27,12 +27,12 @@ void Montgomery_Exponentiator::set_base(const BigInt& base) { window_bits = Power_Mod::window_bits(exp.bits(), base.bits(), hints); - g.resize((1 << window_bits) - 1); + g.resize((1 << window_bits)); SecureVector<word> z(2 * (mod_words + 1)); SecureVector<word> workspace(z.size()); - g[0] = (base >= modulus) ? (base % modulus) : base; + g[0] = 1; bigint_monty_mul(&z[0], z.size(), g[0].data(), g[0].size(), g[0].sig_words(), @@ -42,7 +42,17 @@ void Montgomery_Exponentiator::set_base(const BigInt& base) g[0].assign(&z[0], mod_words + 1); - const BigInt& x = g[0]; + g[1] = (base >= modulus) ? (base % modulus) : base; + + bigint_monty_mul(&z[0], z.size(), + g[1].data(), g[1].size(), g[1].sig_words(), + R2.data(), R2.size(), R2.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + g[1].assign(&z[0], mod_words + 1); + + const BigInt& x = g[1]; const size_t x_sig = x.sig_words(); for(size_t i = 1; i != g.size(); ++i) @@ -86,19 +96,18 @@ BigInt Montgomery_Exponentiator::execute() const x.assign(&z[0], mod_words + 1); } - if(u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits)) - { - const BigInt& y = g[nibble-1]; + const u32bit nibble = exp.get_substring(window_bits*(i-1), window_bits); - zeroise(z); - bigint_monty_mul(&z[0], z.size(), - x.data(), x.size(), x.sig_words(), - y.data(), y.size(), y.sig_words(), - modulus.data(), mod_words, mod_prime, - &workspace[0]); + const BigInt& y = g[nibble]; - x.assign(&z[0], mod_words + 1); - } + zeroise(z); + bigint_monty_mul(&z[0], z.size(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); + + x.assign(&z[0], mod_words + 1); } x.get_reg().resize(2*mod_words+1); diff --git a/src/pubkey/dh/dh.cpp b/src/pubkey/dh/dh.cpp index d58fece..dacae5a 100644 --- a/src/pubkey/dh/dh.cpp +++ b/src/pubkey/dh/dh.cpp @@ -87,6 +87,9 @@ SecureVector<byte> DH_KA_Operation::agree(const byte w[], size_t w_len) { BigInt input = BigInt::decode(w, w_len); + if(input <= 1 || input >= p - 1) + throw Invalid_Argument("DH agreement - invalid key provided"); + BigInt r = blinder.unblind(powermod_x_p(blinder.blind(input))); return BigInt::encode_1363(r, p.bytes()); diff --git a/src/utils/version.cpp b/src/utils/version.cpp index acc8bee..d886587 100644 --- a/src/utils/version.cpp +++ b/src/utils/version.cpp @@ -22,21 +22,23 @@ namespace Botan { */ std::string version_string() { - std::ostringstream out; - - out << "Botan " << version_major() << "." - << version_minor() << "." - << version_patch() << " ("; - - if(BOTAN_VERSION_DATESTAMP == 0) - out << "unreleased version"; - else - out << "released " << version_datestamp(); - - out << ", revision " << BOTAN_VERSION_VC_REVISION; - out << ", distribution " << BOTAN_DISTRIBUTION_INFO << ")"; - - return out.str(); +#define QUOTE(name) #name +#define STR(macro) QUOTE(macro) + + return "Botan " STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH) " (" + +#if (BOTAN_VERSION_DATESTAMP == 0) + "unreleased version" +#else + "released " STR(BOTAN_VERSION_DATESTAMP) +#endif + ", revision " BOTAN_VERSION_VC_REVISION + ", distribution " BOTAN_DISTRIBUTION_INFO ")"; + +#undef STR +#undef QUOTE } u32bit version_datestamp() { return BOTAN_VERSION_DATESTAMP; }