--- a/jdk/make/sun/security/other/Makefile Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/make/sun/security/other/Makefile Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/CipherSuite.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/Debug.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/Debug.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/HandshakeInStream.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/HandshakeInStream.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/HandshakeOutStream.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/HandshakeOutStream.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/KerberosPreMasterSecret.java Thu Nov 12 10:29:21 2009 -0800
+++ /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/jdk/src/share/classes/sun/security/ssl/Krb5Helper.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/Krb5Proxy.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/ProtocolVersion.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/ProtocolVersion.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/SSLSessionImpl.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSessionImpl.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/src/share/classes/sun/security/util/HostnameChecker.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/src/share/classes/sun/security/util/HostnameChecker.java Thu Nov 12 15:42:18 2009 -0800
@@ -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/jdk/test/sun/security/krb5/auto/Action.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/test/sun/security/krb5/auto/Action.java Thu Nov 12 15:42:18 2009 -0800
@@ -30,4 +30,3 @@
*/
byte[] run(Context s, byte[] input) throws Exception;
}
-
--- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java Thu Nov 12 10:29:21 2009 -0800
+++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java Thu Nov 12 15:42:18 2009 -0800
@@ -302,4 +302,3 @@
}
}
}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/SSL.java Thu Nov 12 15:42:18 2009 -0800
@@ -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;
+ }
+ }
+}