Home | History | Annotate | Download | only in testcases
      1 /**
      2  * @license
      3  * Copyright 2016 Google Inc. All rights reserved.
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.security.wycheproof;
     18 
     19 import com.google.security.wycheproof.WycheproofRunner.ProviderType;
     20 import com.google.security.wycheproof.WycheproofRunner.SlowTest;
     21 import java.math.BigInteger;
     22 import java.security.GeneralSecurityException;
     23 import java.security.KeyFactory;
     24 import java.security.KeyPair;
     25 import java.security.KeyPairGenerator;
     26 import java.security.PrivateKey;
     27 import java.security.PublicKey;
     28 import javax.crypto.KeyAgreement;
     29 import javax.crypto.interfaces.DHPrivateKey;
     30 import javax.crypto.spec.DHParameterSpec;
     31 import javax.crypto.spec.DHPublicKeySpec;
     32 import junit.framework.TestCase;
     33 
     34 /**
     35  * Testing Diffie-Hellman key agreement.
     36  *
     37  * <p>Subgroup confinment attacks:
     38  * The papers by van Oorshot and Wiener rsp. Lim and Lee show that Diffie-Hellman keys can
     39  * be found much faster if the short exponents are used and if the multiplicative group modulo p
     40  * contains small subgroups. In particular an attacker can try to send a public key that is an
     41  * element of a small subgroup. If the receiver does not check for such elements then may be
     42  * possible to find the private key modulo the order of the small subgroup.
     43  * Several countermeasures against such attacks have been proposed: For example IKE uses
     44  * fields of order p where p is a safe prime (i.e. q=(p-1)/2), hence the only elements of small
     45  * order are 1 and p-1.
     46  * NIST SP 800-56A rev. 2, Section 5.5.1.1 only requires that the size of the subgroup generated
     47  * by the generator g is big enough to prevent the baby-step giant-step algorithm. I.e. for 80-bit
     48  * security p must be at least 1024 bits long and the prime q must be at least 160 bits long. A 2048
     49  * bit prime p and a 224 bit prime q are sufficient for 112 bit security. To avoid subgroup
     50  * confinment attacks NIST requires that public keys are validated, i.e. by checking that a public
     51  * key y satisfies the conditions 2 <= y <= p-2 and y^q mod p == 1 (Section 5.6.2.3.1). Further,
     52  * after generating the shared secret z = y_a ^ x_b mod p each party should check that z != 1. RFC
     53  * 2785 contains similar recommendations.
     54  * The public key validation described by NIST requires that the order q of the generator g
     55  * is known to the verifier. Unfortunately, the order q is missing in PKCS #3. PKCS #3 describes
     56  * the Diffie-Hellman parameters only by the values p, g and optionally the key size in bits.
     57  *
     58  * <p>The class DHParameterSpec that defines the Diffie-Hellman parameters in JCE contains the same
     59  * values as PKCS#3. In particular, it does not contain the order of the subgroup q.
     60  * Moreover, the SUN provider uses the minimal sizes specified by NIST for q.
     61  * Essentially the provider reuses the parameters for DSA.
     62  *
     63  * <p>Therefore, there is no guarantee that an implementation of Diffie-Hellman is secure against
     64  * subgroup confinement attacks. Without a key validation it is insecure to use the key-pair
     65  * generation from NIST SP 800-56A Section 5.6.1.1 (The key-pair generation there only requires that
     66  * static and ephemeral private keys are randomly chosen in the range 1..q-1).
     67  *
     68  * <p>To avoid big disasters the tests below require that key sizes are not minimal. I.e., currently
     69  * the tests require at least 512 bit keys for 1024 bit fields. We use this lower limit because that
     70  * is what the SUN provider is currently doing. TODO(bleichen): Find a reference supporting or
     71  * disproving that decision.
     72  *
     73  * <p>References: P. C. van Oorschot, M. J. Wiener, "On Diffie-Hellman key agreement with short
     74  * exponents", Eurocrypt 96, pp 332343.
     75  *
     76  * <p>C.H. Lim and P.J. Lee, "A key recovery attack on discrete log-based schemes using a prime
     77  * order subgroup", CRYPTO' 98, pp 249263.
     78  *
     79  * <p>NIST SP 800-56A, revision 2, May 2013
     80  * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
     81  *
     82  * <p>PKCS #3, DiffieHellman Key Agreement
     83  * http://uk.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm
     84  *
     85  * <p>RFC 2785, "Methods for Avoiding 'Small-Subgroup' Attacks on the Diffie-Hellman Key Agreement
     86  * Method for S/MIME", March 2000
     87  * https://www.ietf.org/rfc/rfc2785.txt
     88  *
     89  * <p>D. Adrian et al. "Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice"
     90  * https://weakdh.org/imperfect-forward-secrecy-ccs15.pdf
     91  * A good analysis of various DH implementations.
     92  * Some misconfigurations pointed out in the paper are: p is composite, p-1 contains no large
     93  * prime factor, q is used instead of the generator g.
     94  *
     95  * <p>Sources that might be used for additional tests:
     96  *
     97  * CVE-2015-3193: The Montgomery squaring implementation in crypto/bn/asm/x86_64-mont5.pl
     98  * in OpenSSL 1.0.2 before 1.0.2e on the x86_64 platform, as used by the BN_mod_exp function,
     99  * mishandles carry propagation
    100  * https://blog.fuzzing-project.org/31-Fuzzing-Math-miscalculations-in-OpenSSLs-BN_mod_exp-CVE-2015-3193.html
    101  *
    102  * <p>CVE-2016-0739: libssh before 0.7.3 improperly truncates ephemeral secrets generated for the
    103  * (1) diffie-hellman-group1 and (2) diffie-hellman-group14 key exchange methods to 128 bits ...
    104  *
    105  * <p>CVE-2015-1787 The ssl3_get_client_key_exchange function in s3_srvr.c in OpenSSL 1.0.2 before
    106  * 1.0.2a, when client authentication and an ephemeral Diffie-Hellman ciphersuite are enabled,
    107  * allows remote attackers to cause a denial of service (daemon crash) via a ClientKeyExchange
    108  * message with a length of zero.
    109  *
    110  * <p>CVE-2015-0205 The ssl3_get_cert_verify function in s3_srvr.c in OpenSSL 1.0.0 before 1.0.0p
    111  * and 1.0.1 before 1.0.1k accepts client authentication with a Diffie-Hellman (DH) certificate
    112  * without requiring a CertificateVerify message, which allows remote attackers to obtain access
    113  * without knowledge of a private key via crafted TLS Handshake Protocol traffic to a server that
    114  * recognizes a Certification Authority with DH support.
    115  *
    116  * <p>CVE-2016-0701 The DH_check_pub_key function in crypto/dh/dh_check.c in OpenSSL 1.0.2 before
    117  * 1.0.2f does not ensure that prime numbers are appropriate for Diffie-Hellman (DH) key exchange,
    118  * which makes it easier for remote attackers to discover a private DH exponent by making multiple
    119  * handshakes with a peer that chose an inappropriate number, as demonstrated by a number in an
    120  * X9.42 file.
    121  *
    122  * <p>CVE-2006-1115 nCipher HSM before 2.22.6, when generating a Diffie-Hellman public/private key
    123  * pair without any specified DiscreteLogGroup parameters, chooses random parameters that could
    124  * allow an attacker to crack the private key in significantly less time than a brute force attack.
    125  *
    126  * <p>CVE-2015-1716 Schannel in Microsoft Windows Server 2003 SP2, Windows Vista SP2, Windows Server
    127  * 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, and
    128  * Windows RT Gold and 8.1 does not properly restrict Diffie-Hellman Ephemeral (DHE) key lengths,
    129  * which makes it easier for remote attackers to defeat cryptographic protection mechanisms via
    130  * unspecified vectors, aka "Schannel Information Disclosure Vulnerability.
    131  *
    132  * <p>CVE-2015-2419: Random generation of the prime p allows Pohlig-Hellman and probably other
    133  * stuff.
    134  *
    135  * <p> J. Fried et al. "A kilobit hidden SNFS discrete logarithm computation".
    136  * http://eprint.iacr.org/2016/961.pdf
    137  * Some crypto libraries use fields that can be broken with the SNFS.
    138  *
    139  * @author bleichen (at) google.com (Daniel Bleichenbacher)
    140  */
    141 public class DhTest extends TestCase {
    142   public DHParameterSpec ike1536() {
    143     final BigInteger p =
    144         new BigInteger(
    145             "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
    146                 + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
    147                 + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
    148                 + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
    149                 + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
    150                 + "9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff",
    151             16);
    152     final BigInteger g = new BigInteger("2");
    153     return new DHParameterSpec(p, g);
    154   }
    155 
    156   public DHParameterSpec ike2048() {
    157     final BigInteger p =
    158         new BigInteger(
    159             "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
    160                 + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
    161                 + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
    162                 + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
    163                 + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
    164                 + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b"
    165                 + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718"
    166                 + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff",
    167             16);
    168     final BigInteger g = new BigInteger("2");
    169     return new DHParameterSpec(p, g);
    170   }
    171 
    172   // The default parameters returned for 1024 bit DH keys from OpenJdk as defined in
    173   // openjdk7/releases/v6/trunk/jdk/src/share/classes/sun/security/provider/ParameterCache.java
    174   // I.e., these are the same parameters as used for DSA.
    175   public DHParameterSpec openJdk1024() {
    176     final BigInteger p =
    177         new BigInteger(
    178             "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
    179                 + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
    180                 + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
    181                 + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7",
    182             16);
    183     final BigInteger unusedQ = new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16);
    184     final BigInteger g =
    185         new BigInteger(
    186             "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
    187                 + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
    188                 + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
    189                 + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a",
    190             16);
    191     return new DHParameterSpec(p, g);
    192   }
    193 
    194   /** Check that key agreement using DH works. */
    195   @SuppressWarnings("InsecureCryptoUsage")
    196   public void testDh() throws Exception {
    197     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
    198     DHParameterSpec dhparams = ike2048();
    199     keyGen.initialize(dhparams);
    200     KeyPair keyPairA = keyGen.generateKeyPair();
    201     KeyPair keyPairB = keyGen.generateKeyPair();
    202 
    203     KeyAgreement kaA = KeyAgreement.getInstance("DH");
    204     KeyAgreement kaB = KeyAgreement.getInstance("DH");
    205     kaA.init(keyPairA.getPrivate());
    206     kaB.init(keyPairB.getPrivate());
    207     kaA.doPhase(keyPairB.getPublic(), true);
    208     kaB.doPhase(keyPairA.getPublic(), true);
    209     byte[] kAB = kaA.generateSecret();
    210     byte[] kBA = kaB.generateSecret();
    211     assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA));
    212   }
    213 
    214   /**
    215    * Returns the product of primes that can be found by a simple variant of Pollard-rho.
    216    * The result should contain all prime factors of n smaller than 10^8.
    217    * This method is heuristic, since it could in principle find large prime factors too.
    218    * However, for a random 160-bit prime q the probability of this should be less than 2^{-100}.
    219    */
    220   private BigInteger smoothDivisor(BigInteger n) {
    221     // By examination we verified that for every prime p < 10^8
    222     // the iteration x_n = x_{n-1}^2 + 1 mod p enters a cycle of size < 50000 after at
    223     // most 50000 steps.
    224     int pollardRhoSteps = 50000;
    225     BigInteger u = new BigInteger("2");
    226     for (int i = 0; i < pollardRhoSteps; i++) {
    227       u = u.multiply(u).add(BigInteger.ONE).mod(n);
    228     }
    229     BigInteger v = u;
    230     BigInteger prod = BigInteger.ONE;
    231     for (int i = 0; i < pollardRhoSteps; i++) {
    232       v = v.multiply(v).add(BigInteger.ONE).mod(n);
    233       // This implementation is only looking for the product of small primes.
    234       // Therefore, instead of continuously computing gcds of v-u and n, it is sufficient
    235       // and more efficient to compute the product of of v-u for all v and compute the gcd
    236       // at the end.
    237       prod = prod.multiply(v.subtract(u).abs()).mod(n);
    238     }
    239     BigInteger result = BigInteger.ONE;
    240     while (true) {
    241       BigInteger f = n.gcd(prod);
    242       if (f.equals(BigInteger.ONE)) {
    243         return result;
    244       }
    245       result = result.multiply(f);
    246       n = n.divide(f);
    247     }
    248   }
    249 
    250   @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.SPONGY_CASTLE})
    251   public void testKeyPair(KeyPair keyPair, int expectedKeySize) throws Exception {
    252     DHPrivateKey priv = (DHPrivateKey) keyPair.getPrivate();
    253     BigInteger p = priv.getParams().getP();
    254     BigInteger g = priv.getParams().getG();
    255     int keySize = p.bitLength();
    256     assertEquals("wrong key size", keySize, expectedKeySize);
    257 
    258     // Checks the key size of the private key.
    259     // NIST SP 800-56A requires that x is in the range (1, q-1).
    260     // Such a choice would require a full key validation. Since such a validation
    261     // requires the value q (which is not present in the DH parameters) larger keys
    262     // should be chosen to prevent attacks.
    263     int minPrivateKeyBits = keySize / 2;
    264     BigInteger x = priv.getX();
    265     assertTrue(x.bitLength() >= minPrivateKeyBits - 32);
    266     // TODO(bleichen): add tests for weak random number generators.
    267 
    268     // Verify the DH parameters.
    269     System.out.println("p=" + p.toString(16));
    270     System.out.println("g=" + g.toString(16));
    271     System.out.println("testKeyPairGenerator L=" + priv.getParams().getL());
    272     // Basic parameter checks
    273     assertTrue("Expecting g > 1", g.compareTo(BigInteger.ONE) > 0);
    274     assertTrue("Expecting g < p - 1", g.compareTo(p.subtract(BigInteger.ONE)) < 0);
    275     // Expecting p to be prime.
    276     // No high certainty is needed, since this is a unit test.
    277     assertTrue(p.isProbablePrime(4));
    278     // The order of g should be a large prime divisor q of p-1.
    279     // (see e.g. NIST SP 800-56A, section 5.5.1.1.)
    280     // If the order of g is composite then the the Decision Diffie Hellman assumption is
    281     // not satisfied for the group generated by g. Moreover, attacks using Pohlig-Hellman
    282     // might be feasible.
    283     // A good way to achieve these requirements is to select a safe prime p (i.e. a prime
    284     // where q=(p-1)/2 is prime too. NIST SP 800-56A does not require (or even recommend)
    285     // safe primes and allows Diffie-Hellman parameters where q is significantly smaller.
    286     // Unfortunately, the key does not contain q and thus the conditions above  cannot be
    287     // tested easily.
    288     // We perform a partial test that performs a partial factorization of p-1 and then
    289     // test whether one of the small factors found by the partial factorization divides
    290     // the order of g.
    291     boolean isSafePrime = p.shiftRight(1).isProbablePrime(4);
    292     System.out.println("p is a safe prime:" + isSafePrime);
    293     BigInteger r;  // p-1 divided by small prime factors.
    294     if (isSafePrime) {
    295       r = p.shiftRight(1);
    296     } else {
    297       BigInteger p1 = p.subtract(BigInteger.ONE);
    298       r = p1.divide(smoothDivisor(p1));
    299     }
    300     System.out.println("r=" + r.toString(16));
    301     assertEquals("g likely does not generate a prime oder subgroup", BigInteger.ONE,
    302                  g.modPow(r, p));
    303 
    304     // Checks that there are not too many short prime factors.
    305     // I.e., subgroup confinment attacks can find at least keySize - r.bitLength() bits of the key.
    306     // At least 160 unknown bits should remain.
    307     // Only very weak parameters are detected here, since the factorization above only finds small
    308     // prime factors.
    309     assertTrue(minPrivateKeyBits - (keySize - r.bitLength()) > 160);
    310 
    311     // DH parameters are sometime misconfigures and g and q are swapped.
    312     // A large g that divides p-1 is suspicious.
    313     if (g.bitLength() >= 160) {
    314       assertTrue(p.mod(g).compareTo(BigInteger.ONE) > 0);
    315     }
    316   }
    317 
    318   /**
    319    * Tests Diffie-Hellman key pair generation.
    320    *
    321    * <p> This is a slow test since some providers (e.g. BouncyCastle) generate new safe primes
    322    * for each new key.
    323    */
    324   @SuppressWarnings("InsecureCryptoUsage")
    325   public void testKeyPairGenerator() throws Exception {
    326     int keySize = 1024;
    327     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
    328     keyGen.initialize(keySize);
    329     KeyPair keyPair = keyGen.generateKeyPair();
    330     testKeyPair(keyPair, keySize);
    331   }
    332 
    333   /** This test tries a key agreement with keys using distinct parameters. */
    334   @SuppressWarnings("InsecureCryptoUsage")
    335   public void testDHDistinctParameters() throws Exception {
    336     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
    337     keyGen.initialize(ike1536());
    338     KeyPair keyPairA = keyGen.generateKeyPair();
    339 
    340     keyGen.initialize(ike2048());
    341     KeyPair keyPairB = keyGen.generateKeyPair();
    342 
    343     KeyAgreement kaA = KeyAgreement.getInstance("DH");
    344     kaA.init(keyPairA.getPrivate());
    345     try {
    346       kaA.doPhase(keyPairB.getPublic(), true);
    347       byte[] kAB = kaA.generateSecret();
    348       fail("Generated secrets with mixed keys " + TestUtil.bytesToHex(kAB) + ", ");
    349     } catch (java.security.GeneralSecurityException ex) {
    350       // This is expected.
    351     }
    352   }
    353 
    354   /**
    355    * Tests whether a provider accepts invalid public keys that result in predictable shared secrets.
    356    * This test is based on RFC 2785, Section 4 and NIST SP 800-56A, If an attacker can modify both
    357    * public keys in an ephemeral-ephemeral key agreement scheme then it may be possible to coerce
    358    * both parties into computing the same predictable shared key.
    359    *
    360    * <p> Note: the test is quite whimsical. If the prime p is not a safe prime then the provider
    361    * itself cannot prevent all small-subgroup attacks because of the missing parameter q in the
    362    * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones
    363    * proposed in RFC 2785.
    364    *
    365    * <p> CVE-2016-1000346: BouncyCastle before v.1.56 did not validate the other parties public key.
    366    */
    367   @SuppressWarnings("InsecureCryptoUsage")
    368   public void testSubgroupConfinement() throws Exception {
    369     KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
    370     DHParameterSpec params = ike2048();
    371     BigInteger p = params.getP();
    372     BigInteger g = params.getG();
    373     keyGen.initialize(params);
    374     PrivateKey priv = keyGen.generateKeyPair().getPrivate();
    375     KeyAgreement ka = KeyAgreement.getInstance("DH");
    376     BigInteger[] weakPublicKeys = {
    377       BigInteger.ZERO,
    378       BigInteger.ONE,
    379       p.subtract(BigInteger.ONE),
    380       p,
    381       p.add(BigInteger.ONE),
    382       BigInteger.ONE.negate()
    383     };
    384     for (BigInteger weakKey : weakPublicKeys) {
    385       ka.init(priv);
    386       try {
    387         KeyFactory kf = KeyFactory.getInstance("DH");
    388         DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g);
    389         PublicKey pub = kf.generatePublic(weakSpec);
    390         ka.doPhase(pub, true);
    391         byte[] kAB = ka.generateSecret();
    392         fail(
    393             "Generated secrets with weak public key:"
    394                 + weakKey.toString()
    395                 + " secret:"
    396                 + TestUtil.bytesToHex(kAB));
    397       } catch (GeneralSecurityException ex) {
    398         // this is expected
    399       }
    400     }
    401   }
    402 }
    403