Methods Summary |
---|
protected void | accept(int m_ctx, boolean client_mode)Performs the first part of a SSL/TLS handshaking process with a given
'host' connection and initializes the SSLSession.
// Must be set because no handshaking is necessary
// in this situation
handshakeStarted = true;
nativeaccept(this, m_ctx, client_mode);
ServerSessionContext sessionContext
= sslParameters.getServerSessionContext();
sslSession = new OpenSSLSessionImpl(nativegetsslsession(ssl),
sslParameters, super.getInetAddress().getHostName(),
super.getPort(), sessionContext);
sslSession.lastAccessedTime = System.currentTimeMillis();
sessionContext.putSession(sslSession);
|
public void | addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener listener)Registers a listener to be notified that a SSL handshake
was successfully completed on this connection.
if (listener == null) {
throw new IllegalArgumentException("Provided listener is null");
}
if (listeners == null) {
listeners = new ArrayList();
}
listeners.add(listener);
|
public void | close()Closes the SSL socket. Once closed, a socket is not available for further
use anymore under any circumstance. A new socket must be created.
// TODO: Close SSL sockets using a background thread so they close
// gracefully.
synchronized (handshakeLock) {
if (!handshakeStarted) {
handshakeStarted = true;
synchronized (this) {
nativefree();
if (socket != null) {
if (autoClose && !socket.isClosed()) socket.close();
} else {
if (!super.isClosed()) super.close();
}
}
return;
}
}
nativeinterrupt();
synchronized (this) {
synchronized (writeLock) {
synchronized (readLock) {
IOException pendingException = null;
// Shut down the SSL connection, per se.
try {
if (handshakeStarted) {
nativeclose();
}
} catch (IOException ex) {
/*
* Note the exception at this point, but try to continue
* to clean the rest of this all up before rethrowing.
*/
pendingException = ex;
}
/*
* Even if the above call failed, it is still safe to free
* the native structs, and we need to do so lest we leak
* memory.
*/
nativefree();
if (socket != null) {
if (autoClose && !socket.isClosed())
socket.close();
} else {
if (!super.isClosed())
super.close();
}
if (pendingException != null) {
throw pendingException;
}
}
}
}
|
protected void | finalize()
updateInstanceCount(-1);
if (ssl == 0) {
/*
* It's already been closed, so there's no need to do anything
* more at this point.
*/
return;
}
// Note the underlying socket up-front, for possible later use.
Socket underlyingSocket = socket;
// Fire up a thread to (hopefully) do all the real work.
Finalizer f = new Finalizer();
f.setDaemon(true);
f.start();
/*
* Give the finalizer thread one second to run. If it fails to
* terminate in that time, interrupt it (which may help if it
* is blocked on an interruptible I/O operation), make a note
* in the log, and go ahead and close the underlying socket if
* possible.
*/
try {
f.join(1000);
} catch (InterruptedException ex) {
// Reassert interrupted status.
Thread.currentThread().interrupt();
}
if (f.isAlive()) {
f.interrupt();
Logger.global.log(Level.SEVERE,
"Slow finalization of SSL socket (" + this + ", for " +
underlyingSocket + ")");
if ((underlyingSocket != null) && !underlyingSocket.isClosed()) {
underlyingSocket.close();
}
}
|
private boolean | findSuite(java.lang.String suite)
String[] supportedCipherSuites = nativegetsupportedciphersuites();
for(int i = 0; i < supportedCipherSuites.length; i++)
if (supportedCipherSuites[i].equals(suite)) return true;
throw new IllegalArgumentException("Protocol " + suite +
" is not supported.");
|
private OpenSSLSessionImpl | getCachedClientSession()Gets the suitable session reference from the session cache container.
if (super.getInetAddress() == null ||
super.getInetAddress().getHostAddress() == null ||
super.getInetAddress().getHostName() == null) {
return null;
}
ClientSessionContext sessionContext
= sslParameters.getClientSessionContext();
return (OpenSSLSessionImpl) sessionContext.getSession(
super.getInetAddress().getHostName(),
super.getPort());
|
public boolean | getEnableSessionCreation()Returns true if new SSL sessions may be established by this socket.
return sslParameters.getEnableSessionCreation();
|
public java.lang.String[] | getEnabledCipherSuites()The names of the cipher suites that are in use in the actual the SSL
connection are returned.
return nativegetenabledciphersuites();
|
public java.lang.String[] | getEnabledProtocols()The names of the protocols' versions that are in use on this SSL
connection.
ArrayList<String> array = new ArrayList<String>();
if ((ssl_op_no & SSL_OP_NO_SSLv3) == 0x00000000L) {
array.add(supportedProtocols[1]);
}
if ((ssl_op_no & SSL_OP_NO_TLSv1) == 0x00000000L) {
array.add(supportedProtocols[2]);
}
return array.toArray(new String[array.size()]);
|
public java.io.InputStream | getInputStream()Returns an input stream for this SSL socket using native calls to the
OpenSSL library.
synchronized(this) {
if (is == null) {
is = new SSLInputStream();
}
return is;
}
|
public static int | getInstanceCount()
synchronized (OpenSSLSocketImpl.class) {
return instanceCount;
}
|
public boolean | getNeedClientAuth()Returns true if the SSL socket needs client's authentication. Relevant
only for server sockets!
return sslParameters.getNeedClientAuth();
|
public java.io.OutputStream | getOutputStream()Returns an output stream for this SSL socket using native calls to the
OpenSSL library.
synchronized(this) {
if (os == null) {
os = new SSLOutputStream();
}
return os;
}
|
public javax.net.ssl.SSLSession | getSession()The SSL session used by this connection is returned. The SSL session
determines which cipher suite should be used by all connections within
that session and which identities have the session's client and server.
This method starts the SSL handshake.
try {
startHandshake();
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.WARNING,
"Error negotiating SSL connection.", e);
// return an invalid session with
// invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
return SSLSessionImpl.NULL_SESSION;
}
return sslSession;
|
public java.lang.String[] | getSupportedCipherSuites()The names of the cipher suites which could be used by the SSL connection
are returned.
return nativegetsupportedciphersuites();
|
public java.lang.String[] | getSupportedProtocols()The names of the protocols' versions that may be used on this SSL
connection.
return supportedProtocols.clone();
|
public boolean | getUseClientMode()This method gives true back if the SSL socket is set to client mode.
return sslParameters.getUseClientMode();
|
public boolean | getWantClientAuth()Returns true if the SSL socket requests client's authentication. Relevant
only for server sockets!
return sslParameters.getWantClientAuth();
|
private void | init()Initialize the SSL socket and set the certificates for the
future handshaking.
nativeinitstatic();
String alias = sslParameters.getKeyManager().chooseClientAlias(new String[] { "RSA" }, null, null);
if (alias != null) {
PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
ByteArrayOutputStream privateKeyOS = new ByteArrayOutputStream();
PEMWriter privateKeyPEMWriter = new PEMWriter(new OutputStreamWriter(privateKeyOS));
privateKeyPEMWriter.writeObject(privateKey);
privateKeyPEMWriter.close();
ByteArrayOutputStream certificateOS = new ByteArrayOutputStream();
PEMWriter certificateWriter = new PEMWriter(new OutputStreamWriter(certificateOS));
for (int i = 0; i < certificates.length; i++) {
certificateWriter.writeObject(certificates[i]);
}
certificateWriter.close();
nativeinit(privateKeyOS.toString(), certificateOS.toString(),
sslParameters.getSecureRandomMember() != null ?
sslParameters.getSecureRandomMember().generateSeed(1024) : null);
} else {
nativeinit(null, null,
sslParameters.getSecureRandomMember() != null ?
sslParameters.getSecureRandomMember().generateSeed(1024) : null);
}
|
native synchronized void | nativeaccept(java.net.Socket socketObject, int m_ctx, boolean client_mode)
|
private native java.lang.String | nativecipherauthenticationmethod()
|
private native void | nativeclose()
|
private native boolean | nativeconnect(int ctx, java.net.Socket sock, boolean client_mode, int sslsession)Adds OpenSSL functionality to the existing socket and starts the SSL
handshaking.
|
private native void | nativefree()
|
private native java.lang.String[] | nativegetenabledciphersuites()
|
private native int | nativegetsslsession(int ssl)
|
static native java.lang.String[] | nativegetsupportedciphersuites()Gets all available ciphers from the current OpenSSL library.
Needed by OpenSSLSocketFactory too.
|
private native void | nativeinit(java.lang.String privatekey, java.lang.String certificate, byte[] seed)
|
private static native void | nativeinitstatic()Initialize OpenSSL library.
|
private native void | nativeinterrupt()
|
private native int | nativeread(int timeout)Reads with the native SSL_read function from the encrypted data stream
|
private native int | nativeread(byte[] b, int off, int len, int timeout)
|
private native void | nativesetenabledciphersuites(java.lang.String controlString)Calls the SSL_CTX_set_cipher_list(...) OpenSSL function with the passed
char array.
|
private native void | nativesetenabledprotocols(long l)
|
private static native int | nativeverifysignature(byte[] message, byte[] signature, java.lang.String algorithm, byte[] modulus, byte[] exponent)
|
private native void | nativewrite(int b)Writes with the native SSL_write function to the encrypted data stream.
|
private native void | nativewrite(byte[] b, int off, int len)
|
public void | removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener listener)The method removes a registered listener.
if (listener == null) {
throw new IllegalArgumentException("Provided listener is null");
}
if (listeners == null) {
throw new IllegalArgumentException(
"Provided listener is not registered");
}
if (!listeners.remove(listener)) {
throw new IllegalArgumentException(
"Provided listener is not registered");
}
|
public void | sendUrgentData(int data)This method is not supported for SSLSocket implementation.
throw new SocketException(
"Method sendUrgentData() is not supported.");
|
public void | setEnableSessionCreation(boolean flag)Set a flag for the socket to inhibit or to allow the creation of a new
SSL sessions. If the flag is set to false, and there are no actual
sessions to resume, then there will be no successful handshaking.
sslParameters.setEnableSessionCreation(flag);
|
public void | setEnabledCipherSuites(java.lang.String[] suites)This method enables the cipher suites listed by
getSupportedCipherSuites().
if (suites == null) {
throw new IllegalArgumentException("Provided parameter is null");
}
String controlString = "";
for(int i = 0; i < suites.length; i++) {
findSuite(suites[i]);
if (i == 0) controlString = suites[i];
else controlString += ":" + suites[i];
}
nativesetenabledciphersuites(controlString);
|
public synchronized void | setEnabledProtocols(java.lang.String[] protocols)This method enables the protocols' versions listed by
getSupportedProtocols().
if (protocols == null) {
throw new IllegalArgumentException("Provided parameter is null");
}
ssl_op_no = SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
for(int i = 0; i < protocols.length; i++) {
if (protocols[i].equals("SSLv3"))
ssl_op_no ^= SSL_OP_NO_SSLv3;
else if (protocols[i].equals("TLSv1"))
ssl_op_no ^= SSL_OP_NO_TLSv1;
else throw new IllegalArgumentException("Protocol " + protocols[i] +
" is not supported.");
}
nativesetenabledprotocols(ssl_op_no);
|
public void | setNeedClientAuth(boolean need)Sets the SSL socket to use client's authentication. Relevant only for
server sockets!
sslParameters.setNeedClientAuth(need);
|
public void | setOOBInline(boolean on)This method is not supported for SSLSocket implementation.
throw new SocketException(
"Methods sendUrgentData, setOOBInline are not supported.");
|
public synchronized void | setSoTimeout(int timeout)Set the read timeout on this socket. The SO_TIMEOUT option, is specified
in milliseconds. The read operation will block indefinitely for a zero
value.
super.setSoTimeout(timeout);
this.timeout = timeout;
|
public synchronized void | setUseClientMode(boolean mode)This method set the actual SSL socket to client mode.
if (handshakeStarted) {
throw new IllegalArgumentException(
"Could not change the mode after the initial handshake has begun.");
}
sslParameters.setUseClientMode(mode);
|
public void | setWantClientAuth(boolean want)Sets the SSL socket to use client's authentication. Relevant only for
server sockets! Notice that in contrast to setNeedClientAuth(..) this
method will continue the negotiation if the client decide not to send
authentication credentials.
sslParameters.setWantClientAuth(want);
|
public void | shutdownInput()This method is not supported for this SSLSocket implementation.
throw new UnsupportedOperationException(
"Method shutdownInput() is not supported.");
|
public void | shutdownOutput()This method is not supported for this SSLSocket implementation.
throw new UnsupportedOperationException(
"Method shutdownOutput() is not supported.");
|
public synchronized void | startHandshake()Starts a TLS/SSL handshake on this connection using some native methods
from the OpenSSL library. It can negotiate new encryption keys, change
cipher suites, or initiate a new session. The certificate chain is
verified if the correspondent property in java.Security is set. All
listensers are notified at the end of the TLS/SSL handshake.
synchronized (handshakeLock) {
if (!handshakeStarted) {
handshakeStarted = true;
} else {
return;
}
}
OpenSSLSessionImpl session = getCachedClientSession();
// Check if it's allowed to create a new session (default is true)
if (session == null && !sslParameters.getEnableSessionCreation()) {
throw new SSLHandshakeException("SSL Session may not be created");
} else {
Socket socket = this.socket != null ? this.socket : this;
int sessionId = session != null ? session.session : 0;
boolean reusedSession;
synchronized (OpenSSLSocketImpl.class) {
reusedSession = nativeconnect(ssl_ctx, socket,
sslParameters.getUseClientMode(), sessionId);
}
if (reusedSession) {
// nativeconnect shouldn't return true if the session is not
// done
session.lastAccessedTime = System.currentTimeMillis();
sslSession = session;
LoggerHolder.logger.fine("Reused cached session for "
+ getInetAddress().getHostName() + ".");
} else {
if (session != null) {
LoggerHolder.logger.fine("Reuse of cached session for "
+ getInetAddress().getHostName() + " failed.");
} else {
LoggerHolder.logger.fine("Created new session for "
+ getInetAddress().getHostName() + ".");
}
ClientSessionContext sessionContext
= sslParameters.getClientSessionContext();
synchronized (OpenSSLSocketImpl.class) {
sessionId = nativegetsslsession(ssl);
}
if (address == null) {
sslSession = new OpenSSLSessionImpl(
sessionId, sslParameters,
super.getInetAddress().getHostName(),
super.getPort(), sessionContext);
} else {
sslSession = new OpenSSLSessionImpl(
sessionId, sslParameters,
address.getHostName(), address.getPort(),
sessionContext);
}
try {
X509Certificate[] peerCertificates = (X509Certificate[])
sslSession.getPeerCertificates();
if (peerCertificates == null
|| peerCertificates.length == 0) {
throw new SSLException("Server sends no certificate");
}
String authMethod;
synchronized (OpenSSLSocketImpl.class) {
authMethod = nativecipherauthenticationmethod();
}
sslParameters.getTrustManager().checkServerTrusted(
peerCertificates,
authMethod);
sessionContext.putSession(sslSession);
} catch (CertificateException e) {
throw new SSLException("Not trusted server certificate", e);
}
}
}
if (listeners != null) {
// notify the listeners
HandshakeCompletedEvent event =
new HandshakeCompletedEvent(this, sslSession);
int size = listeners.size();
for (int i = 0; i < size; i++) {
listeners.get(i).handshakeCompleted(event);
}
}
|
private static void | updateInstanceCount(int amount)
synchronized (OpenSSLSocketImpl.class) {
instanceCount += amount;
}
|
public static boolean | verifySignature(byte[] message, byte[] signature, java.lang.String algorithm, java.security.interfaces.RSAPublicKey key)Verifies an RSA signature. Conceptually, this method doesn't really
belong here, but due to its native code being closely tied to OpenSSL
(just like the rest of this class), we put it here for the time being.
This also solves potential problems with native library initialization.
byte[] modulus = key.getModulus().toByteArray();
byte[] exponent = key.getPublicExponent().toByteArray();
return nativeverifysignature(message, signature, algorithm, modulus, exponent) == 1;
|
private int | verify_callback(byte[][] bytes)Callback methode for the OpenSSL native certificate verification process.
try {
X509Certificate[] peerCertificateChain
= new X509Certificate[bytes.length];
for(int i = 0; i < bytes.length; i++) {
peerCertificateChain[i] =
new X509CertImpl(javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded());
}
try {
// TODO "null" String
sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain, "null");
} catch (CertificateException e) {
throw new AlertException(AlertProtocol.BAD_CERTIFICATE,
new SSLException("Not trusted server certificate", e));
}
} catch (javax.security.cert.CertificateException e) {
return 0;
} catch (IOException e) {
return 0;
}
return 1;
|