提交 d8cd5cf6 编写于 作者: X xuelei

8025123: SNI support in Kerberos cipher suites

Reviewed-by: weijun, xuelei
Contributed-by: NArtem Smotrakov <artem.smotrakov@oracle.com>
上级 61b8fdfc
/*
* 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<SNIServerName> requestedServerNames =
Collections.<SNIServerName>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());
......
......@@ -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();
......
......@@ -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);
}
}
......
/*
* 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<String>() {
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
......
/*
* 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<SNIServerName> 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<SNIMatcher> 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...");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册