CVE-2018-12435 (C++, published 2018-06-15T02:29Z)
Description: value: Botan 2.5.0 through 2.6.0 before 2.7.0 allows a memory-cache side-channel attack on ECDSA signatures, aka the Return Of the Hidden Number Problem or ROHNP, related to dsa/dsa.cpp, ec_group/ec_group.cpp, and ecdsa/ecdsa.cpp. To discover an ECDSA key, the attacker needs access to either the local machine or a different virtual machine on the same physical host.
Severity: LOW (CVSS v3 base score: 5.9)
Weakness: CWE-200 \u2014 Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
Repository: https://github.com/randombit/botan
Files changed:
doc/security.rst
src/lib/pubkey/dsa/dsa.cpp
src/lib/pubkey/ec_group/ec_group.cpp
src/lib/pubkey/ec_group/ec_group.h
src/lib/pubkey/ecdsa/ecdsa.cpp
Commit message: Address DSA/ECDSA side channel


Vulnerable code:
      DSA_Signature_Operation(const DSA_PrivateKey& dsa, const std::string& emsa) :
   BigInt i(msg, msg_len, q.bits());
   while(i >= q)
      i -= q;
   const BigInt k = generate_rfc6979_nonce(m_x, q, i, m_rfc6979_hash);
   BigInt s = inverse_mod(k, q);
   s = m_mod_q.multiply(s, mul_add(m_x, r, i));
         {}
DSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
      return std::unique_ptr<PK_Ops::Signature>(new DSA_Signature_Operation(*this, params));
                                const std::string& emsa) :
   const BigInt k_inv = m_group.inverse_mod_order(k);
   const BigInt xrm = m_group.mod_order(m_group.multiply_mod_order(m_x, r) + m);
   const BigInt s = m_group.multiply_mod_order(k_inv, xrm);
   const BigInt u1 = m_group.multiply_mod_order(e, w);
ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
      return std::unique_ptr<PK_Ops::Signature>(new ECDSA_Signature_Operation(*this, params));

Fixed code:
* 2018-06-13 (CVE-2018-0495): ECDSA side channel

  A side channel in the ECDSA signature operation could allow a local attacker
  to recover the secret key. Found by Keegan Ryan of NCC Group.

  Fixed in 2.7.0. Due to a slight difference in code structure, versions before
  2.5.0 are not affected by this issue.

      DSA_Signature_Operation(const DSA_PrivateKey& dsa,
                              const std::string& emsa,
                              RandomNumberGenerator& rng) :

         m_b = BigInt::random_integer(rng, 2, dsa.group_q());
         m_b_inv = inverse_mod(m_b, dsa.group_q());

      BigInt m_b, m_b_inv;
   BigInt m(msg, msg_len, q.bits());
   while(m >= q)
      m -= q;
   const BigInt k = generate_rfc6979_nonce(m_x, q, m, m_rfc6979_hash);
   const BigInt k_inv = inverse_mod(k, q);

   /*
   * Blind the input message and compute x*r+m as (x*r*b + m*b)/b
   */
   m_b = m_mod_q.square(m_b);
   m_b_inv = m_mod_q.square(m_b_inv);

   m = m_mod_q.multiply(m_b, m);
   const BigInt xr = m_mod_q.multiply(m_mod_q.multiply(m_x, m_b), r);

   const BigInt s = m_mod_q.multiply(m_b_inv, m_mod_q.multiply(k_inv, xr + m));
         {
         }
DSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
      return std::unique_ptr<PK_Ops::Signature>(new DSA_Signature_Operation(*this, params, rng));
      BigInt square_mod_order(const BigInt& x) const
         {
         return m_mod_order.square(x);
         }

      BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const
         {
         return m_mod_order.multiply(m_mod_order.multiply(x, y), z);
         }

BigInt EC_Group::square_mod_order(const BigInt& x) const
   {
   return data().square_mod_order(x);
   }

BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const
   {
   return data().multiply_mod_order(x, y, z);
   }

      /*
      * Reduce (x*x) modulo the order
      */
      BigInt square_mod_order(const BigInt& x) const;

      /*
      * Reduce (x*y*z) modulo the order
      */
      BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const;

                                const std::string& emsa,
                                RandomNumberGenerator& rng) :

         m_b = m_group.random_scalar(rng);
         m_b_inv = m_group.inverse_mod_order(m_b);

      BigInt m_b, m_b_inv;
   const BigInt k_inv = m_group.inverse_mod_order(k);

   /*
   * Blind the input message and compute x*r+m as (x*r*b + m*b)/b
   */
   m_b = m_group.square_mod_order(m_b);
   m_b_inv = m_group.square_mod_order(m_b_inv);

   m = m_group.multiply_mod_order(m_b, m);
   const BigInt xr = m_group.multiply_mod_order(m_x, m_b, r);

   const BigInt s = m_group.multiply_mod_order(k_inv, xr + m, m_b_inv);
   const BigInt u1 = m_group.multiply_mod_order(m_group.mod_order(e), w);
ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
      return std::unique_ptr<PK_Ops::Signature>(new ECDSA_Signature_Operation(*this, params, rng));