src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoProvider.java

Print this page
7191662: JCE providers should be located via ServiceLoader

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -24,15 +24,13 @@
  */
 
 package com.oracle.security.ucrypto;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.StringTokenizer;
+import java.io.File;
+import java.util.*;
 import java.security.*;
-import sun.security.action.PutAllAction;
-import sun.security.action.GetPropertyAction;
 
 /**
  * OracleUcrypto provider main class.
  *
  * @since 1.9

@@ -39,96 +37,184 @@
  */
 public final class UcryptoProvider extends Provider {
 
     private static final long serialVersionUID = 351251234302833L;
 
-    private static boolean DEBUG;
-    private static HashMap<String, String> provProp;
+    private static boolean DEBUG = false;
+    private static HashMap<String, ServiceDesc> provProp = null;
+    private static String defConfigName = "";
 
     static {
         try {
-            DEBUG = Boolean.parseBoolean(AccessController.doPrivileged
-                (new GetPropertyAction("com.oracle.security.ucrypto.debug")));
-
             // cannot use LoadLibraryAction because that would make the native
             // library available to the bootclassloader, but we run in the
             // extension classloader.
+            String osname = System.getProperty("os.name");
+            if (osname.startsWith("SunOS")) {
             provProp = AccessController.doPrivileged
-                (new PrivilegedAction<HashMap<String, String>>() {
-                    public HashMap<String, String> run() {
+                    (new PrivilegedAction<HashMap<String, ServiceDesc>>() {
+                        public HashMap<String, ServiceDesc> run() {
                         try {
+                                DEBUG = Boolean.parseBoolean(System.getProperty("com.oracle.security.ucrypto.debug"));
+                                String javaHome = System.getProperty("java.home");
+                                String sep = System.getProperty("file.separator");
+                                defConfigName = javaHome + sep + "conf" + sep + "security" + sep +
+                                    "ucrypto-solaris.cfg";
                             System.loadLibrary("j2ucrypto");
-                            String osname = System.getProperty("os.name");
-                            if (osname.startsWith("SunOS")) {
-                                return new HashMap<String, String>();
-                            } else return null;
+                                return new HashMap<>();
                         } catch (Error err) {
+                                if (DEBUG) err.printStackTrace();
                             return null;
                         } catch (SecurityException se) {
+                                if (DEBUG) se.printStackTrace();
                             return null;
                         }
                     }
                 });
+            }
             if (provProp != null) {
                 boolean[] result = loadLibraries();
                 if (result.length == 2) {
                     if (result[0]) { // successfully loaded libmd
                         provProp.put("MessageDigest.MD5",
-                                     "com.oracle.security.ucrypto.NativeDigest$MD5");
+                            sd("MessageDigest", "MD5",
+                               "com.oracle.security.ucrypto.NativeDigest$MD5"));
                         provProp.put("MessageDigest.SHA",
-                                     "com.oracle.security.ucrypto.NativeDigest$SHA1");
-                        provProp.put("Alg.Alias.MessageDigest.SHA-1", "SHA");
-                        provProp.put("Alg.Alias.MessageDigest.SHA1", "SHA");
+                            sd("MessageDigest", "SHA",
+                               "com.oracle.security.ucrypto.NativeDigest$SHA1",
+                               "SHA-1", "SHA1"));
                         provProp.put("MessageDigest.SHA-256",
-                                     "com.oracle.security.ucrypto.NativeDigest$SHA256");
-                        provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
-                        provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", "SHA-256");
+                            sd("MessageDigest", "SHA-256",
+                               "com.oracle.security.ucrypto.NativeDigest$SHA256",
+                               "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"));
 
                         provProp.put("MessageDigest.SHA-384",
-                                     "com.oracle.security.ucrypto.NativeDigest$SHA384");
-                        provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
-                        provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", "SHA-384");
+                            sd("MessageDigest", "SHA-384",
+                               "com.oracle.security.ucrypto.NativeDigest$SHA384",
+                               "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"));
 
                         provProp.put("MessageDigest.SHA-512",
-                                     "com.oracle.security.ucrypto.NativeDigest$SHA512");
-                        provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
-                        provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", "SHA-512");
-
-                    }
+                            sd("MessageDigest", "SHA-512",
+                               "com.oracle.security.ucrypto.NativeDigest$SHA512",
+                               "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"));
+                    };
                     if (result[1]) { // successfully loaded libsoftcrypto
                         String supportedMechs = getMechList();
                         debug("Prov: supported mechs = " + supportedMechs);
                         for (UcryptoMech m : UcryptoMech.values()) {
                             if (supportedMechs.indexOf(m.name() + ",") != -1) {
-                                String[] jceProps = m.jceProperties();
+                                ServiceDesc[] services = m.getServiceDescriptions();
                                 // skip unsupported UcryptoMech
-                                if (jceProps == null) continue;
-                                for (int p = 0; p < jceProps.length; p++) {
-                                    StringTokenizer st =
-                                        new StringTokenizer(jceProps[p], ";");
-                                    if (st.countTokens() != 2) {
-                                        throw new RuntimeException("Wrong format: " + jceProps[p]);
+                                if (services == null || services.length == 0) continue;
+                                for (int p = 0; p < services.length; p++) {
+                                    ServiceDesc entry = services[p];
+                                    provProp.put(entry.getType() + "." + entry.getAlgorithm(),
+                                                 entry);
                                     }
-                                    provProp.put(st.nextToken(), st.nextToken());
                                 }
                             }
-                        }
                         // NOTE: GCM support is only available since jdk 7
                         provProp.put("AlgorithmParameters.GCM",
-                                     "com.oracle.security.ucrypto.GCMParameters");
+                                     sd("AlgorithmParameters", "GCM", "com.oracle.security.ucrypto.GCMParameters"));
                     }
                 } else {
                     debug("Prov: unexpected ucrypto library loading error, got " + result.length);
                 }
             }
         } catch (AccessControlException ace) {
+            if (DEBUG) ace.printStackTrace();
             // disable Ucrypto provider
-            DEBUG = false;
             provProp = null;
         }
     }
 
+    private static ServiceDesc sd(String type, String algo, String cn,
+        String... aliases) {
+        return new ServiceDesc(type, algo, cn, aliases);
+    }
+
+    private static final class ProviderService extends Provider.Service {
+        ProviderService(Provider p, ServiceDesc sd) {
+            super(p, sd.getType(), sd.getAlgorithm(), sd.getClassName(),
+                  sd.getAliases(), null);
+        }
+
+        @Override
+        public Object newInstance(Object ctrParamObj)
+            throws NoSuchAlgorithmException {
+            String type = getType();
+            if (ctrParamObj != null) {
+                throw new InvalidParameterException
+                    ("constructorParameter not used with " + type + " engines");
+            }
+            String algo = getAlgorithm();
+            try {
+                if (type.equals("Cipher")) {
+                    int keySize = -1;
+                    if (algo.charAt(3) == '_') {
+                        keySize = Integer.parseInt(algo.substring(4, 7))/8;
+                        algo = algo.substring(0, 3) + algo.substring(7);
+                    }
+                    if (algo.equals("AES/ECB/NoPadding")) {
+                        return new NativeCipher.AesEcbNoPadding(keySize);
+                    } else if (algo.equals("AES/ECB/PKCS5Padding")) {
+                        return new NativeCipherWithJavaPadding.AesEcbPKCS5();
+                    } else if (algo.equals("AES/CBC/NoPadding")) {
+                        return new NativeCipher.AesCbcNoPadding(keySize);
+                    } else if (algo.equals("AES/CBC/PKCS5Padding")) {
+                        return new NativeCipherWithJavaPadding.AesCbcPKCS5();
+                    } else if (algo.equals("AES/CTR/NoPadding")) {
+                        return new NativeCipher.AesCtrNoPadding();
+                    } else if (algo.equals("AES/GCM/NoPadding")) {
+                        return new NativeGCMCipher.AesGcmNoPadding(keySize);
+                    } else if (algo.equals("AES/CFB128/NoPadding")) {
+                        return new NativeCipher.AesCfb128NoPadding();
+                    } else if (algo.equals("AES/CFB128/PKCS5Padding")) {
+                        return new NativeCipherWithJavaPadding.AesCfb128PKCS5();
+                    } else if (algo.equals("RSA/ECB/NoPadding")) {
+                        return new NativeRSACipher.NoPadding();
+                    } else if (algo.equals("RSA/ECB/PKCS1Padding")) {
+                        return new NativeRSACipher.PKCS1Padding();
+                    }
+                } else if (type.equals("Signature")) {
+                    if (algo.equals("SHA1withRSA")) {
+                        return new NativeRSASignature.SHA1();
+                    } else if (algo.equals("SHA256withRSA")) {
+                        return new NativeRSASignature.SHA256();
+                    } else if (algo.equals("SHA384withRSA")) {
+                        return new NativeRSASignature.SHA384();
+                    } else if (algo.equals("SHA512withRSA")) {
+                        return new NativeRSASignature.SHA512();
+                    } else if (algo.equals("MD5withRSA")) {
+                        return new NativeRSASignature.MD5();
+                    }
+                } else if (type.equals("MessageDigest")) {
+                    if (algo.equals("SHA")) {
+                        return new NativeDigest.SHA1();
+                    } else if (algo.equals("SHA-256")) {
+                        return new NativeDigest.SHA256();
+                    } else if (algo.equals("SHA-384")) {
+                        return new NativeDigest.SHA384();
+                    } else if (algo.equals("SHA-512")) {
+                        return new NativeDigest.SHA512();
+                    } else if (algo.equals("MD5")) {
+                        return new NativeDigest.MD5();
+                    }
+                } else if (type.equals("AlgorithmParameters")) {
+                    if (algo.equals("GCM")) {
+                        return new GCMParameters();
+                    }
+                }
+            } catch (Exception ex) {
+                throw new NoSuchAlgorithmException("Error constructing " +
+                    type + " for " + algo + " using OracleUcrypto", ex);
+            }
+            throw new ProviderException("No impl for " + algo +
+                " " + type);
+        }
+    }
+
     static Provider provider = null;
     private static native boolean[] loadLibraries();
     private static native String getMechList();
 
     static void debug(String msg) {

@@ -137,40 +223,67 @@
         }
     }
 
     public UcryptoProvider() {
         super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API");
-        if (provProp != null) {
-            AccessController.doPrivileged(new PutAllAction(this, provProp));
+
+        AccessController.doPrivileged(new PrivilegedAction<>() {
+            public Void run() {
+                init(defConfigName);
+                return null;
         }
+        });
         if (provider == null) provider = this;
     }
 
-    public UcryptoProvider(String configName) {
-        super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API");
-        try {
+    private void init(final String configName) {
             if (provProp != null) {
-                HashMap<String, String> customProvProp =
-                    new HashMap<String, String>(provProp);
-                Config c = new Config(configName);
+            debug("Prov: configuration file " + configName);
+            Config c;
+            try {
+                c = new Config(configName);
+            } catch (Exception ex) {
+                throw new UcryptoException("Error parsing Config", ex);
+            }
+
                 String[] disabledServices = c.getDisabledServices();
-                for (int i = 0; i < disabledServices.length; i++) {
-                    if (customProvProp.remove(disabledServices[i]) != null) {
-                        debug("Prov: remove config-disabled service " + disabledServices[i]);
+            for (String ds : disabledServices) {
+                if (provProp.remove(ds) != null) {
+                    debug("Prov: remove config-disabled service " + ds);
                     } else {
-                        debug("Prov: ignore unsupported config-disabled service " +
-                              disabledServices[i]);
+                    debug("Prov: ignore unsupported service " + ds);
                     }
                 }
-                AccessController.doPrivileged(new PutAllAction(this, customProvProp));
+
+            for (ServiceDesc s: provProp.values()) {
+                debug("Prov: add service for " + s);
+                putService(new ProviderService(this, s));
             }
-        } catch (IOException ioe) { // thrown by Config
-            throw new UcryptoException("Error parsing Config", ioe);
         }
-        if (provider == null) provider = this;
     }
 
+    @Override
+    public Provider configure(String configArg) throws InvalidParameterException {
+        if (!defConfigName.equals(configArg)) {
+            throw new InvalidParameterException("Ucrypto provider can only be " +
+                "configured with default configuration file");
+        }
+        return this;
+    }
+    
+    @Override
+    public String getArgument() {
+        try {
+            if (new File(defConfigName).canRead()) {
+                return defConfigName;
+            }
+        } catch (SecurityException se) {
+            debug("Prov: no perm to read config");
+        }
+        return "";
+    }
+
     public boolean equals(Object obj) {
         return this == obj;
     }
 
     public int hashCode() {