1 /* 2 * Copyright (c) 2001, 2011, 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.ssl; 27 28 import java.util.*; 29 import java.math.BigInteger; 30 31 import java.security.*; 32 import java.security.interfaces.RSAPublicKey; 33 import java.security.spec.RSAPublicKeySpec; 34 import java.security.spec.*; 35 36 import javax.crypto.*; 37 38 // explicit import to override the Provider class in this package 39 import java.security.Provider; 40 41 // need internal Sun classes for FIPS tricks 42 import sun.security.jca.Providers; 43 import sun.security.jca.ProviderList; 44 45 import sun.security.ec.ECParameters; 46 import sun.security.ec.NamedCurve; 47 48 import static sun.security.ssl.SunJSSE.cryptoProvider; 49 50 /** 51 * This class contains a few static methods for interaction with the JCA/JCE 52 * to obtain implementations, etc. 53 * 54 * @author Andreas Sterbenz 55 */ 56 final class JsseJce { 57 58 private final static Debug debug = Debug.getInstance("ssl"); 59 60 private final static ProviderList fipsProviderList; 61 62 // Flag indicating whether EC crypto is available. 63 // If null, then we have not checked yet. 64 // If yes, then all the EC based crypto we need is available. 65 private static Boolean ecAvailable; 66 67 // Flag indicating whether Kerberos crypto is available. 68 // If true, then all the Kerberos-based crypto we need is available. 69 private final static boolean kerberosAvailable; 70 static { 71 boolean temp; 72 try { AccessController.doPrivileged( new PrivilegedExceptionAction<Void>() { public Void run() throws Exception { Class.forName("sun.security.krb5.PrincipalName", true, null); return null; } })73 AccessController.doPrivileged( 74 new PrivilegedExceptionAction<Void>() { 75 public Void run() throws Exception { 76 // Test for Kerberos using the bootstrap class loader 77 Class.forName("sun.security.krb5.PrincipalName", true, 78 null); 79 return null; 80 } 81 }); 82 temp = true; 83 84 } catch (Exception e) { 85 temp = false; 86 } 87 kerberosAvailable = temp; 88 } 89 90 static { 91 // force FIPS flag initialization 92 // Because isFIPS() is synchronized and cryptoProvider is not modified 93 // after it completes, this also eliminates the need for any further 94 // synchronization when accessing cryptoProvider 95 if (SunJSSE.isFIPS() == false) { 96 fipsProviderList = null; 97 } else { 98 // Setup a ProviderList that can be used by the trust manager 99 // during certificate chain validation. All the crypto must be 100 // from the FIPS provider, but we also allow the required 101 // certificate related services from the SUN provider. 102 Provider sun = Security.getProvider("SUN"); 103 if (sun == null) { 104 throw new RuntimeException 105 ("FIPS mode: SUN provider must be installed"); 106 } 107 Provider sunCerts = new SunCertificates(sun); 108 fipsProviderList = ProviderList.newList(cryptoProvider, sunCerts); 109 } 110 } 111 112 private static final class SunCertificates extends Provider { SunCertificates(final Provider p)113 SunCertificates(final Provider p) { 114 super("SunCertificates", 1.0d, "SunJSSE internal"); 115 AccessController.doPrivileged(new PrivilegedAction<Object>() { 116 public Object run() { 117 // copy certificate related services from the Sun provider 118 for (Map.Entry<Object,Object> entry : p.entrySet()) { 119 String key = (String)entry.getKey(); 120 if (key.startsWith("CertPathValidator.") 121 || key.startsWith("CertPathBuilder.") 122 || key.startsWith("CertStore.") 123 || key.startsWith("CertificateFactory.")) { 124 put(key, entry.getValue()); 125 } 126 } 127 return null; 128 } 129 }); 130 } 131 } 132 133 /** 134 * JCE transformation string for RSA with PKCS#1 v1.5 padding. 135 * Can be used for encryption, decryption, signing, verifying. 136 */ 137 final static String CIPHER_RSA_PKCS1 = "RSA/ECB/PKCS1Padding"; 138 /** 139 * JCE transformation string for the stream cipher RC4. 140 */ 141 final static String CIPHER_RC4 = "RC4"; 142 /** 143 * JCE transformation string for DES in CBC mode without padding. 144 */ 145 final static String CIPHER_DES = "DES/CBC/NoPadding"; 146 /** 147 * JCE transformation string for (3-key) Triple DES in CBC mode 148 * without padding. 149 */ 150 final static String CIPHER_3DES = "DESede/CBC/NoPadding"; 151 /** 152 * JCE transformation string for AES in CBC mode 153 * without padding. 154 */ 155 final static String CIPHER_AES = "AES/CBC/NoPadding"; 156 /** 157 * JCA identifier string for DSA, i.e. a DSA with SHA-1. 158 */ 159 final static String SIGNATURE_DSA = "DSA"; 160 /** 161 * JCA identifier string for ECDSA, i.e. a ECDSA with SHA-1. 162 */ 163 final static String SIGNATURE_ECDSA = "SHA1withECDSA"; 164 /** 165 * JCA identifier string for Raw DSA, i.e. a DSA signature without 166 * hashing where the application provides the SHA-1 hash of the data. 167 * Note that the standard name is "NONEwithDSA" but we use "RawDSA" 168 * for compatibility. 169 */ 170 final static String SIGNATURE_RAWDSA = "RawDSA"; 171 /** 172 * JCA identifier string for Raw ECDSA, i.e. a DSA signature without 173 * hashing where the application provides the SHA-1 hash of the data. 174 */ 175 final static String SIGNATURE_RAWECDSA = "NONEwithECDSA"; 176 /** 177 * JCA identifier string for Raw RSA, i.e. a RSA PKCS#1 v1.5 signature 178 * without hashing where the application provides the hash of the data. 179 * Used for RSA client authentication with a 36 byte hash. 180 */ 181 final static String SIGNATURE_RAWRSA = "NONEwithRSA"; 182 /** 183 * JCA identifier string for the SSL/TLS style RSA Signature. I.e. 184 * an signature using RSA with PKCS#1 v1.5 padding signing a 185 * concatenation of an MD5 and SHA-1 digest. 186 */ 187 final static String SIGNATURE_SSLRSA = "MD5andSHA1withRSA"; 188 JsseJce()189 private JsseJce() { 190 // no instantiation of this class 191 } 192 isEcAvailable()193 synchronized static boolean isEcAvailable() { 194 if (ecAvailable == null) { 195 try { 196 JsseJce.getSignature(SIGNATURE_ECDSA); 197 JsseJce.getSignature(SIGNATURE_RAWECDSA); 198 JsseJce.getKeyAgreement("ECDH"); 199 JsseJce.getKeyFactory("EC"); 200 JsseJce.getKeyPairGenerator("EC"); 201 ecAvailable = true; 202 } catch (Exception e) { 203 ecAvailable = false; 204 } 205 } 206 return ecAvailable; 207 } 208 clearEcAvailable()209 synchronized static void clearEcAvailable() { 210 ecAvailable = null; 211 } 212 isKerberosAvailable()213 static boolean isKerberosAvailable() { 214 return kerberosAvailable; 215 } 216 217 /** 218 * Return an JCE cipher implementation for the specified algorithm. 219 */ getCipher(String transformation)220 static Cipher getCipher(String transformation) 221 throws NoSuchAlgorithmException { 222 try { 223 if (cryptoProvider == null) { 224 return Cipher.getInstance(transformation); 225 } else { 226 return Cipher.getInstance(transformation, cryptoProvider); 227 } 228 } catch (NoSuchPaddingException e) { 229 throw new NoSuchAlgorithmException(e); 230 } 231 } 232 233 /** 234 * Return an JCA signature implementation for the specified algorithm. 235 * The algorithm string should be one of the constants defined 236 * in this class. 237 */ getSignature(String algorithm)238 static Signature getSignature(String algorithm) 239 throws NoSuchAlgorithmException { 240 if (cryptoProvider == null) { 241 return Signature.getInstance(algorithm); 242 } else { 243 // reference equality 244 if (algorithm == SIGNATURE_SSLRSA) { 245 // The SunPKCS11 provider currently does not support this 246 // special algorithm. We allow a fallback in this case because 247 // the SunJSSE implementation does the actual crypto using 248 // a NONEwithRSA signature obtained from the cryptoProvider. 249 if (cryptoProvider.getService("Signature", algorithm) == null) { 250 // Calling Signature.getInstance() and catching the 251 // exception would be cleaner, but exceptions are a little 252 // expensive. So we check directly via getService(). 253 try { 254 return Signature.getInstance(algorithm, "SunJSSE"); 255 } catch (NoSuchProviderException e) { 256 throw new NoSuchAlgorithmException(e); 257 } 258 } 259 } 260 return Signature.getInstance(algorithm, cryptoProvider); 261 } 262 } 263 getKeyGenerator(String algorithm)264 static KeyGenerator getKeyGenerator(String algorithm) 265 throws NoSuchAlgorithmException { 266 if (cryptoProvider == null) { 267 return KeyGenerator.getInstance(algorithm); 268 } else { 269 return KeyGenerator.getInstance(algorithm, cryptoProvider); 270 } 271 } 272 getKeyPairGenerator(String algorithm)273 static KeyPairGenerator getKeyPairGenerator(String algorithm) 274 throws NoSuchAlgorithmException { 275 if (cryptoProvider == null) { 276 return KeyPairGenerator.getInstance(algorithm); 277 } else { 278 return KeyPairGenerator.getInstance(algorithm, cryptoProvider); 279 } 280 } 281 getKeyAgreement(String algorithm)282 static KeyAgreement getKeyAgreement(String algorithm) 283 throws NoSuchAlgorithmException { 284 if (cryptoProvider == null) { 285 return KeyAgreement.getInstance(algorithm); 286 } else { 287 return KeyAgreement.getInstance(algorithm, cryptoProvider); 288 } 289 } 290 getMac(String algorithm)291 static Mac getMac(String algorithm) 292 throws NoSuchAlgorithmException { 293 if (cryptoProvider == null) { 294 return Mac.getInstance(algorithm); 295 } else { 296 return Mac.getInstance(algorithm, cryptoProvider); 297 } 298 } 299 getKeyFactory(String algorithm)300 static KeyFactory getKeyFactory(String algorithm) 301 throws NoSuchAlgorithmException { 302 if (cryptoProvider == null) { 303 return KeyFactory.getInstance(algorithm); 304 } else { 305 return KeyFactory.getInstance(algorithm, cryptoProvider); 306 } 307 } 308 getSecureRandom()309 static SecureRandom getSecureRandom() throws KeyManagementException { 310 if (cryptoProvider == null) { 311 return new SecureRandom(); 312 } 313 // Try "PKCS11" first. If that is not supported, iterate through 314 // the provider and return the first working implementation. 315 try { 316 return SecureRandom.getInstance("PKCS11", cryptoProvider); 317 } catch (NoSuchAlgorithmException e) { 318 // ignore 319 } 320 for (Provider.Service s : cryptoProvider.getServices()) { 321 if (s.getType().equals("SecureRandom")) { 322 try { 323 return SecureRandom.getInstance(s.getAlgorithm(), cryptoProvider); 324 } catch (NoSuchAlgorithmException ee) { 325 // ignore 326 } 327 } 328 } 329 throw new KeyManagementException("FIPS mode: no SecureRandom " 330 + " implementation found in provider " + cryptoProvider.getName()); 331 } 332 getMD5()333 static MessageDigest getMD5() { 334 return getMessageDigest("MD5"); 335 } 336 getSHA()337 static MessageDigest getSHA() { 338 return getMessageDigest("SHA"); 339 } 340 getMessageDigest(String algorithm)341 static MessageDigest getMessageDigest(String algorithm) { 342 try { 343 if (cryptoProvider == null) { 344 return MessageDigest.getInstance(algorithm); 345 } else { 346 return MessageDigest.getInstance(algorithm, cryptoProvider); 347 } 348 } catch (NoSuchAlgorithmException e) { 349 throw new RuntimeException 350 ("Algorithm " + algorithm + " not available", e); 351 } 352 } 353 getRSAKeyLength(PublicKey key)354 static int getRSAKeyLength(PublicKey key) { 355 BigInteger modulus; 356 if (key instanceof RSAPublicKey) { 357 modulus = ((RSAPublicKey)key).getModulus(); 358 } else { 359 RSAPublicKeySpec spec = getRSAPublicKeySpec(key); 360 modulus = spec.getModulus(); 361 } 362 return modulus.bitLength(); 363 } 364 getRSAPublicKeySpec(PublicKey key)365 static RSAPublicKeySpec getRSAPublicKeySpec(PublicKey key) { 366 if (key instanceof RSAPublicKey) { 367 RSAPublicKey rsaKey = (RSAPublicKey)key; 368 return new RSAPublicKeySpec(rsaKey.getModulus(), 369 rsaKey.getPublicExponent()); 370 } 371 try { 372 KeyFactory factory = JsseJce.getKeyFactory("RSA"); 373 return factory.getKeySpec(key, RSAPublicKeySpec.class); 374 } catch (Exception e) { 375 throw (RuntimeException)new RuntimeException().initCause(e); 376 } 377 } 378 getECParameterSpec(String namedCurveOid)379 static ECParameterSpec getECParameterSpec(String namedCurveOid) { 380 return NamedCurve.getECParameterSpec(namedCurveOid); 381 } 382 getNamedCurveOid(ECParameterSpec params)383 static String getNamedCurveOid(ECParameterSpec params) { 384 return ECParameters.getCurveName(params); 385 } 386 decodePoint(byte[] encoded, EllipticCurve curve)387 static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) 388 throws java.io.IOException { 389 return ECParameters.decodePoint(encoded, curve); 390 } 391 encodePoint(ECPoint point, EllipticCurve curve)392 static byte[] encodePoint(ECPoint point, EllipticCurve curve) { 393 return ECParameters.encodePoint(point, curve); 394 } 395 396 // In FIPS mode, set thread local providers; otherwise a no-op. 397 // Must be paired with endFipsProvider. beginFipsProvider()398 static Object beginFipsProvider() { 399 if (fipsProviderList == null) { 400 return null; 401 } else { 402 return Providers.beginThreadProviderList(fipsProviderList); 403 } 404 } 405 endFipsProvider(Object o)406 static void endFipsProvider(Object o) { 407 if (fipsProviderList != null) { 408 Providers.endThreadProviderList((ProviderList)o); 409 } 410 } 411 412 } 413