Is it possible to change plain socket to SSLSocket?
There is a plain socket server listening on port 12345
;
ServerSocket s = new ServerSocket(12345);
What I want to kn开发者_开发问答ow is that it is possible that:
- If the client send a
http
request, the server handle the request directly, - If the client send a
https
request, the server change client socket to SSLSocket?
Thanks
Is it possible to change plain socket to SSLSocket?
Yes, it is. On the server side, the following works:
ServerSocketFactory ssf = ServerSocketFactory.getDefault();
ServerSocket serverSocket = ssf.createServerSocket(12345);
// I've initialised an sslContext with a keystore, as you normally would.
Socket socket = serverSocket.accept();
SSLSocketFactory sslSf = sslContext.getSocketFactory();
// The host name doesn't really matter, since we're turning it into a server socket
// (No need to match the host name to the certificate on this side).
SSLSocket sslSocket = (SSLSocket) sslSf.createSocket(socket, null,
socket.getPort(), false);
sslSocket.setUseClientMode(false);
// Use the sslSocket InputStream/OutputStream as usual.
SSLSocketFactory.createSocket(Socket, ...)
will by default convert the existing Socket
into a client-mode SSLSocket
. Since the handshake only starts when you start reading/writing with the I/O streams, it's still time to change the mode using setUseClientMode(false)
.
Regarding the rest of the question:
What I want to know is that it is possible that:
- If the client send a http request, the server handle the request directly,
- If the client send a https request, the server change client socket to SSLSocket?
Again, yes, it's possible. It's sometimes referred to as "port unification" and it's implemented in Grizzly and thus Glassfish.
It works because both HTTP and TLS (upon which HTTPS works) are protocols where the client is expected to talk first. Therefore, the server can detect whether what the client initially sends is a TLS ClientHello
message (in which case it should try to proceed with the TLS handshake) or a plain HTTP request (e.g. GET / HTTP/1.1
...).
I suspect port unification is "easier" to do using SSLEngine
, otherwise, it might be hard to implement a read-ahead on a plain socket, which you would still be able to convert via SSLSocketFactory.createSocket(Socket, ...)
.
Note that this is still rather unusual, though.
It is not possible to serve both http and https on the same port. However, it should in theory be possible to upgrade an existing http connection to use TLS if both the client and server supports it, see RFC 2817. The SSLSocketFactory class has a createSocket() function which can be used to upgrade an existing socket to SSL/TLS.
Disclaimer: I have not attempted to do this, and implementing RFC 2817 is likely non-trivial.
Edit: Apparently I was wrong, like Bruno wrote it is possible to serve http and https on the same port using a technology called port unification, which uses the first few bytes received to detect the protocol. There is an example of this included with the Netty (JBoss) framework.
The Socket/SSLSocket interface does not allow convenient content-recognition here - when you start reading from a socket and see that it is only garbage (not plain HTTP), you can't supply this data to a new SSLSocket wrapped around a normal one.
You could use a Socket (or SocketChannel) and look at the data, and then (if it is not the start of a plain HTTP request) pass the same data to an SSLEngine object for decryption/encryption. This means that you have to handle all the encryption/decryption calls yourself, which is not totally trivial (at least, it is a lot more complicated than simply using an SSLSocket with it's two streams - I did it once).
Of course, if you do this, you would likely better implement the RFC 2817 interface, instead of trying automated content sniffing.
I think it's no on both counts, based on what you've posted.
- If the listener on the
ServerSocket
is not interpreting the request as HTTP, then there's no magic that will make it so. - If the listener on the
ServerSocket
is not decrypting the encrypted request, then there's no magic that will make it so.
Did you write the code that's listening on the ServerSocket
? If yes, you can answer your own question by looking at your code.
Did someone else write the code that's listening on the ServerSocket
? If yes, you'll have to ask them. Were you given any information about the expected protocol?
精彩评论