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