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// TODO(bleichen): RFC 3279 allows ECKeys with a number of different parameters.
18//   E.g. public keys can specify the order, base points etc.
19//   We might want to check how well these parameters are verified when parsing
20//   a public key.
21
22package com.google.security.wycheproof;
23
24import java.math.BigInteger;
25import java.security.InvalidAlgorithmParameterException;
26import java.security.KeyFactory;
27import java.security.KeyPair;
28import java.security.KeyPairGenerator;
29import java.security.interfaces.ECPrivateKey;
30import java.security.interfaces.ECPublicKey;
31import java.security.spec.ECParameterSpec;
32import java.security.spec.ECPoint;
33import java.security.spec.ECPublicKeySpec;
34import java.security.spec.InvalidKeySpecException;
35import java.security.spec.PKCS8EncodedKeySpec;
36import java.security.spec.X509EncodedKeySpec;
37import junit.framework.TestCase;
38
39/** EC tests */
40public class EcKeyTest extends TestCase {
41  /**
42   * Encodings of public keys with invalid parameters. There are multiple places where a provider
43   * can validate a public key: some parameters are typically validated by the KeyFactory, more
44   * validation can be done by the cryptographic primitive. Unused parameters are sometimes not
45   * validated at all.
46   *
47   * <p>This following test vectors are public key encodings with invalid parameters where we expect
48   * that KeyFactory.generatePublic recognizes the problem. The documentation simply claims that an
49   * InvalidKeySpecException is thrown if the given key specification is inappropriate but does not
50   * specify what an appropriate key exactly is. Nonetheless we expect that the following minimal
51   * validations are performed: order is a positive integer, cofactor is a small positive integer.
52   * Some modifications may not be detected and must be caught by the primitives using them. E.g.,
53   * it is expensive to verify the order of the group generated by the generator and hence the key
54   * factory may not verify the correctness of this parameter. Thus an implementation of ECDH must
55   * not trust an order claimed in the public key.
56   *
57   * <p>TODO(bleichen): The encoding is defined in https://tools.ietf.org/html/rfc3279 Section
58   * 2.3.5. This document defines a few additional requirements and options which are not yet
59   * checked: - OID for id-public-key_type must be ansi-X9.62 2 - OID for id-ecPublicKey must be
60   * id-publicKeyType 1 - The intended application for the key may be indicated in the key usage
61   * field (RFC 3280). - EcpkParameters can be implicitlyCA (not sure how we would specify the curve
62   * in this case) - the version is always 1 - the points on the curves can be either compressed or
63   * uncompressed (so far all points are uncompressed) - the seed value is optional (so far no test
64   * vector specifies the seed) - the cofactor is optional but must be included for ECDH keys. (so
65   * far all test vectors have a cofactor)
66   *
67   * <p>RFC 3279 also specifies curves over binary fields. Because of attacks against such curves,
68   * i.e. "New algorithm for the discrete logarithm problem on elliptic curves" by I.Semaev
69   * https://eprint.iacr.org/2015/310 such curves should no longer be used and hence testing them
70   * has low priority.
71   */
72  public static final String[] EC_INVALID_PUBLIC_KEYS = {
73    // order = -115792089210356248762697446949407573529996955224135760342422259061068512044369
74    "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
75        + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
76        + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
77        + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
78        + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
79        + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
80        + "576b315ececbb6406837bf51f50221ff00000000ffffffff0000000000000000"
81        + "4319055258e8617b0c46353d039cdaaf02010103420004cdeb39edd03e2b1a11"
82        + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
83        + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
84    // order = 0
85    "308201123081cb06072a8648ce3d02013081bf020101302c06072a8648ce3d01"
86        + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
87        + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
88        + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
89        + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
90        + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
91        + "576b315ececbb6406837bf51f5020002010103420004cdeb39edd03e2b1a11a5"
92        + "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
93        + "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
94    // cofactor = -1
95    "308201333081ec06072a8648ce3d02013081e0020101302c06072a8648ce3d01"
96        + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
97        + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
98        + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
99        + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
100        + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
101        + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
102        + "bce6faada7179e84f3b9cac2fc6325510201ff03420004cdeb39edd03e2b1a11"
103        + "a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b"
104        + "49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
105    // cofactor = 0
106    "308201323081eb06072a8648ce3d02013081df020101302c06072a8648ce3d01"
107        + "01022100ffffffff00000001000000000000000000000000ffffffffffffffff"
108        + "ffffffff30440420ffffffff00000001000000000000000000000000ffffffff"
109        + "fffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53"
110        + "b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277037d"
111        + "812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33"
112        + "576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffff"
113        + "bce6faada7179e84f3b9cac2fc632551020003420004cdeb39edd03e2b1a11a5"
114        + "e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b8429598c0b49"
115        + "bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
116    // cofactor = 115792089210356248762697446949407573529996955224135760342422259061068512044369
117    "308201553082010d06072a8648ce3d020130820100020101302c06072a8648ce"
118        + "3d0101022100ffffffff00000001000000000000000000000000ffffffffffff"
119        + "ffffffffffff30440420ffffffff00000001000000000000000000000000ffff"
120        + "fffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0"
121        + "cc53b0f63bce3c3e27d2604b0441046b17d1f2e12c4247f8bce6e563a440f277"
122        + "037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162b"
123        + "ce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffff"
124        + "ffffbce6faada7179e84f3b9cac2fc632551022100ffffffff00000000ffffff"
125        + "ffffffffffbce6faada7179e84f3b9cac2fc63255103420004cdeb39edd03e2b"
126        + "1a11a5e134ec99d5f25f21673d403f3ecb47bd1fa676638958ea58493b842959"
127        + "8c0b49bbb85c3303ddb1553c3b761c2caacca71606ba9ebac8",
128  };
129
130  public void testEncodedPublicKey() throws Exception {
131    KeyFactory kf = KeyFactory.getInstance("EC");
132    for (String encodedHex : EC_INVALID_PUBLIC_KEYS) {
133      byte[] encoded = TestUtil.hexToBytes(encodedHex);
134      X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(encoded);
135      try {
136        ECPublicKey unused = (ECPublicKey) kf.generatePublic(x509keySpec);
137        fail("Constructed invalid public key from:" + encodedHex);
138      } catch (InvalidKeySpecException ex) {
139        // OK, since the public keys have been modified.
140        System.out.println(ex.toString());
141      }
142    }
143  }
144
145  public void testEncodedPrivateKey() throws Exception {
146    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
147    keyGen.initialize(EcUtil.getNistP256Params());
148    KeyPair keyPair = keyGen.generateKeyPair();
149    ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
150    byte[] encoded = priv.getEncoded();
151    System.out.println("Encoded ECPrivateKey:" + TestUtil.bytesToHex(encoded));
152    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
153    KeyFactory kf = KeyFactory.getInstance("EC");
154    ECPrivateKey decoded = (ECPrivateKey) kf.generatePrivate(spec);
155    assertEquals(priv.getS(), decoded.getS());
156    assertEquals(priv.getParams().getCofactor(), decoded.getParams().getCofactor());
157    assertEquals(priv.getParams().getCurve(), decoded.getParams().getCurve());
158    assertEquals(priv.getParams().getGenerator(), decoded.getParams().getGenerator());
159    assertEquals(priv.getParams().getOrder(), decoded.getParams().getOrder());
160  }
161
162  /**
163   * Tests key generation for given parameters. The test can be skipped if the curve is not a
164   * standard curve.
165   */
166  void testKeyGeneration(ECParameterSpec ecParams, boolean isStandard) throws Exception {
167    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
168    KeyPair keyPair;
169    try {
170      keyGen.initialize(ecParams);
171      keyPair = keyGen.generateKeyPair();
172    } catch (InvalidAlgorithmParameterException ex) {
173      if (!isStandard) {
174        return;
175      }
176      throw ex;
177    }
178    ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
179    ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
180    EcUtil.checkPublicKey(pub);
181    BigInteger s = priv.getS();
182    // Check the length of s. Could fail with probability 2^{-32}.
183    assertTrue(s.bitLength() >= EcUtil.fieldSizeInBits(ecParams.getCurve()) - 32);
184    // TODO(bleichen): correct curve?
185    // TODO(bleichen): use RandomUtil
186  }
187
188  public void testKeyGenerationAll() throws Exception {
189    testKeyGeneration(EcUtil.getNistP224Params(), true);
190    testKeyGeneration(EcUtil.getNistP256Params(), true);
191    testKeyGeneration(EcUtil.getNistP384Params(), true);
192    testKeyGeneration(EcUtil.getNistP521Params(), true);
193    // Curves that are sometimes not supported.
194    testKeyGeneration(EcUtil.getBrainpoolP256r1Params(), false);
195  }
196
197  /**
198   * Checks that the default key size for ECDSA is up to date.
199   * The test uses NIST SP 800-57 part1 revision 4, Table 2, page 53
200   * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf
201   * for the minimal key size of EC keys.
202   * Nist recommends a minimal security strength of 112 bits for the time until 2030.
203   * To achieve this security strength EC keys of at least 224 bits are required.
204   */
205  public void testDefaultKeyGeneration() throws Exception {
206    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
207    KeyPair keyPair = keyGen.generateKeyPair();
208    ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
209    int keySize = EcUtil.fieldSizeInBits(pub.getParams().getCurve());
210    if (keySize < 224) {
211      fail("Expected a default key size of at least 224 bits. Size of generate key is " + keySize);
212    }
213  }
214
215  /**
216   * Tries to generate a public key with a point at infinity. Public keys with a point at infinity
217   * should be rejected to prevent subgroup confinement attacks.
218   */
219  public void testPublicKeyAtInfinity() throws Exception {
220    ECParameterSpec ecSpec = EcUtil.getNistP256Params();
221    try {
222      ECPublicKeySpec pubSpec = new ECPublicKeySpec(ECPoint.POINT_INFINITY, ecSpec);
223      fail(
224          "Point at infinity is not a valid public key. "
225              + pubSpec.getW().equals(ECPoint.POINT_INFINITY));
226    } catch (java.lang.IllegalArgumentException ex) {
227      // This is expected
228    }
229  }
230}
231