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