8038089: TLS optional support for Kerberos cipher suites needs to be re-examine
authorweijun
Tue, 02 Jun 2015 22:26:36 +0800
changeset 30905 bba6fefdd660
parent 30904 ec0224270f90
child 30909 aa5928dda820
8038089: TLS optional support for Kerberos cipher suites needs to be re-examine Reviewed-by: xuelei
jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java
jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchange.java
jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java
jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java
jdk/src/java.base/share/classes/sun/security/ssl/KerberosClientKeyExchange.java
jdk/src/java.base/share/classes/sun/security/ssl/Krb5Helper.java
jdk/src/java.base/share/classes/sun/security/ssl/Krb5Proxy.java
jdk/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java
jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java
jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java
jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java
jdk/src/java.security.jgss/share/classes/META-INF/services/sun.security.ssl.ClientKeyExchangeService
jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java
jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/Krb5KeyExchangeService.java
jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java
jdk/test/sun/security/krb5/auto/SSLwithPerms.java
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Tue Jun 02 04:01:04 2015 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Tue Jun 02 22:26:36 2015 +0800
@@ -44,8 +44,6 @@
 
 import javax.net.ssl.*;
 
-import javax.security.auth.Subject;
-
 import sun.security.ssl.HandshakeMessage.*;
 import static sun.security.ssl.CipherSuite.KeyExchange.*;
 
@@ -234,7 +232,8 @@
 
         case HandshakeMessage.ht_certificate:
             if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON
-                    || keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
+                    || ClientKeyExchangeService.find(keyExchange.name) != null) {
+                // No external key exchange provider needs a cert now.
                 fatalSE(Alerts.alert_unexpected_message,
                     "unexpected server cert chain");
                 // NOTREACHED
@@ -333,13 +332,9 @@
                 throw new SSLProtocolException(
                     "Protocol violation: server sent a server key exchange"
                     + " message for key exchange " + keyExchange);
-            case K_KRB5:
-            case K_KRB5_EXPORT:
-                throw new SSLProtocolException(
-                    "unexpected receipt of server key exchange algorithm");
             default:
                 throw new SSLProtocolException(
-                    "unsupported key exchange algorithm = "
+                    "unsupported or unexpected key exchange algorithm = "
                     + keyExchange);
             }
             break;
@@ -350,10 +345,11 @@
                 throw new SSLHandshakeException(
                     "Client authentication requested for "+
                     "anonymous cipher suite.");
-            } else if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
+            } else if (ClientKeyExchangeService.find(keyExchange.name) != null) {
+                // No external key exchange provider needs a cert now.
                 throw new SSLHandshakeException(
                     "Client certificate requested for "+
-                    "kerberos cipher suite.");
+                    "external cipher suite: " + keyExchange);
             }
             certRequest = new CertificateRequest(input, protocolVersion);
             if (debug != null && Debug.isOn("handshake")) {
@@ -626,45 +622,17 @@
                 }
 
                 // validate subject identity
-                if (sessionSuite.keyExchange == K_KRB5 ||
-                    sessionSuite.keyExchange == K_KRB5_EXPORT) {
+                ClientKeyExchangeService p =
+                        ClientKeyExchangeService.find(sessionSuite.keyExchange.name);
+                if (p != null) {
                     Principal localPrincipal = session.getLocalPrincipal();
 
-                    Subject subject = null;
-                    try {
-                        subject = AccessController.doPrivileged(
-                            new PrivilegedExceptionAction<Subject>() {
-                            @Override
-                            public Subject run() throws Exception {
-                                return Krb5Helper.getClientSubject(getAccSE());
-                            }});
-                    } catch (PrivilegedActionException e) {
-                        subject = null;
-                        if (debug != null && Debug.isOn("session")) {
-                            System.out.println("Attempt to obtain" +
-                                        " subject failed!");
-                        }
-                    }
-
-                    if (subject != null) {
-                        // Eliminate dependency on KerberosPrincipal
-                        Set<Principal> principals =
-                            subject.getPrincipals(Principal.class);
-                        if (!principals.contains(localPrincipal)) {
-                            throw new SSLProtocolException("Server resumed" +
-                                " session with wrong subject identity");
-                        } else {
-                            if (debug != null && Debug.isOn("session"))
-                                System.out.println("Subject identity is same");
-                        }
+                    if (p.isRelated(true, getAccSE(), localPrincipal)) {
+                        if (debug != null && Debug.isOn("session"))
+                            System.out.println("Subject identity is same");
                     } else {
-                        if (debug != null && Debug.isOn("session"))
-                            System.out.println("Kerberos credentials are not" +
-                                " present in the current Subject; check if " +
-                                " javax.security.auth.useSubjectAsCreds" +
-                                " system property has been set to false");
-                        throw new SSLProtocolException
-                            ("Server resumed session with no subject");
+                        throw new SSLProtocolException("Server resumed" +
+                                " session with wrong subject identity or no subject");
                     }
                 }
 
@@ -1012,8 +980,14 @@
             ecdh = new ECDHCrypt(params, sslContext.getSecureRandom());
             m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());
             break;
-        case K_KRB5:
-        case K_KRB5_EXPORT:
+        default:
+            ClientKeyExchangeService p =
+                    ClientKeyExchangeService.find(keyExchange.name);
+            if (p == null) {
+                // somethings very wrong
+                throw new RuntimeException
+                        ("Unsupported key exchange: " + keyExchange);
+            }
             String sniHostname = null;
             for (SNIServerName serverName : requestedServerNames) {
                 if (serverName instanceof SNIHostName) {
@@ -1022,13 +996,13 @@
                 }
             }
 
-            KerberosClientKeyExchange kerberosMsg = null;
+            ClientKeyExchange exMsg = null;
             if (sniHostname != null) {
                 // use first requested SNI hostname
                 try {
-                    kerberosMsg = new KerberosClientKeyExchange(
-                        sniHostname, getAccSE(), protocolVersion,
-                        sslContext.getSecureRandom());
+                    exMsg = p.createClientExchange(
+                            sniHostname, getAccSE(), protocolVersion,
+                            sslContext.getSecureRandom());
                 } catch(IOException e) {
                     if (serverNamesAccepted) {
                         // server accepted requested SNI hostname,
@@ -1044,26 +1018,22 @@
                 }
             }
 
-            if (kerberosMsg == null) {
+            if (exMsg == null) {
                 String hostname = getHostSE();
                 if (hostname == null) {
                     throw new IOException("Hostname is required" +
-                        " to use Kerberos cipher suites");
+                        " to use " + keyExchange + " key exchange");
                 }
-                kerberosMsg = new KerberosClientKeyExchange(
-                     hostname, getAccSE(), protocolVersion,
-                     sslContext.getSecureRandom());
+                exMsg = p.createClientExchange(
+                        hostname, getAccSE(), protocolVersion,
+                        sslContext.getSecureRandom());
             }
 
             // Record the principals involved in exchange
-            session.setPeerPrincipal(kerberosMsg.getPeerPrincipal());
-            session.setLocalPrincipal(kerberosMsg.getLocalPrincipal());
-            m2 = kerberosMsg;
+            session.setPeerPrincipal(exMsg.getPeerPrincipal());
+            session.setLocalPrincipal(exMsg.getLocalPrincipal());
+            m2 = exMsg;
             break;
-        default:
-            // somethings very wrong
-            throw new RuntimeException
-                                ("Unsupported key exchange: " + keyExchange);
         }
         if (debug != null && Debug.isOn("handshake")) {
             m2.print(System.out);
@@ -1094,13 +1064,6 @@
         case K_RSA_EXPORT:
             preMasterSecret = ((RSAClientKeyExchange)m2).preMaster;
             break;
-        case K_KRB5:
-        case K_KRB5_EXPORT:
-            byte[] secretBytes =
-                ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();
-            preMasterSecret = new SecretKeySpec(secretBytes,
-                "TlsPremasterSecret");
-            break;
         case K_DHE_RSA:
         case K_DHE_DSS:
         case K_DH_ANON:
@@ -1116,8 +1079,13 @@
             preMasterSecret = ecdh.getAgreedSecret(serverKey);
             break;
         default:
-            throw new IOException("Internal error: unknown key exchange "
-                + keyExchange);
+            if (ClientKeyExchangeService.find(keyExchange.name) != null) {
+                preMasterSecret =
+                        ((ClientKeyExchange) m2).clientKeyExchange();
+            } else {
+                throw new IOException("Internal error: unknown key exchange "
+                        + keyExchange);
+            }
         }
 
         calculateKeys(preMasterSecret, null);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchange.java	Tue Jun 02 22:26:36 2015 +0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import javax.crypto.SecretKey;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.Principal;
+
+/**
+ * Models a non-certificate based ClientKeyExchange
+ */
+public abstract class ClientKeyExchange extends HandshakeMessage {
+
+    public ClientKeyExchange() {
+    }
+
+    @Override
+    int messageType() {
+        return ht_client_key_exchange;
+    }
+
+    @Override
+    abstract public int messageLength();
+
+    @Override
+    abstract public void send(HandshakeOutStream s) throws IOException;
+
+    @Override
+    abstract public void print(PrintStream s) throws IOException;
+
+    abstract public SecretKey clientKeyExchange();
+
+    abstract public Principal getPeerPrincipal();
+
+    abstract public Principal getLocalPrincipal();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java	Tue Jun 02 22:26:36 2015 +0800
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import sun.security.action.GetPropertyAction;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+import java.util.*;
+
+/**
+ * Models a service that provides support for a particular client key exchange
+ * mode. Currently used to implement Kerberos-related cipher suites.
+ *
+ * @since 1.9
+ */
+public interface ClientKeyExchangeService {
+
+    static class Loader {
+        private static final Map<String,ClientKeyExchangeService>
+                providers = new HashMap<>();
+
+        static {
+            final String key = "java.home";
+            String path = AccessController.doPrivileged(
+                    new GetPropertyAction(key), null,
+                    new PropertyPermission(key, "read"));
+            ServiceLoader<ClientKeyExchangeService> sc =
+                    AccessController.doPrivileged(
+                            (PrivilegedAction<ServiceLoader<ClientKeyExchangeService>>)
+                                    () -> ServiceLoader.loadInstalled(ClientKeyExchangeService.class),
+                            null,
+                            new FilePermission(new File(path, "-").toString(), "read"));
+            Iterator<ClientKeyExchangeService> iter = sc.iterator();
+            while (iter.hasNext()) {
+                ClientKeyExchangeService cs = iter.next();
+                for (String ex: cs.supported()) {
+                    providers.put(ex, cs);
+                }
+            }
+        }
+
+    }
+
+    public static ClientKeyExchangeService find(String ex) {
+        return Loader.providers.get(ex);
+    }
+
+
+    /**
+     * Returns the supported key exchange modes by this provider.
+     * @return the supported key exchange modes
+     */
+    String[] supported();
+
+    /**
+     * Returns a generalized credential object on the server side. The server
+     * side can use the info to determine if a cipher suite can be enabled.
+     * @param acc the AccessControlContext of the SSL session
+     * @return the credential object
+     */
+    Object getServiceCreds(AccessControlContext acc);
+
+    /**
+     * Returns the host name for a service principal. The info can be used in
+     * SNI or host name verifier.
+     * @param principal the principal of a service
+     * @return the string formed host name
+     */
+    String getServiceHostName(Principal principal);
+
+    /**
+     * Returns whether the specified principal is related to the current
+     * SSLSession. The info can be used to verify a SSL resume.
+     * @param isClient if true called from client side, otherwise from server
+     * @param acc the AccessControlContext of the SSL session
+     * @param p the specified principal
+     * @return true if related
+     */
+    boolean isRelated(boolean isClient, AccessControlContext acc, Principal p);
+
+    /**
+     * Creates the ClientKeyExchange object on the client side.
+     * @param serverName the intented peer name
+     * @param acc the AccessControlContext of the SSL session
+     * @param protocolVersion the TLS protocol version
+     * @param rand the SecureRandom that will used to generate the premaster
+     * @return the new Exchanger object
+     * @throws IOException if there is an error
+     */
+    ClientKeyExchange createClientExchange(String serverName, AccessControlContext acc,
+            ProtocolVersion protocolVersion, SecureRandom rand) throws IOException;
+
+    /**
+     * Create the ClientKeyExchange on the server side.
+     * @param protocolVersion the protocol version
+     * @param clientVersion the input protocol version
+     * @param rand a SecureRandom object used to generate premaster
+     *             (if the server has to create one)
+     * @param encodedTicket the ticket from client
+     * @param encrypted the encrypted premaster secret from client
+     * @param acc the AccessControlContext of the SSL session
+     * @param ServiceCreds the service side credentials object as retrived from
+     *                     {@link #getServiceCreds}
+     * @return the new Exchanger object
+     * @throws IOException if there is an error
+     */
+    ClientKeyExchange createServerExchange(
+            ProtocolVersion protocolVersion, ProtocolVersion clientVersion,
+            SecureRandom rand, byte[] encodedTicket, byte[] encrypted,
+            AccessControlContext acc, Object ServiceCreds) throws IOException;
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Tue Jun 02 04:01:04 2015 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Tue Jun 02 22:26:36 2015 +0800
@@ -64,24 +64,9 @@
     // 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>() {
-                    @Override
-                    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;
+        ClientKeyExchangeService p =
+                ClientKeyExchangeService.find("KRB5");
+        kerberosAvailable = (p != null);
     }
 
     static {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/KerberosClientKeyExchange.java	Tue Jun 02 04:01:04 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.security.AccessController;
-import java.security.AccessControlContext;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.SecureRandom;
-import javax.crypto.SecretKey;
-
-/**
- * A helper class that calls the KerberosClientKeyExchange implementation.
- */
-public class KerberosClientKeyExchange extends HandshakeMessage {
-
-    private static final String IMPL_CLASS =
-        "sun.security.ssl.krb5.KerberosClientKeyExchangeImpl";
-
-    private static final Class<?> implClass = AccessController.doPrivileged(
-            new PrivilegedAction<Class<?>>() {
-                @Override
-                public Class<?> run() {
-                    try {
-                        return Class.forName(IMPL_CLASS, true, null);
-                    } catch (ClassNotFoundException cnf) {
-                        return null;
-                    }
-                }
-            }
-        );
-    private final KerberosClientKeyExchange impl = createImpl();
-
-    private KerberosClientKeyExchange createImpl() {
-        if (implClass != null &&
-                getClass() == KerberosClientKeyExchange.class) {
-            try {
-                return (KerberosClientKeyExchange)implClass.newInstance();
-            } catch (InstantiationException e) {
-                throw new AssertionError(e);
-            } catch (IllegalAccessException e) {
-                throw new AssertionError(e);
-            }
-        }
-        return null;
-    }
-
-    // This constructor will be called when constructing an instance of its
-    // subclass -- KerberosClientKeyExchangeImpl.  Please won't check the
-    // value of impl variable in this constructor.
-    protected KerberosClientKeyExchange() {
-        // please won't check the value of impl variable
-    }
-
-    public KerberosClientKeyExchange(String serverName,
-        AccessControlContext acc, ProtocolVersion protocolVersion,
-        SecureRandom rand) throws IOException {
-
-        if (impl != null) {
-            init(serverName, acc, protocolVersion, rand);
-        } else {
-            throw new IllegalStateException("Kerberos is unavailable");
-        }
-    }
-
-    public KerberosClientKeyExchange(ProtocolVersion protocolVersion,
-            ProtocolVersion clientVersion, SecureRandom rand,
-            HandshakeInStream input, AccessControlContext acc,
-            Object serverKeys) throws IOException {
-
-        if (impl != null) {
-            init(protocolVersion, clientVersion, rand, input, acc, serverKeys);
-        } else {
-            throw new IllegalStateException("Kerberos is unavailable");
-        }
-    }
-
-    @Override
-    int messageType() {
-        return ht_client_key_exchange;
-    }
-
-    @Override
-    public int messageLength() {
-        return impl.messageLength();
-    }
-
-    @Override
-    public void send(HandshakeOutStream s) throws IOException {
-        impl.send(s);
-    }
-
-    @Override
-    public void print(PrintStream p) throws IOException {
-        impl.print(p);
-    }
-
-    public void init(String serverName,
-        AccessControlContext acc, ProtocolVersion protocolVersion,
-        SecureRandom rand) throws IOException {
-
-        if (impl != null) {
-            impl.init(serverName, acc, protocolVersion, rand);
-        }
-    }
-
-    public void init(ProtocolVersion protocolVersion,
-            ProtocolVersion clientVersion, SecureRandom rand,
-            HandshakeInStream input, AccessControlContext acc,
-            Object ServiceCreds) throws IOException {
-
-        if (impl != null) {
-            impl.init(protocolVersion, clientVersion,
-                                    rand, input, acc, ServiceCreds);
-        }
-    }
-
-    public byte[] getUnencryptedPreMasterSecret() {
-        return impl.getUnencryptedPreMasterSecret();
-    }
-
-    public Principal getPeerPrincipal(){
-        return impl.getPeerPrincipal();
-    }
-
-    public Principal getLocalPrincipal(){
-        return impl.getLocalPrincipal();
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Krb5Helper.java	Tue Jun 02 04:01:04 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.Permission;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-
-/**
- * A helper class for Kerberos APIs.
- */
-public final class Krb5Helper {
-
-    private Krb5Helper() { }
-
-    // loads Krb5Proxy implementation class if available
-    private static final String IMPL_CLASS =
-        "sun.security.ssl.krb5.Krb5ProxyImpl";
-
-    private static final Krb5Proxy proxy =
-        AccessController.doPrivileged(new PrivilegedAction<Krb5Proxy>() {
-            @Override
-            public Krb5Proxy run() {
-                try {
-                    Class<?> c = Class.forName(IMPL_CLASS, true, null);
-                    return (Krb5Proxy)c.newInstance();
-                } catch (ClassNotFoundException cnf) {
-                    return null;
-                } catch (InstantiationException e) {
-                    throw new AssertionError(e);
-                } catch (IllegalAccessException e) {
-                    throw new AssertionError(e);
-                }
-            }});
-
-    /**
-     * Returns true if Kerberos is available.
-     */
-    public static boolean isAvailable() {
-        return proxy != null;
-    }
-
-    private static void ensureAvailable() {
-        if (proxy == null)
-            throw new AssertionError("Kerberos should have been available");
-    }
-
-    /**
-     * Returns the Subject associated with client-side of the SSL socket.
-     */
-    public static Subject getClientSubject(AccessControlContext acc)
-            throws LoginException {
-        ensureAvailable();
-        return proxy.getClientSubject(acc);
-    }
-
-    /**
-     * Returns the Subject associated with server-side of the SSL socket.
-     */
-    public static Subject getServerSubject(AccessControlContext acc)
-            throws LoginException {
-        ensureAvailable();
-        return proxy.getServerSubject(acc);
-    }
-
-    /**
-     * Returns the KerberosKeys for the default server-side principal.
-     */
-    public static Object getServiceCreds(AccessControlContext acc)
-            throws LoginException {
-        ensureAvailable();
-        return proxy.getServiceCreds(acc);
-    }
-
-    /**
-     * Returns the server-side principal name associated with the KerberosKey.
-     */
-    public static String getServerPrincipalName(Object serviceCreds) {
-        ensureAvailable();
-        return proxy.getServerPrincipalName(serviceCreds);
-    }
-
-    /**
-     * Returns the hostname embedded in the principal name.
-     */
-    public static String getPrincipalHostName(Principal principal) {
-        ensureAvailable();
-        return proxy.getPrincipalHostName(principal);
-    }
-
-    /**
-     * Returns a ServicePermission for the principal name and action.
-     */
-    public static Permission getServicePermission(String principalName,
-            String action) {
-        ensureAvailable();
-        return proxy.getServicePermission(principalName, action);
-    }
-
-    /**
-     * Determines if the Subject might contain creds for princ.
-     */
-    public static boolean isRelated(Subject subject, Principal princ) {
-        ensureAvailable();
-        return proxy.isRelated(subject, princ);
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Krb5Proxy.java	Tue Jun 02 04:01:04 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.AccessControlContext;
-import java.security.Permission;
-import java.security.Principal;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-
-/**
- * An interface to a subset of the Kerberos APIs to avoid a static dependency
- * on the types defined by these APIs.
- */
-public interface Krb5Proxy {
-
-    /**
-     * Returns the Subject associated with the client-side of the SSL socket.
-     */
-    Subject getClientSubject(AccessControlContext acc) throws LoginException;
-
-    /**
-     * Returns the Subject associated with the server-side of the SSL socket.
-     */
-    Subject getServerSubject(AccessControlContext acc) throws LoginException;
-
-
-    /**
-     * Returns the Kerberos ServiceCreds for the default server-side principal.
-     */
-    Object getServiceCreds(AccessControlContext acc) throws LoginException;
-
-    /**
-     * Returns the server-side principal name associated with the KerberosKey.
-     */
-    String getServerPrincipalName(Object serviceCreds);
-
-    /**
-     * Returns the hostname embedded in the principal name.
-     */
-    String getPrincipalHostName(Principal principal);
-
-    /**
-     * Returns a ServicePermission for the principal name and action.
-     */
-    Permission getServicePermission(String principalName, String action);
-
-    /**
-     * Determines if the Subject might contain creds for princ.
-     */
-    boolean isRelated(Subject subject, Principal princ);
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java	Tue Jun 02 04:01:04 2015 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java	Tue Jun 02 22:26:36 2015 +0800
@@ -352,18 +352,13 @@
                         components.add("ECDH_ANON");
                     }
                     break;
-                case K_KRB5:
-                    if (!forCertPathOnly) {
-                        components.add("KRB5");
+                default:
+                    if (ClientKeyExchangeService.find(keyExchange.name) != null) {
+                        if (!forCertPathOnly) {
+                            components.add(keyExchange.name);
+                        }
                     }
-                    break;
-                case K_KRB5_EXPORT:
-                    if (!forCertPathOnly) {
-                        components.add("KRB5_EXPORT");
-                    }
-                    break;
-                default:
-                    // ignore
+                    // otherwise ignore
             }
 
             return components;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Tue Jun 02 04:01:04 2015 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Tue Jun 02 22:26:36 2015 +0800
@@ -425,10 +425,9 @@
         // change record of peer identity even by accident, much
         // less do it intentionally.
         //
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             throw new SSLPeerUnverifiedException("no certificates expected"
-                        + " for Kerberos cipher suites");
+                        + " for " + cipherSuite.keyExchange + " cipher suites");
         }
         if (peerCerts == null) {
             throw new SSLPeerUnverifiedException("peer not authenticated");
@@ -481,10 +480,9 @@
         // change record of peer identity even by accident, much
         // less do it intentionally.
         //
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             throw new SSLPeerUnverifiedException("no certificates expected"
-                        + " for Kerberos cipher suites");
+                        + " for " + cipherSuite.keyExchange + " cipher suites");
         }
         if (peerCerts == null) {
             throw new SSLPeerUnverifiedException("peer not authenticated");
@@ -522,10 +520,9 @@
          * change record of peer identity even by accident, much
          * less do it intentionally.
          */
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             throw new SSLPeerUnverifiedException("no certificates expected"
-                        + " for Kerberos cipher suites");
+                        + " for " + cipherSuite.keyExchange + " cipher suites");
         }
         if (peerCerts != null) {
             return peerCerts.clone();
@@ -540,7 +537,7 @@
      *
      * @return the peer's principal. Returns an X500Principal of the
      * end-entity certificate for X509-based cipher suites, and
-     * Principal for Kerberos cipher suites.
+     * Principal for Kerberos cipher suites, etc.
      *
      * @throws SSLPeerUnverifiedException if the peer's identity has not
      *          been verified
@@ -549,12 +546,10 @@
     public Principal getPeerPrincipal()
                 throws SSLPeerUnverifiedException
     {
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             if (peerPrincipal == null) {
                 throw new SSLPeerUnverifiedException("peer not authenticated");
             } else {
-                // Eliminate dependency on KerberosPrincipal
                 return peerPrincipal;
             }
         }
@@ -569,15 +564,13 @@
      *
      * @return the principal sent to the peer. Returns an X500Principal
      * of the end-entity certificate for X509-based cipher suites, and
-     * Principal for Kerberos cipher suites. If no principal was
+     * Principal for Kerberos cipher suites, etc. If no principal was
      * sent, then null is returned.
      */
     @Override
     public Principal getLocalPrincipal() {
 
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
-                // Eliminate dependency on KerberosPrincipal
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
                 return (localPrincipal == null ? null : localPrincipal);
         }
         return (localCerts == null ? null :
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Tue Jun 02 04:01:04 2015 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Tue Jun 02 22:26:36 2015 +0800
@@ -38,8 +38,6 @@
 
 import javax.net.ssl.*;
 
-import javax.security.auth.Subject;
-
 import sun.security.util.KeyUtil;
 import sun.security.action.GetPropertyAction;
 import sun.security.ssl.HandshakeMessage.*;
@@ -237,18 +235,6 @@
                     handshakeState.update(pms, resumingSession);
                     preMasterSecret = this.clientKeyExchange(pms);
                     break;
-                case K_KRB5:
-                case K_KRB5_EXPORT:
-                    KerberosClientKeyExchange kke =
-                        new KerberosClientKeyExchange(protocolVersion,
-                            clientRequestedVersion,
-                            sslContext.getSecureRandom(),
-                            input,
-                            this.getAccSE(),
-                            serviceCreds);
-                    handshakeState.update(kke, resumingSession);
-                    preMasterSecret = this.clientKeyExchange(kke);
-                    break;
                 case K_DHE_RSA:
                 case K_DHE_DSS:
                 case K_DH_ANON:
@@ -273,8 +259,24 @@
                     preMasterSecret = this.clientKeyExchange(ecdhcke);
                     break;
                 default:
-                    throw new SSLProtocolException
-                        ("Unrecognized key exchange: " + keyExchange);
+                    ClientKeyExchangeService p =
+                            ClientKeyExchangeService.find(keyExchange.name);
+                    if (p == null) {
+                        throw new SSLProtocolException
+                                ("Unrecognized key exchange: " + keyExchange);
+                    }
+                    byte[] encodedTicket = input.getBytes16();
+                    input.getBytes16();
+                    byte[] secret = input.getBytes16();
+                    ClientKeyExchange cke = p.createServerExchange(protocolVersion,
+                            clientRequestedVersion,
+                            sslContext.getSecureRandom(),
+                            encodedTicket,
+                            secret,
+                            this.getAccSE(), serviceCreds);
+                    handshakeState.update(cke, resumingSession);
+                    preMasterSecret = this.clientKeyExchange(cke);
+                    break;
                 }
 
                 //
@@ -624,47 +626,21 @@
                 // validate subject identity
                 if (resumingSession) {
                     CipherSuite suite = previous.getSuite();
-                    if (suite.keyExchange == K_KRB5 ||
-                        suite.keyExchange == K_KRB5_EXPORT) {
+                    ClientKeyExchangeService p =
+                            ClientKeyExchangeService.find(suite.keyExchange.name);
+                    if (p != null) {
                         Principal localPrincipal = previous.getLocalPrincipal();
 
-                        Subject subject = null;
-                        try {
-                            subject = AccessController.doPrivileged(
-                                new PrivilegedExceptionAction<Subject>() {
-                                @Override
-                                public Subject run() throws Exception {
-                                    return
-                                        Krb5Helper.getServerSubject(getAccSE());
-                            }});
-                        } catch (PrivilegedActionException e) {
-                            subject = null;
-                            if (debug != null && Debug.isOn("session")) {
-                                System.out.println("Attempt to obtain" +
-                                                " subject failed!");
-                            }
-                        }
-
-                        if (subject != null) {
-                            // Eliminate dependency on KerberosPrincipal
-                            if (Krb5Helper.isRelated(subject, localPrincipal)) {
-                                if (debug != null && Debug.isOn("session"))
-                                    System.out.println("Subject can" +
-                                            " provide creds for princ");
-                            } else {
-                                resumingSession = false;
-                                if (debug != null && Debug.isOn("session"))
-                                    System.out.println("Subject cannot" +
-                                            " provide creds for princ");
-                            }
+                        if (p.isRelated(
+                                false, getAccSE(), localPrincipal)) {
+                            if (debug != null && Debug.isOn("session"))
+                                System.out.println("Subject can" +
+                                        " provide creds for princ");
                         } else {
                             resumingSession = false;
                             if (debug != null && Debug.isOn("session"))
-                                System.out.println("Kerberos credentials are" +
-                                    " not present in the current Subject;" +
-                                    " check if " +
-                                    " javax.security.auth.useSubjectAsCreds" +
-                                    " system property has been set to false");
+                                System.out.println("Subject cannot" +
+                                        " provide creds for princ");
                         }
                     }
                 }
@@ -871,9 +847,8 @@
          * defined in the protocol spec are explicitly stated to require
          * using RSA certificates.
          */
-        if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
-            // Server certificates are omitted for Kerberos ciphers
-
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
+            // No external key exchange provider needs a cert now.
         } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) {
             if (certs == null) {
                 throw new RuntimeException("no certificates");
@@ -915,9 +890,7 @@
         ServerKeyExchange m3;
         switch (keyExchange) {
         case K_RSA:
-        case K_KRB5:
-        case K_KRB5_EXPORT:
-            // no server key exchange for RSA or KRB5 ciphersuites
+            // no server key exchange for RSA ciphersuites
             m3 = null;
             break;
         case K_RSA_EXPORT:
@@ -980,6 +953,13 @@
             m3 = null;
             break;
         default:
+            ClientKeyExchangeService p =
+                    ClientKeyExchangeService.find(keyExchange.name);
+            if (p != null) {
+                // No external key exchange provider needs a cert now.
+                m3 = null;
+                break;
+            }
             throw new RuntimeException("internal error: " + keyExchange);
         }
         if (m3 != null) {
@@ -1000,10 +980,10 @@
         // Needed only if server requires client to authenticate self.
         // Illegal for anonymous flavors, so we need to check that.
         //
-        // CertificateRequest is omitted for Kerberos ciphers
+        // No external key exchange provider needs a cert now.
         if (doClientAuth != ClientAuthType.CLIENT_AUTH_NONE &&
                 keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON &&
-                keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) {
+                ClientKeyExchangeService.find(keyExchange.name) == null) {
 
             CertificateRequest m4;
             X509Certificate caCerts[];
@@ -1313,13 +1293,6 @@
             }
             setupStaticECDHKeys();
             break;
-        case K_KRB5:
-        case K_KRB5_EXPORT:
-            // need Kerberos Key
-            if (!setupKerberosKeys()) {
-                return false;
-            }
-            break;
         case K_DH_ANON:
             // no certs needed for anonymous
             setupEphemeralDHKeys(suite.exportable, null);
@@ -1331,8 +1304,26 @@
             }
             break;
         default:
-            // internal error, unknown key exchange
-            throw new RuntimeException("Unrecognized cipherSuite: " + suite);
+            ClientKeyExchangeService p =
+                    ClientKeyExchangeService.find(keyExchange.name);
+            if (p == null) {
+                // internal error, unknown key exchange
+                throw new RuntimeException("Unrecognized cipherSuite: " + suite);
+            }
+            // need service creds
+            if (serviceCreds == null) {
+                AccessControlContext acc = getAccSE();
+                serviceCreds = p.getServiceCreds(acc);
+                if (serviceCreds != null) {
+                    if (debug != null && Debug.isOn("handshake")) {
+                        System.out.println("Using serviceCreds");
+                    }
+                }
+                if (serviceCreds == null) {
+                    return false;
+                }
+            }
+            break;
         }
         setCipherSuite(suite);
 
@@ -1522,73 +1513,10 @@
         return true;
     }
 
-    /**
-     * Retrieve the Kerberos key for the specified server principal
-     * from the JAAS configuration file.
-     *
-     * @return true if successful, false if not available or invalid
+    /*
+     * Returns premaster secret for external key exchange services.
      */
-    private boolean setupKerberosKeys() {
-        if (serviceCreds != null) {
-            return true;
-        }
-        try {
-            final AccessControlContext acc = getAccSE();
-            serviceCreds = AccessController.doPrivileged(
-                // Eliminate dependency on KerberosKey
-                new PrivilegedExceptionAction<Object>() {
-                @Override
-                public Object run() throws Exception {
-                    // get kerberos key for the default principal
-                    return Krb5Helper.getServiceCreds(acc);
-                        }});
-
-            // check permission to access and use the secret key of the
-            // Kerberized "host" service
-            if (serviceCreds != null) {
-                if (debug != null && Debug.isOn("handshake")) {
-                    System.out.println("Using Kerberos creds");
-                }
-                String serverPrincipal =
-                        Krb5Helper.getServerPrincipalName(serviceCreds);
-                if (serverPrincipal != null) {
-                    // When service is bound, we check ASAP. Otherwise,
-                    // will check after client request is received
-                    // in Kerberos ClientKeyExchange
-                    SecurityManager sm = System.getSecurityManager();
-                    try {
-                        if (sm != null) {
-                            // Eliminate dependency on ServicePermission
-                            sm.checkPermission(Krb5Helper.getServicePermission(
-                                    serverPrincipal, "accept"), acc);
-                        }
-                    } catch (SecurityException se) {
-                        serviceCreds = null;
-                        // Do not destroy keys. Will affect Subject
-                        if (debug != null && Debug.isOn("handshake")) {
-                            System.out.println("Permission to access Kerberos"
-                                    + " secret key denied");
-                        }
-                        return false;
-                    }
-                }
-            }
-            return serviceCreds != null;
-        } catch (PrivilegedActionException e) {
-            // Likely exception here is LoginExceptin
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("Attempt to obtain Kerberos key failed: "
-                                + e.toString());
-            }
-            return false;
-        }
-    }
-
-    /*
-     * For Kerberos ciphers, the premaster secret is encrypted using
-     * the session key. See RFC 2712.
-     */
-    private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg)
+    private SecretKey clientKeyExchange(ClientKeyExchange mesg)
         throws IOException {
 
         if (debug != null && Debug.isOn("handshake")) {
@@ -1599,8 +1527,7 @@
         session.setPeerPrincipal(mesg.getPeerPrincipal());
         session.setLocalPrincipal(mesg.getLocalPrincipal());
 
-        byte[] b = mesg.getUnencryptedPreMasterSecret();
-        return new SecretKeySpec(b, "TlsPremasterSecret");
+        return mesg.clientKeyExchange();
     }
 
     /*
@@ -1705,7 +1632,7 @@
          */
         if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) {
            // get X500Principal of the end-entity certificate for X509-based
-           // ciphersuites, or Kerberos principal for Kerberos ciphersuites
+           // ciphersuites, or Kerberos principal for Kerberos ciphersuites, etc
            session.getPeerPrincipal();
         }
 
--- a/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java	Tue Jun 02 04:01:04 2015 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java	Tue Jun 02 22:26:36 2015 +0800
@@ -35,7 +35,7 @@
 
 import javax.security.auth.x500.X500Principal;
 
-import sun.security.ssl.Krb5Helper;
+import sun.security.ssl.ClientKeyExchangeService;
 import sun.security.x509.X500Name;
 
 import sun.net.util.IPAddressUtil;
@@ -108,7 +108,12 @@
      * Return the Server name from Kerberos principal.
      */
     public static String getServerName(Principal principal) {
-        return Krb5Helper.getPrincipalHostName(principal);
+        ClientKeyExchangeService p =
+                ClientKeyExchangeService.find("KRB5");
+        if (p == null) {
+            throw new AssertionError("Kerberos should have been available");
+        }
+        return p.getServiceHostName(principal);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.security.jgss/share/classes/META-INF/services/sun.security.ssl.ClientKeyExchangeService	Tue Jun 02 22:26:36 2015 +0800
@@ -0,0 +1,2 @@
+sun.security.krb5.internal.ssl.Krb5KeyExchangeService
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java	Tue Jun 02 22:26:36 2015 +0800
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.krb5.internal.ssl;
+
+import java.io.*;
+import java.security.*;
+import java.util.Arrays;
+
+import javax.net.ssl.*;
+
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.EncryptedData;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.internal.crypto.KeyUsage;
+
+import sun.security.ssl.Debug;
+import sun.security.ssl.HandshakeInStream;
+import sun.security.ssl.HandshakeMessage;
+import sun.security.ssl.ProtocolVersion;
+
+/**
+ * This is the Kerberos premaster secret in the Kerberos client key
+ * exchange message (CLIENT --> SERVER); it holds the
+ * Kerberos-encrypted pre-master secret. The secret is encrypted using the
+ * Kerberos session key.  The padding and size of the resulting message
+ * depends on the session key type, but the pre-master secret is
+ * always exactly 48 bytes.
+ *
+ */
+final class KerberosPreMasterSecret {
+
+    private ProtocolVersion protocolVersion; // preMaster [0,1]
+    private byte preMaster[];           // 48 bytes
+    private byte encrypted[];
+
+    /**
+     * Constructor used by client to generate premaster secret.
+     *
+     * Client randomly creates a pre-master secret and encrypts it
+     * using the Kerberos session key; only the server can decrypt
+     * it, using the session key available in the service ticket.
+     *
+     * @param protocolVersion used to set preMaster[0,1]
+     * @param generator random number generator for generating premaster secret
+     * @param sessionKey Kerberos session key for encrypting premaster secret
+     */
+    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
+            SecureRandom generator, EncryptionKey sessionKey) throws IOException {
+
+        if (sessionKey.getEType() ==
+                EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
+            throw new IOException(
+                    "session keys with des3-cbc-hmac-sha1-kd encryption type " +
+                            "are not supported for TLS Kerberos cipher suites");
+        }
+
+        this.protocolVersion = protocolVersion;
+        preMaster = generatePreMaster(generator, protocolVersion);
+
+        // Encrypt premaster secret
+        try {
+            EncryptedData eData = new EncryptedData(sessionKey, preMaster,
+                    KeyUsage.KU_UNKNOWN);
+            encrypted = eData.getBytes();  // not ASN.1 encoded.
+
+        } catch (KrbException e) {
+            throw (SSLKeyException)new SSLKeyException
+                    ("Kerberos premaster secret error").initCause(e);
+        }
+    }
+
+    /*
+     * Constructor used by server to decrypt encrypted premaster secret.
+     * The protocol version in preMaster[0,1] must match either currentVersion
+     * or clientVersion, otherwise, the premaster secret is set to
+     * a random one to foil possible attack.
+     *
+     * @param currentVersion version of protocol being used
+     * @param clientVersion version requested by client
+     * @param generator random number generator used to generate
+     *        bogus premaster secret if premaster secret verification fails
+     * @param input input stream from which to read the encrypted
+     *        premaster secret
+     * @param sessionKey Kerberos session key to be used for decryption
+     */
+    KerberosPreMasterSecret(ProtocolVersion currentVersion,
+            ProtocolVersion clientVersion,
+            SecureRandom generator, byte[] encrypted,
+            EncryptionKey sessionKey) throws IOException {
+
+        if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+            if (encrypted != null) {
+                Debug.println(System.out,
+                        "encrypted premaster secret", encrypted);
+            }
+        }
+
+        if (sessionKey.getEType() ==
+                EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
+            throw new IOException(
+                    "session keys with des3-cbc-hmac-sha1-kd encryption type " +
+                            "are not supported for TLS Kerberos cipher suites");
+        }
+
+        // Decrypt premaster secret
+        try {
+            EncryptedData data = new EncryptedData(sessionKey.getEType(),
+                    null /* optional kvno */, encrypted);
+
+            byte[] temp = data.decrypt(sessionKey, KeyUsage.KU_UNKNOWN);
+            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+                if (encrypted != null) {
+                    Debug.println(System.out,
+                            "decrypted premaster secret", temp);
+                }
+            }
+
+            // Remove padding bytes after decryption. Only DES and DES3 have
+            // paddings and we don't support DES3 in TLS (see above)
+
+            if (temp.length == 52 &&
+                    data.getEType() == EncryptedData.ETYPE_DES_CBC_CRC) {
+                // For des-cbc-crc, 4 paddings. Value can be 0x04 or 0x00.
+                if (paddingByteIs(temp, 52, (byte)4) ||
+                        paddingByteIs(temp, 52, (byte)0)) {
+                    temp = Arrays.copyOf(temp, 48);
+                }
+            } else if (temp.length == 56 &&
+                    data.getEType() == EncryptedData.ETYPE_DES_CBC_MD5) {
+                // For des-cbc-md5, 8 paddings with 0x08, or no padding
+                if (paddingByteIs(temp, 56, (byte)8)) {
+                    temp = Arrays.copyOf(temp, 48);
+                }
+            }
+
+            preMaster = temp;
+
+            protocolVersion = ProtocolVersion.valueOf(preMaster[0],
+                    preMaster[1]);
+            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+                System.out.println("Kerberos PreMasterSecret version: "
+                        + protocolVersion);
+            }
+        } catch (Exception e) {
+            // catch exception & process below
+            preMaster = null;
+            protocolVersion = currentVersion;
+        }
+
+        // check if the premaster secret version is ok
+        // the specification says that it must be the maximum version supported
+        // by the client from its ClientHello message. However, many
+        // old implementations send the negotiated version, so accept both
+        // for SSL v3.0 and TLS v1.0.
+        // NOTE that we may be comparing two unsupported version numbers in
+        // the second case, which is why we cannot use object references
+        // equality in this special case
+        boolean versionMismatch = (protocolVersion.v != clientVersion.v);
+
+        /*
+         * we never checked the client_version in server side
+         * for TLS v1.0 and SSL v3.0. For compatibility, we
+         * maintain this behavior.
+         */
+        if (versionMismatch && (clientVersion.v <= 0x0301)) {
+            versionMismatch = (protocolVersion.v != currentVersion.v);
+        }
+
+        /*
+         * Bogus decrypted ClientKeyExchange? If so, conjure a
+         * a random preMaster secret that will fail later during
+         * Finished message processing. This is a countermeasure against
+         * the "interactive RSA PKCS#1 encryption envelop attack" reported
+         * in June 1998. Preserving the executation path will
+         * mitigate timing attacks and force consistent error handling
+         * that will prevent an attacking client from differentiating
+         * different kinds of decrypted ClientKeyExchange bogosities.
+         */
+        if ((preMaster == null) || (preMaster.length != 48)
+                || versionMismatch) {
+            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+                System.out.println("Kerberos PreMasterSecret error, "
+                        + "generating random secret");
+                if (preMaster != null) {
+                    Debug.println(System.out, "Invalid secret", preMaster);
+                }
+            }
+
+            /*
+             * Randomize the preMaster secret with the
+             * ClientHello.client_version, as will produce invalid master
+             * secret to prevent the attacks.
+             */
+            preMaster = generatePreMaster(generator, clientVersion);
+            protocolVersion = clientVersion;
+        }
+    }
+
+    /**
+     * Checks if all paddings of data are b
+     * @param data the block with padding
+     * @param len length of data, >= 48
+     * @param b expected padding byte
+     */
+    private static boolean paddingByteIs(byte[] data, int len, byte b) {
+        for (int i=48; i<len; i++) {
+            if (data[i] != b) return false;
+        }
+        return true;
+    }
+
+    /*
+     * Used by server to generate premaster secret in case of
+     * problem decoding ticket.
+     *
+     * @param protocolVersion used for preMaster[0,1]
+     * @param generator random number generator to use for generating secret.
+     */
+    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
+            SecureRandom generator) {
+
+        this.protocolVersion = protocolVersion;
+        preMaster = generatePreMaster(generator, protocolVersion);
+    }
+
+    private static byte[] generatePreMaster(SecureRandom rand,
+            ProtocolVersion ver) {
+
+        byte[] pm = new byte[48];
+        rand.nextBytes(pm);
+        pm[0] = ver.major;
+        pm[1] = ver.minor;
+
+        return pm;
+    }
+
+    // Clone not needed; internal use only
+    byte[] getUnencrypted() {
+        return preMaster;
+    }
+
+    // Clone not needed; internal use only
+    byte[] getEncrypted() {
+        return encrypted;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/Krb5KeyExchangeService.java	Tue Jun 02 22:26:36 2015 +0800
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.krb5.internal.ssl;
+
+import sun.security.ssl.ClientKeyExchange;
+import sun.security.ssl.Debug;
+import sun.security.ssl.ClientKeyExchangeService;
+import sun.security.ssl.HandshakeOutStream;
+
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.krb5.Krb5Util;
+import sun.security.jgss.krb5.ServiceCreds;
+import sun.security.krb5.EncryptedData;
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+import sun.security.krb5.internal.EncTicketPart;
+import sun.security.krb5.internal.Ticket;
+import sun.security.krb5.internal.crypto.KeyUsage;
+import sun.security.ssl.ProtocolVersion;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.kerberos.KeyTab;
+import javax.security.auth.kerberos.ServicePermission;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.util.Set;
+
+/**
+ * The provider for TLS_KRB_ cipher suites.
+ *
+ * @since 1.9
+ */
+public class Krb5KeyExchangeService implements ClientKeyExchangeService {
+
+    public static final Debug debug = Debug.getInstance("ssl");
+
+    @Override
+    public String[] supported() {
+        return new String[] { "KRB5", "KRB5_EXPORT" };
+    }
+
+    @Override
+    public Object getServiceCreds(AccessControlContext acc) {
+        try {
+            ServiceCreds serviceCreds = AccessController.doPrivileged(
+                    (PrivilegedExceptionAction<ServiceCreds>)
+                            () -> Krb5Util.getServiceCreds(
+                                    GSSCaller.CALLER_SSL_SERVER, null, acc));
+            if (debug != null && Debug.isOn("handshake")) {
+                System.out.println("Using Kerberos creds");
+            }
+            String serverPrincipal = serviceCreds.getName();
+            if (serverPrincipal != null) {
+                // When service is bound, we check ASAP. Otherwise,
+                // will check after client request is received
+                // in in Kerberos ClientKeyExchange
+                SecurityManager sm = System.getSecurityManager();
+                try {
+                    if (sm != null) {
+                        // Eliminate dependency on ServicePermission
+                        sm.checkPermission(new ServicePermission(
+                                serverPrincipal, "accept"), acc);
+                    }
+                } catch (SecurityException se) {
+                    if (debug != null && Debug.isOn("handshake")) {
+                        System.out.println("Permission to access Kerberos"
+                                + " secret key denied");
+                    }
+                    return null;
+                }
+            }
+            return serviceCreds;
+        } catch (PrivilegedActionException e) {
+            // Likely exception here is LoginException
+            if (debug != null && Debug.isOn("handshake")) {
+                System.out.println("Attempt to obtain Kerberos key failed: "
+                        + e.toString());
+            }
+            return null;
+        }
+    }
+
+    @Override
+    public String getServiceHostName(Principal principal) {
+        if (principal == null) {
+            return null;
+        }
+        String hostName = null;
+        try {
+            PrincipalName princName =
+                    new PrincipalName(principal.getName(),
+                            PrincipalName.KRB_NT_SRV_HST);
+            String[] nameParts = princName.getNameStrings();
+            if (nameParts.length >= 2) {
+                hostName = nameParts[1];
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+        return hostName;
+    }
+
+
+    @Override
+    public boolean isRelated(boolean isClient,
+            AccessControlContext acc, Principal p) {
+
+        if (p == null) return false;
+        try {
+            Subject subject = AccessController.doPrivileged(
+                    (PrivilegedExceptionAction<Subject>)
+                            () -> Krb5Util.getSubject(
+                                    isClient ? GSSCaller.CALLER_SSL_CLIENT
+                                            : GSSCaller.CALLER_SSL_SERVER,
+                                    acc));
+            if (subject == null) {
+                if (debug != null && Debug.isOn("session")) {
+                    System.out.println("Kerberos credentials are" +
+                            " not present in the current Subject;" +
+                            " check if " +
+                            " javax.security.auth.useSubjectAsCreds" +
+                            " system property has been set to false");
+                }
+                return false;
+            }
+            Set<Principal> principals =
+                    subject.getPrincipals(Principal.class);
+            if (principals.contains(p)) {
+                // bound to this principal
+                return true;
+            } else {
+                if (isClient) {
+                    return false;
+                } else {
+                    for (KeyTab pc : subject.getPrivateCredentials(KeyTab.class)) {
+                        if (!pc.isBound()) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            }
+        } catch (PrivilegedActionException pae) {
+            if (debug != null && Debug.isOn("session")) {
+                System.out.println("Attempt to obtain" +
+                        " subject failed! " + pae);
+            }
+            return false;
+        }
+
+    }
+
+    public ClientKeyExchange createClientExchange(
+            String serverName, AccessControlContext acc,
+            ProtocolVersion protocolVerson, SecureRandom rand) throws IOException {
+        return new ExchangerImpl(serverName, acc, protocolVerson, rand);
+    }
+
+    public ClientKeyExchange createServerExchange(
+            ProtocolVersion protocolVersion, ProtocolVersion clientVersion,
+            SecureRandom rand, byte[] encodedTicket, byte[] encrypted,
+            AccessControlContext acc, Object serviceCreds) throws IOException {
+        return new ExchangerImpl(protocolVersion, clientVersion, rand,
+                encodedTicket, encrypted, acc, serviceCreds);
+    }
+
+    static class ExchangerImpl extends ClientKeyExchange {
+
+        final private KerberosPreMasterSecret preMaster;
+        final private byte[] encodedTicket;
+        final private KerberosPrincipal peerPrincipal;
+        final private KerberosPrincipal localPrincipal;
+
+        @Override
+        public int messageLength() {
+            return encodedTicket.length + preMaster.getEncrypted().length + 6;
+        }
+
+        @Override
+        public void send(HandshakeOutStream s) throws IOException {
+            s.putBytes16(encodedTicket);
+            s.putBytes16(null);
+            s.putBytes16(preMaster.getEncrypted());
+        }
+
+        @Override
+        public void print(PrintStream s) throws IOException {
+            s.println("*** ClientKeyExchange, Kerberos");
+
+            if (debug != null && Debug.isOn("verbose")) {
+                Debug.println(s, "Kerberos service ticket", encodedTicket);
+                Debug.println(s, "Random Secret", preMaster.getUnencrypted());
+                Debug.println(s, "Encrypted random Secret", preMaster.getEncrypted());
+            }
+        }
+
+        ExchangerImpl(String serverName, AccessControlContext acc,
+                ProtocolVersion protocolVersion, SecureRandom rand) throws IOException {
+
+            // Get service ticket
+            KerberosTicket ticket = getServiceTicket(serverName, acc);
+            encodedTicket = ticket.getEncoded();
+
+            // Record the Kerberos principals
+            peerPrincipal = ticket.getServer();
+            localPrincipal = ticket.getClient();
+
+            // Optional authenticator, encrypted using session key,
+            // currently ignored
+
+            // Generate premaster secret and encrypt it using session key
+            EncryptionKey sessionKey = new EncryptionKey(
+                    ticket.getSessionKeyType(),
+                    ticket.getSessionKey().getEncoded());
+
+            preMaster = new KerberosPreMasterSecret(protocolVersion,
+                    rand, sessionKey);
+        }
+
+        ExchangerImpl(
+                ProtocolVersion protocolVersion, ProtocolVersion clientVersion, SecureRandom rand,
+                byte[] encodedTicket, byte[] encrypted,
+                AccessControlContext acc, Object serviceCreds) throws IOException {
+
+            // Read ticket
+            this.encodedTicket = encodedTicket;
+
+            if (debug != null && Debug.isOn("verbose")) {
+                Debug.println(System.out,
+                        "encoded Kerberos service ticket", encodedTicket);
+            }
+
+            EncryptionKey sessionKey = null;
+            KerberosPrincipal tmpPeer = null;
+            KerberosPrincipal tmpLocal = null;
+
+            try {
+                Ticket t = new Ticket(encodedTicket);
+
+                EncryptedData encPart = t.encPart;
+                PrincipalName ticketSname = t.sname;
+
+                final ServiceCreds creds = (ServiceCreds)serviceCreds;
+                final KerberosPrincipal princ =
+                        new KerberosPrincipal(ticketSname.toString());
+
+                // For bound service, permission already checked at setup
+                if (creds.getName() == null) {
+                    SecurityManager sm = System.getSecurityManager();
+                    try {
+                        if (sm != null) {
+                            // Eliminate dependency on ServicePermission
+                            sm.checkPermission(new ServicePermission(
+                                    ticketSname.toString(), "accept"), acc);
+                        }
+                    } catch (SecurityException se) {
+                        serviceCreds = null;
+                        // Do not destroy keys. Will affect Subject
+                        if (debug != null && Debug.isOn("handshake")) {
+                            System.out.println("Permission to access Kerberos"
+                                    + " secret key denied");
+                            se.printStackTrace(System.out);
+                        }
+                        throw new IOException("Kerberos service not allowedy");
+                    }
+                }
+                KerberosKey[] serverKeys = AccessController.doPrivileged(
+                        new PrivilegedAction<KerberosKey[]>() {
+                            @Override
+                            public KerberosKey[] run() {
+                                return creds.getKKeys(princ);
+                            }
+                        });
+                if (serverKeys.length == 0) {
+                    throw new IOException("Found no key for " + princ +
+                            (creds.getName() == null ? "" :
+                                    (", this keytab is for " + creds.getName() + " only")));
+                }
+
+                /*
+                 * permission to access and use the secret key of the Kerberized
+                 * "host" service is done in ServerHandshaker.getKerberosKeys()
+                 * to ensure server has the permission to use the secret key
+                 * before promising the client
+                 */
+
+                // See if we have the right key to decrypt the ticket to get
+                // the session key.
+                int encPartKeyType = encPart.getEType();
+                Integer encPartKeyVersion = encPart.getKeyVersionNumber();
+                KerberosKey dkey = null;
+                try {
+                    dkey = findKey(encPartKeyType, encPartKeyVersion, serverKeys);
+                } catch (KrbException ke) { // a kvno mismatch
+                    throw new IOException(
+                            "Cannot find key matching version number", ke);
+                }
+                if (dkey == null) {
+                    // %%% Should print string repr of etype
+                    throw new IOException("Cannot find key of appropriate type" +
+                            " to decrypt ticket - need etype " + encPartKeyType);
+                }
+
+                EncryptionKey secretKey = new EncryptionKey(
+                        encPartKeyType,
+                        dkey.getEncoded());
+
+                // Decrypt encPart using server's secret key
+                byte[] bytes = encPart.decrypt(secretKey, KeyUsage.KU_TICKET);
+
+                // Reset data stream after decryption, remove redundant bytes
+                byte[] temp = encPart.reset(bytes);
+                EncTicketPart encTicketPart = new EncTicketPart(temp);
+
+                // Record the Kerberos Principals
+                tmpPeer = new KerberosPrincipal(encTicketPart.cname.getName());
+                tmpLocal = new KerberosPrincipal(ticketSname.getName());
+
+                sessionKey = encTicketPart.key;
+
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("server principal: " + ticketSname);
+                    System.out.println("cname: " + encTicketPart.cname.toString());
+                }
+            } catch (IOException e) {
+                throw e;
+            } catch (Exception e) {
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("KerberosWrapper error getting session key,"
+                            + " generating random secret (" + e.getMessage() + ")");
+                }
+                sessionKey = null;
+            }
+
+            //input.getBytes16();   // XXX Read and ignore authenticator
+
+            if (sessionKey != null) {
+                preMaster = new KerberosPreMasterSecret(protocolVersion,
+                        clientVersion, rand, encrypted, sessionKey);
+            } else {
+                // Generate bogus premaster secret
+                preMaster = new KerberosPreMasterSecret(clientVersion, rand);
+            }
+
+            peerPrincipal = tmpPeer;
+            localPrincipal = tmpLocal;
+        }
+
+        // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context
+        private static KerberosTicket getServiceTicket(String serverName,
+                final AccessControlContext acc) throws IOException {
+
+            if ("localhost".equals(serverName) ||
+                    "localhost.localdomain".equals(serverName)) {
+
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("Get the local hostname");
+                }
+                String localHost = java.security.AccessController.doPrivileged(
+                        new java.security.PrivilegedAction<String>() {
+                            public String run() {
+                                try {
+                                    return InetAddress.getLocalHost().getHostName();
+                                } catch (java.net.UnknownHostException e) {
+                                    if (debug != null && Debug.isOn("handshake")) {
+                                        System.out.println("Warning,"
+                                                + " cannot get the local hostname: "
+                                                + e.getMessage());
+                                    }
+                                    return null;
+                                }
+                            }
+                        });
+                if (localHost != null) {
+                    serverName = localHost;
+                }
+            }
+
+            // Resolve serverName (possibly in IP addr form) to Kerberos principal
+            // name for service with hostname
+            String serviceName = "host/" + serverName;
+            PrincipalName principal;
+            try {
+                principal = new PrincipalName(serviceName,
+                        PrincipalName.KRB_NT_SRV_HST);
+            } catch (SecurityException se) {
+                throw se;
+            } catch (Exception e) {
+                IOException ioe = new IOException("Invalid service principal" +
+                        " name: " + serviceName);
+                ioe.initCause(e);
+                throw ioe;
+            }
+            String realm = principal.getRealmAsString();
+
+            final String serverPrincipal = principal.toString();
+            final String tgsPrincipal = "krbtgt/" + realm + "@" + realm;
+            final String clientPrincipal = null;  // use default
+
+
+            // check permission to obtain a service ticket to initiate a
+            // context with the "host" service
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(new ServicePermission(serverPrincipal,
+                        "initiate"), acc);
+            }
+
+            try {
+                KerberosTicket ticket = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<KerberosTicket>() {
+                            public KerberosTicket run() throws Exception {
+                                return Krb5Util.getTicketFromSubjectAndTgs(
+                                        GSSCaller.CALLER_SSL_CLIENT,
+                                        clientPrincipal, serverPrincipal,
+                                        tgsPrincipal, acc);
+                            }});
+
+                if (ticket == null) {
+                    throw new IOException("Failed to find any kerberos service" +
+                            " ticket for " + serverPrincipal);
+                }
+                return ticket;
+            } catch (PrivilegedActionException e) {
+                IOException ioe = new IOException(
+                        "Attempt to obtain kerberos service ticket for " +
+                                serverPrincipal + " failed!");
+                ioe.initCause(e);
+                throw ioe;
+            }
+        }
+
+        @Override
+        public SecretKey clientKeyExchange() {
+            byte[] secretBytes = preMaster.getUnencrypted();
+            return new SecretKeySpec(secretBytes, "TlsPremasterSecret");
+        }
+
+        @Override
+        public Principal getPeerPrincipal() {
+            return peerPrincipal;
+        }
+
+        @Override
+        public Principal getLocalPrincipal() {
+            return localPrincipal;
+        }
+
+        /**
+         * Determines if a kvno matches another kvno. Used in the method
+         * findKey(etype, version, keys). Always returns true if either input
+         * is null or zero, in case any side does not have kvno info available.
+         *
+         * Note: zero is included because N/A is not a legal value for kvno
+         * in javax.security.auth.kerberos.KerberosKey. Therefore, the info
+         * that the kvno is N/A might be lost when converting between
+         * EncryptionKey and KerberosKey.
+         */
+        private static boolean versionMatches(Integer v1, int v2) {
+            if (v1 == null || v1 == 0 || v2 == 0) {
+                return true;
+            }
+            return v1.equals(v2);
+        }
+
+        private static KerberosKey findKey(int etype, Integer version,
+                KerberosKey[] keys) throws KrbException {
+            int ktype;
+            boolean etypeFound = false;
+
+            // When no matched kvno is found, returns tke key of the same
+            // etype with the highest kvno
+            int kvno_found = 0;
+            KerberosKey key_found = null;
+
+            for (int i = 0; i < keys.length; i++) {
+                ktype = keys[i].getKeyType();
+                if (etype == ktype) {
+                    int kv = keys[i].getVersionNumber();
+                    etypeFound = true;
+                    if (versionMatches(version, kv)) {
+                        return keys[i];
+                    } else if (kv > kvno_found) {
+                        key_found = keys[i];
+                        kvno_found = kv;
+                    }
+                }
+            }
+            // Key not found.
+            // %%% kludge to allow DES keys to be used for diff etypes
+            if ((etype == EncryptedData.ETYPE_DES_CBC_CRC ||
+                    etype == EncryptedData.ETYPE_DES_CBC_MD5)) {
+                for (int i = 0; i < keys.length; i++) {
+                    ktype = keys[i].getKeyType();
+                    if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
+                            ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
+                        int kv = keys[i].getVersionNumber();
+                        etypeFound = true;
+                        if (versionMatches(version, kv)) {
+                            return new KerberosKey(keys[i].getPrincipal(),
+                                    keys[i].getEncoded(),
+                                    etype,
+                                    kv);
+                        } else if (kv > kvno_found) {
+                            key_found = new KerberosKey(keys[i].getPrincipal(),
+                                    keys[i].getEncoded(),
+                                    etype,
+                                    kv);
+                            kvno_found = kv;
+                        }
+                    }
+                }
+            }
+            if (etypeFound) {
+                return key_found;
+            }
+            return null;
+        }
+    }
+}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Tue Jun 02 04:01:04 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,463 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl.krb5;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.security.AccessController;
-import java.security.AccessControlContext;
-import java.security.PrivilegedExceptionAction;
-import java.security.PrivilegedActionException;
-import java.security.SecureRandom;
-import java.net.InetAddress;
-import java.security.PrivilegedAction;
-
-import javax.security.auth.kerberos.KerberosTicket;
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.kerberos.ServicePermission;
-import sun.security.jgss.GSSCaller;
-
-import sun.security.krb5.EncryptionKey;
-import sun.security.krb5.EncryptedData;
-import sun.security.krb5.PrincipalName;
-import sun.security.krb5.internal.Ticket;
-import sun.security.krb5.internal.EncTicketPart;
-import sun.security.krb5.internal.crypto.KeyUsage;
-
-import sun.security.jgss.krb5.Krb5Util;
-import sun.security.jgss.krb5.ServiceCreds;
-import sun.security.krb5.KrbException;
-import sun.security.krb5.internal.Krb5;
-
-import sun.security.ssl.Debug;
-import sun.security.ssl.HandshakeInStream;
-import sun.security.ssl.HandshakeOutStream;
-import sun.security.ssl.Krb5Helper;
-import sun.security.ssl.ProtocolVersion;
-
-/**
- * This is Kerberos option in the client key exchange message
- * (CLIENT -> SERVER). It holds the Kerberos ticket and the encrypted
- * premaster secret encrypted with the session key sealed in the ticket.
- * From RFC 2712:
- *  struct
- *  {
- *    opaque Ticket;
- *    opaque authenticator;            // optional
- *    opaque EncryptedPreMasterSecret; // encrypted with the session key
- *                                     // which is sealed in the ticket
- *  } KerberosWrapper;
- *
- *
- * Ticket and authenticator are encrypted as per RFC 1510 (in ASN.1)
- * Encrypted pre-master secret has the same structure as it does for RSA
- * except for Kerberos, the encryption key is the session key instead of
- * the RSA public key.
- *
- * XXX authenticator currently ignored
- *
- */
-public final class KerberosClientKeyExchangeImpl
-    extends sun.security.ssl.KerberosClientKeyExchange {
-
-    private KerberosPreMasterSecret preMaster;
-    private byte[] encodedTicket;
-    private KerberosPrincipal peerPrincipal;
-    private KerberosPrincipal localPrincipal;
-
-    public KerberosClientKeyExchangeImpl() {
-    }
-
-    /**
-     * Creates an instance of KerberosClientKeyExchange consisting of the
-     * Kerberos service ticket, authenticator and encrypted premaster secret.
-     * Called by client handshaker.
-     *
-     * @param serverName name of server with which to do handshake;
-     *             this is used to get the Kerberos service ticket
-     * @param protocolVersion Maximum version supported by client (i.e,
-     *          version it requested in client hello)
-     * @param rand random number generator to use for generating pre-master
-     *          secret
-     */
-    @Override
-    public void init(String serverName,
-        AccessControlContext acc, ProtocolVersion protocolVersion,
-        SecureRandom rand) throws IOException {
-
-         // Get service ticket
-         KerberosTicket ticket = getServiceTicket(serverName, acc);
-         encodedTicket = ticket.getEncoded();
-
-         // Record the Kerberos principals
-         peerPrincipal = ticket.getServer();
-         localPrincipal = ticket.getClient();
-
-         // Optional authenticator, encrypted using session key,
-         // currently ignored
-
-         // Generate premaster secret and encrypt it using session key
-         EncryptionKey sessionKey = new EncryptionKey(
-                                        ticket.getSessionKeyType(),
-                                        ticket.getSessionKey().getEncoded());
-
-         preMaster = new KerberosPreMasterSecret(protocolVersion,
-             rand, sessionKey);
-    }
-
-    /**
-     * Creates an instance of KerberosClientKeyExchange from its ASN.1 encoding.
-     * Used by ServerHandshaker to verify and obtain premaster secret.
-     *
-     * @param protocolVersion current protocol version
-     * @param clientVersion version requested by client in its ClientHello;
-     *          used by premaster secret version check
-     * @param rand random number generator used for generating random
-     *          premaster secret if ticket and/or premaster verification fails
-     * @param input inputstream from which to get ASN.1-encoded KerberosWrapper
-     * @param acc the AccessControlContext of the handshaker
-     * @param serviceCreds server's creds
-     */
-    @Override
-    public void init(ProtocolVersion protocolVersion,
-        ProtocolVersion clientVersion,
-        SecureRandom rand, HandshakeInStream input, AccessControlContext acc, Object serviceCreds)
-        throws IOException {
-
-        // Read ticket
-        encodedTicket = input.getBytes16();
-
-        if (debug != null && Debug.isOn("verbose")) {
-            Debug.println(System.out,
-                "encoded Kerberos service ticket", encodedTicket);
-        }
-
-        EncryptionKey sessionKey = null;
-
-        try {
-            Ticket t = new Ticket(encodedTicket);
-
-            EncryptedData encPart = t.encPart;
-            PrincipalName ticketSname = t.sname;
-
-            final ServiceCreds creds = (ServiceCreds)serviceCreds;
-            final KerberosPrincipal princ =
-                    new KerberosPrincipal(ticketSname.toString());
-
-            // For bound service, permission already checked at setup
-            if (creds.getName() == null) {
-                SecurityManager sm = System.getSecurityManager();
-                try {
-                    if (sm != null) {
-                        // Eliminate dependency on ServicePermission
-                        sm.checkPermission(Krb5Helper.getServicePermission(
-                                ticketSname.toString(), "accept"), acc);
-                    }
-                } catch (SecurityException se) {
-                    serviceCreds = null;
-                    // Do not destroy keys. Will affect Subject
-                    if (debug != null && Debug.isOn("handshake")) {
-                        System.out.println("Permission to access Kerberos"
-                                + " secret key denied");
-                    }
-                    throw new IOException("Kerberos service not allowedy");
-                }
-            }
-            KerberosKey[] serverKeys = AccessController.doPrivileged(
-                    new PrivilegedAction<KerberosKey[]>() {
-                        @Override
-                        public KerberosKey[] run() {
-                            return creds.getKKeys(princ);
-                        }
-                    });
-            if (serverKeys.length == 0) {
-                throw new IOException("Found no key for " + princ +
-                        (creds.getName() == null ? "" :
-                        (", this keytab is for " + creds.getName() + " only")));
-            }
-
-            /*
-             * permission to access and use the secret key of the Kerberized
-             * "host" service is done in ServerHandshaker.getKerberosKeys()
-             * to ensure server has the permission to use the secret key
-             * before promising the client
-             */
-
-            // See if we have the right key to decrypt the ticket to get
-            // the session key.
-            int encPartKeyType = encPart.getEType();
-            Integer encPartKeyVersion = encPart.getKeyVersionNumber();
-            KerberosKey dkey = null;
-            try {
-                dkey = findKey(encPartKeyType, encPartKeyVersion, serverKeys);
-            } catch (KrbException ke) { // a kvno mismatch
-                throw new IOException(
-                        "Cannot find key matching version number", ke);
-            }
-            if (dkey == null) {
-                // %%% Should print string repr of etype
-                throw new IOException("Cannot find key of appropriate type" +
-                        " to decrypt ticket - need etype " + encPartKeyType);
-            }
-
-            EncryptionKey secretKey = new EncryptionKey(
-                encPartKeyType,
-                dkey.getEncoded());
-
-            // Decrypt encPart using server's secret key
-            byte[] bytes = encPart.decrypt(secretKey, KeyUsage.KU_TICKET);
-
-            // Reset data stream after decryption, remove redundant bytes
-            byte[] temp = encPart.reset(bytes);
-            EncTicketPart encTicketPart = new EncTicketPart(temp);
-
-            // Record the Kerberos Principals
-            peerPrincipal =
-                new KerberosPrincipal(encTicketPart.cname.getName());
-            localPrincipal = new KerberosPrincipal(ticketSname.getName());
-
-            sessionKey = encTicketPart.key;
-
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("server principal: " + ticketSname);
-                System.out.println("cname: " + encTicketPart.cname.toString());
-            }
-        } catch (IOException e) {
-            throw e;
-        } catch (Exception e) {
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("KerberosWrapper error getting session key,"
-                        + " generating random secret (" + e.getMessage() + ")");
-            }
-            sessionKey = null;
-        }
-
-        input.getBytes16();   // XXX Read and ignore authenticator
-
-        if (sessionKey != null) {
-            preMaster = new KerberosPreMasterSecret(protocolVersion,
-                clientVersion, rand, input, sessionKey);
-        } else {
-            // Generate bogus premaster secret
-            preMaster = new KerberosPreMasterSecret(clientVersion, rand);
-        }
-    }
-
-    @Override
-    public int messageLength() {
-        return (6 + encodedTicket.length + preMaster.getEncrypted().length);
-    }
-
-    @Override
-    public void send(HandshakeOutStream s) throws IOException {
-        s.putBytes16(encodedTicket);
-        s.putBytes16(null); // XXX no authenticator
-        s.putBytes16(preMaster.getEncrypted());
-    }
-
-    @Override
-    public void print(PrintStream s) throws IOException {
-        s.println("*** ClientKeyExchange, Kerberos");
-
-        if (debug != null && Debug.isOn("verbose")) {
-            Debug.println(s, "Kerberos service ticket", encodedTicket);
-            Debug.println(s, "Random Secret", preMaster.getUnencrypted());
-            Debug.println(s, "Encrypted random Secret",
-                preMaster.getEncrypted());
-        }
-    }
-
-    // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context
-    private static KerberosTicket getServiceTicket(String serverName,
-        final AccessControlContext acc) throws IOException {
-
-        if ("localhost".equals(serverName) ||
-                "localhost.localdomain".equals(serverName)) {
-
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("Get the local hostname");
-            }
-            String localHost = java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<String>() {
-                public String run() {
-                    try {
-                        return InetAddress.getLocalHost().getHostName();
-                    } catch (java.net.UnknownHostException e) {
-                        if (debug != null && Debug.isOn("handshake")) {
-                            System.out.println("Warning,"
-                                + " cannot get the local hostname: "
-                                + e.getMessage());
-                        }
-                        return null;
-                    }
-                }
-            });
-            if (localHost != null) {
-                serverName = localHost;
-            }
-        }
-
-        // Resolve serverName (possibly in IP addr form) to Kerberos principal
-        // name for service with hostname
-        String serviceName = "host/" + serverName;
-        PrincipalName principal;
-        try {
-            principal = new PrincipalName(serviceName,
-                                PrincipalName.KRB_NT_SRV_HST);
-        } catch (SecurityException se) {
-            throw se;
-        } catch (Exception e) {
-            IOException ioe = new IOException("Invalid service principal" +
-                                " name: " + serviceName);
-            ioe.initCause(e);
-            throw ioe;
-        }
-        String realm = principal.getRealmAsString();
-
-        final String serverPrincipal = principal.toString();
-        final String tgsPrincipal = "krbtgt/" + realm + "@" + realm;
-        final String clientPrincipal = null;  // use default
-
-
-        // check permission to obtain a service ticket to initiate a
-        // context with the "host" service
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-           sm.checkPermission(new ServicePermission(serverPrincipal,
-                                "initiate"), acc);
-        }
-
-        try {
-            KerberosTicket ticket = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<KerberosTicket>() {
-                public KerberosTicket run() throws Exception {
-                    return Krb5Util.getTicketFromSubjectAndTgs(
-                        GSSCaller.CALLER_SSL_CLIENT,
-                        clientPrincipal, serverPrincipal,
-                        tgsPrincipal, acc);
-                        }});
-
-            if (ticket == null) {
-                throw new IOException("Failed to find any kerberos service" +
-                        " ticket for " + serverPrincipal);
-            }
-            return ticket;
-        } catch (PrivilegedActionException e) {
-            IOException ioe = new IOException(
-                "Attempt to obtain kerberos service ticket for " +
-                        serverPrincipal + " failed!");
-            ioe.initCause(e);
-            throw ioe;
-        }
-    }
-
-    @Override
-    public byte[] getUnencryptedPreMasterSecret() {
-        return preMaster.getUnencrypted();
-    }
-
-    @Override
-    public KerberosPrincipal getPeerPrincipal() {
-        return peerPrincipal;
-    }
-
-    @Override
-    public KerberosPrincipal getLocalPrincipal() {
-        return localPrincipal;
-    }
-
-    /**
-     * Determines if a kvno matches another kvno. Used in the method
-     * findKey(etype, version, keys). Always returns true if either input
-     * is null or zero, in case any side does not have kvno info available.
-     *
-     * Note: zero is included because N/A is not a legal value for kvno
-     * in javax.security.auth.kerberos.KerberosKey. Therefore, the info
-     * that the kvno is N/A might be lost when converting between
-     * EncryptionKey and KerberosKey.
-     */
-    private static boolean versionMatches(Integer v1, int v2) {
-        if (v1 == null || v1 == 0 || v2 == 0) {
-            return true;
-        }
-        return v1.equals(v2);
-    }
-
-    private static KerberosKey findKey(int etype, Integer version,
-            KerberosKey[] keys) throws KrbException {
-        int ktype;
-        boolean etypeFound = false;
-
-        // When no matched kvno is found, returns tke key of the same
-        // etype with the highest kvno
-        int kvno_found = 0;
-        KerberosKey key_found = null;
-
-        for (int i = 0; i < keys.length; i++) {
-            ktype = keys[i].getKeyType();
-            if (etype == ktype) {
-                int kv = keys[i].getVersionNumber();
-                etypeFound = true;
-                if (versionMatches(version, kv)) {
-                    return keys[i];
-                } else if (kv > kvno_found) {
-                    key_found = keys[i];
-                    kvno_found = kv;
-                }
-            }
-        }
-        // Key not found.
-        // %%% kludge to allow DES keys to be used for diff etypes
-        if ((etype == EncryptedData.ETYPE_DES_CBC_CRC ||
-            etype == EncryptedData.ETYPE_DES_CBC_MD5)) {
-            for (int i = 0; i < keys.length; i++) {
-                ktype = keys[i].getKeyType();
-                if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
-                        ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
-                    int kv = keys[i].getVersionNumber();
-                    etypeFound = true;
-                    if (versionMatches(version, kv)) {
-                        return new KerberosKey(keys[i].getPrincipal(),
-                            keys[i].getEncoded(),
-                            etype,
-                            kv);
-                    } else if (kv > kvno_found) {
-                        key_found = new KerberosKey(keys[i].getPrincipal(),
-                                keys[i].getEncoded(),
-                                etype,
-                                kv);
-                        kvno_found = kv;
-                    }
-                }
-            }
-        }
-        if (etypeFound) {
-            return key_found;
-        }
-        return null;
-    }
-}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java	Tue Jun 02 04:01:04 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl.krb5;
-
-import java.io.*;
-import java.security.*;
-import java.util.Arrays;
-
-import javax.net.ssl.*;
-
-import sun.security.krb5.EncryptionKey;
-import sun.security.krb5.EncryptedData;
-import sun.security.krb5.KrbException;
-import sun.security.krb5.internal.crypto.KeyUsage;
-
-import sun.security.ssl.Debug;
-import sun.security.ssl.HandshakeInStream;
-import sun.security.ssl.HandshakeMessage;
-import sun.security.ssl.ProtocolVersion;
-
-/**
- * This is the Kerberos premaster secret in the Kerberos client key
- * exchange message (CLIENT --> SERVER); it holds the
- * Kerberos-encrypted pre-master secret. The secret is encrypted using the
- * Kerberos session key.  The padding and size of the resulting message
- * depends on the session key type, but the pre-master secret is
- * always exactly 48 bytes.
- *
- */
-final class KerberosPreMasterSecret {
-
-    private ProtocolVersion protocolVersion; // preMaster [0,1]
-    private byte preMaster[];           // 48 bytes
-    private byte encrypted[];
-
-    /**
-     * Constructor used by client to generate premaster secret.
-     *
-     * Client randomly creates a pre-master secret and encrypts it
-     * using the Kerberos session key; only the server can decrypt
-     * it, using the session key available in the service ticket.
-     *
-     * @param protocolVersion used to set preMaster[0,1]
-     * @param generator random number generator for generating premaster secret
-     * @param sessionKey Kerberos session key for encrypting premaster secret
-     */
-    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
-        SecureRandom generator, EncryptionKey sessionKey) throws IOException {
-
-        if (sessionKey.getEType() ==
-            EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
-            throw new IOException(
-               "session keys with des3-cbc-hmac-sha1-kd encryption type " +
-               "are not supported for TLS Kerberos cipher suites");
-        }
-
-        this.protocolVersion = protocolVersion;
-        preMaster = generatePreMaster(generator, protocolVersion);
-
-        // Encrypt premaster secret
-        try {
-            EncryptedData eData = new EncryptedData(sessionKey, preMaster,
-                KeyUsage.KU_UNKNOWN);
-            encrypted = eData.getBytes();  // not ASN.1 encoded.
-
-        } catch (KrbException e) {
-            throw (SSLKeyException)new SSLKeyException
-                ("Kerberos premaster secret error").initCause(e);
-        }
-    }
-
-    /*
-     * Constructor used by server to decrypt encrypted premaster secret.
-     * The protocol version in preMaster[0,1] must match either currentVersion
-     * or clientVersion, otherwise, the premaster secret is set to
-     * a random one to foil possible attack.
-     *
-     * @param currentVersion version of protocol being used
-     * @param clientVersion version requested by client
-     * @param generator random number generator used to generate
-     *        bogus premaster secret if premaster secret verification fails
-     * @param input input stream from which to read the encrypted
-     *        premaster secret
-     * @param sessionKey Kerberos session key to be used for decryption
-     */
-    KerberosPreMasterSecret(ProtocolVersion currentVersion,
-        ProtocolVersion clientVersion,
-        SecureRandom generator, HandshakeInStream input,
-        EncryptionKey sessionKey) throws IOException {
-
-         // Extract encrypted premaster secret from message
-         encrypted = input.getBytes16();
-
-         if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-            if (encrypted != null) {
-                Debug.println(System.out,
-                     "encrypted premaster secret", encrypted);
-            }
-         }
-
-        if (sessionKey.getEType() ==
-            EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
-            throw new IOException(
-               "session keys with des3-cbc-hmac-sha1-kd encryption type " +
-               "are not supported for TLS Kerberos cipher suites");
-        }
-
-        // Decrypt premaster secret
-        try {
-            EncryptedData data = new EncryptedData(sessionKey.getEType(),
-                        null /* optional kvno */, encrypted);
-
-            byte[] temp = data.decrypt(sessionKey, KeyUsage.KU_UNKNOWN);
-            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-                 if (encrypted != null) {
-                     Debug.println(System.out,
-                         "decrypted premaster secret", temp);
-                 }
-            }
-
-            // Remove padding bytes after decryption. Only DES and DES3 have
-            // paddings and we don't support DES3 in TLS (see above)
-
-            if (temp.length == 52 &&
-                    data.getEType() == EncryptedData.ETYPE_DES_CBC_CRC) {
-                // For des-cbc-crc, 4 paddings. Value can be 0x04 or 0x00.
-                if (paddingByteIs(temp, 52, (byte)4) ||
-                        paddingByteIs(temp, 52, (byte)0)) {
-                    temp = Arrays.copyOf(temp, 48);
-                }
-            } else if (temp.length == 56 &&
-                    data.getEType() == EncryptedData.ETYPE_DES_CBC_MD5) {
-                // For des-cbc-md5, 8 paddings with 0x08, or no padding
-                if (paddingByteIs(temp, 56, (byte)8)) {
-                    temp = Arrays.copyOf(temp, 48);
-                }
-            }
-
-            preMaster = temp;
-
-            protocolVersion = ProtocolVersion.valueOf(preMaster[0],
-                 preMaster[1]);
-            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-                 System.out.println("Kerberos PreMasterSecret version: "
-                        + protocolVersion);
-            }
-        } catch (Exception e) {
-            // catch exception & process below
-            preMaster = null;
-            protocolVersion = currentVersion;
-        }
-
-        // check if the premaster secret version is ok
-        // the specification says that it must be the maximum version supported
-        // by the client from its ClientHello message. However, many
-        // old implementations send the negotiated version, so accept both
-        // for SSL v3.0 and TLS v1.0.
-        // NOTE that we may be comparing two unsupported version numbers in
-        // the second case, which is why we cannot use object references
-        // equality in this special case
-        boolean versionMismatch = (protocolVersion.v != clientVersion.v);
-
-        /*
-         * we never checked the client_version in server side
-         * for TLS v1.0 and SSL v3.0. For compatibility, we
-         * maintain this behavior.
-         */
-        if (versionMismatch && (clientVersion.v <= 0x0301)) {
-            versionMismatch = (protocolVersion.v != currentVersion.v);
-        }
-
-        /*
-         * Bogus decrypted ClientKeyExchange? If so, conjure a
-         * a random preMaster secret that will fail later during
-         * Finished message processing. This is a countermeasure against
-         * the "interactive RSA PKCS#1 encryption envelop attack" reported
-         * in June 1998. Preserving the executation path will
-         * mitigate timing attacks and force consistent error handling
-         * that will prevent an attacking client from differentiating
-         * different kinds of decrypted ClientKeyExchange bogosities.
-         */
-         if ((preMaster == null) || (preMaster.length != 48)
-                || versionMismatch) {
-            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-                System.out.println("Kerberos PreMasterSecret error, "
-                                   + "generating random secret");
-                if (preMaster != null) {
-                    Debug.println(System.out, "Invalid secret", preMaster);
-                }
-            }
-
-            /*
-             * Randomize the preMaster secret with the
-             * ClientHello.client_version, as will produce invalid master
-             * secret to prevent the attacks.
-             */
-            preMaster = generatePreMaster(generator, clientVersion);
-            protocolVersion = clientVersion;
-        }
-    }
-
-    /**
-     * Checks if all paddings of data are b
-     * @param data the block with padding
-     * @param len length of data, >= 48
-     * @param b expected padding byte
-     */
-    private static boolean paddingByteIs(byte[] data, int len, byte b) {
-        for (int i=48; i<len; i++) {
-            if (data[i] != b) return false;
-        }
-        return true;
-    }
-
-    /*
-     * Used by server to generate premaster secret in case of
-     * problem decoding ticket.
-     *
-     * @param protocolVersion used for preMaster[0,1]
-     * @param generator random number generator to use for generating secret.
-     */
-    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
-        SecureRandom generator) {
-
-        this.protocolVersion = protocolVersion;
-        preMaster = generatePreMaster(generator, protocolVersion);
-    }
-
-    private static byte[] generatePreMaster(SecureRandom rand,
-        ProtocolVersion ver) {
-
-        byte[] pm = new byte[48];
-        rand.nextBytes(pm);
-        pm[0] = ver.major;
-        pm[1] = ver.minor;
-
-        return pm;
-    }
-
-    // Clone not needed; internal use only
-    byte[] getUnencrypted() {
-        return preMaster;
-    }
-
-    // Clone not needed; internal use only
-    byte[] getEncrypted() {
-        return encrypted;
-    }
-}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java	Tue Jun 02 04:01:04 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl.krb5;
-
-import java.security.AccessControlContext;
-import java.security.Permission;
-import java.security.Principal;
-import java.util.Set;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KeyTab;
-import javax.security.auth.kerberos.ServicePermission;
-import javax.security.auth.login.LoginException;
-
-import sun.security.jgss.GSSCaller;
-import sun.security.jgss.krb5.Krb5Util;
-import sun.security.jgss.krb5.ServiceCreds;
-import sun.security.krb5.PrincipalName;
-import sun.security.ssl.Krb5Proxy;
-
-/**
- * An implementation of Krb5Proxy that simply delegates to the appropriate
- * Kerberos APIs.
- */
-public class Krb5ProxyImpl implements Krb5Proxy {
-
-    public Krb5ProxyImpl() { }
-
-    @Override
-    public Subject getClientSubject(AccessControlContext acc)
-            throws LoginException {
-        return Krb5Util.getSubject(GSSCaller.CALLER_SSL_CLIENT, acc);
-    }
-
-    @Override
-    public Subject getServerSubject(AccessControlContext acc)
-            throws LoginException {
-        return Krb5Util.getSubject(GSSCaller.CALLER_SSL_SERVER, acc);
-    }
-
-    @Override
-    public Object getServiceCreds(AccessControlContext acc)
-            throws LoginException {
-        ServiceCreds serviceCreds =
-            Krb5Util.getServiceCreds(GSSCaller.CALLER_SSL_SERVER, null, acc);
-        return serviceCreds;
-    }
-
-    @Override
-    public String getServerPrincipalName(Object serviceCreds) {
-        return ((ServiceCreds)serviceCreds).getName();
-    }
-
-    @Override
-    public String getPrincipalHostName(Principal principal) {
-        if (principal == null) {
-           return null;
-        }
-        String hostName = null;
-        try {
-            PrincipalName princName =
-                new PrincipalName(principal.getName(),
-                        PrincipalName.KRB_NT_SRV_HST);
-            String[] nameParts = princName.getNameStrings();
-            if (nameParts.length >= 2) {
-                hostName = nameParts[1];
-            }
-        } catch (Exception e) {
-            // ignore
-        }
-        return hostName;
-    }
-
-
-    @Override
-    public Permission getServicePermission(String principalName,
-            String action) {
-        return new ServicePermission(principalName, action);
-    }
-
-    @Override
-    public boolean isRelated(Subject subject, Principal princ) {
-        if (princ == null) return false;
-        Set<Principal> principals =
-                subject.getPrincipals(Principal.class);
-        if (principals.contains(princ)) {
-            // bound to this principal
-            return true;
-        }
-        for (KeyTab pc: subject.getPrivateCredentials(KeyTab.class)) {
-            if (!pc.isBound()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/SSLwithPerms.java	Tue Jun 02 22:26:36 2015 +0800
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8038089
+ * @summary TLS optional support for Kerberos cipher suites needs to be re-examined
+ * @library ../../../../java/security/testlibrary/
+ * @run main/othervm SSLwithPerms
+ */
+import java.io.*;
+import javax.net.ssl.*;
+import javax.security.auth.AuthPermission;
+import javax.security.auth.kerberos.ServicePermission;
+import java.net.SocketPermission;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.Principal;
+import java.security.Security;
+import java.security.SecurityPermission;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.PropertyPermission;
+
+import sun.security.jgss.GSSUtil;
+
+public class SSLwithPerms {
+
+    static String KRB5_CONF = "krb5.conf";
+    static String JAAS_CONF = "jaas.conf";
+    static String REALM = "REALM";
+    static String KTAB = "ktab";
+    static String HOST = "host." + REALM.toLowerCase(Locale.US);
+    static String SERVER = "host/" + HOST;
+    static String USER = "user";
+    static char[] PASS = "password".toCharArray();
+
+    public static void main(String[] args) throws Exception {
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        if (args.length == 0) {
+            KDC kdc = KDC.create(REALM, HOST, 0, true);
+
+            kdc.addPrincipal(USER, PASS);
+            kdc.addPrincipalRandKey("krbtgt/" + REALM);
+            kdc.addPrincipalRandKey(SERVER);
+            KDC.saveConfig(KRB5_CONF, kdc);
+            kdc.writeKtab(KTAB);
+
+            File f = new File(JAAS_CONF);
+            FileOutputStream fos = new FileOutputStream(f);
+            fos.write((
+                    "ssl {\n" +
+                            "    com.sun.security.auth.module.Krb5LoginModule required\n" +
+                            "    principal=\"" + SERVER + "\"\n" +
+                            "    useKeyTab=true\n" +
+                            "    keyTab=" + KTAB + "\n" +
+                            "    isInitiator=false\n" +
+                            "    storeKey=true;\n};\n"
+            ).getBytes());
+            fos.close();
+
+            Proc pc = Proc.create("SSLwithPerms")
+                    .args("client")
+                    .inheritIO()
+                    .prop("java.security.manager", "")
+                    .prop("java.security.krb5.conf", KRB5_CONF)
+                    .prop("sun.net.spi.nameservice.provider.1", "ns,mock")
+                    .prop("javax.net.ssl", "handshake")
+                    .prop("sun.security.krb5.debug", "true")
+                    .perm(new SecurityPermission("setProperty.jdk.tls.disabledAlgorithms"))
+                    .perm(new PropertyPermission("sun.security.krb5.principal", "read"))
+                    .perm(new FilePermission("port", "read"))
+                    .perm(new FilePermission(KTAB, "read"))
+                    .perm(new RuntimePermission("accessClassInPackage.sun.net.spi.nameservice"))
+                    .perm(new AuthPermission("modifyPrincipals"))
+                    .perm(new AuthPermission("modifyPrivateCredentials"))
+                    .perm(new AuthPermission("doAs"))
+                    .perm(new SocketPermission("127.0.0.1", "connect"))
+                    .perm(new ServicePermission("host/host.realm@REALM", "initiate"))
+                    .start();
+
+            Proc ps = Proc.create("SSLwithPerms")
+                    .args("server")
+                    .inheritIO()
+                    .prop("java.security.manager", "")
+                    .prop("java.security.krb5.conf", KRB5_CONF)
+                    .prop("java.security.auth.login.config", JAAS_CONF)
+                    .prop("javax.net.ssl", "handshake")
+                    .prop("sun.security.krb5.debug", "true")
+                    .perm(new SecurityPermission("setProperty.jdk.tls.disabledAlgorithms"))
+                    .perm(new AuthPermission("createLoginContext.ssl"))
+                    .perm(new AuthPermission("doAs"))
+                    .perm(new FilePermission("port", "write"))
+                    .perm(new SocketPermission("127.0.0.1", "accept"))
+                    .perm(new ServicePermission("host/host.realm@REALM", "accept"))
+                    .start();
+
+            if (pc.waitFor() != 0) {
+                throw new Exception();
+            }
+            if (ps.waitFor() != 0) {
+                throw new Exception();
+            }
+        } else if (args[0].equals("client")) {
+            Context c;
+            c = Context.fromUserPass(USER, PASS, false);
+            c.doAs(new JsseClientAction(), null);
+        } else if (args[0].equals("server")) {
+            final Context s = Context.fromJAAS("ssl");
+            s.doAs(new JsseServerAction(), null);
+        }
+    }
+
+    private static class JsseClientAction implements Action {
+        public byte[] run(Context s, byte[] input) throws Exception {
+            SSLSocketFactory sslsf =
+                (SSLSocketFactory) SSLSocketFactory.getDefault();
+            while (!Files.exists(Paths.get("port"))) {
+                Thread.sleep(100);
+            }
+            int port = ByteBuffer.allocate(4)
+                    .put(Files.readAllBytes(Paths.get("port"))).getInt(0);
+            System.out.println("Connecting " + SERVER + ":" + port);
+            SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(HOST, port);
+
+            // Enable only a KRB5 cipher suite.
+            String enabledSuites[] = {"TLS_KRB5_WITH_RC4_128_SHA"};
+            sslSocket.setEnabledCipherSuites(enabledSuites);
+
+            SSLParameters params = sslSocket.getSSLParameters();
+            params.setServerNames(Collections.singletonList(new SNIHostName(HOST)));
+            sslSocket.setSSLParameters(params);
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(
+                sslSocket.getInputStream()));
+            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
+                sslSocket.getOutputStream()));
+
+            String outStr = "Hello There!\n";
+            out.write(outStr);
+            out.flush();
+            System.out.print("Sending " + outStr);
+
+            String inStr = in.readLine();
+            System.out.println("Received " + inStr);
+
+            String cipherSuiteChosen = sslSocket.getSession().getCipherSuite();
+            System.out.println("Cipher suite in use: " + cipherSuiteChosen);
+            Principal self = sslSocket.getSession().getLocalPrincipal();
+            System.out.println("I am: " + self.toString());
+            Principal peer = sslSocket.getSession().getPeerPrincipal();
+            System.out.println("Server is: " + peer.toString());
+
+            sslSocket.close();
+            return null;
+        }
+    }
+
+    private static class JsseServerAction implements Action {
+        public byte[] run(Context s, byte[] input) throws Exception {
+            SSLServerSocketFactory sslssf =
+                (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+            SSLServerSocket sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(0); // any port
+            int port = sslServerSocket.getLocalPort();
+            System.out.println("Listening on " + port);
+
+            String enabledSuites[] = {"TLS_KRB5_WITH_RC4_128_SHA"};
+            sslServerSocket.setEnabledCipherSuites(enabledSuites);
+
+            Files.write(Paths.get("port"), ByteBuffer.allocate(4).putInt(port).array());
+            System.out.println("Waiting for incoming connection...");
+
+            SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+
+            System.out.println("Got connection from client "
+                + sslSocket.getInetAddress());
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(
+                sslSocket.getInputStream()));
+            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
+                sslSocket.getOutputStream()));
+
+            String inStr = in.readLine();
+            System.out.println("Received " + inStr);
+
+            String outStr = inStr + " " + new Date().toString() + "\n";
+            out.write(outStr);
+            System.out.println("Sending " + outStr);
+            out.flush();
+
+            String cipherSuiteChosen =
+                sslSocket.getSession().getCipherSuite();
+            System.out.println("Cipher suite in use: " + cipherSuiteChosen);
+            Principal self = sslSocket.getSession().getLocalPrincipal();
+            System.out.println("I am: " + self.toString());
+            Principal peer = sslSocket.getSession().getPeerPrincipal();
+            System.out.println("Client is: " + peer.toString());
+
+            sslSocket.close();
+            return null;
+        }
+    }
+}