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