Request for review: 8144093: JEP 244/8051498 - TLS Application-Layer Protocol Negotiation Extension
Bradford Wetmore
bradford.wetmore at oracle.com
Wed Dec 2 00:04:41 UTC 2015
> I just would like to remind that session resumption is a very
> important use case to support for ALPN.
Understood. The ALPN value is tied to a handshake, either already
completed and active (getApplicationProtocol()) or still in progress
(getHandshakeApplicationProtocol()). Each handshake results in a
complete ALPN negotiation. So a session resumption will always do a
ALPN negotiation from scratch.
> I have not seen anything related to this review for session resumption.
> Has it been tested ?
The current unit tests don't have resumption, but there should be a RFE
(if not already) for resumption testing along with some other cases.
Vinnie is working on these.
> It is still not clear to me what a client and a server have to do to
> support ALPN.
If you want to use the default behavior (server-prioritized list looking
for a common element), just call SSLParameters.setApplicationProtocols()
on both sides.
If you want to do very specific protocol/ciphersuite/alpn configuration
before handshaking, then do the configuration before starting the
handshake (more details and similar to what you suggested below). This
is what was decided back in October when we pulled out the Matcher
mechanism in v6/v7. [1]
> From my understanding a server has to:
>
> * read encrypted bytes into a ByteBuffer
BTW, during the initial handshake on a connection, these are not encrypted.
> * parse the TLS ClientHello frame on its own
> * extract from the ClientHello the TLS Protocol version, the ALPN
> extension, and the ciphers
> * run some logic to determine the AP
> ** if no AP can be chosen, generate a TLS Alert frame on its own to
> close the connection and bail out
I would create a regular SSLContext/SSLEngine/configureALPN and start
the handshake as usual. The JSSE implementation will create the TLS
ALPN Alert when it realizes it doesn't have any ALPN values in common.
The server then should obtain those bytes from the wrap() and send to
the peer, as usual.
> * otherwise, an AP/cipher combo has been chosen
Filling in a few more details:
SSLContext.getInstance("protocol"); // returns a context with
// "protocol" and possibly
// other protocols enabled.
SSLEngine ssle = SSLContext.createSSLEngine(...);
Read ClientHello from Socket/SocketChannel/AsynchronousSocketChannel/etc.
Parse ClientHello for requested protocol/alpn/ciphersuites
choose protocol/alpn/ciphersuite value(s)
SSLParameters sslParameters = ssle.getSSLParameters();
sslParameters.setProtocols(protocols); // possibly just one
// You could use some non-matching value like
// "no_application_protocol" if you want to generate the
// no_application_protocol alert.
sslParameters.setApplicationProtocols(APs); // possibly just one
sslParameters.setCipherSuites(ciphers) // possibly just one
sslEngine.setSSLParameters(sslParameters)
reset the ByteBuffer position to the beginning
sslEngine.unwrap()
JDK implementation will re-parse the ClientHello, and use the
sslParameters data during handshake and when generating the
ServerHello. Any error alerts will be output by the SSLEngine as usual.
sslEngine.wrap()/unwrap() as usual.
> A client has to:
>
> * read encrypted bytes into a ByteBuffer
> * parse a ServerHello frame on its own
> * extract the ALPN extension and the cipher
You could parse this if you want, but wasn't expecting client apps
would. See below.
> * run some logic to verify that the AP and the cipher can be used together
> ** if AP and cipher don't match, generate a TLS Alert frame on its own
> to close the connection and bail out.
There is nothing in the ALPN RFC about this situation. In the HTTP
spec, if such a situation is negotiated, the application layer waits for
the handshake completion, examines the state, sends a HTTP2 connection
error of type INADEQUATE_SECURITY, then closes.
BTW, we would lose the ability to parse plaintext ServerHellos in
TLSv1.3, as ServerHello is now encrypted.
> * otherwise the AP/cipher combo is ok
> * reset the ByteBuffer position to the beginning
> * pass the ByteBuffer to sslEngine.unwrap()
> * JDK implementation will re-parse the ServerHello and complete the
> TLS handshake
>
> Is that right ?
If you really want to parse it, yes.
> In that scenario, what is the use of
> SSLEngine.getHandshakeApplicationProtocol() ?
When either side needs to determine the selected ALPN value before the
completion of the handshake, say during X509KeyManager selection or
X509TrustManager verification. On the server side, let's say we have
two possible keys/certs, and we receive a ClientHello.
ClientHello ->
JSSE chooses protocol/ALPN
JSSE iterates on ciphersuite
iter calls X509KeyManager to find a key
X509KM calls setHandshakeApplicationProtocol()
to see which protocol/ALPN value was negotiated,
uses that for selecting which key to use.
<- ServerHello
> Also, I don't understand how the above could work for SSLSocket ?
> Can someone write down the steps a client and a server should do to
> actually use ALPN with SSLSocket ?
Server
======
Filing in a few more extra details so it's hopefully clear.
Open a plaintext ServerSocket
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
byte[] ba = is.readFully();
// extract from the ClientHello the TLS Protocol version, the ALPN
// extension, and the ciphers
parseTLSClientHello(ba);
determineProtocolALPNCiphersuites();
SSLContext ctx = \
SSLContext.getInstance("protocol") // returns a context with
// "protocol" and possibly
// other protocols enabled.
SSLParameters sslParameters = ctx.getDefaultSSLParameters();
SSLParameters sslParameters =
sslParameters.setProtocols(protocol);
sslParameters.setApplicationProtocols(AP) // just one protocol
sslParameters.setCipherSuites(cipher) // just one cipher
// Overlay the partially consumed InputStream
ByteArrayInputStream bais = new ByteArrayInputStream(ba);
SSLSocket sslSocket = \
ctx.createSocketFactory(...).createSocket(socket, bais, ...);
sslSocket.setSSLParameters(sslParameters)
sslSocket.startHandshake();
Brad
[1]
http://mail.openjdk.java.net/pipermail/security-dev/2015-October/012912.html
More information about the security-dev
mailing list