mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-08 05:58:38 +00:00
8025123: SNI support in Kerberos cipher suites
Reviewed-by: weijun, xuelei
This commit is contained in:
parent
fdf6a159f5
commit
54ebd8d42e
@ -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<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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<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
|
||||
|
||||
@ -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<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...");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user