JsseJce.java 14.8 KB
Newer Older
D
duke 已提交
1
/*
X
xuelei 已提交
2
 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
 */

package sun.security.ssl;

import java.util.*;
import java.math.BigInteger;

import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;

import javax.crypto.*;

// explicit import to override the Provider class in this package
import java.security.Provider;

// need internal Sun classes for FIPS tricks
import sun.security.jca.Providers;
import sun.security.jca.ProviderList;

import sun.security.ec.ECParameters;
import sun.security.ec.NamedCurve;

import static sun.security.ssl.SunJSSE.cryptoProvider;

/**
 * This class contains a few static methods for interaction with the JCA/JCE
 * to obtain implementations, etc.
 *
 * @author  Andreas Sterbenz
 */
final class JsseJce {

    private final static ProviderList fipsProviderList;

    // Flag indicating whether EC crypto is available.
    // If null, then we have not checked yet.
    // If yes, then all the EC based crypto we need is available.
62
    private static Boolean ecAvailable;
D
duke 已提交
63

64 65 66 67 68 69 70 71
    // Flag indicating whether Kerberos crypto is available.
    // If true, then all the Kerberos-based crypto we need is available.
    private final static boolean kerberosAvailable;
    static {
        boolean temp;
        try {
            AccessController.doPrivileged(
                new PrivilegedExceptionAction<Void>() {
72
                    @Override
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
                    public Void run() throws Exception {
                        // Test for Kerberos using the bootstrap class loader
                        Class.forName("sun.security.krb5.PrincipalName", true,
                                null);
                        return null;
                    }
                });
            temp = true;

        } catch (Exception e) {
            temp = false;
        }
        kerberosAvailable = temp;
    }

D
duke 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    static {
        // force FIPS flag initialization
        // Because isFIPS() is synchronized and cryptoProvider is not modified
        // after it completes, this also eliminates the need for any further
        // synchronization when accessing cryptoProvider
        if (SunJSSE.isFIPS() == false) {
            fipsProviderList = null;
        } else {
            // Setup a ProviderList that can be used by the trust manager
            // during certificate chain validation. All the crypto must be
            // from the FIPS provider, but we also allow the required
            // certificate related services from the SUN provider.
            Provider sun = Security.getProvider("SUN");
            if (sun == null) {
                throw new RuntimeException
                    ("FIPS mode: SUN provider must be installed");
            }
            Provider sunCerts = new SunCertificates(sun);
            fipsProviderList = ProviderList.newList(cryptoProvider, sunCerts);
        }
    }

    private static final class SunCertificates extends Provider {
111 112
        private static final long serialVersionUID = -3284138292032213752L;

D
duke 已提交
113 114 115
        SunCertificates(final Provider p) {
            super("SunCertificates", 1.0d, "SunJSSE internal");
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
116
                @Override
D
duke 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
                public Object run() {
                    // copy certificate related services from the Sun provider
                    for (Map.Entry<Object,Object> entry : p.entrySet()) {
                        String key = (String)entry.getKey();
                        if (key.startsWith("CertPathValidator.")
                                || key.startsWith("CertPathBuilder.")
                                || key.startsWith("CertStore.")
                                || key.startsWith("CertificateFactory.")) {
                            put(key, entry.getValue());
                        }
                    }
                    return null;
                }
            });
        }
    }

    /**
     * JCE transformation string for RSA with PKCS#1 v1.5 padding.
     * Can be used for encryption, decryption, signing, verifying.
     */
    final static String CIPHER_RSA_PKCS1 = "RSA/ECB/PKCS1Padding";
    /**
     * JCE transformation string for the stream cipher RC4.
     */
    final static String CIPHER_RC4 = "RC4";
    /**
     * JCE transformation string for DES in CBC mode without padding.
     */
    final static String CIPHER_DES = "DES/CBC/NoPadding";
    /**
     * JCE transformation string for (3-key) Triple DES in CBC mode
     * without padding.
     */
    final static String CIPHER_3DES = "DESede/CBC/NoPadding";
    /**
     * JCE transformation string for AES in CBC mode
     * without padding.
     */
    final static String CIPHER_AES = "AES/CBC/NoPadding";
X
xuelei 已提交
157 158 159 160 161
    /**
     * JCE transformation string for AES in GCM mode
     * without padding.
     */
    final static String CIPHER_AES_GCM = "AES/GCM/NoPadding";
D
duke 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
    /**
     * JCA identifier string for DSA, i.e. a DSA with SHA-1.
     */
    final static String SIGNATURE_DSA = "DSA";
    /**
     * JCA identifier string for ECDSA, i.e. a ECDSA with SHA-1.
     */
    final static String SIGNATURE_ECDSA = "SHA1withECDSA";
    /**
     * JCA identifier string for Raw DSA, i.e. a DSA signature without
     * hashing where the application provides the SHA-1 hash of the data.
     * Note that the standard name is "NONEwithDSA" but we use "RawDSA"
     * for compatibility.
     */
    final static String SIGNATURE_RAWDSA = "RawDSA";
    /**
     * JCA identifier string for Raw ECDSA, i.e. a DSA signature without
     * hashing where the application provides the SHA-1 hash of the data.
     */
    final static String SIGNATURE_RAWECDSA = "NONEwithECDSA";
    /**
     * JCA identifier string for Raw RSA, i.e. a RSA PKCS#1 v1.5 signature
     * without hashing where the application provides the hash of the data.
     * Used for RSA client authentication with a 36 byte hash.
     */
    final static String SIGNATURE_RAWRSA = "NONEwithRSA";
    /**
     * JCA identifier string for the SSL/TLS style RSA Signature. I.e.
     * an signature using RSA with PKCS#1 v1.5 padding signing a
     * concatenation of an MD5 and SHA-1 digest.
     */
    final static String SIGNATURE_SSLRSA = "MD5andSHA1withRSA";

    private JsseJce() {
        // no instantiation of this class
    }

199
    synchronized static boolean isEcAvailable() {
D
duke 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
        if (ecAvailable == null) {
            try {
                JsseJce.getSignature(SIGNATURE_ECDSA);
                JsseJce.getSignature(SIGNATURE_RAWECDSA);
                JsseJce.getKeyAgreement("ECDH");
                JsseJce.getKeyFactory("EC");
                JsseJce.getKeyPairGenerator("EC");
                ecAvailable = true;
            } catch (Exception e) {
                ecAvailable = false;
            }
        }
        return ecAvailable;
    }

215
    synchronized static void clearEcAvailable() {
D
duke 已提交
216 217 218
        ecAvailable = null;
    }

219 220 221 222
    static boolean isKerberosAvailable() {
        return kerberosAvailable;
    }

D
duke 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
    /**
     * Return an JCE cipher implementation for the specified algorithm.
     */
    static Cipher getCipher(String transformation)
            throws NoSuchAlgorithmException {
        try {
            if (cryptoProvider == null) {
                return Cipher.getInstance(transformation);
            } else {
                return Cipher.getInstance(transformation, cryptoProvider);
            }
        } catch (NoSuchPaddingException e) {
            throw new NoSuchAlgorithmException(e);
        }
    }

    /**
     * Return an JCA signature implementation for the specified algorithm.
     * The algorithm string should be one of the constants defined
     * in this class.
     */
    static Signature getSignature(String algorithm)
            throws NoSuchAlgorithmException {
        if (cryptoProvider == null) {
            return Signature.getInstance(algorithm);
        } else {
            // reference equality
            if (algorithm == SIGNATURE_SSLRSA) {
                // The SunPKCS11 provider currently does not support this
                // special algorithm. We allow a fallback in this case because
                // the SunJSSE implementation does the actual crypto using
                // a NONEwithRSA signature obtained from the cryptoProvider.
                if (cryptoProvider.getService("Signature", algorithm) == null) {
256 257 258
                    // Calling Signature.getInstance() and catching the
                    // exception would be cleaner, but exceptions are a little
                    // expensive. So we check directly via getService().
D
duke 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
                    try {
                        return Signature.getInstance(algorithm, "SunJSSE");
                    } catch (NoSuchProviderException e) {
                        throw new NoSuchAlgorithmException(e);
                    }
                }
            }
            return Signature.getInstance(algorithm, cryptoProvider);
        }
    }

    static KeyGenerator getKeyGenerator(String algorithm)
            throws NoSuchAlgorithmException {
        if (cryptoProvider == null) {
            return KeyGenerator.getInstance(algorithm);
        } else {
            return KeyGenerator.getInstance(algorithm, cryptoProvider);
        }
    }

    static KeyPairGenerator getKeyPairGenerator(String algorithm)
            throws NoSuchAlgorithmException {
        if (cryptoProvider == null) {
            return KeyPairGenerator.getInstance(algorithm);
        } else {
            return KeyPairGenerator.getInstance(algorithm, cryptoProvider);
        }
    }

    static KeyAgreement getKeyAgreement(String algorithm)
            throws NoSuchAlgorithmException {
        if (cryptoProvider == null) {
            return KeyAgreement.getInstance(algorithm);
        } else {
            return KeyAgreement.getInstance(algorithm, cryptoProvider);
        }
    }

    static Mac getMac(String algorithm)
            throws NoSuchAlgorithmException {
        if (cryptoProvider == null) {
            return Mac.getInstance(algorithm);
        } else {
            return Mac.getInstance(algorithm, cryptoProvider);
        }
    }

    static KeyFactory getKeyFactory(String algorithm)
            throws NoSuchAlgorithmException {
        if (cryptoProvider == null) {
            return KeyFactory.getInstance(algorithm);
        } else {
            return KeyFactory.getInstance(algorithm, cryptoProvider);
        }
    }

    static SecureRandom getSecureRandom() throws KeyManagementException {
        if (cryptoProvider == null) {
            return new SecureRandom();
        }
        // Try "PKCS11" first. If that is not supported, iterate through
        // the provider and return the first working implementation.
        try {
            return SecureRandom.getInstance("PKCS11", cryptoProvider);
        } catch (NoSuchAlgorithmException e) {
            // ignore
        }
        for (Provider.Service s : cryptoProvider.getServices()) {
            if (s.getType().equals("SecureRandom")) {
                try {
                    return SecureRandom.getInstance(s.getAlgorithm(), cryptoProvider);
                } catch (NoSuchAlgorithmException ee) {
                    // ignore
                }
            }
        }
        throw new KeyManagementException("FIPS mode: no SecureRandom "
            + " implementation found in provider " + cryptoProvider.getName());
    }

    static MessageDigest getMD5() {
        return getMessageDigest("MD5");
    }

    static MessageDigest getSHA() {
        return getMessageDigest("SHA");
    }

    static MessageDigest getMessageDigest(String algorithm) {
        try {
            if (cryptoProvider == null) {
                return MessageDigest.getInstance(algorithm);
            } else {
                return MessageDigest.getInstance(algorithm, cryptoProvider);
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException
                        ("Algorithm " + algorithm + " not available", e);
        }
    }

    static int getRSAKeyLength(PublicKey key) {
        BigInteger modulus;
        if (key instanceof RSAPublicKey) {
            modulus = ((RSAPublicKey)key).getModulus();
        } else {
            RSAPublicKeySpec spec = getRSAPublicKeySpec(key);
            modulus = spec.getModulus();
        }
        return modulus.bitLength();
    }

    static RSAPublicKeySpec getRSAPublicKeySpec(PublicKey key) {
        if (key instanceof RSAPublicKey) {
            RSAPublicKey rsaKey = (RSAPublicKey)key;
            return new RSAPublicKeySpec(rsaKey.getModulus(),
                                        rsaKey.getPublicExponent());
        }
        try {
            KeyFactory factory = JsseJce.getKeyFactory("RSA");
379
            return factory.getKeySpec(key, RSAPublicKeySpec.class);
D
duke 已提交
380
        } catch (Exception e) {
381
            throw new RuntimeException(e);
D
duke 已提交
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
        }
    }

    static ECParameterSpec getECParameterSpec(String namedCurveOid) {
        return NamedCurve.getECParameterSpec(namedCurveOid);
    }

    static String getNamedCurveOid(ECParameterSpec params) {
        return ECParameters.getCurveName(params);
    }

    static ECPoint decodePoint(byte[] encoded, EllipticCurve curve)
            throws java.io.IOException {
        return ECParameters.decodePoint(encoded, curve);
    }

    static byte[] encodePoint(ECPoint point, EllipticCurve curve) {
        return ECParameters.encodePoint(point, curve);
    }

    // In FIPS mode, set thread local providers; otherwise a no-op.
    // Must be paired with endFipsProvider.
    static Object beginFipsProvider() {
        if (fipsProviderList == null) {
            return null;
        } else {
            return Providers.beginThreadProviderList(fipsProviderList);
        }
    }

    static void endFipsProvider(Object o) {
        if (fipsProviderList != null) {
            Providers.endThreadProviderList((ProviderList)o);
        }
    }

}