1 /*
2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.ec;
27 
28 import java.io.IOException;
29 import java.math.BigInteger;
30 import java.security.spec.AlgorithmParameterSpec;
31 import java.security.spec.NamedParameterSpec;
32 import java.util.Collections;
33 import java.util.Map;
34 import java.util.HashMap;
35 import java.util.Optional;
36 import java.util.function.Function;
37 import java.util.function.Supplier;
38 
39 import sun.security.util.ObjectIdentifier;
40 import sun.security.x509.AlgorithmId;
41 
42 public class XECParameters {
43 
44     // Naming/identification parameters
45     private final ObjectIdentifier oid;
46     private final String name;
47 
48     // Curve/field parameters
49     private final int bits;
50     private final BigInteger p;
51     private final int logCofactor;
52     private final int a24;
53     private final byte basePoint;
54 
55     /**
56      *
57      * Construct an object holding the supplied parameters. No parameters are
58      * checked, so this method always succeeds. This method supports
59      * Montgomery curves of the form y^2 = x^3 + ax^2 + x.
60      *
61      * @param bits The number of relevant bits in a public/private key.
62      * @param p The prime that defines the finite field.
63      * @param a24 The value of (a - 2) / 4, where a is the second-degree curve
64      *            coefficient.
65      * @param basePoint The point that generates the desired group
66      * @param logCofactor The base-2 logarithm of the cofactor of the curve
67      * @param oid
68      * @param name
69      */
XECParameters(int bits, BigInteger p, int a24, byte basePoint, int logCofactor, ObjectIdentifier oid, String name)70     public XECParameters(int bits, BigInteger p, int a24,
71                          byte basePoint, int logCofactor,
72                          ObjectIdentifier oid, String name) {
73 
74         this.bits = bits;
75         this.logCofactor = logCofactor;
76         this.p = p;
77         this.a24 = a24;
78         this.basePoint = basePoint;
79         this.oid = oid;
80         this.name = name;
81 
82     }
83 
getBits()84     public int getBits() {
85         return bits;
86     }
getBytes()87     public int getBytes() {
88         return (bits + 7) / 8;
89     }
getLogCofactor()90     public int getLogCofactor() {
91         return logCofactor;
92     }
getP()93     public BigInteger getP() {
94         return p;
95     }
getA24()96     public int getA24() {
97         return a24;
98     }
getBasePoint()99     public byte getBasePoint() {
100         return basePoint;
101     }
getOid()102     public ObjectIdentifier getOid() {
103         return oid;
104     }
getName()105     public String getName() {
106         return name;
107     }
108 
109     private static final Map<Integer, XECParameters> SIZE_MAP;
110     private static final Map<ObjectIdentifier, XECParameters> OID_MAP;
111     private static final Map<String, XECParameters> NAME_MAP;
112 
113     static {
114         final BigInteger TWO = BigInteger.valueOf(2);
115 
116         Map<Integer, XECParameters> bySize = new HashMap<>();
117         Map<ObjectIdentifier, XECParameters> byOid = new HashMap<>();
118         Map<String, XECParameters> byName = new HashMap<>();
119 
120         // set up X25519
121         try {
122             BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19));
123             addParameters(255, p, 121665, (byte) 0x09, 3,
124                 new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(),
125                 bySize, byOid, byName);
126 
127         } catch (IOException ex) {
128             // Unable to set X25519 parameters---it will be disabled
129         }
130 
131         // set up X448
132         try {
133             BigInteger p = TWO.pow(448).subtract(TWO.pow(224))
134                 .subtract(BigInteger.ONE);
135             addParameters(448, p, 39081, (byte) 0x05, 2,
136                 new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(),
137                 bySize, byOid, byName);
138 
139         } catch (IOException ex) {
140             // Unable to set X448 parameters---it will be disabled
141         }
142 
143         SIZE_MAP = Collections.unmodifiableMap(bySize);
144         OID_MAP = Collections.unmodifiableMap(byOid);
145         NAME_MAP = Collections.unmodifiableMap(byName);
146     }
147 
addParameters(int bits, BigInteger p, int a24, byte basePoint, int logCofactor, int[] oidBytes, String name, Map<Integer, XECParameters> bySize, Map<ObjectIdentifier, XECParameters> byOid, Map<String, XECParameters> byName)148     private static void addParameters(int bits, BigInteger p, int a24,
149         byte basePoint, int logCofactor, int[] oidBytes, String name,
150         Map<Integer, XECParameters> bySize,
151         Map<ObjectIdentifier, XECParameters> byOid,
152         Map<String, XECParameters> byName) throws IOException {
153 
154         ObjectIdentifier oid = new ObjectIdentifier(oidBytes);
155         XECParameters params =
156             new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
157         bySize.put(bits, params);
158         byOid.put(oid, params);
159         byName.put(name.toLowerCase(), params);
160     }
161 
getByOid(ObjectIdentifier id)162     public static Optional<XECParameters> getByOid(ObjectIdentifier id) {
163         return Optional.ofNullable(OID_MAP.get(id));
164     }
getBySize(int size)165     public static Optional<XECParameters> getBySize(int size) {
166         return Optional.ofNullable(SIZE_MAP.get(size));
167     }
getByName(String name)168     public static Optional<XECParameters> getByName(String name) {
169         return Optional.ofNullable(NAME_MAP.get(name.toLowerCase()));
170     }
171 
oidEquals(XECParameters other)172     boolean oidEquals(XECParameters other) {
173         return oid.equals(other.getOid());
174     }
175 
176     // Utility method that is used by the methods below to handle exception
177     // suppliers
178     private static
apply(final Function<A, B> func, final A a)179     <A, B> Supplier<B> apply(final Function<A, B> func, final A a) {
180         return new Supplier<B>() {
181             @Override
182             public B get() {
183                 return func.apply(a);
184             }
185         };
186     }
187 
188     /**
189      * Get parameters by key size, or throw an exception if no parameters are
190      * defined for the specified key size. This method is used in several
191      * contexts that should throw different exceptions when the parameters
192      * are not found. The first argument is a function that produces the
193      * desired exception.
194      *
195      * @param exception a function that produces an exception from a string
196      * @param size the desired key size
197      * @param <T> the type of exception that is thrown
198      * @return the parameters for the specified key size
199      * @throws T when suitable parameters do not exist
200      */
201     public static
202     <T extends Throwable>
203     XECParameters getBySize(Function<String, T> exception,
204                             int size) throws T {
205 
206         Optional<XECParameters> xecParams = getBySize(size);
207         return xecParams.orElseThrow(
208             apply(exception, "Unsupported size: " + size));
209     }
210 
211     /**
212      * Get parameters by algorithm ID, or throw an exception if no
213      * parameters are defined for the specified ID. This method is used in
214      * several contexts that should throw different exceptions when the
215      * parameters are not found. The first argument is a function that produces
216      * the desired exception.
217      *
218      * @param exception a function that produces an exception from a string
219      * @param algId the algorithm ID
220      * @param <T> the type of exception that is thrown
221      * @return the parameters for the specified algorithm ID
222      * @throws T when suitable parameters do not exist
223      */
224     public static
225     <T extends Throwable>
226     XECParameters get(Function<String, T> exception,
227                       AlgorithmId algId) throws T {
228 
229         Optional<XECParameters> xecParams = getByOid(algId.getOID());
230         return xecParams.orElseThrow(
231             apply(exception, "Unsupported OID: " + algId.getOID()));
232     }
233 
234     /**
235      * Get parameters by algorithm parameter spec, or throw an exception if no
236      * parameters are defined for the spec. This method is used in
237      * several contexts that should throw different exceptions when the
238      * parameters are not found. The first argument is a function that produces
239      * the desired exception.
240      *
241      * @param exception a function that produces an exception from a string
242      * @param params the algorithm parameters spec
243      * @param <T> the type of exception that is thrown
244      * @return the parameters for the spec
245      * @throws T when suitable parameters do not exist
246      */
247     public static
248     <T extends Throwable>
249     XECParameters get(Function<String, T> exception,
250                       AlgorithmParameterSpec params) throws T {
251 
252         if (params instanceof NamedParameterSpec) {
253             NamedParameterSpec namedParams = (NamedParameterSpec) params;
254             Optional<XECParameters> xecParams =
255                 getByName(namedParams.getName());
256             return xecParams.orElseThrow(
257                 apply(exception, "Unsupported name: " + namedParams.getName()));
258         } else {
259             throw exception.apply("Only NamedParameterSpec is supported.");
260         }
261     }
262 }
263 
264