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