Merge
This commit is contained in:
commit
77bbeddd31
@ -39,6 +39,7 @@ AUTO_FILES_JAVA_DIRS = \
|
|||||||
sun/security/provider \
|
sun/security/provider \
|
||||||
sun/security/rsa \
|
sun/security/rsa \
|
||||||
sun/security/ssl \
|
sun/security/ssl \
|
||||||
|
sun/security/ssl/krb5 \
|
||||||
sun/security/timestamp \
|
sun/security/timestamp \
|
||||||
sun/security/validator \
|
sun/security/validator \
|
||||||
sun/security/x509 \
|
sun/security/x509 \
|
||||||
|
@ -40,7 +40,6 @@ import java.util.List;
|
|||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
@ -413,14 +412,15 @@ final public class StartTlsResponseImpl extends StartTlsResponse {
|
|||||||
try {
|
try {
|
||||||
HostnameChecker checker = HostnameChecker.getInstance(
|
HostnameChecker checker = HostnameChecker.getInstance(
|
||||||
HostnameChecker.TYPE_LDAP);
|
HostnameChecker.TYPE_LDAP);
|
||||||
Principal principal = getPeerPrincipal(session);
|
// Use ciphersuite to determine whether Kerberos is active.
|
||||||
if (principal instanceof KerberosPrincipal) {
|
if (session.getCipherSuite().startsWith("TLS_KRB5")) {
|
||||||
if (!checker.match(hostname, (KerberosPrincipal) principal)) {
|
Principal principal = getPeerPrincipal(session);
|
||||||
|
if (!checker.match(hostname, principal)) {
|
||||||
throw new SSLPeerUnverifiedException(
|
throw new SSLPeerUnverifiedException(
|
||||||
"hostname of the kerberos principal:" + principal +
|
"hostname of the kerberos principal:" + principal +
|
||||||
" does not match the hostname:" + hostname);
|
" does not match the hostname:" + hostname);
|
||||||
}
|
}
|
||||||
} else {
|
} else { // X.509
|
||||||
|
|
||||||
// get the subject's certificate
|
// get the subject's certificate
|
||||||
certs = session.getPeerCertificates();
|
certs = session.getPeerCertificates();
|
||||||
|
@ -36,7 +36,6 @@ import java.security.Principal;
|
|||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
|
||||||
|
|
||||||
import sun.security.util.HostnameChecker;
|
import sun.security.util.HostnameChecker;
|
||||||
import sun.security.util.DerValue;
|
import sun.security.util.DerValue;
|
||||||
@ -109,20 +108,18 @@ class VerifierWrapper implements javax.net.ssl.HostnameVerifier {
|
|||||||
/*
|
/*
|
||||||
* In com.sun.net.ssl.HostnameVerifier the method is defined
|
* In com.sun.net.ssl.HostnameVerifier the method is defined
|
||||||
* as verify(String urlHostname, String certHostname).
|
* as verify(String urlHostname, String certHostname).
|
||||||
* This means we need to extract the hostname from the certificate
|
* This means we need to extract the hostname from the X.509 certificate
|
||||||
* in this wrapper
|
* or from the Kerberos principal name, in this wrapper.
|
||||||
*/
|
*/
|
||||||
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
|
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
|
||||||
try {
|
try {
|
||||||
String serverName;
|
String serverName;
|
||||||
Principal principal = getPeerPrincipal(session);
|
// Use ciphersuite to determine whether Kerberos is active.
|
||||||
// X.500 principal or Kerberos principal.
|
if (session.getCipherSuite().startsWith("TLS_KRB5")) {
|
||||||
// (Use ciphersuite check to determine whether Kerberos is present.)
|
|
||||||
if (session.getCipherSuite().startsWith("TLS_KRB5") &&
|
|
||||||
principal instanceof KerberosPrincipal) {
|
|
||||||
serverName =
|
serverName =
|
||||||
HostnameChecker.getServerName((KerberosPrincipal)principal);
|
HostnameChecker.getServerName(getPeerPrincipal(session));
|
||||||
} else {
|
|
||||||
|
} else { // X.509
|
||||||
Certificate[] serverChain = session.getPeerCertificates();
|
Certificate[] serverChain = session.getPeerCertificates();
|
||||||
if ((serverChain == null) || (serverChain.length == 0)) {
|
if ((serverChain == null) || (serverChain.length == 0)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -54,7 +54,6 @@ import java.util.Iterator;
|
|||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
import sun.security.x509.X500Name;
|
import sun.security.x509.X500Name;
|
||||||
@ -466,16 +465,14 @@ final class HttpsClient extends HttpClient
|
|||||||
HostnameChecker checker = HostnameChecker.getInstance(
|
HostnameChecker checker = HostnameChecker.getInstance(
|
||||||
HostnameChecker.TYPE_TLS);
|
HostnameChecker.TYPE_TLS);
|
||||||
|
|
||||||
Principal principal = getPeerPrincipal();
|
// Use ciphersuite to determine whether Kerberos is present.
|
||||||
// X.500 principal or Kerberos principal.
|
if (cipher.startsWith("TLS_KRB5")) {
|
||||||
// (Use ciphersuite check to determine whether Kerberos is present.)
|
if (!checker.match(host, getPeerPrincipal())) {
|
||||||
if (cipher.startsWith("TLS_KRB5") &&
|
|
||||||
principal instanceof KerberosPrincipal) {
|
|
||||||
if (!checker.match(host, (KerberosPrincipal)principal)) {
|
|
||||||
throw new SSLPeerUnverifiedException("Hostname checker" +
|
throw new SSLPeerUnverifiedException("Hostname checker" +
|
||||||
" failed for Kerberos");
|
" failed for Kerberos");
|
||||||
}
|
}
|
||||||
} else {
|
} else { // X.509
|
||||||
|
|
||||||
// get the subject's certificate
|
// get the subject's certificate
|
||||||
peerCerts = session.getPeerCertificates();
|
peerCerts = session.getPeerCertificates();
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ final class CipherSuite implements Comparable {
|
|||||||
// Flag indicating if CipherSuite availability can change dynamically.
|
// Flag indicating if CipherSuite availability can change dynamically.
|
||||||
// This is the case when we rely on a JCE cipher implementation that
|
// This is the case when we rely on a JCE cipher implementation that
|
||||||
// may not be available in the installed JCE providers.
|
// 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;
|
final static boolean DYNAMIC_AVAILABILITY = true;
|
||||||
|
|
||||||
private final static boolean ALLOW_ECC = Debug.getBooleanProperty
|
private final static boolean ALLOW_ECC = Debug.getBooleanProperty
|
||||||
|
@ -44,9 +44,6 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
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;
|
import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
|
||||||
|
|
||||||
@ -362,9 +359,7 @@ final class ClientHandshaker extends Handshaker {
|
|||||||
subject = AccessController.doPrivileged(
|
subject = AccessController.doPrivileged(
|
||||||
new PrivilegedExceptionAction<Subject>() {
|
new PrivilegedExceptionAction<Subject>() {
|
||||||
public Subject run() throws Exception {
|
public Subject run() throws Exception {
|
||||||
return Krb5Util.getSubject(
|
return Krb5Helper.getClientSubject(getAccSE());
|
||||||
GSSCaller.CALLER_SSL_CLIENT,
|
|
||||||
getAccSE());
|
|
||||||
}});
|
}});
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
subject = null;
|
subject = null;
|
||||||
@ -375,8 +370,9 @@ final class ClientHandshaker extends Handshaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subject != null) {
|
if (subject != null) {
|
||||||
Set<KerberosPrincipal> principals =
|
// Eliminate dependency on KerberosPrincipal
|
||||||
subject.getPrincipals(KerberosPrincipal.class);
|
Set<Principal> principals =
|
||||||
|
subject.getPrincipals(Principal.class);
|
||||||
if (!principals.contains(localPrincipal)) {
|
if (!principals.contains(localPrincipal)) {
|
||||||
throw new SSLProtocolException("Server resumed" +
|
throw new SSLProtocolException("Server resumed" +
|
||||||
" session with wrong subject identity");
|
" session with wrong subject identity");
|
||||||
@ -754,7 +750,7 @@ final class ClientHandshaker extends Handshaker {
|
|||||||
case K_KRB5:
|
case K_KRB5:
|
||||||
case K_KRB5_EXPORT:
|
case K_KRB5_EXPORT:
|
||||||
byte[] secretBytes =
|
byte[] secretBytes =
|
||||||
((KerberosClientKeyExchange)m2).getPreMasterSecret().getUnencrypted();
|
((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();
|
||||||
preMasterSecret = new SecretKeySpec(secretBytes, "TlsPremasterSecret");
|
preMasterSecret = new SecretKeySpec(secretBytes, "TlsPremasterSecret");
|
||||||
break;
|
break;
|
||||||
case K_DHE_RSA:
|
case K_DHE_RSA:
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -160,7 +160,7 @@ public class Debug {
|
|||||||
System.err.println(prefix + ": "+message);
|
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 + ": { ");
|
s.print(name + ": { ");
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
s.print("null");
|
s.print("null");
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -52,7 +52,7 @@ import javax.net.ssl.SSLException;
|
|||||||
*
|
*
|
||||||
* @author David Brownell
|
* @author David Brownell
|
||||||
*/
|
*/
|
||||||
class HandshakeInStream extends InputStream {
|
public class HandshakeInStream extends InputStream {
|
||||||
|
|
||||||
InputRecord r;
|
InputRecord r;
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ class HandshakeInStream extends InputStream {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] getBytes16() throws IOException {
|
public byte[] getBytes16() throws IOException {
|
||||||
int len = getInt16();
|
int len = getInt16();
|
||||||
byte b[] = new byte[len];
|
byte b[] = new byte[len];
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,7 +23,6 @@
|
|||||||
* have any questions.
|
* have any questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package sun.security.ssl;
|
package sun.security.ssl;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -73,7 +72,7 @@ import sun.security.ssl.CipherSuite.*;
|
|||||||
*
|
*
|
||||||
* @author David Brownell
|
* @author David Brownell
|
||||||
*/
|
*/
|
||||||
abstract class HandshakeMessage {
|
public abstract class HandshakeMessage {
|
||||||
|
|
||||||
HandshakeMessage() { }
|
HandshakeMessage() { }
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ abstract class HandshakeMessage {
|
|||||||
static final byte ht_finished = 20;
|
static final byte ht_finished = 20;
|
||||||
|
|
||||||
/* Class and subclass dynamic debugging support */
|
/* 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
|
* Utility method to convert a BigInteger to a byte array in unsigned
|
||||||
@ -468,7 +467,6 @@ class CertificateMsg extends HandshakeMessage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ServerKeyExchange ... SERVER --> CLIENT
|
* ServerKeyExchange ... SERVER --> CLIENT
|
||||||
*
|
*
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -41,7 +41,7 @@ import java.security.MessageDigest;
|
|||||||
*
|
*
|
||||||
* @author David Brownell
|
* @author David Brownell
|
||||||
*/
|
*/
|
||||||
class HandshakeOutStream extends OutputStream {
|
public class HandshakeOutStream extends OutputStream {
|
||||||
|
|
||||||
private SSLSocketImpl socket;
|
private SSLSocketImpl socket;
|
||||||
private SSLEngineImpl engine;
|
private SSLEngineImpl engine;
|
||||||
@ -196,7 +196,7 @@ class HandshakeOutStream extends OutputStream {
|
|||||||
write(b, 0, b.length);
|
write(b, 0, b.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void putBytes16(byte b[]) throws IOException {
|
public void putBytes16(byte b[]) throws IOException {
|
||||||
if (b == null) {
|
if (b == null) {
|
||||||
putInt16(0);
|
putInt16(0);
|
||||||
return;
|
return;
|
||||||
|
@ -29,199 +29,67 @@ import java.io.IOException;
|
|||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.AccessControlContext;
|
import java.security.AccessControlContext;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.Principal;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedAction;
|
||||||
import java.security.SecureRandom;
|
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is Kerberos option in the client key exchange message
|
* A helper class that calls the KerberosClientKeyExchange implementation.
|
||||||
* (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
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
final class KerberosClientKeyExchange extends HandshakeMessage {
|
public class KerberosClientKeyExchange extends HandshakeMessage {
|
||||||
|
|
||||||
private KerberosPreMasterSecret preMaster;
|
private static final String IMPL_CLASS =
|
||||||
private byte[] encodedTicket;
|
"sun.security.ssl.krb5.KerberosClientKeyExchangeImpl";
|
||||||
private KerberosPrincipal peerPrincipal;
|
|
||||||
private KerberosPrincipal localPrincipal;
|
|
||||||
|
|
||||||
/**
|
private static final Class<?> implClass = AccessController.doPrivileged(
|
||||||
* Creates an instance of KerberosClientKeyExchange consisting of the
|
new PrivilegedAction<Class<?>>() {
|
||||||
* Kerberos service ticket, authenticator and encrypted premaster secret.
|
public Class<?> run() {
|
||||||
* Called by client handshaker.
|
try {
|
||||||
*
|
return Class.forName(IMPL_CLASS, true, null);
|
||||||
* @param serverName name of server with which to do handshake;
|
} catch (ClassNotFoundException cnf) {
|
||||||
* this is used to get the Kerberos service ticket
|
return null;
|
||||||
* @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
|
);
|
||||||
*/
|
private final KerberosClientKeyExchange impl = createImpl();
|
||||||
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,
|
AccessControlContext acc, ProtocolVersion protocolVersion,
|
||||||
SecureRandom rand) throws IOException {
|
SecureRandom rand) throws IOException {
|
||||||
|
|
||||||
// Get service ticket
|
if (impl != null) {
|
||||||
KerberosTicket ticket = getServiceTicket(serverName, isLoopback, acc);
|
init(serverName, isLoopback, acc, protocolVersion, rand);
|
||||||
encodedTicket = ticket.getEncoded();
|
} else {
|
||||||
|
throw new IllegalStateException("Kerberos is unavailable");
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public KerberosClientKeyExchange(ProtocolVersion protocolVersion,
|
||||||
* Creates an instance of KerberosClientKeyExchange from its ASN.1 encoding.
|
ProtocolVersion clientVersion, SecureRandom rand,
|
||||||
* Used by ServerHandshaker to verify and obtain premaster secret.
|
HandshakeInStream input, SecretKey[] serverKeys) throws IOException {
|
||||||
*
|
|
||||||
* @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
|
if (impl != null) {
|
||||||
encodedTicket = input.getBytes16();
|
init(protocolVersion, clientVersion, rand, input, serverKeys);
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
// Generate bogus premaster secret
|
throw new IllegalStateException("Kerberos is unavailable");
|
||||||
preMaster = new KerberosPreMasterSecret(protocolVersion, rand);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,138 +97,46 @@ final class KerberosClientKeyExchange extends HandshakeMessage {
|
|||||||
return ht_client_key_exchange;
|
return ht_client_key_exchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
int messageLength() {
|
public int messageLength() {
|
||||||
return (6 + encodedTicket.length + preMaster.getEncrypted().length);
|
return impl.messageLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
void send(HandshakeOutStream s) throws IOException {
|
public void send(HandshakeOutStream s) throws IOException {
|
||||||
s.putBytes16(encodedTicket);
|
impl.send(s);
|
||||||
s.putBytes16(null); // XXX no authenticator
|
|
||||||
s.putBytes16(preMaster.getEncrypted());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PrintStream s) throws IOException {
|
@Override
|
||||||
s.println("*** ClientKeyExchange, Kerberos");
|
public void print(PrintStream p) throws IOException {
|
||||||
|
impl.print(p);
|
||||||
|
}
|
||||||
|
|
||||||
if (debug != null && Debug.isOn("verbose")) {
|
public void init(String serverName, boolean isLoopback,
|
||||||
Debug.println(s, "Kerberos service ticket", encodedTicket);
|
AccessControlContext acc, ProtocolVersion protocolVersion,
|
||||||
Debug.println(s, "Random Secret", preMaster.getUnencrypted());
|
SecureRandom rand) throws IOException {
|
||||||
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
|
public void init(ProtocolVersion protocolVersion,
|
||||||
private static KerberosTicket getServiceTicket(String srvName,
|
ProtocolVersion clientVersion, SecureRandom rand,
|
||||||
boolean isLoopback, final AccessControlContext acc) throws IOException {
|
HandshakeInStream input, SecretKey[] serverKeys) throws IOException {
|
||||||
|
|
||||||
// get the local hostname if srvName is loopback address
|
if (impl != null) {
|
||||||
String serverName = srvName;
|
impl.init(protocolVersion, clientVersion, rand, input, serverKeys);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KerberosPreMasterSecret getPreMasterSecret() {
|
public byte[] getUnencryptedPreMasterSecret() {
|
||||||
return preMaster;
|
return impl.getUnencryptedPreMasterSecret();
|
||||||
}
|
}
|
||||||
|
|
||||||
KerberosPrincipal getPeerPrincipal() {
|
public Principal getPeerPrincipal(){
|
||||||
return peerPrincipal;
|
return impl.getPeerPrincipal();
|
||||||
}
|
}
|
||||||
|
|
||||||
KerberosPrincipal getLocalPrincipal() {
|
public Principal getLocalPrincipal(){
|
||||||
return localPrincipal;
|
return impl.getLocalPrincipal();
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
126
jdk/src/share/classes/sun/security/ssl/Krb5Helper.java
Normal file
126
jdk/src/share/classes/sun/security/ssl/Krb5Helper.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
71
jdk/src/share/classes/sun/security/ssl/Krb5Proxy.java
Normal file
71
jdk/src/share/classes/sun/security/ssl/Krb5Proxy.java
Normal file
@ -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);
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -45,7 +45,7 @@ package sun.security.ssl;
|
|||||||
* @author Andreas Sterbenz
|
* @author Andreas Sterbenz
|
||||||
* @since 1.4.1
|
* @since 1.4.1
|
||||||
*/
|
*/
|
||||||
final class ProtocolVersion {
|
public final class ProtocolVersion {
|
||||||
|
|
||||||
// dummy protocol version value for invalid SSLSession
|
// dummy protocol version value for invalid SSLSession
|
||||||
final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
|
final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
|
||||||
@ -80,10 +80,10 @@ final class ProtocolVersion {
|
|||||||
|
|
||||||
// version in 16 bit MSB format as it appears in records and
|
// version in 16 bit MSB format as it appears in records and
|
||||||
// messages, i.e. 0x0301 for TLS 1.0
|
// messages, i.e. 0x0301 for TLS 1.0
|
||||||
final int v;
|
public final int v;
|
||||||
|
|
||||||
// major and minor version
|
// major and minor version
|
||||||
final byte major, minor;
|
public final byte major, minor;
|
||||||
|
|
||||||
// name used in JSSE (e.g. TLSv1 for TLS 1.0)
|
// name used in JSSE (e.g. TLSv1 for TLS 1.0)
|
||||||
final String name;
|
final String name;
|
||||||
@ -117,7 +117,7 @@ final class ProtocolVersion {
|
|||||||
* Return a ProtocolVersion with the specified major and minor version
|
* Return a ProtocolVersion with the specified major and minor version
|
||||||
* numbers. Never throws exceptions.
|
* numbers. Never throws exceptions.
|
||||||
*/
|
*/
|
||||||
static ProtocolVersion valueOf(int major, int minor) {
|
public static ProtocolVersion valueOf(int major, int minor) {
|
||||||
major &= 0xff;
|
major &= 0xff;
|
||||||
minor &= 0xff;
|
minor &= 0xff;
|
||||||
int v = (major << 8) | minor;
|
int v = (major << 8) | minor;
|
||||||
|
@ -48,7 +48,6 @@ import javax.net.ssl.SSLPeerUnverifiedException;
|
|||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLPermission;
|
import javax.net.ssl.SSLPermission;
|
||||||
|
|
||||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
|
||||||
import static sun.security.ssl.CipherSuite.*;
|
import static sun.security.ssl.CipherSuite.*;
|
||||||
@ -469,8 +468,8 @@ final class SSLSessionImpl implements SSLSession {
|
|||||||
* defining the session.
|
* defining the session.
|
||||||
*
|
*
|
||||||
* @return the peer's principal. Returns an X500Principal of the
|
* @return the peer's principal. Returns an X500Principal of the
|
||||||
* end-entity certiticate for X509-based cipher suites, and
|
* end-entity certificate for X509-based cipher suites, and
|
||||||
* KerberosPrincipal for Kerberos cipher suites.
|
* Principal for Kerberos cipher suites.
|
||||||
*
|
*
|
||||||
* @throws SSLPeerUnverifiedException if the peer's identity has not
|
* @throws SSLPeerUnverifiedException if the peer's identity has not
|
||||||
* been verified
|
* been verified
|
||||||
@ -483,7 +482,8 @@ final class SSLSessionImpl implements SSLSession {
|
|||||||
if (peerPrincipal == null) {
|
if (peerPrincipal == null) {
|
||||||
throw new SSLPeerUnverifiedException("peer not authenticated");
|
throw new SSLPeerUnverifiedException("peer not authenticated");
|
||||||
} else {
|
} else {
|
||||||
return (KerberosPrincipal)peerPrincipal;
|
// Eliminate dependency on KerberosPrincipal
|
||||||
|
return peerPrincipal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peerCerts == null) {
|
if (peerCerts == null) {
|
||||||
@ -497,15 +497,15 @@ final class SSLSessionImpl implements SSLSession {
|
|||||||
*
|
*
|
||||||
* @return the principal sent to the peer. Returns an X500Principal
|
* @return the principal sent to the peer. Returns an X500Principal
|
||||||
* of the end-entity certificate for X509-based cipher suites, and
|
* 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.
|
* sent, then null is returned.
|
||||||
*/
|
*/
|
||||||
public Principal getLocalPrincipal() {
|
public Principal getLocalPrincipal() {
|
||||||
|
|
||||||
if ((cipherSuite.keyExchange == K_KRB5) ||
|
if ((cipherSuite.keyExchange == K_KRB5) ||
|
||||||
(cipherSuite.keyExchange == K_KRB5_EXPORT)) {
|
(cipherSuite.keyExchange == K_KRB5_EXPORT)) {
|
||||||
return (localPrincipal == null ? null :
|
// Eliminate dependency on KerberosPrincipal
|
||||||
(KerberosPrincipal)localPrincipal);
|
return (localPrincipal == null ? null : localPrincipal);
|
||||||
}
|
}
|
||||||
return (localCerts == null ? null :
|
return (localCerts == null ? null :
|
||||||
localCerts[0].getSubjectX500Principal());
|
localCerts[0].getSubjectX500Principal());
|
||||||
|
@ -39,11 +39,6 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
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;
|
import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
|
||||||
|
|
||||||
@ -69,7 +64,7 @@ final class ServerHandshaker extends Handshaker {
|
|||||||
private X509Certificate[] certs;
|
private X509Certificate[] certs;
|
||||||
private PrivateKey privateKey;
|
private PrivateKey privateKey;
|
||||||
|
|
||||||
private KerberosKey[] kerberosKeys;
|
private SecretKey[] kerberosKeys;
|
||||||
|
|
||||||
// flag to check for clientCertificateVerify message
|
// flag to check for clientCertificateVerify message
|
||||||
private boolean needClientVerify = false;
|
private boolean needClientVerify = false;
|
||||||
@ -366,9 +361,8 @@ final class ServerHandshaker extends Handshaker {
|
|||||||
subject = AccessController.doPrivileged(
|
subject = AccessController.doPrivileged(
|
||||||
new PrivilegedExceptionAction<Subject>() {
|
new PrivilegedExceptionAction<Subject>() {
|
||||||
public Subject run() throws Exception {
|
public Subject run() throws Exception {
|
||||||
return Krb5Util.getSubject(
|
return
|
||||||
GSSCaller.CALLER_SSL_SERVER,
|
Krb5Helper.getServerSubject(getAccSE());
|
||||||
getAccSE());
|
|
||||||
}});
|
}});
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
subject = null;
|
subject = null;
|
||||||
@ -379,8 +373,9 @@ final class ServerHandshaker extends Handshaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subject != null) {
|
if (subject != null) {
|
||||||
Set<KerberosPrincipal> principals =
|
// Eliminate dependency on KerberosPrincipal
|
||||||
subject.getPrincipals(KerberosPrincipal.class);
|
Set<Principal> principals =
|
||||||
|
subject.getPrincipals(Principal.class);
|
||||||
if (!principals.contains(localPrincipal)) {
|
if (!principals.contains(localPrincipal)) {
|
||||||
resumingSession = false;
|
resumingSession = false;
|
||||||
if (debug != null && Debug.isOn("session")) {
|
if (debug != null && Debug.isOn("session")) {
|
||||||
@ -914,11 +909,11 @@ final class ServerHandshaker extends Handshaker {
|
|||||||
try {
|
try {
|
||||||
final AccessControlContext acc = getAccSE();
|
final AccessControlContext acc = getAccSE();
|
||||||
kerberosKeys = AccessController.doPrivileged(
|
kerberosKeys = AccessController.doPrivileged(
|
||||||
new PrivilegedExceptionAction<KerberosKey[]>() {
|
// Eliminate dependency on KerberosKey
|
||||||
public KerberosKey[] run() throws Exception {
|
new PrivilegedExceptionAction<SecretKey[]>() {
|
||||||
|
public SecretKey[] run() throws Exception {
|
||||||
// get kerberos key for the default principal
|
// get kerberos key for the default principal
|
||||||
return Krb5Util.getKeys(
|
return Krb5Helper.getServerKeys(acc);
|
||||||
GSSCaller.CALLER_SSL_SERVER, null, acc);
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
// check permission to access and use the secret key of the
|
// check permission to access and use the secret key of the
|
||||||
@ -931,12 +926,13 @@ final class ServerHandshaker extends Handshaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String serverPrincipal =
|
String serverPrincipal =
|
||||||
kerberosKeys[0].getPrincipal().getName();
|
Krb5Helper.getServerPrincipalName(kerberosKeys[0]);
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
try {
|
try {
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
sm.checkPermission(new ServicePermission(serverPrincipal,
|
// Eliminate dependency on ServicePermission
|
||||||
"accept"), acc);
|
sm.checkPermission(Krb5Helper.getServicePermission(
|
||||||
|
serverPrincipal, "accept"), acc);
|
||||||
}
|
}
|
||||||
} catch (SecurityException se) {
|
} catch (SecurityException se) {
|
||||||
kerberosKeys = null;
|
kerberosKeys = null;
|
||||||
@ -973,7 +969,7 @@ final class ServerHandshaker extends Handshaker {
|
|||||||
session.setPeerPrincipal(mesg.getPeerPrincipal());
|
session.setPeerPrincipal(mesg.getPeerPrincipal());
|
||||||
session.setLocalPrincipal(mesg.getLocalPrincipal());
|
session.setLocalPrincipal(mesg.getLocalPrincipal());
|
||||||
|
|
||||||
byte[] b = mesg.getPreMasterSecret().getUnencrypted();
|
byte[] b = mesg.getUnencryptedPreMasterSecret();
|
||||||
return new SecretKeySpec(b, "TlsPremasterSecret");
|
return new SecretKeySpec(b, "TlsPremasterSecret");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,7 +23,7 @@
|
|||||||
* have any questions.
|
* have any questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sun.security.ssl;
|
package sun.security.ssl.krb5;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
@ -36,6 +36,11 @@ import sun.security.krb5.EncryptedData;
|
|||||||
import sun.security.krb5.KrbException;
|
import sun.security.krb5.KrbException;
|
||||||
import sun.security.krb5.internal.crypto.KeyUsage;
|
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
|
* This is the Kerberos premaster secret in the Kerberos client key
|
||||||
* exchange message (CLIENT --> SERVER); it holds the
|
* exchange message (CLIENT --> SERVER); it holds the
|
||||||
@ -211,12 +216,12 @@ final class KerberosPreMasterSecret {
|
|||||||
return pm;
|
return pm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone not needed; package internal use only
|
// Clone not needed; internal use only
|
||||||
byte[] getUnencrypted() {
|
byte[] getUnencrypted() {
|
||||||
return preMaster;
|
return preMaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone not needed; package internal use only
|
// Clone not needed; internal use only
|
||||||
byte[] getEncrypted() {
|
byte[] getEncrypted() {
|
||||||
return encrypted;
|
return encrypted;
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -32,10 +32,9 @@ import java.security.Principal;
|
|||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
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.x509.X500Name;
|
||||||
import sun.security.krb5.PrincipalName;
|
|
||||||
|
|
||||||
import sun.net.util.IPAddressUtil;
|
import sun.net.util.IPAddressUtil;
|
||||||
|
|
||||||
@ -98,8 +97,7 @@ public class HostnameChecker {
|
|||||||
/**
|
/**
|
||||||
* Perform the check for Kerberos.
|
* Perform the check for Kerberos.
|
||||||
*/
|
*/
|
||||||
public static boolean match(String expectedName,
|
public static boolean match(String expectedName, Principal principal) {
|
||||||
KerberosPrincipal principal) {
|
|
||||||
String hostName = getServerName(principal);
|
String hostName = getServerName(principal);
|
||||||
return (expectedName.equalsIgnoreCase(hostName));
|
return (expectedName.equalsIgnoreCase(hostName));
|
||||||
}
|
}
|
||||||
@ -107,23 +105,8 @@ public class HostnameChecker {
|
|||||||
/**
|
/**
|
||||||
* Return the Server name from Kerberos principal.
|
* Return the Server name from Kerberos principal.
|
||||||
*/
|
*/
|
||||||
public static String getServerName(KerberosPrincipal principal) {
|
public static String getServerName(Principal principal) {
|
||||||
if (principal == null) {
|
return Krb5Helper.getPrincipalHostName(principal);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,4 +30,3 @@ public interface Action {
|
|||||||
*/
|
*/
|
||||||
byte[] run(Context s, byte[] input) throws Exception;
|
byte[] run(Context s, byte[] input) throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,4 +302,3 @@ public class HttpNegotiateServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
168
jdk/test/sun/security/krb5/auto/SSL.java
Normal file
168
jdk/test/sun/security/krb5/auto/SSL.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user