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 }