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