diff --git a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java index 459a0aed7f8..5c3abbcdab5 100644 --- a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,6 +92,8 @@ final class ClientHandshaker extends Handshaker { private List requestedServerNames = Collections.emptyList(); + private boolean serverNamesAccepted = false; + /* * Constructors */ @@ -567,7 +569,9 @@ final class ClientHandshaker extends Handshaker { // check extensions for (HelloExtension ext : mesg.extensions.list()) { ExtensionType type = ext.type; - if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) + if (type == ExtensionType.EXT_SERVER_NAME) { + serverNamesAccepted = true; + } else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) && (type != ExtensionType.EXT_EC_POINT_FORMATS) && (type != ExtensionType.EXT_SERVER_NAME) && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) { @@ -864,15 +868,47 @@ final class ClientHandshaker extends Handshaker { break; case K_KRB5: case K_KRB5_EXPORT: - String hostname = getHostSE(); - if (hostname == null) { - throw new IOException("Hostname is required" + - " to use Kerberos cipher suites"); + String sniHostname = null; + for (SNIServerName serverName : requestedServerNames) { + if (serverName instanceof SNIHostName) { + sniHostname = ((SNIHostName) serverName).getAsciiName(); + break; + } } - KerberosClientKeyExchange kerberosMsg = - new KerberosClientKeyExchange( - hostname, isLoopbackSE(), getAccSE(), protocolVersion, - sslContext.getSecureRandom()); + + KerberosClientKeyExchange kerberosMsg = null; + if (sniHostname != null) { + // use first requested SNI hostname + try { + kerberosMsg = new KerberosClientKeyExchange( + sniHostname, getAccSE(), protocolVersion, + sslContext.getSecureRandom()); + } catch(IOException e) { + if (serverNamesAccepted) { + // server accepted requested SNI hostname, + // so it must be used + throw e; + } + // fallback to using hostname + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Warning, cannot use Server Name Indication: " + + e.getMessage()); + } + } + } + + if (kerberosMsg == null) { + String hostname = getHostSE(); + if (hostname == null) { + throw new IOException("Hostname is required" + + " to use Kerberos cipher suites"); + } + kerberosMsg = new KerberosClientKeyExchange( + hostname, getAccSE(), protocolVersion, + sslContext.getSecureRandom()); + } + // Record the principals involved in exchange session.setPeerPrincipal(kerberosMsg.getPeerPrincipal()); session.setLocalPrincipal(kerberosMsg.getLocalPrincipal()); diff --git a/jdk/src/share/classes/sun/security/ssl/Handshaker.java b/jdk/src/share/classes/sun/security/ssl/Handshaker.java index a92320451e0..7fde1d22ef6 100644 --- a/jdk/src/share/classes/sun/security/ssl/Handshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/Handshaker.java @@ -335,14 +335,6 @@ abstract class Handshaker { } } - boolean isLoopbackSE() { - if (conn != null) { - return conn.getInetAddress().isLoopbackAddress(); - } else { - return false; - } - } - int getPortSE() { if (conn != null) { return conn.getPort(); diff --git a/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java index 7b4decf1be7..ff393d9a5c3 100644 --- a/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java @@ -77,12 +77,12 @@ public class KerberosClientKeyExchange extends HandshakeMessage { // please won't check the value of impl variable } - public KerberosClientKeyExchange(String serverName, boolean isLoopback, + public KerberosClientKeyExchange(String serverName, AccessControlContext acc, ProtocolVersion protocolVersion, SecureRandom rand) throws IOException { if (impl != null) { - init(serverName, isLoopback, acc, protocolVersion, rand); + init(serverName, acc, protocolVersion, rand); } else { throw new IllegalStateException("Kerberos is unavailable"); } @@ -120,12 +120,12 @@ public class KerberosClientKeyExchange extends HandshakeMessage { impl.print(p); } - public void init(String serverName, boolean isLoopback, + public void init(String serverName, AccessControlContext acc, ProtocolVersion protocolVersion, SecureRandom rand) throws IOException { if (impl != null) { - impl.init(serverName, isLoopback, acc, protocolVersion, rand); + impl.init(serverName, acc, protocolVersion, rand); } } diff --git a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java index bd6f04e61ad..1fb770871d8 100644 --- a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,12 +105,12 @@ public final class KerberosClientKeyExchangeImpl * secret */ @Override - public void init(String serverName, boolean isLoopback, + public void init(String serverName, AccessControlContext acc, ProtocolVersion protocolVersion, SecureRandom rand) throws IOException { // Get service ticket - KerberosTicket ticket = getServiceTicket(serverName, isLoopback, acc); + KerberosTicket ticket = getServiceTicket(serverName, acc); encodedTicket = ticket.getEncoded(); // Record the Kerberos principals @@ -292,25 +292,33 @@ public final class KerberosClientKeyExchangeImpl } // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context - private static KerberosTicket getServiceTicket(String srvName, - boolean isLoopback, final AccessControlContext acc) throws IOException { + private static KerberosTicket getServiceTicket(String serverName, + final AccessControlContext acc) throws IOException { - // get the local hostname if srvName is loopback address - String serverName = srvName; - if (isLoopback) { + if ("localhost".equals(serverName) || + "localhost.localdomain".equals(serverName)) { + + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Get the local hostname"); + } String localHost = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public String run() { - String hostname; try { - hostname = InetAddress.getLocalHost().getHostName(); + return InetAddress.getLocalHost().getHostName(); } catch (java.net.UnknownHostException e) { - hostname = "localhost"; + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Warning," + + " cannot get the local hostname: " + + e.getMessage()); + } + return null; } - return hostname; } }); - serverName = localHost; + if (localHost != null) { + serverName = localHost; + } } // Resolve serverName (possibly in IP addr form) to Kerberos principal diff --git a/jdk/test/sun/security/krb5/auto/SSL.java b/jdk/test/sun/security/krb5/auto/SSL.java index 8d64460430d..aab262244ac 100644 --- a/jdk/test/sun/security/krb5/auto/SSL.java +++ b/jdk/test/sun/security/krb5/auto/SSL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,12 @@ /* * @test - * @bug 6894643 6913636 8005523 + * @bug 6894643 6913636 8005523 8025123 * @summary Test JSSE Kerberos ciphersuite * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_SHA * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_SHA unbound + * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_SHA unbound sni * @run main/othervm SSL TLS_KRB5_WITH_3DES_EDE_CBC_SHA * @run main/othervm SSL TLS_KRB5_WITH_3DES_EDE_CBC_MD5 * @run main/othervm SSL TLS_KRB5_WITH_DES_CBC_SHA @@ -44,6 +45,9 @@ import java.security.Permission; import javax.net.ssl.*; import java.security.Principal; import java.util.Date; +import java.util.List; +import java.util.ArrayList; +import java.util.Locale; import javax.security.auth.kerberos.ServicePermission; import sun.security.jgss.GSSUtil; import sun.security.krb5.PrincipalName; @@ -56,6 +60,8 @@ public class SSL extends SecurityManager { private static int loopCount = 0; private static volatile String server; private static volatile int port; + private static String sniHostname = null; + private static String sniMatcherPattern = null; private static String permChecks = ""; @@ -84,11 +90,11 @@ public class SSL extends SecurityManager { System.setSecurityManager(new SSL()); KDC kdc = KDC.create(OneKDC.REALM); - // Run this after KDC, so our own DNS service can be started - try { - server = InetAddress.getLocalHost().getHostName().toLowerCase(); - } catch (java.net.UnknownHostException e) { - server = "localhost"; + server = "host." + OneKDC.REALM.toLowerCase(Locale.US); + + if (args.length > 2) { + sniHostname = "test." + server; + sniMatcherPattern = ".*"; } kdc.addPrincipal(OneKDC.USER, OneKDC.PASS); @@ -98,15 +104,21 @@ public class SSL extends SecurityManager { // Add 3 versions of keys into keytab KeyTab ktab = KeyTab.create(OneKDC.KTAB); + String serviceName = null; + if (sniHostname != null) { + serviceName = "host/" + sniHostname; + } else { + serviceName = "host/" + server; + } PrincipalName service = new PrincipalName( - "host/" + server, PrincipalName.KRB_NT_SRV_HST); + serviceName, PrincipalName.KRB_NT_SRV_HST); ktab.addEntry(service, "pass1".toCharArray(), 1, true); ktab.addEntry(service, "pass2".toCharArray(), 2, true); ktab.addEntry(service, "pass3".toCharArray(), 3, true); ktab.save(); // and use the middle one as the real key - kdc.addPrincipal("host/" + server, "pass2".toCharArray()); + kdc.addPrincipal(serviceName, "pass2".toCharArray()); // JAAS config entry name ssl @@ -118,7 +130,7 @@ public class SSL extends SecurityManager { " com.sun.security.auth.module.Krb5LoginModule required\n" + (unbound ? " principal=*\n" : - " principal=\"host/" + server + "\"\n") + + " principal=\"" + serviceName + "\"\n") + " useKeyTab=true\n" + " keyTab=" + OneKDC.KTAB + "\n" + " isInitiator=false\n" + @@ -153,7 +165,7 @@ public class SSL extends SecurityManager { } c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); - c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); // Add another version of key, make sure it can be loaded @@ -161,10 +173,10 @@ public class SSL extends SecurityManager { ktab = KeyTab.getInstance(OneKDC.KTAB); ktab.addEntry(service, "pass4".toCharArray(), 4, true); ktab.save(); - kdc.addPrincipal("host/" + server, "pass4".toCharArray()); + kdc.addPrincipal(serviceName, "pass4".toCharArray()); c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); - c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); // Permission checking check. Please note this is highly @@ -199,6 +211,14 @@ public class SSL extends SecurityManager { sslSocket.setEnabledCipherSuites(enabledSuites); // Should check for exception if enabledSuites is not supported + if (sniHostname != null) { + List serverNames = new ArrayList<>(); + serverNames.add(new SNIHostName(sniHostname)); + SSLParameters params = sslSocket.getSSLParameters(); + params.setServerNames(serverNames); + sslSocket.setSSLParameters(params); + } + BufferedReader in = new BufferedReader(new InputStreamReader( sslSocket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter( @@ -242,6 +262,14 @@ public class SSL extends SecurityManager { sslServerSocket.setEnabledCipherSuites(enabledSuites); // Should check for exception if enabledSuites is not supported + if (sniMatcherPattern != null) { + List matchers = new ArrayList<>(); + matchers.add(SNIHostName.createSNIMatcher(sniMatcherPattern)); + SSLParameters params = sslServerSocket.getSSLParameters(); + params.setSNIMatchers(matchers); + sslServerSocket.setSSLParameters(params); + } + while (loopCount++ < LOOP_LIMIT) { System.out.println("Waiting for incoming connection...");