1 /*
   2  * Copyright (c) 2009, 2016, 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.util.*;
  29 import java.security.*;
  30 import java.util.regex.Pattern;
  31 import sun.security.util.CurveDB;
  32 import sun.security.util.NamedCurve;
  33 import sun.security.util.ECParameters;
  34 import static sun.security.util.SecurityConstants.PROVIDER_VER;
  35 
  36 /**
  37  * Provider class for the Elliptic Curve provider.
  38  * Supports EC keypair and parameter generation, ECDSA signing and
  39  * ECDH key agreement.
  40  *
  41  * IMPLEMENTATION NOTE:
  42  * The Java classes in this provider access a native ECC implementation
  43  * via JNI to a C++ wrapper class which in turn calls C functions.
  44  * The Java classes are packaged into the jdk.crypto.sunec module and the
  45  * C++ and C functions are packaged into libsunec.so or sunec.dll in the
  46  * JRE native libraries directory.  If the native library is not present
  47  * then this provider is registered with support for fewer ECC algorithms
  48  * (KeyPairGenerator, Signature and KeyAgreement are omitted).
  49  *
  50  * @since   1.7
  51  */
  52 public final class SunEC extends Provider {
  53 
  54     private static final long serialVersionUID = -2279741672933606418L;
  55 
  56     // flag indicating whether the full EC implementation is present
  57     // (when native library is absent then fewer EC algorithms are available)
  58     private static boolean useFullImplementation = true;
  59     static {
  60         try {
  61             AccessController.doPrivileged(new PrivilegedAction<Void>() {
  62                 public Void run() {
  63                     System.loadLibrary("sunec"); // check for native library
  64                     return null;
  65                 }
  66             });
  67         } catch (UnsatisfiedLinkError e) {
  68             useFullImplementation = false;
  69         }
  70     }
  71 
  72     private static class ProviderService extends Provider.Service {
  73 
  74         ProviderService(Provider p, String type, String algo, String cn) {
  75             super(p, type, algo, cn, null, null);
  76         }
  77 
  78         ProviderService(Provider p, String type, String algo, String cn,
  79             String[] aliases, HashMap<String, String> attrs) {
  80             super(p, type, algo, cn,
  81                   (aliases == null? null : Arrays.asList(aliases)), attrs);
  82         }
  83 
  84         @Override
  85         public Object newInstance(Object ctrParamObj)
  86             throws NoSuchAlgorithmException {
  87             String type = getType();
  88             if (ctrParamObj != null) {
  89                 throw new InvalidParameterException
  90                     ("constructorParameter not used with " + type + " engines");
  91             }
  92 
  93             String algo = getAlgorithm();
  94             try {
  95                 if (type.equals("Signature")) {
  96                     boolean inP1363 = algo.endsWith("inP1363Format");
  97                     if (inP1363) {
  98                         algo = algo.substring(0, algo.length() - 13);
  99                     }
 100                     if (algo.equals("SHA1withECDSA")) {
 101                         return (inP1363? new ECDSASignature.SHA1inP1363Format() :
 102                             new ECDSASignature.SHA1());
 103                     } else if (algo.equals("SHA224withECDSA")) {
 104                         return (inP1363? new ECDSASignature.SHA224inP1363Format() :
 105                             new ECDSASignature.SHA224());
 106                     } else if (algo.equals("SHA256withECDSA")) {
 107                         return (inP1363? new ECDSASignature.SHA256inP1363Format() :
 108                             new ECDSASignature.SHA256());
 109                     } else if (algo.equals("SHA384withECDSA")) {
 110                         return (inP1363? new ECDSASignature.SHA384inP1363Format() :
 111                             new ECDSASignature.SHA384());
 112                     } else if (algo.equals("SHA512withECDSA")) {
 113                         return (inP1363? new ECDSASignature.SHA512inP1363Format() :
 114                             new ECDSASignature.SHA512());
 115                     } else if (algo.equals("NONEwithECDSA")) {
 116                         return (inP1363? new ECDSASignature.RawinP1363Format() :
 117                             new ECDSASignature.Raw());
 118                     }
 119                 } else  if (type.equals("KeyFactory")) {
 120                     if (algo.equals("EC")) {
 121                         return new ECKeyFactory();
 122                     }
 123                 } else  if (type.equals("AlgorithmParameters")) {
 124                     if (algo.equals("EC")) {
 125                         return new sun.security.util.ECParameters();
 126                     }
 127                 } else  if (type.equals("KeyPairGenerator")) {
 128                     if (algo.equals("EC")) {
 129                         return new ECKeyPairGenerator();
 130                     }
 131                 } else  if (type.equals("KeyAgreement")) {
 132                     if (algo.equals("ECDH")) {
 133                         return new ECDHKeyAgreement();
 134                     }
 135                 }
 136             } catch (Exception ex) {
 137                 throw new NoSuchAlgorithmException("Error constructing " +
 138                     type + " for " + algo + " using SunEC", ex);
 139             }
 140             throw new ProviderException("No impl for " + algo +
 141                 " " + type);
 142         }
 143     }
 144 
 145     public SunEC() {
 146         super("SunEC", PROVIDER_VER,
 147             "Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
 148         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 149             public Void run() {
 150                 putEntries(useFullImplementation);
 151                 return null;
 152             }
 153         });
 154     }
 155 
 156     void putEntries(boolean useFullImplementation) {
 157         HashMap<String, String> ATTRS = new HashMap<>(3);
 158         ATTRS.put("ImplementedIn", "Software");
 159         String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
 160                  "|java.security.interfaces.ECPrivateKey";
 161         ATTRS.put("SupportedKeyClasses", ecKeyClasses);
 162         ATTRS.put("KeySize", "256");
 163 
 164         /*
 165          *  Key Factory engine
 166          */
 167         putService(new ProviderService(this, "KeyFactory",
 168             "EC", "sun.security.ec.ECKeyFactory",
 169             new String[] { "EllipticCurve" }, ATTRS));
 170 
 171         /*
 172          * Algorithm Parameter engine
 173          */
 174         // "AlgorithmParameters.EC SupportedCurves" prop used by unit test
 175         boolean firstCurve = true;
 176         StringBuilder names = new StringBuilder();
 177         Pattern nameSplitPattern = Pattern.compile(CurveDB.SPLIT_PATTERN);
 178 
 179         Collection<? extends NamedCurve> supportedCurves =
 180             CurveDB.getSupportedCurves();
 181         for (NamedCurve namedCurve : supportedCurves) {
 182             if (!firstCurve) {
 183                 names.append("|");
 184             } else {
 185                 firstCurve = false;
 186             }
 187 
 188             names.append("[");
 189 
 190             String[] commonNames = nameSplitPattern.split(namedCurve.getName());
 191             for (String commonName : commonNames) {
 192                 names.append(commonName.trim());
 193                 names.append(",");
 194             }
 195 
 196             names.append(namedCurve.getObjectId());
 197             names.append("]");
 198         }
 199 
 200         HashMap<String, String> apAttrs = new HashMap<>(ATTRS);
 201         apAttrs.put("SupportedCurves", names.toString());
 202 
 203         putService(new ProviderService(this, "AlgorithmParameters",
 204             "EC", "sun.security.util.ECParameters",
 205             new String[] { "EllipticCurve", "1.2.840.10045.2.1", "OID.1.2.840.10045.2.1" },
 206             apAttrs));
 207 
 208         /*
 209          * Register the algorithms below only when the full ECC implementation
 210          * is available
 211          */
 212         if (!useFullImplementation) {
 213             return;
 214         }
 215 
 216         /*
 217          * Signature engines
 218          */
 219         putService(new ProviderService(this, "Signature",
 220             "NONEwithECDSA", "sun.security.ec.ECDSASignature$Raw",
 221             null, ATTRS));
 222         putService(new ProviderService(this, "Signature",
 223             "SHA1withECDSA", "sun.security.ec.ECDSASignature$SHA1",
 224             new String[] { "1.2.840.10045.4.1", "OID.1.2.840.10045.4.1" },
 225             ATTRS));
 226         putService(new ProviderService(this, "Signature",
 227             "SHA224withECDSA", "sun.security.ec.ECDSASignature$SHA224",
 228             new String[] { "1.2.840.10045.4.3.1", "OID.1.2.840.10045.4.3.1"},
 229             ATTRS));
 230         putService(new ProviderService(this, "Signature",
 231             "SHA256withECDSA", "sun.security.ec.ECDSASignature$SHA256",
 232             new String[] { "1.2.840.10045.4.3.2", "OID.1.2.840.10045.4.3.2"},
 233             ATTRS));
 234         putService(new ProviderService(this, "Signature",
 235             "SHA384withECDSA", "sun.security.ec.ECDSASignature$SHA384",
 236             new String[] { "1.2.840.10045.4.3.3", "OID.1.2.840.10045.4.3.3" },
 237             ATTRS));
 238         putService(new ProviderService(this, "Signature",
 239             "SHA512withECDSA", "sun.security.ec.ECDSASignature$SHA512",
 240             new String[] { "1.2.840.10045.4.3.4", "OID.1.2.840.10045.4.3.4" },
 241             ATTRS));
 242 
 243         putService(new ProviderService(this, "Signature",
 244              "NONEwithECDSAinP1363Format",
 245              "sun.security.ec.ECDSASignature$RawinP1363Format"));
 246         putService(new ProviderService(this, "Signature",
 247              "SHA1withECDSAinP1363Format",
 248              "sun.security.ec.ECDSASignature$SHA1inP1363Format"));
 249         putService(new ProviderService(this, "Signature",
 250              "SHA224withECDSAinP1363Format",
 251              "sun.security.ec.ECDSASignature$SHA224inP1363Format"));
 252         putService(new ProviderService(this, "Signature",
 253              "SHA256withECDSAinP1363Format",
 254              "sun.security.ec.ECDSASignature$SHA256inP1363Format"));
 255         putService(new ProviderService(this, "Signature",
 256             "SHA384withECDSAinP1363Format",
 257             "sun.security.ec.ECDSASignature$SHA384inP1363Format"));
 258         putService(new ProviderService(this, "Signature",
 259             "SHA512withECDSAinP1363Format",
 260             "sun.security.ec.ECDSASignature$SHA512inP1363Format"));
 261 
 262         /*
 263          *  Key Pair Generator engine
 264          */
 265         putService(new ProviderService(this, "KeyPairGenerator",
 266             "EC", "sun.security.ec.ECKeyPairGenerator",
 267             new String[] { "EllipticCurve" }, ATTRS));
 268 
 269         /*
 270          * Key Agreement engine
 271          */
 272         putService(new ProviderService(this, "KeyAgreement",
 273             "ECDH", "sun.security.ec.ECDHKeyAgreement", null, ATTRS));
 274     }
 275 }