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