jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,398 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * 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
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.ssl;
+
+import java.net.Socket;
+
+import java.security.*;
+import java.security.cert.*;
+
+import javax.net.ssl.*;
+
+public class SSLContextImpl extends SSLContextSpi {
+
+    private static final Debug debug = Debug.getInstance("ssl");
+
+    private final EphemeralKeyManager ephemeralKeyManager;
+    private final SSLSessionContextImpl clientCache;
+    private final SSLSessionContextImpl serverCache;
+
+    private boolean isInitialized;
+
+    private X509ExtendedKeyManager keyManager;
+    private X509TrustManager trustManager;
+    private SecureRandom secureRandom;
+
+    public SSLContextImpl() {
+        this(null);
+    }
+
+    SSLContextImpl(SSLContextImpl other) {
+        if (other == null) {
+            ephemeralKeyManager = new EphemeralKeyManager();
+            clientCache = new SSLSessionContextImpl();
+            serverCache = new SSLSessionContextImpl();
+        } else {
+            ephemeralKeyManager = other.ephemeralKeyManager;
+            clientCache = other.clientCache;
+            serverCache = other.serverCache;
+        }
+    }
+
+    protected void engineInit(KeyManager[] km, TrustManager[] tm,
+                                SecureRandom sr) throws KeyManagementException {
+        isInitialized = false;
+        keyManager = chooseKeyManager(km);
+
+        if (tm == null) {
+            try {
+                TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+                        TrustManagerFactory.getDefaultAlgorithm());
+                tmf.init((KeyStore)null);
+                tm = tmf.getTrustManagers();
+            } catch (Exception e) {
+                // eat
+            }
+        }
+        trustManager = chooseTrustManager(tm);
+
+        if (sr == null) {
+            secureRandom = JsseJce.getSecureRandom();
+        } else {
+            if (SunJSSE.isFIPS() && (sr.getProvider() != SunJSSE.cryptoProvider)) {
+                throw new KeyManagementException
+                    ("FIPS mode: SecureRandom must be from provider "
+                    + SunJSSE.cryptoProvider.getName());
+            }
+            secureRandom = sr;
+        }
+
+        /*
+         * The initial delay of seeding the random number generator
+         * could be long enough to cause the initial handshake on our
+         * first connection to timeout and fail. Make sure it is
+         * primed and ready by getting some initial output from it.
+         */
+        if (debug != null && Debug.isOn("sslctx")) {
+            System.out.println("trigger seeding of SecureRandom");
+        }
+        secureRandom.nextInt();
+        if (debug != null && Debug.isOn("sslctx")) {
+            System.out.println("done seeding SecureRandom");
+        }
+        isInitialized = true;
+    }
+
+    private X509TrustManager chooseTrustManager(TrustManager[] tm)
+            throws KeyManagementException {
+        // We only use the first instance of X509TrustManager passed to us.
+        for (int i = 0; tm != null && i < tm.length; i++) {
+            if (tm[i] instanceof X509TrustManager) {
+                if (SunJSSE.isFIPS() && !(tm[i] instanceof X509TrustManagerImpl)) {
+                    throw new KeyManagementException
+                        ("FIPS mode: only SunJSSE TrustManagers may be used");
+                }
+                return (X509TrustManager)tm[i];
+            }
+        }
+
+        // nothing found, return a dummy X509TrustManager.
+        return DummyX509TrustManager.INSTANCE;
+    }
+
+    private X509ExtendedKeyManager chooseKeyManager(KeyManager[] kms)
+            throws KeyManagementException {
+        for (int i = 0; kms != null && i < kms.length; i++) {
+            KeyManager km = kms[i];
+            if (km instanceof X509KeyManager == false) {
+                continue;
+            }
+            if (SunJSSE.isFIPS()) {
+                // In FIPS mode, require that one of SunJSSE's own keymanagers
+                // is used. Otherwise, we cannot be sure that only keys from
+                // the FIPS token are used.
+                if ((km instanceof X509KeyManagerImpl)
+                            || (km instanceof SunX509KeyManagerImpl)) {
+                    return (X509ExtendedKeyManager)km;
+                } else {
+                    // throw exception, we don't want to silently use the
+                    // dummy keymanager without telling the user.
+                    throw new KeyManagementException
+                        ("FIPS mode: only SunJSSE KeyManagers may be used");
+                }
+            }
+            if (km instanceof X509ExtendedKeyManager) {
+                return (X509ExtendedKeyManager)km;
+            }
+            if (debug != null && Debug.isOn("sslctx")) {
+                System.out.println(
+                    "X509KeyManager passed to " +
+                    "SSLContext.init():  need an " +
+                    "X509ExtendedKeyManager for SSLEngine use");
+            }
+            return new AbstractWrapper((X509KeyManager)km);
+        }
+
+        // nothing found, return a dummy X509ExtendedKeyManager
+        return DummyX509KeyManager.INSTANCE;
+    }
+
+    protected SSLSocketFactory engineGetSocketFactory() {
+        if (!isInitialized) {
+            throw new IllegalStateException(
+                "SSLContextImpl is not initialized");
+        }
+        return new SSLSocketFactoryImpl(this);
+    }
+
+    protected SSLServerSocketFactory engineGetServerSocketFactory() {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+        return new SSLServerSocketFactoryImpl(this);
+    }
+
+    protected SSLEngine engineCreateSSLEngine() {
+        if (!isInitialized) {
+            throw new IllegalStateException(
+                "SSLContextImpl is not initialized");
+        }
+        return new SSLEngineImpl(this);
+    }
+
+    protected SSLEngine engineCreateSSLEngine(String host, int port) {
+        if (!isInitialized) {
+            throw new IllegalStateException(
+                "SSLContextImpl is not initialized");
+        }
+        return new SSLEngineImpl(this, host, port);
+    }
+
+    protected SSLSessionContext engineGetClientSessionContext() {
+        return clientCache;
+    }
+
+    protected SSLSessionContext engineGetServerSessionContext() {
+        return serverCache;
+    }
+
+    SecureRandom getSecureRandom() {
+        return secureRandom;
+    }
+
+    X509ExtendedKeyManager getX509KeyManager() {
+        return keyManager;
+    }
+
+    X509TrustManager getX509TrustManager() {
+        return trustManager;
+    }
+
+    EphemeralKeyManager getEphemeralKeyManager() {
+        return ephemeralKeyManager;
+    }
+
+}
+
+// Dummy X509TrustManager implementation, rejects all peer certificates.
+// Used if the application did not specify a proper X509TrustManager.
+final class DummyX509TrustManager implements X509TrustManager {
+
+    static final X509TrustManager INSTANCE = new DummyX509TrustManager();
+
+    private DummyX509TrustManager() {
+        // empty
+    }
+
+    /*
+     * Given the partial or complete certificate chain
+     * provided by the peer, build a certificate path
+     * to a trusted root and return if it can be
+     * validated and is trusted for client SSL authentication.
+     * If not, it throws an exception.
+     */
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+        throws CertificateException {
+        throw new CertificateException(
+            "No X509TrustManager implementation avaiable");
+    }
+
+    /*
+     * Given the partial or complete certificate chain
+     * provided by the peer, build a certificate path
+     * to a trusted root and return if it can be
+     * validated and is trusted for server SSL authentication.
+     * If not, it throws an exception.
+     */
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+        throws CertificateException {
+        throw new CertificateException(
+            "No X509TrustManager implementation available");
+    }
+
+    /*
+     * Return an array of issuer certificates which are trusted
+     * for authenticating peers.
+     */
+    public X509Certificate[] getAcceptedIssuers() {
+        return new X509Certificate[0];
+    }
+}
+
+/*
+ * A wrapper class to turn a X509KeyManager into an X509ExtendedKeyManager
+ */
+final class AbstractWrapper extends X509ExtendedKeyManager {
+
+    private final X509KeyManager km;
+
+    AbstractWrapper(X509KeyManager km) {
+        this.km = km;
+    }
+
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        return km.getClientAliases(keyType, issuers);
+    }
+
+    public String chooseClientAlias(String[] keyType, Principal[] issuers,
+            Socket socket) {
+        return km.chooseClientAlias(keyType, issuers, socket);
+    }
+
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        return km.getServerAliases(keyType, issuers);
+    }
+
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+            Socket socket) {
+        return km.chooseServerAlias(keyType, issuers, socket);
+    }
+
+    public X509Certificate[] getCertificateChain(String alias) {
+        return km.getCertificateChain(alias);
+    }
+
+    public PrivateKey getPrivateKey(String alias) {
+        return km.getPrivateKey(alias);
+    }
+
+    // Inherit chooseEngineClientAlias() and chooseEngineServerAlias() from
+    // X509ExtendedKeymanager. It defines them to return null;
+}
+
+
+// Dummy X509KeyManager implementation, never returns any certificates/keys.
+// Used if the application did not specify a proper X509TrustManager.
+final class DummyX509KeyManager extends X509ExtendedKeyManager {
+
+    static final X509ExtendedKeyManager INSTANCE = new DummyX509KeyManager();
+
+    private DummyX509KeyManager() {
+        // empty
+    }
+
+    /*
+     * Get the matching aliases for authenticating the client side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     */
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        return null;
+    }
+
+    /*
+     * Choose an alias to authenticate the client side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     */
+    public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
+            Socket socket) {
+        return null;
+    }
+
+    /*
+     * Choose an alias to authenticate the client side of an
+     * engine given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     */
+    public String chooseEngineClientAlias(
+            String[] keyTypes, Principal[] issuers, SSLEngine engine) {
+        return null;
+    }
+
+    /*
+     * Get the matching aliases for authenticating the server side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     */
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        return null;
+    }
+
+    /*
+     * Choose an alias to authenticate the server side of a secure
+     * socket given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     */
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+            Socket socket) {
+        return null;
+    }
+
+    /*
+     * Choose an alias to authenticate the server side of an engine
+     * given the public key type and the list of
+     * certificate issuer authorities recognized by the peer (if any).
+     */
+    public String chooseEngineServerAlias(
+            String keyType, Principal[] issuers, SSLEngine engine) {
+        return null;
+    }
+
+    /**
+     * Returns the certificate chain associated with the given alias.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate chain (ordered with the user's certificate first
+     * and the root certificate authority last)
+     */
+    public X509Certificate[] getCertificateChain(String alias) {
+        return null;
+    }
+
+    /*
+     * Returns the key associated with the given alias, using the given
+     * password to recover it.
+     *
+     * @param alias the alias name
+     *
+     * @return the requested key
+     */
+    public PrivateKey getPrivateKey(String alias) {
+        return null;
+    }
+}