changeset 1966:7475a2e71c40

6894643: Separate out dependency on Kerberos Reviewed-by: alanb, xuelei
author vinnie
date Thu, 12 Nov 2009 23:00:23 +0000
parents fe9db22a220f
children 49eb9c3d7ce7
files make/sun/security/other/Makefile src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java src/share/classes/sun/net/www/protocol/https/HttpsClient.java src/share/classes/sun/security/ssl/CipherSuite.java src/share/classes/sun/security/ssl/ClientHandshaker.java src/share/classes/sun/security/ssl/Debug.java src/share/classes/sun/security/ssl/HandshakeInStream.java src/share/classes/sun/security/ssl/HandshakeMessage.java src/share/classes/sun/security/ssl/HandshakeOutStream.java src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java src/share/classes/sun/security/ssl/KerberosPreMasterSecret.java src/share/classes/sun/security/ssl/Krb5Helper.java src/share/classes/sun/security/ssl/Krb5Proxy.java src/share/classes/sun/security/ssl/ProtocolVersion.java src/share/classes/sun/security/ssl/SSLSessionImpl.java src/share/classes/sun/security/ssl/ServerHandshaker.java src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java src/share/classes/sun/security/util/HostnameChecker.java test/sun/security/krb5/auto/Action.java test/sun/security/krb5/auto/HttpNegotiateServer.java test/sun/security/krb5/auto/SSL.java
diffstat 24 files changed, 1216 insertions(+), 622 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/security/other/Makefile	Fri Oct 30 21:31:02 2009 +0000
+++ b/make/sun/security/other/Makefile	Thu Nov 12 23:00:23 2009 +0000
@@ -39,6 +39,7 @@
     sun/security/provider \
     sun/security/rsa \
     sun/security/ssl \
+    sun/security/ssl/krb5 \
     sun/security/timestamp \
     sun/security/validator \
     sun/security/x509 \
--- a/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java	Thu Nov 12 23:00:23 2009 +0000
@@ -40,7 +40,6 @@
 import java.security.Principal;
 import java.security.cert.X509Certificate;
 import java.security.cert.CertificateException;
-import javax.security.auth.kerberos.KerberosPrincipal;
 
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
@@ -413,14 +412,15 @@
         try {
             HostnameChecker checker = HostnameChecker.getInstance(
                                                 HostnameChecker.TYPE_LDAP);
-            Principal principal = getPeerPrincipal(session);
-            if (principal instanceof KerberosPrincipal) {
-                if (!checker.match(hostname, (KerberosPrincipal) principal)) {
+            // Use ciphersuite to determine whether Kerberos is active.
+            if (session.getCipherSuite().startsWith("TLS_KRB5")) {
+                Principal principal = getPeerPrincipal(session);
+                if (!checker.match(hostname, principal)) {
                     throw new SSLPeerUnverifiedException(
                         "hostname of the kerberos principal:" + principal +
                         " does not match the hostname:" + hostname);
                 }
-            } else {
+            } else { // X.509
 
                 // get the subject's certificate
                 certs = session.getPeerCertificates();
--- a/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java	Thu Nov 12 23:00:23 2009 +0000
@@ -36,7 +36,6 @@
 import java.security.cert.*;
 
 import javax.security.auth.x500.X500Principal;
-import javax.security.auth.kerberos.KerberosPrincipal;
 
 import sun.security.util.HostnameChecker;
 import sun.security.util.DerValue;
@@ -109,20 +108,18 @@
     /*
      * In com.sun.net.ssl.HostnameVerifier the method is defined
      * as verify(String urlHostname, String certHostname).
-     * This means we need to extract the hostname from the certificate
-     * in this wrapper
+     * This means we need to extract the hostname from the X.509 certificate
+     * or from the Kerberos principal name, in this wrapper.
      */
     public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
         try {
             String serverName;
-            Principal principal = getPeerPrincipal(session);
-            // X.500 principal or Kerberos principal.
-            // (Use ciphersuite check to determine whether Kerberos is present.)
-            if (session.getCipherSuite().startsWith("TLS_KRB5") &&
-                    principal instanceof KerberosPrincipal) {
+            // Use ciphersuite to determine whether Kerberos is active.
+            if (session.getCipherSuite().startsWith("TLS_KRB5")) {
                 serverName =
-                    HostnameChecker.getServerName((KerberosPrincipal)principal);
-            } else {
+                    HostnameChecker.getServerName(getPeerPrincipal(session));
+
+            } else { // X.509
                 Certificate[] serverChain = session.getPeerCertificates();
                 if ((serverChain == null) || (serverChain.length == 0)) {
                     return false;
--- a/src/share/classes/sun/net/www/protocol/https/HttpsClient.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/net/www/protocol/https/HttpsClient.java	Thu Nov 12 23:00:23 2009 +0000
@@ -54,7 +54,6 @@
 import java.security.AccessController;
 
 import javax.security.auth.x500.X500Principal;
-import javax.security.auth.kerberos.KerberosPrincipal;
 
 import javax.net.ssl.*;
 import sun.security.x509.X500Name;
@@ -466,16 +465,14 @@
             HostnameChecker checker = HostnameChecker.getInstance(
                                                 HostnameChecker.TYPE_TLS);
 
-            Principal principal = getPeerPrincipal();
-            // X.500 principal or Kerberos principal.
-            // (Use ciphersuite check to determine whether Kerberos is present.)
-            if (cipher.startsWith("TLS_KRB5") &&
-                    principal instanceof KerberosPrincipal) {
-                if (!checker.match(host, (KerberosPrincipal)principal)) {
+            // Use ciphersuite to determine whether Kerberos is present.
+            if (cipher.startsWith("TLS_KRB5")) {
+                if (!checker.match(host, getPeerPrincipal())) {
                     throw new SSLPeerUnverifiedException("Hostname checker" +
                                 " failed for Kerberos");
                 }
-            } else {
+            } else { // X.509
+
                 // get the subject's certificate
                 peerCerts = session.getPeerCertificates();
 
--- a/src/share/classes/sun/security/ssl/CipherSuite.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/CipherSuite.java	Thu Nov 12 23:00:23 2009 +0000
@@ -74,7 +74,7 @@
     // Flag indicating if CipherSuite availability can change dynamically.
     // This is the case when we rely on a JCE cipher implementation that
     // may not be available in the installed JCE providers.
-    // It is true because we might not have an ECC or Kerberos implementation.
+    // It is true because we might not have an ECC implementation.
     final static boolean DYNAMIC_AVAILABILITY = true;
 
     private final static boolean ALLOW_ECC = Debug.getBooleanProperty
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java	Thu Nov 12 23:00:23 2009 +0000
@@ -44,9 +44,6 @@
 import javax.net.ssl.*;
 
 import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import sun.security.jgss.krb5.Krb5Util;
-import sun.security.jgss.GSSCaller;
 
 import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
 
@@ -362,9 +359,7 @@
                         subject = AccessController.doPrivileged(
                             new PrivilegedExceptionAction<Subject>() {
                             public Subject run() throws Exception {
-                                return Krb5Util.getSubject(
-                                    GSSCaller.CALLER_SSL_CLIENT,
-                                    getAccSE());
+                                return Krb5Helper.getClientSubject(getAccSE());
                             }});
                     } catch (PrivilegedActionException e) {
                         subject = null;
@@ -375,8 +370,9 @@
                     }
 
                     if (subject != null) {
-                        Set<KerberosPrincipal> principals =
-                                subject.getPrincipals(KerberosPrincipal.class);
+                        // 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");
@@ -754,7 +750,7 @@
         case K_KRB5:
         case K_KRB5_EXPORT:
             byte[] secretBytes =
-                ((KerberosClientKeyExchange)m2).getPreMasterSecret().getUnencrypted();
+                ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();
             preMasterSecret = new SecretKeySpec(secretBytes, "TlsPremasterSecret");
             break;
         case K_DHE_RSA:
--- a/src/share/classes/sun/security/ssl/Debug.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/Debug.java	Thu Nov 12 23:00:23 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1999-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -160,7 +160,7 @@
         System.err.println(prefix + ": "+message);
     }
 
-    static void println(PrintStream s, String name, byte[] data) {
+    public static void println(PrintStream s, String name, byte[] data) {
         s.print(name + ":  { ");
         if (data == null) {
             s.print("null");
--- a/src/share/classes/sun/security/ssl/HandshakeInStream.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/HandshakeInStream.java	Thu Nov 12 23:00:23 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@
  *
  * @author David Brownell
  */
-class HandshakeInStream extends InputStream {
+public class HandshakeInStream extends InputStream {
 
     InputRecord r;
 
@@ -196,7 +196,7 @@
         return b;
     }
 
-    byte[] getBytes16() throws IOException {
+    public byte[] getBytes16() throws IOException {
         int len = getInt16();
         byte b[] = new byte[len];
 
--- a/src/share/classes/sun/security/ssl/HandshakeMessage.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java	Thu Nov 12 23:00:23 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
  * have any questions.
  */
 
-
 package sun.security.ssl;
 
 import java.io.*;
@@ -73,7 +72,7 @@
  *
  * @author David Brownell
  */
-abstract class HandshakeMessage {
+public abstract class HandshakeMessage {
 
     HandshakeMessage() { }
 
@@ -92,7 +91,7 @@
     static final byte   ht_finished = 20;
 
     /* Class and subclass dynamic debugging support */
-    static final Debug debug = Debug.getInstance("ssl");
+    public static final Debug debug = Debug.getInstance("ssl");
 
     /**
      * Utility method to convert a BigInteger to a byte array in unsigned
@@ -468,7 +467,6 @@
     }
 }
 
-
 /*
  * ServerKeyExchange ... SERVER --> CLIENT
  *
--- a/src/share/classes/sun/security/ssl/HandshakeOutStream.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/HandshakeOutStream.java	Thu Nov 12 23:00:23 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@
  *
  * @author  David Brownell
  */
-class HandshakeOutStream extends OutputStream {
+public class HandshakeOutStream extends OutputStream {
 
     private SSLSocketImpl socket;
     private SSLEngineImpl engine;
@@ -196,7 +196,7 @@
         write(b, 0, b.length);
     }
 
-    void putBytes16(byte b[]) throws IOException {
+    public void putBytes16(byte b[]) throws IOException {
         if (b == null) {
             putInt16(0);
             return;
--- a/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java	Thu Nov 12 23:00:23 2009 +0000
@@ -29,199 +29,67 @@
 import java.io.PrintStream;
 import java.security.AccessController;
 import java.security.AccessControlContext;
-import java.security.PrivilegedExceptionAction;
-import java.security.PrivilegedActionException;
+import java.security.Principal;
+import java.security.PrivilegedAction;
 import java.security.SecureRandom;
-import java.net.InetAddress;
-
-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.Realm;
-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 javax.crypto.SecretKey;
 
 /**
- * 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
- *
+ * A helper class that calls the KerberosClientKeyExchange implementation.
  */
-final class KerberosClientKeyExchange extends HandshakeMessage {
+public class KerberosClientKeyExchange extends HandshakeMessage {
+
+    private static final String IMPL_CLASS =
+        "sun.security.ssl.krb5.KerberosClientKeyExchangeImpl";
 
-    private KerberosPreMasterSecret preMaster;
-    private byte[] encodedTicket;
-    private KerberosPrincipal peerPrincipal;
-    private KerberosPrincipal localPrincipal;
+    private static final Class<?> implClass = AccessController.doPrivileged(
+            new PrivilegedAction<Class<?>>() {
+                public Class<?> run() {
+                    try {
+                        return Class.forName(IMPL_CLASS, true, null);
+                    } catch (ClassNotFoundException cnf) {
+                        return null;
+                    }
+                }
+            }
+        );
+    private final KerberosClientKeyExchange impl = createImpl();
 
-    /**
-     * 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
-     */
-    KerberosClientKeyExchange(String serverName, boolean isLoopback,
+    private KerberosClientKeyExchange createImpl() {
+        if (getClass() == KerberosClientKeyExchange.class) {
+            try {
+                return (KerberosClientKeyExchange)implClass.newInstance();
+            } catch (InstantiationException e) {
+                throw new AssertionError(e);
+            } catch (IllegalAccessException e) {
+                throw new AssertionError(e);
+            }
+        }
+        return null;
+    }
+
+    public KerberosClientKeyExchange() {
+    }
+
+    public KerberosClientKeyExchange(String serverName, boolean isLoopback,
         AccessControlContext acc, ProtocolVersion protocolVersion,
         SecureRandom rand) throws IOException {
 
-         // Get service ticket
-         KerberosTicket ticket = getServiceTicket(serverName, isLoopback, 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);
+        if (impl != null) {
+            init(serverName, isLoopback, acc, protocolVersion, rand);
+        } else {
+            throw new IllegalStateException("Kerberos is unavailable");
+        }
     }
 
-    /**
-     * 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 serverKey server's master secret key
-     */
-    KerberosClientKeyExchange(ProtocolVersion protocolVersion,
-        ProtocolVersion clientVersion,
-        SecureRandom rand, HandshakeInStream input, KerberosKey[] serverKeys)
-        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;
-            Realm ticketRealm = t.realm;
-
-            String serverPrincipal = serverKeys[0].getPrincipal().getName();
-
-            /*
-             * 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
-             */
+    public KerberosClientKeyExchange(ProtocolVersion protocolVersion,
+        ProtocolVersion clientVersion, SecureRandom rand,
+        HandshakeInStream input, SecretKey[] serverKeys) throws IOException {
 
-            // Check that ticket Sname matches serverPrincipal
-            String ticketPrinc = ticketSname.toString().concat("@" +
-                                        ticketRealm.toString());
-            if (!ticketPrinc.equals(serverPrincipal)) {
-                if (debug != null && Debug.isOn("handshake"))
-                   System.out.println("Service principal in Ticket does not"
-                        + " match associated principal in KerberosKey");
-                throw new IOException("Server principal is " +
-                    serverPrincipal + " but ticket is for " +
-                    ticketPrinc);
-            }
-
-            // See if we have the right key to decrypt the ticket to get
-            // the session key.
-            int encPartKeyType = encPart.getEType();
-            KerberosKey dkey = findKey(encPartKeyType, serverKeys);
-            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, true);
-            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: " + serverPrincipal);
-                System.out.println("realm: " + encTicketPart.crealm.toString());
-                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);
+        if (impl != null) {
+            init(protocolVersion, clientVersion, rand, input, serverKeys);
         } else {
-            // Generate bogus premaster secret
-            preMaster = new KerberosPreMasterSecret(protocolVersion, rand);
+            throw new IllegalStateException("Kerberos is unavailable");
         }
     }
 
@@ -229,138 +97,46 @@
         return ht_client_key_exchange;
     }
 
-    int messageLength() {
-        return (6 + encodedTicket.length + preMaster.getEncrypted().length);
+    public int  messageLength() {
+        return impl.messageLength();
+    }
+
+    public void send(HandshakeOutStream s) throws IOException {
+        impl.send(s);
     }
 
-    void send(HandshakeOutStream s) throws IOException {
-        s.putBytes16(encodedTicket);
-        s.putBytes16(null); // XXX no authenticator
-        s.putBytes16(preMaster.getEncrypted());
+    @Override
+    public void print(PrintStream p) throws IOException {
+        impl.print(p);
     }
 
-    void print(PrintStream s) throws IOException {
-        s.println("*** ClientKeyExchange, Kerberos");
+    public void init(String serverName, boolean isLoopback,
+        AccessControlContext acc, ProtocolVersion protocolVersion,
+        SecureRandom rand) throws IOException {
 
-        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());
+        if (impl != null) {
+            impl.init(serverName, isLoopback, acc, protocolVersion, rand);
         }
     }
 
-    // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context
-    private static KerberosTicket getServiceTicket(String srvName,
-        boolean isLoopback, final AccessControlContext acc) throws IOException {
-
-        // get the local hostname if srvName is loopback address
-        String serverName = srvName;
-        if (isLoopback) {
-            String localHost = java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<String>() {
-                public String run() {
-                    String hostname;
-                    try {
-                        hostname = InetAddress.getLocalHost().getHostName();
-                    } catch (java.net.UnknownHostException e) {
-                        hostname = "localhost";
-                    }
-                    return hostname;
-                }
-            });
-          serverName = localHost;
-        }
+    public void init(ProtocolVersion protocolVersion,
+        ProtocolVersion clientVersion, SecureRandom rand,
+        HandshakeInStream input, SecretKey[] serverKeys) throws IOException {
 
-        // 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;
+        if (impl != null) {
+            impl.init(protocolVersion, clientVersion, rand, input, serverKeys);
         }
     }
 
-    KerberosPreMasterSecret getPreMasterSecret() {
-        return preMaster;
-    }
-
-    KerberosPrincipal getPeerPrincipal() {
-        return peerPrincipal;
-    }
-
-    KerberosPrincipal getLocalPrincipal() {
-        return localPrincipal;
+    public byte[] getUnencryptedPreMasterSecret() {
+        return impl.getUnencryptedPreMasterSecret();
     }
 
-    private static KerberosKey findKey(int etype, KerberosKey[] keys) {
-        int ktype;
-        for (int i = 0; i < keys.length; i++) {
-            ktype = keys[i].getKeyType();
-            if (etype == ktype) {
-                return keys[i];
-            }
-        }
-        // 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) {
-                    return new KerberosKey(keys[i].getPrincipal(),
-                        keys[i].getEncoded(),
-                        etype,
-                        keys[i].getVersionNumber());
-                }
-            }
-        }
-        return null;
+    public Principal getPeerPrincipal(){
+        return impl.getPeerPrincipal();
+    }
+
+    public Principal getLocalPrincipal(){
+        return impl.getLocalPrincipal();
     }
 }
--- a/src/share/classes/sun/security/ssl/KerberosPreMasterSecret.java	Fri Oct 30 21:31:02 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-/*
- * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.security.*;
-import java.security.interfaces.*;
-
-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;
-
-/**
- * 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);
-                 }
-            }
-
-            // Reset data stream after decryption, remove redundant bytes
-            preMaster =  data.reset(temp, false);
-
-            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
-        // implementations send the negotiated version, so accept both
-        // 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 != currentVersion) &&
-                                  (protocolVersion.v != clientVersion.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);
-                }
-            }
-            preMaster = generatePreMaster(generator, currentVersion);
-            protocolVersion = currentVersion;
-        }
-    }
-
-    /*
-     * 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; package internal use only
-    byte[] getUnencrypted() {
-        return preMaster;
-    }
-
-    // Clone not needed; package internal use only
-    byte[] getEncrypted() {
-        return encrypted;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/Krb5Helper.java	Thu Nov 12 23:00:23 2009 +0000
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.ssl;
+
+import java.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>() {
+            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 SecretKey[] getServerKeys(AccessControlContext acc)
+            throws LoginException {
+        ensureAvailable();
+        return proxy.getServerKeys(acc);
+    }
+
+    /**
+     * Returns the server-side principal name associated with the KerberosKey.
+     */
+    public static String getServerPrincipalName(SecretKey kerberosKey) {
+        ensureAvailable();
+        return proxy.getServerPrincipalName(kerberosKey);
+    }
+
+    /**
+     * 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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/Krb5Proxy.java	Thu Nov 12 23:00:23 2009 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.ssl;
+
+import java.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 KerberosKeys for the default server-side principal.
+     */
+    SecretKey[] getServerKeys(AccessControlContext acc) throws LoginException;
+
+    /**
+     * Returns the server-side principal name associated with the KerberosKey.
+     */
+    String getServerPrincipalName(SecretKey kerberosKey);
+
+    /**
+     * 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);
+}
--- a/src/share/classes/sun/security/ssl/ProtocolVersion.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/ProtocolVersion.java	Thu Nov 12 23:00:23 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2002-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,7 @@
  * @author  Andreas Sterbenz
  * @since   1.4.1
  */
-final class ProtocolVersion {
+public final class ProtocolVersion {
 
     // dummy protocol version value for invalid SSLSession
     final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
@@ -80,10 +80,10 @@
 
     // version in 16 bit MSB format as it appears in records and
     // messages, i.e. 0x0301 for TLS 1.0
-    final int v;
+    public final int v;
 
     // major and minor version
-    final byte major, minor;
+    public final byte major, minor;
 
     // name used in JSSE (e.g. TLSv1 for TLS 1.0)
     final String name;
@@ -117,7 +117,7 @@
      * Return a ProtocolVersion with the specified major and minor version
      * numbers. Never throws exceptions.
      */
-    static ProtocolVersion valueOf(int major, int minor) {
+    public static ProtocolVersion valueOf(int major, int minor) {
         major &= 0xff;
         minor &= 0xff;
         int v = (major << 8) | minor;
--- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java	Thu Nov 12 23:00:23 2009 +0000
@@ -48,7 +48,6 @@
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLPermission;
 
-import javax.security.auth.kerberos.KerberosPrincipal;
 import javax.security.auth.x500.X500Principal;
 
 import static sun.security.ssl.CipherSuite.*;
@@ -469,8 +468,8 @@
      * defining the session.
      *
      * @return the peer's principal. Returns an X500Principal of the
-     * end-entity certiticate for X509-based cipher suites, and
-     * KerberosPrincipal for Kerberos cipher suites.
+     * end-entity certificate for X509-based cipher suites, and
+     * Principal for Kerberos cipher suites.
      *
      * @throws SSLPeerUnverifiedException if the peer's identity has not
      *          been verified
@@ -483,7 +482,8 @@
             if (peerPrincipal == null) {
                 throw new SSLPeerUnverifiedException("peer not authenticated");
             } else {
-                return (KerberosPrincipal)peerPrincipal;
+                // Eliminate dependency on KerberosPrincipal
+                return peerPrincipal;
             }
         }
         if (peerCerts == null) {
@@ -497,15 +497,15 @@
      *
      * @return the principal sent to the peer. Returns an X500Principal
      * of the end-entity certificate for X509-based cipher suites, and
-     * KerberosPrincipal for Kerberos cipher suites. If no principal was
+     * Principal for Kerberos cipher suites. If no principal was
      * sent, then null is returned.
      */
     public Principal getLocalPrincipal() {
 
         if ((cipherSuite.keyExchange == K_KRB5) ||
             (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
-                return (localPrincipal == null ? null :
-                        (KerberosPrincipal)localPrincipal);
+                // Eliminate dependency on KerberosPrincipal
+                return (localPrincipal == null ? null : localPrincipal);
         }
         return (localCerts == null ? null :
                 localCerts[0].getSubjectX500Principal());
--- a/src/share/classes/sun/security/ssl/ServerHandshaker.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java	Thu Nov 12 23:00:23 2009 +0000
@@ -39,11 +39,6 @@
 import javax.net.ssl.*;
 
 import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.kerberos.ServicePermission;
-import sun.security.jgss.krb5.Krb5Util;
-import sun.security.jgss.GSSCaller;
 
 import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
 
@@ -69,7 +64,7 @@
     private X509Certificate[]   certs;
     private PrivateKey          privateKey;
 
-    private KerberosKey[]       kerberosKeys;
+    private SecretKey[]       kerberosKeys;
 
     // flag to check for clientCertificateVerify message
     private boolean             needClientVerify = false;
@@ -366,9 +361,8 @@
                             subject = AccessController.doPrivileged(
                                 new PrivilegedExceptionAction<Subject>() {
                                 public Subject run() throws Exception {
-                                    return Krb5Util.getSubject(
-                                        GSSCaller.CALLER_SSL_SERVER,
-                                        getAccSE());
+                                    return
+                                        Krb5Helper.getServerSubject(getAccSE());
                             }});
                         } catch (PrivilegedActionException e) {
                             subject = null;
@@ -379,8 +373,9 @@
                         }
 
                         if (subject != null) {
-                            Set<KerberosPrincipal> principals =
-                                subject.getPrincipals(KerberosPrincipal.class);
+                            // Eliminate dependency on KerberosPrincipal
+                            Set<Principal> principals =
+                                subject.getPrincipals(Principal.class);
                             if (!principals.contains(localPrincipal)) {
                                 resumingSession = false;
                                 if (debug != null && Debug.isOn("session")) {
@@ -914,11 +909,11 @@
         try {
             final AccessControlContext acc = getAccSE();
             kerberosKeys = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<KerberosKey[]>() {
-                public KerberosKey[] run() throws Exception {
+                // Eliminate dependency on KerberosKey
+                new PrivilegedExceptionAction<SecretKey[]>() {
+                public SecretKey[] run() throws Exception {
                     // get kerberos key for the default principal
-                    return Krb5Util.getKeys(
-                        GSSCaller.CALLER_SSL_SERVER, null, acc);
+                    return Krb5Helper.getServerKeys(acc);
                         }});
 
             // check permission to access and use the secret key of the
@@ -931,12 +926,13 @@
                 }
 
                 String serverPrincipal =
-                    kerberosKeys[0].getPrincipal().getName();
+                    Krb5Helper.getServerPrincipalName(kerberosKeys[0]);
                 SecurityManager sm = System.getSecurityManager();
                 try {
                    if (sm != null) {
-                      sm.checkPermission(new ServicePermission(serverPrincipal,
-                                                "accept"), acc);
+                      // Eliminate dependency on ServicePermission
+                      sm.checkPermission(Krb5Helper.getServicePermission(
+                          serverPrincipal, "accept"), acc);
                    }
                 } catch (SecurityException se) {
                    kerberosKeys = null;
@@ -973,7 +969,7 @@
         session.setPeerPrincipal(mesg.getPeerPrincipal());
         session.setLocalPrincipal(mesg.getLocalPrincipal());
 
-        byte[] b = mesg.getPreMasterSecret().getUnencrypted();
+        byte[] b = mesg.getUnencryptedPreMasterSecret();
         return new SecretKeySpec(b, "TlsPremasterSecret");
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Thu Nov 12 23:00:23 2009 +0000
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2003-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.ssl.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 javax.crypto.SecretKey;
+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.Realm;
+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.ssl.Debug;
+import sun.security.ssl.HandshakeInStream;
+import sun.security.ssl.HandshakeOutStream;
+import sun.security.ssl.KerberosClientKeyExchange;
+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, boolean isLoopback,
+        AccessControlContext acc, ProtocolVersion protocolVersion,
+        SecureRandom rand) throws IOException {
+
+         // Get service ticket
+         KerberosTicket ticket = getServiceTicket(serverName, isLoopback, 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 serverKey server's master secret key
+     */
+    @Override
+    public void init(ProtocolVersion protocolVersion,
+        ProtocolVersion clientVersion,
+        SecureRandom rand, HandshakeInStream input, SecretKey[] secretKeys)
+        throws IOException {
+
+        KerberosKey[] serverKeys = (KerberosKey[])secretKeys;
+
+        // 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;
+            Realm ticketRealm = t.realm;
+
+            String serverPrincipal = serverKeys[0].getPrincipal().getName();
+
+            /*
+             * 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
+             */
+
+            // Check that ticket Sname matches serverPrincipal
+            String ticketPrinc = ticketSname.toString().concat("@" +
+                                        ticketRealm.toString());
+            if (!ticketPrinc.equals(serverPrincipal)) {
+                if (debug != null && Debug.isOn("handshake"))
+                   System.out.println("Service principal in Ticket does not"
+                        + " match associated principal in KerberosKey");
+                throw new IOException("Server principal is " +
+                    serverPrincipal + " but ticket is for " +
+                    ticketPrinc);
+            }
+
+            // See if we have the right key to decrypt the ticket to get
+            // the session key.
+            int encPartKeyType = encPart.getEType();
+            KerberosKey dkey = findKey(encPartKeyType, serverKeys);
+            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, true);
+            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: " + serverPrincipal);
+                System.out.println("realm: " + encTicketPart.crealm.toString());
+                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(protocolVersion, 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 srvName,
+        boolean isLoopback, final AccessControlContext acc) throws IOException {
+
+        // get the local hostname if srvName is loopback address
+        String serverName = srvName;
+        if (isLoopback) {
+            String localHost = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<String>() {
+                public String run() {
+                    String hostname;
+                    try {
+                        hostname = InetAddress.getLocalHost().getHostName();
+                    } catch (java.net.UnknownHostException e) {
+                        hostname = "localhost";
+                    }
+                    return hostname;
+                }
+            });
+          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;
+    }
+
+    private static KerberosKey findKey(int etype, KerberosKey[] keys) {
+        int ktype;
+        for (int i = 0; i < keys.length; i++) {
+            ktype = keys[i].getKeyType();
+            if (etype == ktype) {
+                return keys[i];
+            }
+        }
+        // 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) {
+                    return new KerberosKey(keys[i].getPrincipal(),
+                        keys[i].getEncoded(),
+                        etype,
+                        keys[i].getVersionNumber());
+                }
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java	Thu Nov 12 23:00:23 2009 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2003-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.ssl.krb5;
+
+import java.io.*;
+import java.security.*;
+import java.security.interfaces.*;
+
+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);
+                 }
+            }
+
+            // Reset data stream after decryption, remove redundant bytes
+            preMaster =  data.reset(temp, false);
+
+            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
+        // implementations send the negotiated version, so accept both
+        // 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 != currentVersion) &&
+                                  (protocolVersion.v != clientVersion.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);
+                }
+            }
+            preMaster = generatePreMaster(generator, currentVersion);
+            protocolVersion = currentVersion;
+        }
+    }
+
+    /*
+     * 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/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java	Thu Nov 12 23:00:23 2009 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.ssl.krb5;
+
+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.kerberos.KerberosKey;
+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.krb5.PrincipalName;
+import sun.security.ssl.Krb5Proxy;
+
+/**
+ * An implementatin 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 SecretKey[] getServerKeys(AccessControlContext acc)
+            throws LoginException {
+        return Krb5Util.getKeys(GSSCaller.CALLER_SSL_SERVER, null, acc);
+    }
+
+    @Override
+    public String getServerPrincipalName(SecretKey kerberosKey) {
+        return ((KerberosKey)kerberosKey).getPrincipal().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);
+    }
+}
--- a/src/share/classes/sun/security/util/HostnameChecker.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/src/share/classes/sun/security/util/HostnameChecker.java	Thu Nov 12 23:00:23 2009 +0000
@@ -32,10 +32,9 @@
 import java.security.cert.*;
 
 import javax.security.auth.x500.X500Principal;
-import javax.security.auth.kerberos.KerberosPrincipal;
 
+import sun.security.ssl.Krb5Helper;
 import sun.security.x509.X500Name;
-import sun.security.krb5.PrincipalName;
 
 import sun.net.util.IPAddressUtil;
 
@@ -98,8 +97,7 @@
     /**
      * Perform the check for Kerberos.
      */
-    public static boolean match(String expectedName,
-                        KerberosPrincipal principal) {
+    public static boolean match(String expectedName, Principal principal) {
         String hostName = getServerName(principal);
         return (expectedName.equalsIgnoreCase(hostName));
     }
@@ -107,23 +105,8 @@
     /**
      * Return the Server name from Kerberos principal.
      */
-    public static String getServerName(KerberosPrincipal 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;
+    public static String getServerName(Principal principal) {
+        return Krb5Helper.getPrincipalHostName(principal);
     }
 
     /**
--- a/test/sun/security/krb5/auto/Action.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/test/sun/security/krb5/auto/Action.java	Thu Nov 12 23:00:23 2009 +0000
@@ -30,4 +30,3 @@
      */
     byte[] run(Context s, byte[] input) throws Exception;
 }
-
--- a/test/sun/security/krb5/auto/HttpNegotiateServer.java	Fri Oct 30 21:31:02 2009 +0000
+++ b/test/sun/security/krb5/auto/HttpNegotiateServer.java	Thu Nov 12 23:00:23 2009 +0000
@@ -302,4 +302,3 @@
         }
     }
 }
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/krb5/auto/SSL.java	Thu Nov 12 23:00:23 2009 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6894643
+ * @summary Test JSSE Kerberos ciphersuite
+ */
+import java.io.*;
+import java.net.InetAddress;
+import javax.net.ssl.*;
+import java.security.Principal;
+import java.util.Date;
+import sun.security.jgss.GSSUtil;
+
+public class SSL {
+
+    private static final String KRB5_CIPHER = "TLS_KRB5_WITH_3DES_EDE_CBC_SHA";
+    private static final int PORT = 4569;
+    private static final int LOOP_LIMIT = 1;
+    private static final char[] PASS = "secret".toCharArray();
+    private static int loopCount = 0;
+
+    private static String SERVER;
+
+    public static void main(String[] args) throws Exception {
+
+        KDC kdc = KDC.create(OneKDC.REALM);
+        // Run this after KDC, so our own DNS service can be started
+        try {
+            SERVER = InetAddress.getLocalHost().getHostName();
+        } catch (java.net.UnknownHostException e) {
+            SERVER = "localhost";
+        }
+
+        kdc.addPrincipal(OneKDC.USER, OneKDC.PASS);
+        kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
+        kdc.addPrincipal("host/" + SERVER, PASS);
+        KDC.saveConfig(OneKDC.KRB5_CONF, kdc);
+        System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF);
+
+        final Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
+        final Context s = Context.fromUserPass("host/" + SERVER, PASS, true);
+
+        c.startAsClient("host/" + SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+        s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    s.doAs(new JsseServerAction(), null);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+
+        // Warm the server
+        Thread.sleep(2000);
+
+        c.doAs(new JsseClientAction(), null);
+    }
+
+    // Following codes copied from
+    // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/lab/part2.html#JSSE
+    private static class JsseClientAction implements Action {
+        public byte[] run(Context s, byte[] input) throws Exception {
+            SSLSocketFactory sslsf =
+                (SSLSocketFactory) SSLSocketFactory.getDefault();
+            SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(SERVER, PORT);
+
+            // Enable only a KRB5 cipher suite.
+            String enabledSuites[] = {KRB5_CIPHER};
+            sslSocket.setEnabledCipherSuites(enabledSuites);
+            // Should check for exception if enabledSuites is not supported
+
+            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(PORT);
+
+            // Enable only a KRB5 cipher suite.
+            String enabledSuites[] = {KRB5_CIPHER};
+            sslServerSocket.setEnabledCipherSuites(enabledSuites);
+            // Should check for exception if enabledSuites is not supported
+
+            while (loopCount++ < LOOP_LIMIT) {
+                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;
+        }
+    }
+}