1 /*
  2  * Copyright (c) 2009, 2020, 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.security.AccessController;
 29 import java.security.InvalidParameterException;
 30 import java.security.NoSuchAlgorithmException;
 31 import java.security.PrivilegedAction;
 32 import java.security.Provider;
 33 import java.security.ProviderException;
 34 import java.util.Collection;
 35 import java.util.Collections;
 36 import java.util.HashMap;
 37 import java.util.List;
 38 
 39 import sun.security.ec.ed.EdDSAAlgorithmParameters;
 40 import sun.security.ec.ed.EdDSAKeyFactory;
 41 import sun.security.ec.ed.EdDSAKeyPairGenerator;
 42 import sun.security.ec.ed.EdDSASignature;
 43 import sun.security.util.CurveDB;
 44 import sun.security.util.NamedCurve;
 45 
 46 import static sun.security.util.SecurityConstants.PROVIDER_VER;
 47 import static sun.security.util.SecurityProviderConstants.*;
 48 
 49 /**
 50  * Provider class for the Elliptic Curve provider.
 51  * Supports EC keypair and parameter generation, ECDSA signing and
 52  * ECDH key agreement.
 53  *
 54  * IMPLEMENTATION NOTE:
 55  * The Java classes in this provider access a native ECC implementation
 56  * via JNI to a C++ wrapper class which in turn calls C functions.
 57  * The Java classes are packaged into the jdk.crypto.sunec module and the
 58  * C++ and C functions are packaged into libsunec.so or sunec.dll in the
 59  * JRE native libraries directory.  If the native library is not present
 60  * then this provider is registered with support for fewer ECC algorithms
 61  * (KeyPairGenerator, Signature and KeyAgreement are omitted).
 62  *
 63  * @since   1.7
 64  */
 65 public final class SunEC extends Provider {
 66 
 67     private static final long serialVersionUID = -2279741672933606418L;
 68 
 69     // This flag is true if the native library is disabled or not loaded.
 70     private static boolean disableNative = true;
 71 
 72     static {
 73         String s = sun.security.action.GetPropertyAction.privilegedGetProperty(
 74                 "jdk.sunec.disableNative");
 75         if (s != null && s.equalsIgnoreCase("false")) {
 76             disableNative = false;
 77         }
 78 
 79         // If native is enabled, verify the library is available.
 80         if (!disableNative) {
 81             try {
 82                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
 83                     public Void run() {
 84                         System.loadLibrary("sunec"); // check for native library
 85                         return null;
 86                     }
 87                 });
 88             } catch (UnsatisfiedLinkError e) {
 89                 disableNative = true;
 90             }
 91         }
 92     }
 93 
 94     // Check if native library support is disabled.
 95     static boolean isNativeDisabled() {
 96         return SunEC.disableNative;
 97     }
 98 
 99     private static class ProviderServiceA extends ProviderService {
100         ProviderServiceA(Provider p, String type, String algo, String cn,
101             HashMap<String, String> attrs) {
102             super(p, type, algo, cn, getAliases(algo), attrs);
103         }
104     }
105 
106     private static class ProviderService extends Provider.Service {
107 
108         ProviderService(Provider p, String type, String algo, String cn) {
109             super(p, type, algo, cn, null, null);
110         }
111 
112         ProviderService(Provider p, String type, String algo, String cn,
113             List<String> aliases, HashMap<String, String> attrs) {
114             super(p, type, algo, cn, aliases, attrs);
115         }
116 
117         @Override
118         public Object newInstance(Object ctrParamObj)
119             throws NoSuchAlgorithmException {
120             String type = getType();
121             if (ctrParamObj != null) {
122                 throw new InvalidParameterException
123                     ("constructorParameter not used with " + type + " engines");
124             }
125 
126             String algo = getAlgorithm();
127             try {
128                 if (type.equals("Signature")) {
129 
130                     if (algo.equalsIgnoreCase("EdDSA")) {
131                         return new EdDSASignature();
132                     } else if (algo.equalsIgnoreCase("Ed25519")) {
133                         return new EdDSASignature.Ed25519();
134                     } else if (algo.equalsIgnoreCase("Ed448")) {
135                         return new EdDSASignature.Ed448();
136                     }
137 
138                     boolean inP1363 = algo.endsWith("inP1363Format");
139                     if (inP1363) {
140                         algo = algo.substring(0, algo.length() - 13);
141                     }
142                     if (algo.equals("SHA1withECDSA")) {
143                         return (inP1363? new ECDSASignature.SHA1inP1363Format() :
144                             new ECDSASignature.SHA1());
145                     } else if (algo.equals("SHA224withECDSA")) {
146                         return (inP1363? new ECDSASignature.SHA224inP1363Format() :
147                             new ECDSASignature.SHA224());
148                     } else if (algo.equals("SHA256withECDSA")) {
149                         return (inP1363? new ECDSASignature.SHA256inP1363Format() :
150                             new ECDSASignature.SHA256());
151                     } else if (algo.equals("SHA384withECDSA")) {
152                         return (inP1363? new ECDSASignature.SHA384inP1363Format() :
153                             new ECDSASignature.SHA384());
154                     } else if (algo.equals("SHA512withECDSA")) {
155                         return (inP1363? new ECDSASignature.SHA512inP1363Format() :
156                             new ECDSASignature.SHA512());
157                     } else if (algo.equals("NONEwithECDSA")) {
158                         return (inP1363? new ECDSASignature.RawinP1363Format() :
159                             new ECDSASignature.Raw());
160                     }
161                 } else  if (type.equals("KeyFactory")) {
162                     if (algo.equals("EC")) {
163                         return new ECKeyFactory();
164                     } else if (algo.equals("XDH")) {
165                         return new XDHKeyFactory();
166                     } else if (algo.equals("X25519")) {
167                         return new XDHKeyFactory.X25519();
168                     } else if (algo.equals("X448")) {
169                         return new XDHKeyFactory.X448();
170                     } else if (algo.equalsIgnoreCase("EdDSA")) {
171                         return new EdDSAKeyFactory();
172                     } else if (algo.equalsIgnoreCase("Ed25519")) {
173                         return new EdDSAKeyFactory.Ed25519();
174                     } else if (algo.equalsIgnoreCase("Ed448")) {
175                         return new EdDSAKeyFactory.Ed448();
176                     }
177                 } else  if (type.equals("AlgorithmParameters")) {
178                     if (algo.equals("EC")) {
179                         return new sun.security.util.ECParameters();
180                     }
181                 } else  if (type.equals("KeyPairGenerator")) {
182                     if (algo.equals("EC")) {
183                         return new ECKeyPairGenerator();
184                     } else if (algo.equals("XDH")) {
185                         return new XDHKeyPairGenerator();
186                     } else if (algo.equals("X25519")) {
187                         return new XDHKeyPairGenerator.X25519();
188                     } else if (algo.equals("X448")) {
189                         return new XDHKeyPairGenerator.X448();
190                     } else if (algo.equalsIgnoreCase("EdDSA")) {
191                         return new EdDSAKeyPairGenerator();
192                     } else if (algo.equalsIgnoreCase("Ed25519")) {
193                         return new EdDSAKeyPairGenerator.Ed25519();
194                     } else if (algo.equalsIgnoreCase("Ed448")) {
195                         return new EdDSAKeyPairGenerator.Ed448();
196                     }
197                 } else  if (type.equals("KeyAgreement")) {
198                     if (algo.equals("ECDH")) {
199                         return new ECDHKeyAgreement();
200                     } else if (algo.equals("XDH")) {
201                         return new XDHKeyAgreement();
202                     } else if (algo.equals("X25519")) {
203                         return new XDHKeyAgreement.X25519();
204                     } else if (algo.equals("X448")) {
205                         return new XDHKeyAgreement.X448();
206                     }
207                 }
208             } catch (Exception ex) {
209                 throw new NoSuchAlgorithmException("Error constructing " +
210                     type + " for " + algo + " using SunEC", ex);
211             }
212             throw new ProviderException("No impl for " + algo +
213                 " " + type);
214         }
215     }
216 
217     public SunEC() {
218         super("SunEC", PROVIDER_VER, "Sun Elliptic Curve provider");
219         AccessController.doPrivileged(new PrivilegedAction<Void>() {
220             public Void run() {
221                 putEntries();
222                 return null;
223             }
224         });
225     }
226 
227     void putEntries() {
228         HashMap<String, String> ATTRS = new HashMap<>(3);
229         ATTRS.put("ImplementedIn", "Software");
230         String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
231                  "|java.security.interfaces.ECPrivateKey";
232         ATTRS.put("SupportedKeyClasses", ecKeyClasses);
233         ATTRS.put("KeySize", "256");
234 
235         /*
236          *  Key Factory engine
237          */
238         putService(new ProviderService(this, "KeyFactory",
239             "EC", "sun.security.ec.ECKeyFactory",
240             List.of("EllipticCurve"), ATTRS));
241 
242         /*
243          * Algorithm Parameter engine
244          */
245         // "AlgorithmParameters.EC SupportedCurves" prop used by unit test
246         boolean firstCurve = true;
247         StringBuilder names = new StringBuilder();
248 
249         Collection<? extends NamedCurve> supportedCurves;
250         if (SunEC.isNativeDisabled()) {
251             supportedCurves = Collections.unmodifiableList(List.of(
252                     CurveDB.lookup("secp256r1"),
253                     CurveDB.lookup("secp384r1"),
254                     CurveDB.lookup("secp521r1")));
255         } else {
256             supportedCurves = CurveDB.getSupportedCurves();
257         }
258 
259         for (NamedCurve namedCurve : supportedCurves) {
260             if (!firstCurve) {
261                 names.append("|");
262             } else {
263                 firstCurve = false;
264             }
265 
266             names.append("[");
267             String[] commonNames = namedCurve.getNameAndAliases();
268             for (String commonName : commonNames) {
269                 names.append(commonName);
270                 names.append(",");
271             }
272 
273             names.append(namedCurve.getObjectId());
274             names.append("]");
275         }
276 
277         HashMap<String, String> apAttrs = new HashMap<>(ATTRS);
278         apAttrs.put("SupportedCurves", names.toString());
279 
280         putService(new ProviderServiceA(this, "AlgorithmParameters",
281             "EC", "sun.security.util.ECParameters", apAttrs));
282 
283         putXDHEntries();
284         putEdDSAEntries();
285 
286         /*
287          * Signature engines
288          */
289         putService(new ProviderService(this, "Signature",
290             "NONEwithECDSA", "sun.security.ec.ECDSASignature$Raw",
291             null, ATTRS));
292         putService(new ProviderServiceA(this, "Signature",
293             "SHA1withECDSA", "sun.security.ec.ECDSASignature$SHA1",
294             ATTRS));
295         putService(new ProviderServiceA(this, "Signature",
296             "SHA224withECDSA", "sun.security.ec.ECDSASignature$SHA224",
297             ATTRS));
298         putService(new ProviderServiceA(this, "Signature",
299             "SHA256withECDSA", "sun.security.ec.ECDSASignature$SHA256",
300             ATTRS));
301         putService(new ProviderServiceA(this, "Signature",
302             "SHA384withECDSA", "sun.security.ec.ECDSASignature$SHA384",
303             ATTRS));
304         putService(new ProviderServiceA(this, "Signature",
305             "SHA512withECDSA", "sun.security.ec.ECDSASignature$SHA512",
306             ATTRS));
307 
308         putService(new ProviderService(this, "Signature",
309              "NONEwithECDSAinP1363Format",
310              "sun.security.ec.ECDSASignature$RawinP1363Format"));
311         putService(new ProviderService(this, "Signature",
312              "SHA1withECDSAinP1363Format",
313              "sun.security.ec.ECDSASignature$SHA1inP1363Format"));
314         putService(new ProviderService(this, "Signature",
315              "SHA224withECDSAinP1363Format",
316              "sun.security.ec.ECDSASignature$SHA224inP1363Format"));
317         putService(new ProviderService(this, "Signature",
318              "SHA256withECDSAinP1363Format",
319              "sun.security.ec.ECDSASignature$SHA256inP1363Format"));
320         putService(new ProviderService(this, "Signature",
321             "SHA384withECDSAinP1363Format",
322             "sun.security.ec.ECDSASignature$SHA384inP1363Format"));
323         putService(new ProviderService(this, "Signature",
324             "SHA512withECDSAinP1363Format",
325             "sun.security.ec.ECDSASignature$SHA512inP1363Format"));
326 
327         /*
328          *  Key Pair Generator engine
329          */
330         putService(new ProviderService(this, "KeyPairGenerator",
331             "EC", "sun.security.ec.ECKeyPairGenerator",
332             List.of("EllipticCurve"), ATTRS));
333 
334         /*
335          * Key Agreement engine
336          */
337         putService(new ProviderService(this, "KeyAgreement",
338             "ECDH", "sun.security.ec.ECDHKeyAgreement", null, ATTRS));
339     }
340 
341     private void putXDHEntries() {
342 
343         HashMap<String, String> ATTRS = new HashMap<>(1);
344         ATTRS.put("ImplementedIn", "Software");
345 
346         /* XDH does not require native implementation */
347         putService(new ProviderService(this, "KeyFactory",
348             "XDH", "sun.security.ec.XDHKeyFactory", null, ATTRS));
349         putService(new ProviderServiceA(this, "KeyFactory",
350             "X25519", "sun.security.ec.XDHKeyFactory.X25519",
351             ATTRS));
352         putService(new ProviderServiceA(this, "KeyFactory",
353             "X448", "sun.security.ec.XDHKeyFactory.X448",
354             ATTRS));
355 
356         putService(new ProviderService(this, "KeyPairGenerator",
357             "XDH", "sun.security.ec.XDHKeyPairGenerator", null, ATTRS));
358         putService(new ProviderServiceA(this, "KeyPairGenerator",
359             "X25519", "sun.security.ec.XDHKeyPairGenerator.X25519",
360             ATTRS));
361         putService(new ProviderServiceA(this, "KeyPairGenerator",
362             "X448", "sun.security.ec.XDHKeyPairGenerator.X448",
363             ATTRS));
364 
365         putService(new ProviderService(this, "KeyAgreement",
366             "XDH", "sun.security.ec.XDHKeyAgreement", null, ATTRS));
367         putService(new ProviderServiceA(this, "KeyAgreement",
368             "X25519", "sun.security.ec.XDHKeyAgreement.X25519",
369             ATTRS));
370         putService(new ProviderServiceA(this, "KeyAgreement",
371             "X448", "sun.security.ec.XDHKeyAgreement.X448",
372             ATTRS));
373     }
374 
375     private void putEdDSAEntries() {
376 
377         HashMap<String, String> ATTRS = new HashMap<>(1);
378         ATTRS.put("ImplementedIn", "Software");
379 
380         /* EdDSA does not require native implementation */
381         putService(new ProviderService(this, "KeyFactory",
382             "EdDSA", "sun.security.ec.ed.EdDSAKeyFactory", null, ATTRS));
383         putService(new ProviderServiceA(this, "KeyFactory",
384             "Ed25519", "sun.security.ec.ed.EdDSAKeyFactory.Ed25519", ATTRS));
385         putService(new ProviderServiceA(this, "KeyFactory",
386             "Ed448", "sun.security.ec.ed.EdDSAKeyFactory.Ed448", ATTRS));
387 
388         putService(new ProviderService(this, "KeyPairGenerator",
389             "EdDSA", "sun.security.ec.ed.EdDSAKeyPairGenerator", null, ATTRS));
390         putService(new ProviderServiceA(this, "KeyPairGenerator",
391             "Ed25519", "sun.security.ec.ed.EdDSAKeyPairGenerator.Ed25519",
392             ATTRS));
393         putService(new ProviderServiceA(this, "KeyPairGenerator",
394             "Ed448", "sun.security.ec.ed.EdDSAKeyPairGenerator.Ed448",
395             ATTRS));
396 
397         putService(new ProviderService(this, "Signature",
398             "EdDSA", "sun.security.ec.ed.EdDSASignature", null, ATTRS));
399         putService(new ProviderServiceA(this, "Signature",
400             "Ed25519", "sun.security.ec.ed.EdDSASignature.Ed25519", ATTRS));
401         putService(new ProviderServiceA(this, "Signature",
402             "Ed448", "sun.security.ec.ed.EdDSASignature.Ed448", ATTRS));
403 
404     }
405 }