UcryptoProvider.java revision 12245:2f69eb7d4b90
1/* 2 * Copyright (c) 2014, 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 26package com.oracle.security.ucrypto; 27 28import java.io.IOException; 29import java.io.File; 30import java.util.*; 31import java.security.*; 32 33/** 34 * OracleUcrypto provider main class. 35 * 36 * @since 1.9 37 */ 38public final class UcryptoProvider extends Provider { 39 40 private static final long serialVersionUID = 351251234302833L; 41 42 private static boolean DEBUG = false; 43 private static HashMap<String, ServiceDesc> provProp = null; 44 private static String defConfigName = ""; 45 46 static { 47 try { 48 // cannot use LoadLibraryAction because that would make the native 49 // library available to the bootclassloader, but we run in the 50 // extension classloader. 51 String osname = System.getProperty("os.name"); 52 if (osname.startsWith("SunOS")) { 53 provProp = AccessController.doPrivileged 54 (new PrivilegedAction<HashMap<String, ServiceDesc>>() { 55 public HashMap<String, ServiceDesc> run() { 56 try { 57 DEBUG = Boolean.parseBoolean(System.getProperty("com.oracle.security.ucrypto.debug")); 58 String javaHome = System.getProperty("java.home"); 59 String sep = System.getProperty("file.separator"); 60 defConfigName = javaHome + sep + "conf" + sep + "security" + sep + 61 "ucrypto-solaris.cfg"; 62 System.loadLibrary("j2ucrypto"); 63 return new HashMap<>(); 64 } catch (Error err) { 65 if (DEBUG) err.printStackTrace(); 66 return null; 67 } catch (SecurityException se) { 68 if (DEBUG) se.printStackTrace(); 69 return null; 70 } 71 } 72 }); 73 } 74 if (provProp != null) { 75 boolean[] result = loadLibraries(); 76 if (result.length == 2) { 77 if (result[0]) { // successfully loaded libmd 78 provProp.put("MessageDigest.MD5", 79 sd("MessageDigest", "MD5", 80 "com.oracle.security.ucrypto.NativeDigest$MD5")); 81 provProp.put("MessageDigest.SHA", 82 sd("MessageDigest", "SHA", 83 "com.oracle.security.ucrypto.NativeDigest$SHA1", 84 "SHA-1", "SHA1")); 85 provProp.put("MessageDigest.SHA-256", 86 sd("MessageDigest", "SHA-256", 87 "com.oracle.security.ucrypto.NativeDigest$SHA256", 88 "2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1")); 89 90 provProp.put("MessageDigest.SHA-384", 91 sd("MessageDigest", "SHA-384", 92 "com.oracle.security.ucrypto.NativeDigest$SHA384", 93 "2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2")); 94 95 provProp.put("MessageDigest.SHA-512", 96 sd("MessageDigest", "SHA-512", 97 "com.oracle.security.ucrypto.NativeDigest$SHA512", 98 "2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3")); 99 }; 100 if (result[1]) { // successfully loaded libsoftcrypto 101 String supportedMechs = getMechList(); 102 debug("Prov: supported mechs = " + supportedMechs); 103 for (UcryptoMech m : UcryptoMech.values()) { 104 if (supportedMechs.indexOf(m.name() + ",") != -1) { 105 ServiceDesc[] services = m.getServiceDescriptions(); 106 // skip unsupported UcryptoMech 107 if (services == null || services.length == 0) continue; 108 for (int p = 0; p < services.length; p++) { 109 ServiceDesc entry = services[p]; 110 provProp.put(entry.getType() + "." + entry.getAlgorithm(), 111 entry); 112 } 113 } 114 } 115 // NOTE: GCM support is only available since jdk 7 116 provProp.put("AlgorithmParameters.GCM", 117 sd("AlgorithmParameters", "GCM", "com.oracle.security.ucrypto.GCMParameters")); 118 } 119 } else { 120 debug("Prov: unexpected ucrypto library loading error, got " + result.length); 121 } 122 } 123 } catch (AccessControlException ace) { 124 if (DEBUG) ace.printStackTrace(); 125 // disable Ucrypto provider 126 provProp = null; 127 } 128 } 129 130 private static ServiceDesc sd(String type, String algo, String cn, 131 String... aliases) { 132 return new ServiceDesc(type, algo, cn, aliases); 133 } 134 135 private static final class ProviderService extends Provider.Service { 136 ProviderService(Provider p, ServiceDesc sd) { 137 super(p, sd.getType(), sd.getAlgorithm(), sd.getClassName(), 138 sd.getAliases(), null); 139 } 140 141 @Override 142 public Object newInstance(Object ctrParamObj) 143 throws NoSuchAlgorithmException { 144 String type = getType(); 145 if (ctrParamObj != null) { 146 throw new InvalidParameterException 147 ("constructorParameter not used with " + type + " engines"); 148 } 149 String algo = getAlgorithm(); 150 try { 151 if (type.equals("Cipher")) { 152 int keySize = -1; 153 if (algo.charAt(3) == '_') { 154 keySize = Integer.parseInt(algo.substring(4, 7))/8; 155 algo = algo.substring(0, 3) + algo.substring(7); 156 } 157 if (algo.equals("AES/ECB/NoPadding")) { 158 return new NativeCipher.AesEcbNoPadding(keySize); 159 } else if (algo.equals("AES/ECB/PKCS5Padding")) { 160 return new NativeCipherWithJavaPadding.AesEcbPKCS5(); 161 } else if (algo.equals("AES/CBC/NoPadding")) { 162 return new NativeCipher.AesCbcNoPadding(keySize); 163 } else if (algo.equals("AES/CBC/PKCS5Padding")) { 164 return new NativeCipherWithJavaPadding.AesCbcPKCS5(); 165 } else if (algo.equals("AES/CTR/NoPadding")) { 166 return new NativeCipher.AesCtrNoPadding(); 167 } else if (algo.equals("AES/GCM/NoPadding")) { 168 return new NativeGCMCipher.AesGcmNoPadding(keySize); 169 } else if (algo.equals("AES/CFB128/NoPadding")) { 170 return new NativeCipher.AesCfb128NoPadding(); 171 } else if (algo.equals("AES/CFB128/PKCS5Padding")) { 172 return new NativeCipherWithJavaPadding.AesCfb128PKCS5(); 173 } else if (algo.equals("RSA/ECB/NoPadding")) { 174 return new NativeRSACipher.NoPadding(); 175 } else if (algo.equals("RSA/ECB/PKCS1Padding")) { 176 return new NativeRSACipher.PKCS1Padding(); 177 } 178 } else if (type.equals("Signature")) { 179 if (algo.equals("SHA1withRSA")) { 180 return new NativeRSASignature.SHA1(); 181 } else if (algo.equals("SHA256withRSA")) { 182 return new NativeRSASignature.SHA256(); 183 } else if (algo.equals("SHA384withRSA")) { 184 return new NativeRSASignature.SHA384(); 185 } else if (algo.equals("SHA512withRSA")) { 186 return new NativeRSASignature.SHA512(); 187 } else if (algo.equals("MD5withRSA")) { 188 return new NativeRSASignature.MD5(); 189 } 190 } else if (type.equals("MessageDigest")) { 191 if (algo.equals("SHA")) { 192 return new NativeDigest.SHA1(); 193 } else if (algo.equals("SHA-256")) { 194 return new NativeDigest.SHA256(); 195 } else if (algo.equals("SHA-384")) { 196 return new NativeDigest.SHA384(); 197 } else if (algo.equals("SHA-512")) { 198 return new NativeDigest.SHA512(); 199 } else if (algo.equals("MD5")) { 200 return new NativeDigest.MD5(); 201 } 202 } else if (type.equals("AlgorithmParameters")) { 203 if (algo.equals("GCM")) { 204 return new GCMParameters(); 205 } 206 } 207 } catch (Exception ex) { 208 throw new NoSuchAlgorithmException("Error constructing " + 209 type + " for " + algo + " using OracleUcrypto", ex); 210 } 211 throw new ProviderException("No impl for " + algo + 212 " " + type); 213 } 214 } 215 216 static Provider provider = null; 217 private static native boolean[] loadLibraries(); 218 private static native String getMechList(); 219 220 static void debug(String msg) { 221 if (DEBUG) { 222 System.out.println("UCrypto/" + msg); 223 } 224 } 225 226 public UcryptoProvider() { 227 super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API"); 228 229 AccessController.doPrivileged(new PrivilegedAction<>() { 230 public Void run() { 231 init(defConfigName); 232 return null; 233 } 234 }); 235 if (provider == null) provider = this; 236 } 237 238 private void init(final String configName) { 239 if (provProp != null) { 240 debug("Prov: configuration file " + configName); 241 Config c; 242 try { 243 c = new Config(configName); 244 } catch (Exception ex) { 245 throw new UcryptoException("Error parsing Config", ex); 246 } 247 248 String[] disabledServices = c.getDisabledServices(); 249 for (String ds : disabledServices) { 250 if (provProp.remove(ds) != null) { 251 debug("Prov: remove config-disabled service " + ds); 252 } else { 253 debug("Prov: ignore unsupported service " + ds); 254 } 255 } 256 257 for (ServiceDesc s: provProp.values()) { 258 debug("Prov: add service for " + s); 259 putService(new ProviderService(this, s)); 260 } 261 } 262 } 263 264 @Override 265 public Provider configure(String configArg) throws InvalidParameterException { 266 // default policy entry only grants read access to default config 267 if (!defConfigName.equals(configArg)) { 268 throw new InvalidParameterException("Ucrypto provider can only be " + 269 "configured with default configuration file"); 270 } 271 // re-read the config 272 init(defConfigName); 273 return this; 274 } 275 276 public boolean equals(Object obj) { 277 return this == obj; 278 } 279 280 public int hashCode() { 281 return System.identityHashCode(this); 282 } 283} 284