1 /* 2 * Copyright (c) 2014, 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 com.oracle.security.ucrypto; 27 28 import java.io.IOException; 29 import java.io.File; 30 import java.lang.reflect.Constructor; 31 import java.util.*; 32 import java.security.*; 33 import static sun.security.util.SecurityConstants.PROVIDER_VER; 34 35 36 /** 37 * OracleUcrypto provider main class. 38 * 39 * @since 9 40 */ 41 public final class UcryptoProvider extends Provider { 42 43 private static final long serialVersionUID = 351251234302833L; 44 45 private static boolean DEBUG = false; 46 private static HashMap<String, ServiceDesc> provProp = null; 47 private static String defConfigName = ""; 48 49 static { 50 try { 51 // cannot use LoadLibraryAction because that would make the native 52 // library available to the bootclassloader, but we run in the 53 // platform classloader. 54 provProp = AccessController.doPrivileged 55 (new PrivilegedAction<>() { 56 @Override 57 public HashMap<String, ServiceDesc> run() { 58 String osname = System.getProperty("os.name"); 59 if (osname.startsWith("SunOS")) { 60 try { 61 DEBUG = Boolean.parseBoolean(System.getProperty("com.oracle.security.ucrypto.debug")); 62 String javaHome = System.getProperty("java.home"); 63 String sep = System.getProperty("file.separator"); 64 defConfigName = javaHome + sep + "conf" + sep + "security" + sep + 65 "ucrypto-solaris.cfg"; 66 System.loadLibrary("j2ucrypto"); 67 return new HashMap<>(); 68 } catch (Error err) { 69 if (DEBUG) err.printStackTrace(); 70 } catch (SecurityException se) { 71 if (DEBUG) se.printStackTrace(); 72 } 73 } 74 return null; 75 } 76 }); 77 if (provProp != null) { 78 boolean[] result = loadLibraries(); 79 if (result.length == 2) { 80 // true when libsoftcrypto or libucrypto(S12) has been successfully loaded 81 if (result[1]) { 82 String supportedMechs = getMechList(); 83 debug("Prov: supported mechs = " + supportedMechs); 84 StringTokenizer st = new StringTokenizer(supportedMechs, ":,;"); 85 // format: numOfSupportedMechs:[mechName,mechValue;]+ 86 // skip the first one which is numberOfSupportedMechs 87 st.nextToken(); 88 while (st.hasMoreTokens()) { 89 String mechName = st.nextToken(); 90 int nativeMechVal = Integer.parseInt(st.nextToken()); 91 try { 92 UcryptoMech m = Enum.valueOf(UcryptoMech.class, mechName); 93 m.setValue(nativeMechVal); 94 ServiceDesc[] services = m.getServiceDescriptions(); 95 // defined in UcryptoMech as unsupported 96 if (services == null || services.length == 0) { 97 debug("Skip Unsupported Algorithm: " + mechName); 98 continue; 99 } 100 for (int p = 0; p < services.length; p++) { 101 ServiceDesc entry = services[p]; 102 provProp.put(entry.getType() + "." + entry.getAlgorithm(), 103 entry); 104 } 105 } catch (IllegalArgumentException iae) { 106 // not defined in UcryptoMech 107 debug("Skip Unrecognized Algorithm: " + mechName); 108 } 109 } 110 // NOTE: GCM support is only available since jdk 7 111 provProp.put("AlgorithmParameters.GCM", 112 sd("AlgorithmParameters", "GCM", 113 "com.oracle.security.ucrypto.GCMParameters")); 114 } 115 // true when libmd is needed and has been successfully loaded 116 if (result[0]) { 117 for (LibMDMech m : LibMDMech.values()) { 118 ServiceDesc[] services = m.getServiceDescriptions(); 119 for (ServiceDesc entry : services) { 120 String sKey = entry.getType() + "." + entry.getAlgorithm(); 121 // only register if none has been registered 122 provProp.putIfAbsent(sKey, entry); 123 } 124 } 125 }; 126 } else { 127 debug("Prov: unexpected ucrypto library loading error, got " + result.length); 128 } 129 } 130 } catch (AccessControlException ace) { 131 if (DEBUG) ace.printStackTrace(); 132 // disable Ucrypto provider 133 provProp = null; 134 } 135 } 136 137 private static ServiceDesc sd(String type, String algo, String cn, 138 String... aliases) { 139 return new ServiceDesc(type, algo, cn, aliases); 140 } 141 142 private static final class ProviderService extends Provider.Service { 143 ProviderService(Provider p, ServiceDesc sd) { 144 super(p, sd.getType(), sd.getAlgorithm(), sd.getClassName(), 145 sd.getAliases(), null); 146 } 147 148 @SuppressWarnings("deprecation") 149 @Override 150 public Object newInstance(Object ctrParamObj) 151 throws NoSuchAlgorithmException { 152 String type = getType(); 153 if (ctrParamObj != null) { 154 throw new InvalidParameterException 155 ("constructorParameter not used with " + type + " engines"); 156 } 157 String algo = getAlgorithm(); 158 try { 159 if (type.equals("Cipher")) { 160 int keySize = -1; 161 if (algo.charAt(3) == '_') { 162 keySize = Integer.parseInt(algo.substring(4, 7))/8; 163 } 164 String implClass = getClassName(); 165 Class<?> clz = Class.forName(implClass); 166 if (keySize != -1) { 167 Constructor<?> ctr = clz.getConstructor(int.class); 168 return ctr.newInstance(keySize); 169 } else { 170 return clz.newInstance(); 171 } 172 } else if (type.equals("Signature") || type.equals("MessageDigest")) { 173 String implClass = getClassName(); 174 Class<?> clz = Class.forName(implClass); 175 return clz.newInstance(); 176 } else if (type.equals("AlgorithmParameters")) { 177 if (algo.equals("GCM")) { 178 return new GCMParameters(); 179 } 180 } 181 } catch (Exception ex) { 182 throw new NoSuchAlgorithmException("Error constructing " + 183 type + " for " + algo + " using OracleUcrypto", ex); 184 } 185 throw new ProviderException("No impl for " + algo + 186 " " + type); 187 } 188 } 189 190 static Provider provider = null; 191 private static native boolean[] loadLibraries(); 192 private static native String getMechList(); 193 194 static void debug(String msg) { 195 if (DEBUG) { 196 System.out.println("UCrypto/" + msg); 197 } 198 } 199 200 public UcryptoProvider() { 201 super("OracleUcrypto", PROVIDER_VER, "Provider using Oracle Ucrypto API"); 202 203 AccessController.doPrivileged(new PrivilegedAction<>() { 204 public Void run() { 205 init(defConfigName); 206 return null; 207 } 208 }); 209 if (provider == null) provider = this; 210 } 211 212 private void init(final String configName) { 213 if (provProp != null) { 214 debug("Prov: configuration file " + configName); 215 Config c; 216 try { 217 c = new Config(configName); 218 } catch (Exception ex) { 219 throw new UcryptoException("Error parsing Config", ex); 220 } 221 222 String[] disabledServices = c.getDisabledServices(); 223 for (String ds : disabledServices) { 224 if (provProp.remove(ds) != null) { 225 debug("Prov: remove config-disabled service " + ds); 226 } else { 227 debug("Prov: ignore unsupported service " + ds); 228 } 229 } 230 231 for (ServiceDesc s: provProp.values()) { 232 debug("Prov: add service for " + s); 233 putService(new ProviderService(this, s)); 234 } 235 } 236 } 237 238 @Override 239 public Provider configure(String configArg) throws InvalidParameterException { 240 try { 241 init(configArg); 242 } catch (UcryptoException ue) { 243 InvalidParameterException ipe = 244 new InvalidParameterException("Error using " + configArg); 245 ipe.initCause(ue.getCause()); 246 throw ipe; 247 } 248 return this; 249 } 250 251 public boolean equals(Object obj) { 252 return this == obj; 253 } 254 255 public int hashCode() { 256 return System.identityHashCode(this); 257 } 258 }