Re: TLS ALPN Proposal v7
On Sat, Oct 3, 2015 at 2:19 AM, Bradford Wetmore wrote: Thanks for the comments everyone. I'm submitting the following to the CCC (internal review board): http://cr.openjdk.java.net/~wetmore/8051498/webrev.17/ Changes: 1. No H2 Blacklist/Comparator 2. set/getApplicationProtocols() back to SSLParameters. Have you implemented this solution already ? It is underway. The guts was already done based on previous API versions. The new API is less involved, so it should be simpler to do as it's just cutting out the existing ciphersuite/ALPN selection stuff. Also for clients ? Client/server are both externally(API)/internally essentially the same. The big difference is that for clients you send all the values passed in, for servers you only consult the first which is the selected ALPN value. Do you have feedback on actually implementing ALPN in this way ? Based on what I saw previously, it should be pretty straighforward. Brad
Re: TLS ALPN Proposal v7
Bradford, On Sat, Oct 3, 2015 at 2:19 AM, Bradford Wetmore wrote: > Thanks for the comments everyone. I'm submitting the following to the CCC > (internal review board): > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.17/ > > Changes: > > 1. No H2 Blacklist/Comparator > > 2. set/getApplicationProtocols() back to SSLParameters. Have you implemented this solution already ? Also for clients ? Do you have feedback on actually implementing ALPN in this way ? -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v7
I didn't reply on this last week, but this looks workable to me. Thanks! On 10/02/2015 07:19 PM, Bradford Wetmore wrote: On 10/1/2015 7:35 PM, Xuelei Fan wrote: On 10/2/2015 9:03 AM, Bradford Wetmore wrote: Major changes: 1. ApplicationProtocols is gone. The H2 black list and comparator were moved to StandardConstants. 2. StandardConstants. Strings for "h2" and "http/1.1" are back. And now that you are parsing the raw network bytes, I added a convenience mapping between the two byte ciphersuite IANA-assigned value and the Java Standard Name. There is no SSLExplorer in OpenJDK. I think, maybe, the map is not belong to OpenJDK either. I think, the constants for HTTP2 is also belong to application protocol (HTTP2) layer. Application (HTTP2) implementation would take care of them. Maybe, they are not a part of JSSE framework either. Ok, I've removed all of the H2 constants from StandardConstants. I've mentioned to the the H2/network team that this is something they will need to handle/include (e.g. Blacklist/Comparator) in their code, and they might want to consider APIs similar to what I had. I personally found it very useful to have a proper mapping to get the SSL_ vs. TLS_ prefix correct in the blacklist. I would like to have "h2" and "http/1.1" defined as Standard Algorithms Docs as we usually did for other standard constants. Of course, they will be added as Standard Algorithm names. 3. SSLParameter (set/get) are moved to SSLSocket/SSLEngine. Even though these could go into SSLParameters, this change makes backporting much easier. The helper code simply has to reflectively look for the four methods in the implementation classes, and call if they are there. Otherwise, there would have to be reflection both in the user code (above) and implementation (to see if the passed SSLParameters had the new methods via a subclass). But, looking forward, per JSSE framework, SSLParameters should be the central place to define SSL/TLS configuration parameters. We'd better follow the conventions so that application developers won't get confused about where SSL/TLS parameters should be configured. I went back and forth on this many, many times yesterday. Maybe, we cannot add public APIs for backporting. I figured we'd have to use reflection on user-derived classes to see if the methods were there, but apparently implementation-specifc APIs can be added in an update release, just not Java APIs. So if we really can do that, then we can add a jdk.SSLParameters/ org.openjdk.jsse.SSLParameters extends SSLParameters, and in the implementation, look for instanceof. I think backporting is another history, and would better not impact too much of the design for JDK 9 and future releases. Ok, so get/setApplicationProtocols() is back in SSLParameters. Thanks for the comments everyone. I'm submitting the following to the CCC (internal review board): http://cr.openjdk.java.net/~wetmore/8051498/webrev.17/ Changes: 1. No H2 Blacklist/Comparator 2. set/getApplicationProtocols() back to SSLParameters. Thanks, Brad -- - DML
Re: TLS ALPN Proposal v7
Thanks! Xuelei On 10/3/2015 8:19 AM, Bradford Wetmore wrote: > > > On 10/1/2015 7:35 PM, Xuelei Fan wrote: >> On 10/2/2015 9:03 AM, Bradford Wetmore wrote: >>> Major changes: >>> >>> 1. ApplicationProtocols is gone. The H2 black list and comparator were >>> moved to StandardConstants. >>> >>> 2. StandardConstants. Strings for "h2" and "http/1.1" are back. And >>> now that you are parsing the raw network bytes, I added a convenience >>> mapping between the two byte ciphersuite IANA-assigned value and the >>> Java Standard Name. >>> >> There is no SSLExplorer in OpenJDK. I think, maybe, the map is not >> belong to OpenJDK either. >> >> I think, the constants for HTTP2 is also belong to application protocol >> (HTTP2) layer. Application (HTTP2) implementation would take care of >> them. Maybe, they are not a part of JSSE framework either. > > Ok, I've removed all of the H2 constants from StandardConstants. I've > mentioned to the the H2/network team that this is something they will > need to handle/include (e.g. Blacklist/Comparator) in their code, and > they might want to consider APIs similar to what I had. > > I personally found it very useful to have a proper mapping to get the > SSL_ vs. TLS_ prefix correct in the blacklist. > >> I would like to have "h2" and "http/1.1" defined as Standard Algorithms >> Docs as we usually did for other standard constants. > > Of course, they will be added as Standard Algorithm names. > >>> 3. SSLParameter (set/get) are moved to SSLSocket/SSLEngine. Even >>> though these could go into SSLParameters, this change makes backporting >>> much easier. The helper code simply has to reflectively look for the >>> four methods in the implementation classes, and call if they are there. >>> >>> Otherwise, there would have to be reflection both in the user code >>> (above) and implementation (to see if the passed SSLParameters had the >>> new methods via a subclass). >> But, looking forward, per JSSE framework, SSLParameters should be the >> central place to define SSL/TLS configuration parameters. We'd better >> follow the conventions so that application developers won't get confused >> about where SSL/TLS parameters should be configured. > > I went back and forth on this many, many times yesterday. > >> Maybe, we cannot add public APIs for backporting. > > I figured we'd have to use reflection on user-derived classes to see if > the methods were there, but apparently implementation-specifc APIs can > be added in an update release, just not Java APIs. So if we really can > do that, then we can add a jdk.SSLParameters/ > org.openjdk.jsse.SSLParameters extends SSLParameters, and in the > implementation, look for instanceof. > >> I think backporting is >> another history, and would better not impact too much of the design for >> JDK 9 and future releases. > > Ok, so get/setApplicationProtocols() is back in SSLParameters. > > Thanks for the comments everyone. I'm submitting the following to the > CCC (internal review board): > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.17/ > > Changes: > > 1. No H2 Blacklist/Comparator > > 2. set/getApplicationProtocols() back to SSLParameters. > > Thanks, > > Brad >
TLS ALPN Proposal v7
On 10/1/2015 7:35 PM, Xuelei Fan wrote: On 10/2/2015 9:03 AM, Bradford Wetmore wrote: Major changes: 1. ApplicationProtocols is gone. The H2 black list and comparator were moved to StandardConstants. 2. StandardConstants. Strings for "h2" and "http/1.1" are back. And now that you are parsing the raw network bytes, I added a convenience mapping between the two byte ciphersuite IANA-assigned value and the Java Standard Name. There is no SSLExplorer in OpenJDK. I think, maybe, the map is not belong to OpenJDK either. I think, the constants for HTTP2 is also belong to application protocol (HTTP2) layer. Application (HTTP2) implementation would take care of them. Maybe, they are not a part of JSSE framework either. Ok, I've removed all of the H2 constants from StandardConstants. I've mentioned to the the H2/network team that this is something they will need to handle/include (e.g. Blacklist/Comparator) in their code, and they might want to consider APIs similar to what I had. I personally found it very useful to have a proper mapping to get the SSL_ vs. TLS_ prefix correct in the blacklist. I would like to have "h2" and "http/1.1" defined as Standard Algorithms Docs as we usually did for other standard constants. Of course, they will be added as Standard Algorithm names. 3. SSLParameter (set/get) are moved to SSLSocket/SSLEngine. Even though these could go into SSLParameters, this change makes backporting much easier. The helper code simply has to reflectively look for the four methods in the implementation classes, and call if they are there. Otherwise, there would have to be reflection both in the user code (above) and implementation (to see if the passed SSLParameters had the new methods via a subclass). But, looking forward, per JSSE framework, SSLParameters should be the central place to define SSL/TLS configuration parameters. We'd better follow the conventions so that application developers won't get confused about where SSL/TLS parameters should be configured. I went back and forth on this many, many times yesterday. Maybe, we cannot add public APIs for backporting. I figured we'd have to use reflection on user-derived classes to see if the methods were there, but apparently implementation-specifc APIs can be added in an update release, just not Java APIs. So if we really can do that, then we can add a jdk.SSLParameters/ org.openjdk.jsse.SSLParameters extends SSLParameters, and in the implementation, look for instanceof. > I think backporting is another history, and would better not impact too much of the design for JDK 9 and future releases. Ok, so get/setApplicationProtocols() is back in SSLParameters. Thanks for the comments everyone. I'm submitting the following to the CCC (internal review board): http://cr.openjdk.java.net/~wetmore/8051498/webrev.17/ Changes: 1. No H2 Blacklist/Comparator 2. set/getApplicationProtocols() back to SSLParameters. Thanks, Brad
Re: TLS ALPN Proposal v6
On 10/2/2015 9:03 AM, Bradford Wetmore wrote: > Major changes: > > 1. ApplicationProtocols is gone. The H2 black list and comparator were > moved to StandardConstants. > > 2. StandardConstants. Strings for "h2" and "http/1.1" are back. And > now that you are parsing the raw network bytes, I added a convenience > mapping between the two byte ciphersuite IANA-assigned value and the > Java Standard Name. > There is no SSLExplorer in OpenJDK. I think, maybe, the map is not belong to OpenJDK either. I think, the constants for HTTP2 is also belong to application protocol (HTTP2) layer. Application (HTTP2) implementation would take care of them. Maybe, they are not a part of JSSE framework either. I would like to have "h2" and "http/1.1" defined as Standard Algorithms Docs as we usually did for other standard constants. > 3. SSLParameter (set/get) are moved to SSLSocket/SSLEngine. Even > though these could go into SSLParameters, this change makes backporting > much easier. The helper code simply has to reflectively look for the > four methods in the implementation classes, and call if they are there. > > Otherwise, there would have to be reflection both in the user code > (above) and implementation (to see if the passed SSLParameters had the > new methods via a subclass). But, looking forward, per JSSE framework, SSLParameters should be the central place to define SSL/TLS configuration parameters. We'd better follow the conventions so that application developers won't get confused about where SSL/TLS parameters should be configured. Maybe, we cannot add public APIs for backporting. I think backporting is another history, and would better not impact too much of the design for JDK 9 and future releases. Hope it helps! Xuelei
TLS ALPN Proposal v6
You guys (David/Simone/Bernd/Jason) are more on the front lines in server development and how functional this API will be, so I'll trust your judgement here. If you are ok with: 1. potentially being blind during renegotiations in the existing TLSv1/v1.1/v1.2, and, 2. not having an SSLExplorer as part of the JDK (i.e. you parsing the ClientHellos ala SSLExplorer), 3. requiring all ALPN logic be in the application and none in the JDK, I'm willing to go with this approach. It doesn't seem optimal for what I would call casual users, but it does solve the ugly issues with the matches() API. (BTW, I did consider adding a ClientHelloCallback/ClientHello/ServerHelloCallback/ServerHello class that would handle callbacks, but that was getting complicated also.) For current renegotiations, the big use case is adding client authentication, so it seems likely that the same ciphersuite will be offered/chosen, so it's likely moot. For the existing URL code, do you think we need: 1. to provide a "https.alpn" System Property for the existing URLConnections? 2. a getApplicationProtocol() for HttpsURLConnection? Michael (net-dev) says H2 will not be backported into the URL mechanism and doesn't see a need for it yet, so I'm inclined to say no. More inline: On 9/29/2015 8:07 AM, David M. Lloyd wrote: Hi Brad, thanks for replying; comments are inline: On 09/28/2015 08:40 PM, Bradford Wetmore wrote: 1. Only the initial ClientHellos are parsable. === The biggest problem I have with an Explorer-based design is that only the initial ClientHello on a connection is passed in the clear. Subsequent negotiations on this connection will be completely missed, as the ClientHellos are now encrypted. This seems like a deal breaker for me. You are right, I cannot come up with a good solution for this, so that might mean the idea is shot - *however* - I would point out that the latest draft of TLS 1.3 [1] completely kills off the capability of the client to renegotiate a connection, meaning that this will no longer be possible anyway, and given it's a 1% kind of use case, that might be enough to let it slide. Combine this with what I consider to be the unlikelihood of this working with HTTP/2.0, and I would feel very safe assuming that nobody will ever actually do this. Thanks for pointing this out, I thought PSK+tickets were a replacement for a renegotiation (Section 6.2.3), but it's apparently only for session resumption. BTW, the WG is up to a Sept 29, 2015 version (draft-09). [1] https://tlswg.github.io/tls13-spec/ I would also note that, as you state later on, it would be possible to combine this solution with any other solution (including the proposed one) to cover both cases. And given that this is still (in my estimation) a "99%" solution, in my opinion it is still a viable candidate for adding this functionality to Java 8 as a first pass or stopgap as I described in my emails, particularly if the method(s) to establish/query the protocol names are a strict subset of the proposed Java 9 API (given that we cannot really overhaul the Java SE 8 API at this point). [...] 2. "SSLExplorer" or something similar is needed. = This approach depends on "examining SSLClientHello"s, but there isn't a class for this other than some sample code from a previous attempt. I am assuming that this approach would make such an external API a necessity? Being able to parse possible ClientHello formats is not a straightforward/easy job. This will add a fair amount of complexity, and likely not an easy job in the remaining few weeks. It could be added later for JDK 10 but that means apps would likely need to roll their own for 9. And 8, yes, you definitely would need to roll your own, though Xuelei Fan already has a nice example up on his blog that was built for SNI (but uses the same principle). If you are referring to: http://simsmi.blogspot.com/2014/01/jep-114-tls-sni-extension-virtual.html This is just describing the general approach for the sample SSLExplorer/SSLCapabilities code in the JSSE Reference Guide. The actual code can be found here: http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#CodeExamples My hope is to expand it to include parsing the ciphersuites and ALPN extensions. I've moved/added some helper functions from ApplicationProtocol to StandardConstants. If it were me, I wouldn't even bother adding it even in JDK 10, since (a) it applies only to the server side and (b) there are a plethora of third-party server-side network I/O and security libraries which are natural candidates to host this type of logic. Ok. 3. "no_application_protocol" = If the server doesn't support the protocols that the client advertises, the "no_application_protocol" must be thrown. We could add a "no_application_protocol" p
Re: TLS ALPN Proposal v5
Hi Brad, thanks for replying; comments are inline: On 09/28/2015 08:40 PM, Bradford Wetmore wrote: Several comments about David's proposal: 1. Only the initial ClientHellos are parsable. === The biggest problem I have with an Explorer-based design is that only the initial ClientHello on a connection is passed in the clear. Subsequent negotiations on this connection will be completely missed, as the ClientHellos are now encrypted. This seems like a deal breaker for me. You are right, I cannot come up with a good solution for this, so that might mean the idea is shot - *however* - I would point out that the latest draft of TLS 1.3 [1] completely kills off the capability of the client to renegotiate a connection, meaning that this will no longer be possible anyway, and given it's a 1% kind of use case, that might be enough to let it slide. Combine this with what I consider to be the unlikelihood of this working with HTTP/2.0, and I would feel very safe assuming that nobody will ever actually do this. I would also note that, as you state later on, it would be possible to combine this solution with any other solution (including the proposed one) to cover both cases. And given that this is still (in my estimation) a "99%" solution, in my opinion it is still a viable candidate for adding this functionality to Java 8 as a first pass or stopgap as I described in my emails, particularly if the method(s) to establish/query the protocol names are a strict subset of the proposed Java 9 API (given that we cannot really overhaul the Java SE 8 API at this point). [...] 2. "SSLExplorer" or something similar is needed. = This approach depends on "examining SSLClientHello"s, but there isn't a class for this other than some sample code from a previous attempt. I am assuming that this approach would make such an external API a necessity? Being able to parse possible ClientHello formats is not a straightforward/easy job. This will add a fair amount of complexity, and likely not an easy job in the remaining few weeks. It could be added later for JDK 10 but that means apps would likely need to roll their own for 9. And 8, yes, you definitely would need to roll your own, though Xuelei Fan already has a nice example up on his blog that was built for SNI (but uses the same principle). If it were me, I wouldn't even bother adding it even in JDK 10, since (a) it applies only to the server side and (b) there are a plethora of third-party server-side network I/O and security libraries which are natural candidates to host this type of logic. 3. "no_application_protocol" = If the server doesn't support the protocols that the client advertises, the "no_application_protocol" must be thrown. We could add a "no_application_protocol" protocol String that would flag such a condition internally. Sure, though if you use the same method on both the client and server to specify the matched protocol, then the method necessarily accepts an array, in which case a null/unset could mean "no ALPN response" and an empty array could mean "no acceptable protocols". But yeah I agree otherwise. 4. Much of this is already possible. = If we were to go with the current API/internal and apps provided their own ClientHello scanner, many of the benefits of what was proposed are already available. Apps can ask for the desired SSLContext, get the SSLSocket/SSLengine, check the SNI/ALPN values, order/set the enabled protocols/ciphers/etc + single ALPN value, then wrap the raw socket using SSLSocketFactory.createSocket(Socket s, InputStream consumed, boolean autoClose), and start the handshake. The internal code would still call matches() but only once. If you want to be sure the internals select the ApplicationProtocol, just put in a permissive ApplicationProtocol. The API is still more complicated unfortunately as ApplicationProtocol is still present, but the overall behavior is quite similar. +1 yep exactly. I would however turn it around and also say, a more complex API could later be added on top of this simpler proposed solution, especially after more real world data is acquired, which might lower the overall risk as well. 5. Other failure mode/fallback. In the new proposal, suppose you do set a single ALPN value in the application level, and the ServerHandshaker finds some other aspect of the handshake wasn't appropriate (creds were mentioned several times, but maybe a ciphersuite went dark due to new AlgorithmConstraints). This would cause the ServerHandshaker to fail and there's no way to go back to a different version unless you add a "for ALPN" loop into application. Yeah all that validation would have to be done up front or manually in whatever server configuration is relevant. If a cipher suit
Re: TLS ALPN Proposal v5
Several comments about David's proposal: 1. Only the initial ClientHellos are parsable. === The biggest problem I have with an Explorer-based design is that only the initial ClientHello on a connection is passed in the clear. Subsequent negotiations on this connection will be completely missed, as the ClientHellos are now encrypted. This seems like a deal breaker for me. Also, and this is moot if the ClientHellos are encrypted, unless you wrap the underlying raw socket in your own "observer" socket wrapper, you won't be able to view the raw data once the SSLSocket starts processing. SSLEngine doesn't have this problem since it's just ByteBuffers. One other comments while on the topic of renegotiations/resumptions as there were some incorrect statements in previous emails. H2 (RFC 7540-Sec 9.2.1) allows for renegotiations/resumptions to occur before the initial connection preface to protect *CLIENT CREDENTIALS* only, but prohibits it once data has started passing. But there is no such restriction on HTTP/1.1, nor on ALPN in general. So in such a case, there's no way you can change it with this proposal, and the ALPN RFC specifically allows for it. 2. "SSLExplorer" or something similar is needed. = This approach depends on "examining SSLClientHello"s, but there isn't a class for this other than some sample code from a previous attempt. I am assuming that this approach would make such an external API a necessity? Being able to parse possible ClientHello formats is not a straightforward/easy job. This will add a fair amount of complexity, and likely not an easy job in the remaining few weeks. It could be added later for JDK 10 but that means apps would likely need to roll their own for 9. 3. "no_application_protocol" = If the server doesn't support the protocols that the client advertises, the "no_application_protocol" must be thrown. We could add a "no_application_protocol" protocol String that would flag such a condition internally. 4. Much of this is already possible. = If we were to go with the current API/internal and apps provided their own ClientHello scanner, many of the benefits of what was proposed are already available. Apps can ask for the desired SSLContext, get the SSLSocket/SSLengine, check the SNI/ALPN values, order/set the enabled protocols/ciphers/etc + single ALPN value, then wrap the raw socket using SSLSocketFactory.createSocket(Socket s, InputStream consumed, boolean autoClose), and start the handshake. The internal code would still call matches() but only once. If you want to be sure the internals select the ApplicationProtocol, just put in a permissive ApplicationProtocol. The API is still more complicated unfortunately as ApplicationProtocol is still present, but the overall behavior is quite similar. 5. Other failure mode/fallback. In the new proposal, suppose you do set a single ALPN value in the application level, and the ServerHandshaker finds some other aspect of the handshake wasn't appropriate (creds were mentioned several times, but maybe a ciphersuite went dark due to new AlgorithmConstraints). This would cause the ServerHandshaker to fail and there's no way to go back to a different version unless you add a "for ALPN" loop into application. 6. "Only one new method on SSLSocket/SSLEngine to set the protocol list (client) or selected single protocol (server)" == I think you would need two, "use this value on the next handshake" and "this was last negotiated/currently in effect." One other comment: Simone wrote: > I don't know if all the blacklisted ciphers are actually lower > strength of all the remaining ciphers, Mainly it's about removing support for various algorithms. e.g. static RSA/DH Key Exchange, DSA (draft-09), non-AEAD ciphers, customer DHE groups. https://tlswg.github.io/tls13-spec/#rfc.section.1.2 Unfortunately, this is a big change in direction and is coming very late. I'm getting very significant pushback and schedule pressure from management now, so without an "Aha" moment, we may not be able to go this route. Thanks, Brad On 9/28/2015 11:06 AM, Jason Greene wrote: On Sep 25, 2015, at 3:22 PM, David M. Lloyd wrote: On 09/25/2015 02:11 PM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 7:23 PM, David M. Lloyd wrote: The application protocol implementation chooses only valid cipher suites for the protocol. Why would it choose one that is not valid, considering that the protocol implementation itself is the only thing that "knows" what is valid or not? The cipher could fail for the number of reasons it fails in trySetCipherSuite(), even if the application has chosen the right combination of (applica
Re: TLS ALPN Proposal v5
> On Sep 25, 2015, at 3:22 PM, David M. Lloyd wrote: > > On 09/25/2015 02:11 PM, Simone Bordet wrote: >> Hi, >> >> On Fri, Sep 25, 2015 at 7:23 PM, David M. Lloyd >> wrote: >>> The application protocol implementation chooses only valid cipher suites for >>> the protocol. Why would it choose one that is not valid, considering that >>> the protocol implementation itself is the only thing that "knows" what is >>> valid or not? >> >> The cipher could fail for the number of reasons it fails in >> trySetCipherSuite(), even if the application has chosen the right >> combination of (application protocol, cipher, whatever else). >> At that point you have to try another application protocol. > > From my reading of that code, it can only fail if you specifically set up > invalid combinations of cipher suite, protocol, and credentials. The > application code should have all the information it needs to set up a correct > configuration though. One example approach for a server-side H1 fallback scenario can be achieved using this approach, is to take the desired enabled portion of the supported cipher suite list for TLS 1.2+ (e.g. getSupportedCipherSuites, getSupportedSSLParameters, etc), which in simple scenarios is just the default suites (e.g. getDefaultSSLParameters, etc). Remove the H2 black-list from that and you have the h2 possible cipher-suite list. This list can then be further paired down based on key material (e.g disable ECDSA ciphers if only an RSA cert is present in the keystore). Finally the cipher list in client hello can be compared to find a possible intersection. If there is no intersection then use h1, otherwise configure h2. One additional topic that I see came up on this list is the notion that cipher suite selection using ALPN is a temporary use-case, since H2 loses this problem with TLS 1.3. I think this viewpoint is too limiting. Fundamentally, the key use case that ALPN is achieving, is multiplexing two TLS ports over one. Any TLS policy that was required for a single protocol over a single port is likely to still be needed in a mixed protocol setup. Once you have non-overlapping policies then you need the ability to have logic which is distinguished by ALPN. We shouldn’t just look at H2 here, but think of it more generically. Absent a non-limited TLS stack that does all the heavy lifting, deferring to the application is the next best thing. In some ways it can actually be better, since the portion of the logic on top of the JVM can evolve independently and more expediently than SE schedule allows. I also like David’s point that a simple solution is easier to backport to SE8, which is very important since EE8 is planned to require http2 and SE8 support. -- Jason T. Greene WildFly Lead / JBoss EAP Platform Architect JBoss, a division of Red Hat
Re: TLS ALPN Proposal v5
It is obvious, but I thought I might mention it: it does absolutely not help the user if a server refuses to negotiate a "MAY not use" cipher only to fallback to http/1.1 with exactly that cipher. I can see the motivation for deprecating those ciphers in modern servers (although I am note sure why CBC with TLS 1.2 is such a biggie), but then you must stick to the decision and not fall back and use them anyway. Feels much like overstepping a border in protocol design which causes a lot of interop problems and API grief. Given that it might be a good idea to not do anything special in JSSE and give the client and server developers full control over the use of ciphers. Gruss Bernd -- http://bernd.eckenfels.net -Original Message- From: Xuelei Fan To: "David M. Lloyd" , Simone Bordet Cc: OpenJDK , "net-...@openjdk.java.net >> OpenJDK Network Dev list" Sent: Sa., 26 Sep. 2015 3:19 Subject: Re: TLS ALPN Proposal v5 I would second David's proposal based on the #1/#A ideas. Here are some background and options. 1. a HTTP2 server should support HTTP2 If a HTTP2 server declare to support HTTP2, it should support HTTP2 protocol. What happens if corner cases happen that the security is not sufficient (client requested cipher suites are all blacklisted)? Two approaches, refuse the connection or complete the connection. It is easy to understand if refusing the connection for corner cases. But why complete the connection with insufficient cipher suite? It's because for HTTP2, the client side need to check the security strength outside of SSL/TLS layer in case the SSL/TLS server uses insufficient security parameters. If the security is insufficient, the client side can request abbreviate handshaking (Section 3.1, RFC 7301) for a low level application protocols (application protocol downgrade), or close the connection. Here is the scenarios: A.1. client requests {HTTP2, HTTP1.1) A.2. server negotiates HTTP2 and HTTP2 blacklisted cipher suite. A.3. client checks the security sufficiency. The negotiated cipher suite is insufficient. A.4. client requests an abbreviated handshaking for {HTTP 1.1} A.5. server negotiates HTTP1.1 A.6. client checks the security sufficiency. The negotiated cipher suite is sufficient for HTTP 1.1. There are might be one question? Should client check the security sufficiency even if OpenJDK can do it pretty well. I would think client need to do so because the client may also want to connect to other TLS vendors, known or unknown. Client need to make sure the negotiated TLS strength is sufficient for the specified application protocol. If the story happens in this way, everything get more simple. 2. a HTTP2 server should support both HTTP2 and HTTP1.1 If an HTTP2 server support both HTTP2 and HTTP1.1, AND it is expected to do HTTP protocol version negotiated by itself internally (fail-over to HTTP 1.1) (I did not find the spec in HTTP2 RFC, but HTTP experts said a server may support both HTTP2 and HTTP1.1), what happens if corner cases happen that the security is not sufficient for HTTP 2? Three approaches: refuse the connection, complete the connection with HTTP2, fail-over to HTTP1.1 in server side. The first two approaches are the same as #1. For the 3rd approach, the server implementation and APIs design get much more complicated. For the 2nd approach, the scenarios is similar to #1.1. The server implementation part may looks like: B.1. receive a ClientHello message. B.2. negotiate the TLS protocol version, independently B.3. negotiate the TLS cipher suite, independently B.4. negotiate the application protocols, independently B.5. sending the ServerHello message. For the 3rd approach, the server implementation may looks like: C.1. receive a ClientHello message. C.2. negotiate the TLS protocol version, independently, get negotiated_protocol C.3. try to negotiate an TLS cipher suite, candidate_cipher_suite C.4. try to negotiate an application protocol with negotiated_protocol and candidate_cipher_suite. If the application protocol does not work for the TLS protocol and cipher suites, goto #3.3 and try again. Otherwise, move forward. C.5. if application protocol can be negotiated, sending the ServerHello message; otherwise, terminated the connection immediately. For the case above, looks like client may not need to do application protocol renegotiation. But actually, it may be able to avoid the coding job because the client may not know whether the server would behavior like #B, or #C. #1/#A do the application protocol version negotiation in client side, and #2/#C do the application protocol version negotiation in server side. And there is no spec about which behavior should be expected as far as I know. #1/#A is simple and straightforward, and #2/#C makes a smart (and complicated) server. OpenJDK now is trying to support both #1 and #2. Thanks, Xuelei On 9/26/2015 4:22 AM, David M. Lloyd wrote: > On 09/25/20
Re: TLS ALPN Proposal v5
On 9/26/2015 8:47 AM, Bradford Wetmore wrote: >> It might be not customers expected behavior to re-order/sort their >> preference of cipher suites or preference. > > Are we are clear that the intention was never for the JDK to internally > resort the ciphersuites, but rather to provide an external helper > function (H2BLACKLISTCOMPARATOR) with which applications can do their > own sorting and pass the results to setEnabledCiphersuite()? My points: 1. OpenJDK should not do the re-sort internally. The preference decision should be made before the call to setEnabledCiphersuite(). I think Simone agreed with this point. 2. A handy function to resort the cipher suite is useful. But it is out of the scope of ALPN, or even out of the scope of OpenJDK. Application can do whatever resorting, H2BLACKLISTCOMPARATOR does not belong to OpenJDK. Xuelei
Re: TLS ALPN Proposal v5
On 9/26/2015 8:47 AM, Bradford Wetmore wrote: >> {TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384} > > BTW, in case anyone was wondering, both of these suites are on the RFC > 7540 blacklist. Ooops, I meant to use "TLS_ECDHE_" as HTTP2 non-blacklisted cipher suite. Xuelei
Re: TLS ALPN Proposal v5
I would second David's proposal based on the #1/#A ideas. Here are some background and options. 1. a HTTP2 server should support HTTP2 If a HTTP2 server declare to support HTTP2, it should support HTTP2 protocol. What happens if corner cases happen that the security is not sufficient (client requested cipher suites are all blacklisted)? Two approaches, refuse the connection or complete the connection. It is easy to understand if refusing the connection for corner cases. But why complete the connection with insufficient cipher suite? It's because for HTTP2, the client side need to check the security strength outside of SSL/TLS layer in case the SSL/TLS server uses insufficient security parameters. If the security is insufficient, the client side can request abbreviate handshaking (Section 3.1, RFC 7301) for a low level application protocols (application protocol downgrade), or close the connection. Here is the scenarios: A.1. client requests {HTTP2, HTTP1.1) A.2. server negotiates HTTP2 and HTTP2 blacklisted cipher suite. A.3. client checks the security sufficiency. The negotiated cipher suite is insufficient. A.4. client requests an abbreviated handshaking for {HTTP 1.1} A.5. server negotiates HTTP1.1 A.6. client checks the security sufficiency. The negotiated cipher suite is sufficient for HTTP 1.1. There are might be one question? Should client check the security sufficiency even if OpenJDK can do it pretty well. I would think client need to do so because the client may also want to connect to other TLS vendors, known or unknown. Client need to make sure the negotiated TLS strength is sufficient for the specified application protocol. If the story happens in this way, everything get more simple. 2. a HTTP2 server should support both HTTP2 and HTTP1.1 If an HTTP2 server support both HTTP2 and HTTP1.1, AND it is expected to do HTTP protocol version negotiated by itself internally (fail-over to HTTP 1.1) (I did not find the spec in HTTP2 RFC, but HTTP experts said a server may support both HTTP2 and HTTP1.1), what happens if corner cases happen that the security is not sufficient for HTTP 2? Three approaches: refuse the connection, complete the connection with HTTP2, fail-over to HTTP1.1 in server side. The first two approaches are the same as #1. For the 3rd approach, the server implementation and APIs design get much more complicated. For the 2nd approach, the scenarios is similar to #1.1. The server implementation part may looks like: B.1. receive a ClientHello message. B.2. negotiate the TLS protocol version, independently B.3. negotiate the TLS cipher suite, independently B.4. negotiate the application protocols, independently B.5. sending the ServerHello message. For the 3rd approach, the server implementation may looks like: C.1. receive a ClientHello message. C.2. negotiate the TLS protocol version, independently, get negotiated_protocol C.3. try to negotiate an TLS cipher suite, candidate_cipher_suite C.4. try to negotiate an application protocol with negotiated_protocol and candidate_cipher_suite. If the application protocol does not work for the TLS protocol and cipher suites, goto #3.3 and try again. Otherwise, move forward. C.5. if application protocol can be negotiated, sending the ServerHello message; otherwise, terminated the connection immediately. For the case above, looks like client may not need to do application protocol renegotiation. But actually, it may be able to avoid the coding job because the client may not know whether the server would behavior like #B, or #C. #1/#A do the application protocol version negotiation in client side, and #2/#C do the application protocol version negotiation in server side. And there is no spec about which behavior should be expected as far as I know. #1/#A is simple and straightforward, and #2/#C makes a smart (and complicated) server. OpenJDK now is trying to support both #1 and #2. Thanks, Xuelei On 9/26/2015 4:22 AM, David M. Lloyd wrote: > On 09/25/2015 02:11 PM, Simone Bordet wrote: >> Hi, >> >> On Fri, Sep 25, 2015 at 7:23 PM, David M. Lloyd >> wrote: >>> The application protocol implementation chooses only valid cipher >>> suites for >>> the protocol. Why would it choose one that is not valid, considering >>> that >>> the protocol implementation itself is the only thing that "knows" >>> what is >>> valid or not? >> >> The cipher could fail for the number of reasons it fails in >> trySetCipherSuite(), even if the application has chosen the right >> combination of (application protocol, cipher, whatever else). >> At that point you have to try another application protocol. > > From my reading of that code, it can only fail if you specifically set > up invalid combinations of cipher suite, protocol, and credentials. The > application code should have all the information it needs to set up a > correct configuration though. > >>> This validation should have happened before the JDK ever has a chance >>> to be >>> involved. >> >>
Re: TLS ALPN Proposal v5
You guys certainly were prolific in your discussions last night. ;) Many comments to touch on, and I definitely won't have time today to respond to everything. Xuelei wrote: > I don't think we really need to re-order the cipher suites. Simone wrote: > Of course you need to re-order in this case. In an iterative implementation like SunJSSE is currently, if you want to have the preference order of H2/H1, you need to try all of the H2-compatible ciphersuites first. Once you try a non-H2-compatible suite, the H2 matcher will fail, and it will then go to the H1 matcher, which will succeed. This particular situation was discussed in RFC 7540. > It might be not customers expected behavior to re-order/sort their > preference of cipher suites or preference. Are we are clear that the intention was never for the JDK to internally resort the ciphersuites, but rather to provide an external helper function (H2BLACKLISTCOMPARATOR) with which applications can do their own sorting and pass the results to setEnabledCiphersuite()? I think maybe the confusion came from the 3 roles you describe later. > If there are three roles, OpenJDK, application, customers, there are > three result: For JDK developers, the line between application/customer is quite blurry. You/I are concerned about the interface between the OpenJDK and (application+customers). The application folks will mainly be handling the customer configuration. > {TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384} BTW, in case anyone was wondering, both of these suites are on the RFC 7540 blacklist. Simone wrote: > for each cipher > for each application protocol > end > end > > All the rest being equal, ciphers dominate application protocol > selection. Correct. That's the current proposal. It's a chicken/egg problem. The KeyManager is part of the ciphersuite selection mechanims, and should have a proposed ALPN value value to use (ala RFC 7301), but the ALPN mechanism needs to have a ciphersuite in mind for it's calculation. I will think over David's proposal over the weekend. Much of the I/O required is already there using the JDK 1.8 method SSLSocketFactory.createSocket(Socket s, InputStream consumed, boolean autoClose), which was added for this very purpose. There's nothing to do for SSLEngine. Just a bit of history, we did consider a ClientHello parser when working on SNI. I don't remember the details as to why we didn't add it, but the SSLCapabilities/SSLExplorer classes in the JSSE sample code came from that attempt. I have a vague recollection that the API was getting too complicated in the time we had. More next week. Have a good weekend, all. Brad
Re: TLS ALPN Proposal v5
On 09/25/2015 02:11 PM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 7:23 PM, David M. Lloyd wrote: The application protocol implementation chooses only valid cipher suites for the protocol. Why would it choose one that is not valid, considering that the protocol implementation itself is the only thing that "knows" what is valid or not? The cipher could fail for the number of reasons it fails in trySetCipherSuite(), even if the application has chosen the right combination of (application protocol, cipher, whatever else). At that point you have to try another application protocol. From my reading of that code, it can only fail if you specifically set up invalid combinations of cipher suite, protocol, and credentials. The application code should have all the information it needs to set up a correct configuration though. This validation should have happened before the JDK ever has a chance to be involved. See above. Unless it is verified that trySetCipherSuite() cannot *ever* fail after a cipher has been chosen (but then the method should return void), then I don't see how your proposal could work. The method isn't magical; it is just working off of known inputs. If you give inputs that will ultimately result in a correct negotiation (and nothing leads me to believe that there is any reason that the application protocol user cannot do this), then you will get a successful output. On the other hand, if (for example) the user selects a cipher suite that is incompatible with their credentials, or which is incompatible with the protocol which the user *also* selected, I don't see any good reason to give them another chance. In other words, you're assuming that the only way to know if a configuration is correct is to try it, but that just isn't true. Have you written an implementation already ? That would help. No. -- - DML
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 7:23 PM, David M. Lloyd wrote: > The application protocol implementation chooses only valid cipher suites for > the protocol. Why would it choose one that is not valid, considering that > the protocol implementation itself is the only thing that "knows" what is > valid or not? The cipher could fail for the number of reasons it fails in trySetCipherSuite(), even if the application has chosen the right combination of (application protocol, cipher, whatever else). At that point you have to try another application protocol. > This validation should have happened before the JDK ever has a chance to be > involved. See above. Unless it is verified that trySetCipherSuite() cannot *ever* fail after a cipher has been chosen (but then the method should return void), then I don't see how your proposal could work. Have you written an implementation already ? That would help. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
Here are some solid reasons that this is the best possible approach: * It will work for 100% of foreseeable use cases - i.e. there is 0% risk of permanently baking in flawed logic into the API * It is dead simple - only one new method on SSLSocket/SSLEngine to set the protocol list (client) or selected single protocol (server) * Because it is dead simple, it should be very easy to backport to Java 8 *Example 1*: Add a static org.openjdk.jsse.ALPN#setApplicationProtocol(SSLEngine | SSLSocket s, String[] protocols) method, which calls (maybe even reflectively?) the setApplicationProtocol() method on the SSLEngine/SSLSocket implementation if it is present & public *Example 2*: Add an org.openjdk.jsse.ALPNAware interface with the setApplicationProtocol(String[]) method, which is implemented by JSSE providers * Now Java EE 8 can trivially achieve HTTP/2.0 support with very low risk to either the JDK/SE timeline or the EE timeline * Since most or all of the "hard" logic is on the server side, the majority of API consumers will have an easy time using the API * We server developers can handle the rest! On 09/25/2015 12:23 PM, David M. Lloyd wrote: On 09/25/2015 12:13 PM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 6:49 PM, David M. Lloyd wrote: A: receive raw SSL packet on Socket or SocketChannel A: examine SSL ClientHello, extract SNI, ALPN, cipher suite info This requires the application to write a TLS parser. This is currently not necessary, nor provided. It is already necessary to make many non-trivial SNI decisions. I don't see ALPN as deserving higher treatment than SNI. You think this could be provided via a JDK utility class ? And if so, how can it be extended in the future when more TLS Extensions are defined ? I don't think it's necessary, no. A: use whatever algorithm(s) you want to analyze SNI/ALPN/cipher suite info The application must intersect the ciphers, application protocols... perhaps again this can be done by some JDK utility class. The point of the approach is that it is unlikely that any JDK-driven logic will be adequate for all use cases. It's better to let the application be a black box: ALPN+SNI+Ciphers -> app logic -> one ALPN protocol, one SNI name, only valid ciphers. A: either proxy the connection, or obtain or create the relevant SSLContext from the desired provider A: construct server-side SSLSocket/SSLEngine from SSLContext A: setApplicationProtocol(H2) A: setEnabledCipherSuites(only allowed suites in desired order) A: start handshake J: receive ClientHello (buffered from A) J: verify SNI is matched, fail otherwise (as today) J: verify ALPN is matched, fail otherwise (new) There is a missing step here which is to verify the cipher (trySetCipherSuite() logic). The application protocol implementation chooses only valid cipher suites for the protocol. Why would it choose one that is not valid, considering that the protocol implementation itself is the only thing that "knows" what is valid or not? If that fails then we must try another application protocol. We cannot just fail the connection. How do we go from here to the top again to choose another protocol ? J: send ServerHello (with the single, user-selected protocol) ... This is very simple from the JDK perspective, and also much more flexible. Well, I kinda like it, but I have strong reservations that it cannot really "negotiate" the application protocol, meaning that if one application protocol fails, try the next, and then the next and so forth until one succeeds (or they all fail). This validation should have happened before the JDK ever has a chance to be involved. -- - DML
Re: TLS ALPN Proposal v5
On 09/25/2015 12:13 PM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 6:49 PM, David M. Lloyd wrote: A: receive raw SSL packet on Socket or SocketChannel A: examine SSL ClientHello, extract SNI, ALPN, cipher suite info This requires the application to write a TLS parser. This is currently not necessary, nor provided. It is already necessary to make many non-trivial SNI decisions. I don't see ALPN as deserving higher treatment than SNI. You think this could be provided via a JDK utility class ? And if so, how can it be extended in the future when more TLS Extensions are defined ? I don't think it's necessary, no. A: use whatever algorithm(s) you want to analyze SNI/ALPN/cipher suite info The application must intersect the ciphers, application protocols... perhaps again this can be done by some JDK utility class. The point of the approach is that it is unlikely that any JDK-driven logic will be adequate for all use cases. It's better to let the application be a black box: ALPN+SNI+Ciphers -> app logic -> one ALPN protocol, one SNI name, only valid ciphers. A: either proxy the connection, or obtain or create the relevant SSLContext from the desired provider A: construct server-side SSLSocket/SSLEngine from SSLContext A: setApplicationProtocol(H2) A: setEnabledCipherSuites(only allowed suites in desired order) A: start handshake J: receive ClientHello (buffered from A) J: verify SNI is matched, fail otherwise (as today) J: verify ALPN is matched, fail otherwise (new) There is a missing step here which is to verify the cipher (trySetCipherSuite() logic). The application protocol implementation chooses only valid cipher suites for the protocol. Why would it choose one that is not valid, considering that the protocol implementation itself is the only thing that "knows" what is valid or not? If that fails then we must try another application protocol. We cannot just fail the connection. How do we go from here to the top again to choose another protocol ? J: send ServerHello (with the single, user-selected protocol) ... This is very simple from the JDK perspective, and also much more flexible. Well, I kinda like it, but I have strong reservations that it cannot really "negotiate" the application protocol, meaning that if one application protocol fails, try the next, and then the next and so forth until one succeeds (or they all fail). This validation should have happened before the JDK ever has a chance to be involved. -- - DML
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 6:49 PM, David M. Lloyd wrote: > A: receive raw SSL packet on Socket or SocketChannel > A: examine SSL ClientHello, extract SNI, ALPN, cipher suite info This requires the application to write a TLS parser. This is currently not necessary, nor provided. You think this could be provided via a JDK utility class ? And if so, how can it be extended in the future when more TLS Extensions are defined ? > A: use whatever algorithm(s) you want to analyze SNI/ALPN/cipher suite info The application must intersect the ciphers, application protocols... perhaps again this can be done by some JDK utility class. > A: either proxy the connection, or obtain or create the relevant SSLContext > from the desired provider > A: construct server-side SSLSocket/SSLEngine from SSLContext > A: setApplicationProtocol(H2) > A: setEnabledCipherSuites(only allowed suites in desired order) > A: start handshake > J: receive ClientHello (buffered from A) > J: verify SNI is matched, fail otherwise (as today) > J: verify ALPN is matched, fail otherwise (new) There is a missing step here which is to verify the cipher (trySetCipherSuite() logic). If that fails then we must try another application protocol. We cannot just fail the connection. How do we go from here to the top again to choose another protocol ? > J: send ServerHello (with the single, user-selected protocol) > ... > > This is very simple from the JDK perspective, and also much more flexible. Well, I kinda like it, but I have strong reservations that it cannot really "negotiate" the application protocol, meaning that if one application protocol fails, try the next, and then the next and so forth until one succeeds (or they all fail). Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
On 09/25/2015 11:37 AM, Simone Bordet wrote: David, sorry, but I don't understand your proposal. Can you please write it down in pseudo code what a server application should do and what the JDK should do to negotiate HTTP/2 with a client ? Sure. A: receive raw SSL packet on Socket or SocketChannel A: examine SSL ClientHello, extract SNI, ALPN, cipher suite info A: use whatever algorithm(s) you want to analyze SNI/ALPN/cipher suite info A: either proxy the connection, or obtain or create the relevant SSLContext from the desired provider A: construct server-side SSLSocket/SSLEngine from SSLContext A: setApplicationProtocol(H2) A: setEnabledCipherSuites(only allowed suites in desired order) A: start handshake J: receive ClientHello (buffered from A) J: verify SNI is matched, fail otherwise (as today) J: verify ALPN is matched, fail otherwise (new) J: send ServerHello (with the single, user-selected protocol) ... This is very simple from the JDK perspective, and also much more flexible. I don't see how it is even possible for a user to decide anything *before* the handshaking is even initiated, like you say. It obviously does not have enough information. It has the ClientHello, which should be more than enough. This is the current algorithm (A=app code, J=JDK code): A: sslParameters.setApplicationProtocols(H2, H1); A: (optional, only needed for H2) sort ciphers to favor H2 A: start handshake J: receive ClientHello J: ciphers = intersect client/server ciphers J: aps = intersect client/server application protocols J: for each cipher in ciphers J:for each ap in aps J:if (ap.matches(cipher & other info)) break J end // aps [A: ap.matches() calls into application code to return whether ap is good for the given info] J:if (ap was not selected) continue; // to next cipher J:if (trySetCipherSuite(cipher)) break; // success J: end // ciphers J: send ServerHello J: terminate handshake A: sslEngine/sslSocket.getApplicationProtocol() So complex! What if this algorithm is not adequate for new protocols? Is there not a danger associated with assuming HTTP/2 is your only use case? What if the application wants to make a decision that this scheme cannot support? Note that the JDK provides default implementations for H1 and H2 for ap.matches(), but in general these will be implemented by application code. For an application that wants to support H2, this boils down to the first 2 lines, the rest is in the JDK. -- - DML
Re: TLS ALPN Proposal v5
David, sorry, but I don't understand your proposal. Can you please write it down in pseudo code what a server application should do and what the JDK should do to negotiate HTTP/2 with a client ? I don't see how it is even possible for a user to decide anything *before* the handshaking is even initiated, like you say. It obviously does not have enough information. This is the current algorithm (A=app code, J=JDK code): A: sslParameters.setApplicationProtocols(H2, H1); A: (optional, only needed for H2) sort ciphers to favor H2 A: start handshake J: receive ClientHello J: ciphers = intersect client/server ciphers J: aps = intersect client/server application protocols J: for each cipher in ciphers J:for each ap in aps J:if (ap.matches(cipher & other info)) break J end // aps [A: ap.matches() calls into application code to return whether ap is good for the given info] J:if (ap was not selected) continue; // to next cipher J:if (trySetCipherSuite(cipher)) break; // success J: end // ciphers J: send ServerHello J: terminate handshake A: sslEngine/sslSocket.getApplicationProtocol() Note that the JDK provides default implementations for H1 and H2 for ap.matches(), but in general these will be implemented by application code. For an application that wants to support H2, this boils down to the first 2 lines, the rest is in the JDK. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
On 09/25/2015 10:13 AM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 4:48 PM, David M. Lloyd wrote: Yes, you would have to add a method - *one* method - to SSLSocket/SSLEngine to specify the selected protocol; this would be done during setup before you initiate handshake (which is why you need to explore the Hello packet in the first place). You also need to add another method to specify the cipher suite that goes along with the application protocol. No you wouldn't, because there already is a method for that: setEnabledCipherSuites(). You can only send one protocol back in the response, so there's nothing else to do. Matching suites to protocols is the responsibility of the application protocol developer and must be done before handshake. We have already discussed this approach: it's the "tuple" approach where the application is given the list of TLS protocols, the list of ciphers, the list of application protocols, the list of aliases and decides what is the right tuple, and return that to the JDK. Also, what if the JDK implementation refuses to use the cipher you chose along with the application protocol, for whatever reason ? Then you'd get an alert, I'd expect. That would be wrong, because you could actually speak another protocol. If you could, then the server would have chosen another protocol before handshake even begins. But my point is that it's not the JDK's business to introspect the application protocol! The JDK should only be looking at (TLS) protocol and cipher suite as it does today. It's up to the application protocol to determine if there are unacceptable cipher suites for that protocol. Any other approach is inherently broken! What if I add a new application protocol, and some cipher suites are unacceptable for it? Should I just rely on the JDK for half the time? Definitely not - the protocol implementation *must* be fully responsible for its own security policy. I don't understand where you got the impression that the JDK has to inspect the application protocol. We are discussing an API exposed by the JDK to applications, exactly because the application decides whether to accept or not the combination of application protocol, cipher, etc. Yes, but doing so by SSLContext is already too late in many cases. Trying to make a hook into handshaking is the wrong way of looking at this. The user needs to make decisions *before* handshaking is even initiated on the server. -- - DML
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 4:48 PM, David M. Lloyd wrote: > Yes, you would have to add a method - *one* method - to SSLSocket/SSLEngine > to specify the selected protocol; this would be done during setup before you > initiate handshake (which is why you need to explore the Hello packet in the > first place). You also need to add another method to specify the cipher suite that goes along with the application protocol. We have already discussed this approach: it's the "tuple" approach where the application is given the list of TLS protocols, the list of ciphers, the list of application protocols, the list of aliases and decides what is the right tuple, and return that to the JDK. >> Also, what if the JDK implementation refuses to use the cipher you >> chose along with the application protocol, for whatever reason ? > > Then you'd get an alert, I'd expect. That would be wrong, because you could actually speak another protocol. > But my point is that it's not the > JDK's business to introspect the application protocol! The JDK should only > be looking at (TLS) protocol and cipher suite as it does today. It's up to > the application protocol to determine if there are unacceptable cipher > suites for that protocol. Any other approach is inherently broken! What if > I add a new application protocol, and some cipher suites are unacceptable > for it? Should I just rely on the JDK for half the time? Definitely not - > the protocol implementation *must* be fully responsible for its own security > policy. I don't understand where you got the impression that the JDK has to inspect the application protocol. We are discussing an API exposed by the JDK to applications, exactly because the application decides whether to accept or not the combination of application protocol, cipher, etc. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
On 09/25/2015 07:29 AM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 2:15 PM, David M. Lloyd wrote: ...why does sorting even matter? Why should selection not be implemented 100% in user code, based on both the cipher suites list and application protocol, rendering this whole discussion pointless? It's clearly a complex enough process (which is highly protocol-specific) that it seems to me quite unlikely that the JDK can possibly implement this in a way that will work for all use cases. Bradford can certainly provide more context here, but the "tuple selection" approach would have required a (large) rewrite of the current mechanism, and it was discarded because of resource constraints. In fact, why not just use the SSLExplorer approach and be done with this already? You mean this ? http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/samples/sni/SSLExplorer.java Can you expand on how such approach would look like ? Seems overkill to me, and all in the hands of application developers ? Well, SNI already basically works this way, so it's not so great a stretch. I imagine the client code simply specifying a list of protocols along with today's list of cipher suites. The user-space server side logic would go like this: * Receive SSL ServerHello * Examine the packet for ALPN and SNI information * Read the list of cipher suites * Evaluate * Select an SSLContext based on protocol and/or server name * Construct an SSLSocket or SSLEngine as appropriate * Set a property on the SSLSocket/SSLEngine to indicate ALPN protocol name * (optional) Change/sort the cipher suite list on the SSLSocket/SSLEngine as appropriate * Resume negotation by passing the ServerHello in to the SSLSocket/SSLEngine as initial data It's not super elegant but it should work just as well as SNI works, and it would cover 100% of use cases since the user has complete flexibility to make a decision based on any combination of cipher suite selection, protocol name, and host name, even potentially with the option to pretend that ALPN wasn't recognized. -- - DML
Re: TLS ALPN Proposal v5
On 09/25/2015 06:42 AM, Simone Bordet wrote: Hi, On Fri, Sep 25, 2015 at 11:47 AM, Xuelei Fan wrote: Here is the question to answer, which preference should be respected firstly between cipher suite and application protocol? If application protocol are preferred at first, of course, application preference should be respected at first; otherwise, cipher suite preference should be respected at first. The answer to this question has been decided when the algorithm has been chosen to be: for each cipher for each application protocol end end All the rest being equal, ciphers dominate application protocol selection. Are you suggesting to change this to: for each application protocol for each cipher end end ? It's in the hands of the role that configures application protocols and ciphers to decide whether it's more important to prefer a protocol or a cipher. I agree with this, but... Put it in a different way: If the role prefers application protocols, it has to sort the ciphers to influence that. If the role prefers ciphers, it has to sort the ciphers. No matter what, it has to sort the ciphers. ...why does sorting even matter? Why should selection not be implemented 100% in user code, based on both the cipher suites list and application protocol, rendering this whole discussion pointless? It's clearly a complex enough process (which is highly protocol-specific) that it seems to me quite unlikely that the JDK can possibly implement this in a way that will work for all use cases. Therefore, personally, I think application may want a handy tool to sort the cipher suite for the strength for general purpose, but not for application protocol. Because HTTP/2 would probably be popular given the success of its predecessor, it would be handy to have a HTTP/2 comparator to influence the selection of the HTTP/2 protocol. Nothing forbids to offer a comparator by cipher strength too. Ugh, why not just let the user decide *if* they want to sort (and filter) ciphers, and if so, they can do it themselves using Arrays.sort() on the ciphers array which already should be more than adequate. In fact, why not just use the SSLExplorer approach and be done with this already? -- - DML
Re: TLS ALPN Proposal v5
CC security-dev. On 9/25/2015 9:14 PM, Simone Bordet wrote: > Hi, > > On Fri, Sep 25, 2015 at 2:46 PM, David M. Lloyd > wrote: >> Well, SNI already basically works this way, so it's not so great a stretch. > > I don't follow ? > SNI has APIs in JDK 8, you don't use SSLExplorer at all. > > Also, SNI is a client-to-server information only, while with ALPN you > have to reply to the client, so you have to modify the ServerHello. > I don't see how you can do this without support from the JDK via APIs ? > >> I imagine the client code simply specifying a list of protocols along with >> today's list of cipher suites. >> >> The user-space server side logic would go like this: >> >> * Receive SSL ServerHello >> * Examine the packet for ALPN and SNI information >> * Read the list of cipher suites >> * Evaluate >> * Select an SSLContext based on protocol and/or server name >> * Construct an SSLSocket or SSLEngine as appropriate >> * Set a property on the SSLSocket/SSLEngine to indicate ALPN protocol name >> * (optional) Change/sort the cipher suite list on the SSLSocket/SSLEngine as >> appropriate >> * Resume negotation by passing the ServerHello in to the SSLSocket/SSLEngine >> as initial data >> >> It's not super elegant but it should work just as well as SNI works, and it >> would cover 100% of use cases since the user has complete flexibility to >> make a decision based on any combination of cipher suite selection, protocol >> name, and host name, even potentially with the option to pretend that ALPN >> wasn't recognized. > > Are you saying that every application has to write its own TLS parser ? > Would not that be overkill and full of potential security issues if > one does not get the implementation strictly correct ? > > Also, what if the JDK implementation refuses to use the cipher you > chose along with the application protocol, for whatever reason ? > > Thanks ! >
Re: TLS ALPN Proposal v5
On 9/25/2015 10:20 PM, Simone Bordet wrote: > Hi, > > On Fri, Sep 25, 2015 at 3:20 PM, Xuelei Fan wrote: >> For the complication, I posted the comments in previous mail here: >> >> - >>> In case you have [HTTP/2, AP_NEW, HTTP/1.1], then you can simply >>> compose the comparators to sort first with the H2.CIPHER_COMPARATOR, >>> then with AP_NEW.CIPHER_COMPARATOR. >>> >>> cipherSuites = Arrays.sort(cipherSuites, >>>ApplicationProtocol.H2.CIPHER_COMPARATOR. >>>thenComparing(AP_NEW.CIPHER_COMPARATOR)); >>> >> Let's look at an example. application_protocol_1 prefer cipher_suite_1, >> and application_protocol_1 prefer cipher_suite_2. >> >> The comparator for application_protocol_1 would set the preference as >> {cipher_suite_1, cipher_suite_2}. and the comparator for >> application_protocol_2} would set the preference as {cipher_suite_2, >> cipher_suite_1}. >> >> The result to sort 1 and then 2, and the result to sort 2 and then 1 are >> different. >> >> The call sequence to the comparators, and the call to each comparator >> would result in difference result. That's may be not the expected behavior. > > The example is malformed, since it does not specify which ciphers are > good for which application protocol, and neither the order of the > application protocols. > > Let me rewrite it: > > application protocols: [ap1, ap2] > ciphers: [c1, c2] > > ap1 requires c1, does not work with c2 > ap2 requires c2, does not work with c1 > OK, as make the case more simple. > Now the question is: you have to configure your system, what you want to do ? > > If you want to favor ap1, then you sort [c1, c2] > If you want to favor ap2, then you sort [c2, c1] > If you want to favor c1, then you sort [c1, c2] > If you want to favor c2, then you sort [c2, c1] > > If you want to favor ap1 *and* c2, you have to decide what is more > important between the two, because you cannot have both. > > I don't see any problem, really. > If "you" as the customer, I don't see any problem. If "you" as OpenJDK, the problem is that OpenJDK know nothing about the conditions (if you want to favor ...), and therefore cannot make the decision (sort) internally. I think we should be on the same page: customers can make any sort as they want. SSLParameters.setCipherSuite() and SSLParameters.setAppliationProtocols() can be used for any decision they made. > That the results are different, sure, but they are predictable. > When the configuration uses one comparator, it will always be that > result, and same for the other comparator. > > But you configure the comparators in base of what you want to do. > Need a confirmation. I think you agree that the sort happens before the calls to SSLParameters.setCipherSuite() and SSLParameters.setAppliationProtocols(), right? As the case I commented in previous mail: // the customers' decision // (1) String[] cipherSuites = {}; // customer preference List appProtocols = {...}; // customer preference + + // reorde the cipher suites // (1.1) + cipherSuites = ... // the actual customer preference + + // reorder application protocols preference + appProtocols = ... // the actual customer preference // configure the parameters // (2) // // customer preferences should be respected. sslParameters.setCipherSuites(cipherSuites); sslParameters.setApplicationProtocols(appProtocols); Xuelei
Re: TLS ALPN Proposal v5
Sorry I didn't get the reply from Simone Bordet - it must have gone to only one of the two lists (which I'm not on). On 9/25/2015 9:14 PM, Simone Bordet wrote: I don't follow ? SNI has APIs in JDK 8, you don't use SSLExplorer at all. They're highly limited; you can only tell the socket/engine to accept or reject a connection based on the SNI information. The ability to react to the server name in order to configure other parameters is highly limited, let alone being able to do things like select a different SSLContext altogether, or proxy the connection to another host. Also, SNI is a client-to-server information only, while with ALPN you have to reply to the client, so you have to modify the ServerHello. I don't see how you can do this without support from the JDK via APIs ? Yes, you would have to add a method - *one* method - to SSLSocket/SSLEngine to specify the selected protocol; this would be done during setup before you initiate handshake (which is why you need to explore the Hello packet in the first place). Better to start simple in any event. With this one single method change, we *could* have a 100% effective solution for all use cases. There could be a fancier solution later, when time isn't ticking towards a JDK 9 deadline. Are you saying that every application has to write its own TLS parser ? Every *server* application, yes, though most users will rely on a security or server library to do this already. Of course we could always add an SSLExplorer-like function to the JSSE API - that would be very nice - but the point of this suggestion is to keep things realistic and get the job *done*. Would not that be overkill and full of potential security issues if one does not get the implementation strictly correct ? Nah, you don't have to do much other than look in the hello packet, make a decision, and then hand it off to the SSL context, which would then do a much more rigorous validation. I don't think there's much risk here. Also, what if the JDK implementation refuses to use the cipher you chose along with the application protocol, for whatever reason ? Then you'd get an alert, I'd expect. But my point is that it's not the JDK's business to introspect the application protocol! The JDK should only be looking at (TLS) protocol and cipher suite as it does today. It's up to the application protocol to determine if there are unacceptable cipher suites for that protocol. Any other approach is inherently broken! What if I add a new application protocol, and some cipher suites are unacceptable for it? Should I just rely on the JDK for half the time? Definitely not - the protocol implementation *must* be fully responsible for its own security policy. On 09/25/2015 09:19 AM, Xuelei Fan wrote: There are two typical cases for SNI and ALPN. One is that the same server is used for difference SNI/ALPN. Another one is that different server is used for different SNI/ALPN. For example, there is a TLS server 101.101.1.1 for delegation. If SNI www.example.com get requested, the delegation server may redirect the connection to 192.168.1.100 (provide the service for www.example.com). If SNI www.another.com get requested, the delegation server may redirect the connection to 192.168.1.101 (provide the service for www.another.com). Similarly, ALPN need to support the case as above. Another example, there is a server 101.101.1.1. If SNI www.example.com get requested, the server would act as the service for www.example.com. If SNI www.another.com get requested, the server would act as the service for www.another.com. Similarly, ALPN also need to support the case as above. Exactly - you may want or need to choose different SSL contexts, or even forward to another host, based on this information. Relying solely on SNIMatcher (for example) is already not adequate by itself for many use cases. Consider also that we're talking about server side code here: the number of potential users is small! I believe that end users will only indirectly use this mechanism through server frameworks, meaning that only the framework authors are really the direct consumers. -- - DML
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 3:20 PM, Xuelei Fan wrote: > For the complication, I posted the comments in previous mail here: > > - >> In case you have [HTTP/2, AP_NEW, HTTP/1.1], then you can simply >> compose the comparators to sort first with the H2.CIPHER_COMPARATOR, >> then with AP_NEW.CIPHER_COMPARATOR. >> >> cipherSuites = Arrays.sort(cipherSuites, >>ApplicationProtocol.H2.CIPHER_COMPARATOR. >>thenComparing(AP_NEW.CIPHER_COMPARATOR)); >> > Let's look at an example. application_protocol_1 prefer cipher_suite_1, > and application_protocol_1 prefer cipher_suite_2. > > The comparator for application_protocol_1 would set the preference as > {cipher_suite_1, cipher_suite_2}. and the comparator for > application_protocol_2} would set the preference as {cipher_suite_2, > cipher_suite_1}. > > The result to sort 1 and then 2, and the result to sort 2 and then 1 are > different. > > The call sequence to the comparators, and the call to each comparator > would result in difference result. That's may be not the expected behavior. The example is malformed, since it does not specify which ciphers are good for which application protocol, and neither the order of the application protocols. Let me rewrite it: application protocols: [ap1, ap2] ciphers: [c1, c2] ap1 requires c1, does not work with c2 ap2 requires c2, does not work with c1 Now the question is: you have to configure your system, what you want to do ? If you want to favor ap1, then you sort [c1, c2] If you want to favor ap2, then you sort [c2, c1] If you want to favor c1, then you sort [c1, c2] If you want to favor c2, then you sort [c2, c1] If you want to favor ap1 *and* c2, you have to decide what is more important between the two, because you cannot have both. I don't see any problem, really. That the results are different, sure, but they are predictable. When the configuration uses one comparator, it will always be that result, and same for the other comparator. But you configure the comparators in base of what you want to do. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
On 9/25/2015 9:14 PM, Simone Bordet wrote: > On Fri, Sep 25, 2015 at 2:46 PM, David M. Lloyd > wrote: >> > Well, SNI already basically works this way, so it's not so great a stretch. > I don't follow ? > SNI has APIs in JDK 8, you don't use SSLExplorer at all. There are two typical cases for SNI and ALPN. One is that the same server is used for difference SNI/ALPN. Another one is that different server is used for different SNI/ALPN. For example, there is a TLS server 101.101.1.1 for delegation. If SNI www.example.com get requested, the delegation server may redirect the connection to 192.168.1.100 (provide the service for www.example.com). If SNI www.another.com get requested, the delegation server may redirect the connection to 192.168.1.101 (provide the service for www.another.com). Similarly, ALPN need to support the case as above. Another example, there is a server 101.101.1.1. If SNI www.example.com get requested, the server would act as the service for www.example.com. If SNI www.another.com get requested, the server would act as the service for www.another.com. Similarly, ALPN also need to support the case as above. Actually, it was a puzzle to me: whether a concrete server can support both HTTP/2 and HTTP/1.1, or not. If HTTP/2 mode of the server does not work, is it OK to fall-over to use HTTP/1.1 mode? I did not get the answer from the HTTP/2 spec. The current design is based on the idea that a concrete server may support both HTTP/2 and HTTP/1.1 at the same time, and fall-over mode is necessary. Otherwise, the API and implementation can be simplified a lot. Xuelei
Re: TLS ALPN Proposal v5
On 9/25/2015 8:48 PM, Simone Bordet wrote: > Hi, > > On Fri, Sep 25, 2015 at 2:26 PM, Xuelei Fan wrote: >> Maybe, we are not on the same page, I think. > > We are. > >> I think a general cipher strength comparator is sufficient for HTTP/2 >> preference too. What do you think? > > I don't know if all the blacklisted ciphers are actually lower > strength of all the remaining ciphers, nor what is the exact > definition of "strength" that you can use in a comparator. > But because the HTTP/2 specification bothered to say what's > blacklisted, I would just use that. > HTTP/2 blacklists them because they are no so strong because of various reasons. The definition of "strength" can be customized by the customers. Therefore, I don't worry too much because of this flexibility. >> Maybe, need no extra comparator for HTTP2. Extra comparator would make >> behaviors pretty complicated and hard to get expected, as I described in >> the previous mail. > > There is no complication, really. Two comparators would compose, not exclude. > For the complication, I posted the comments in previous mail here: - > In case you have [HTTP/2, AP_NEW, HTTP/1.1], then you can simply > compose the comparators to sort first with the H2.CIPHER_COMPARATOR, > then with AP_NEW.CIPHER_COMPARATOR. > > cipherSuites = Arrays.sort(cipherSuites, >ApplicationProtocol.H2.CIPHER_COMPARATOR. >thenComparing(AP_NEW.CIPHER_COMPARATOR)); > Let's look at an example. application_protocol_1 prefer cipher_suite_1, and application_protocol_1 prefer cipher_suite_2. The comparator for application_protocol_1 would set the preference as {cipher_suite_1, cipher_suite_2}. and the comparator for application_protocol_2} would set the preference as {cipher_suite_2, cipher_suite_1}. The result to sort 1 and then 2, and the result to sort 2 and then 1 are different. The call sequence to the comparators, and the call to each comparator would result in difference result. That's may be not the expected behavior. - It's not easy to use application comparator, I think. > For example, let's say that you want to sort by "bit" strength in a > way that you want to prefer 128 bits or lower to favor performance, > but also do HTTP/2. > > The H2 comparator will sort the blacklisted at the end. > Among the good ones, they all compare == 0 for the H2 comparator. > That is where the second comparator will kick in, grep the cipher name > for the bits number and sort them accordingly. > It's flexible to meet the requirement by customer's customization. Maybe, extra comparator is not necessary here. I think the comparator can be a handy tool, but not belong to ALPN. Xuelei
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 2:26 PM, Xuelei Fan wrote: > Maybe, we are not on the same page, I think. We are. > I think a general cipher strength comparator is sufficient for HTTP/2 > preference too. What do you think? I don't know if all the blacklisted ciphers are actually lower strength of all the remaining ciphers, nor what is the exact definition of "strength" that you can use in a comparator. But because the HTTP/2 specification bothered to say what's blacklisted, I would just use that. > Maybe, need no extra comparator for HTTP2. Extra comparator would make > behaviors pretty complicated and hard to get expected, as I described in > the previous mail. There is no complication, really. Two comparators would compose, not exclude. For example, let's say that you want to sort by "bit" strength in a way that you want to prefer 128 bits or lower to favor performance, but also do HTTP/2. The H2 comparator will sort the blacklisted at the end. Among the good ones, they all compare == 0 for the H2 comparator. That is where the second comparator will kick in, grep the cipher name for the bits number and sort them accordingly. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
On 9/25/2015 7:42 PM, Simone Bordet wrote: > Hi, > > On Fri, Sep 25, 2015 at 11:47 AM, Xuelei Fan wrote: >> Here is the question to answer, which preference should be respected >> firstly between cipher suite and application protocol? If application >> protocol are preferred at first, of course, application preference >> should be respected at first; otherwise, cipher suite preference should >> be respected at first. > > The answer to this question has been decided when the algorithm has > been chosen to be: > > for each cipher > for each application protocol > end > end > > All the rest being equal, ciphers dominate application protocol selection. > > Are you suggesting to change this to: > > for each application protocol > for each cipher > end > end > > ? > No, I would prefer the first approach. Good, we are at the same page at this point, I think. > It's in the hands of the role that configures application protocols > and ciphers to decide whether it's more important to prefer a protocol > or a cipher. > > Put it in a different way: > > If the role prefers application protocols, it has to sort the ciphers > to influence that. > If the role prefers ciphers, it has to sort the ciphers. > I did not catch the idea. if the tole prefers ciphers, why still need to sort the ciphers? Sort for what? > No matter what, it has to sort the ciphers. > I did not get your ideas. Who would sort the preferences? and when the preferences should be sorted? Maybe, we are not on the same page, I think. >From the viewpoint of application or library, if an administrator had made his decision about the preference of application protocols and cipher suites, applications and OpenJDK may be better to respect the decision. // the customers' decision//(1) String[] cipherSuites = {}; // customer preference, sorted. List appProtocols = {...}; // customer preference, sorted. // configure the parameters // (2) // // customer preferences should be respected. sslParameters.setCipherSuites(cipherSuites); sslParameters.setApplicationProtocols(appProtocols); There might be concerns, customers preference may be not right and need to adjusted. Maybe, a re-order tool is needed before (not after) the configuration of the parameters. // the customers' decision // (1) String[] cipherSuites = {}; // customer preference List appProtocols = {...}; // customer preference + + // reorde the cipher suites // (1.1) + cipherSuites = ... // the actual customer preference + + // reorder application protocols preference + appProtocols = ... // the actual customer preference // configure the parameters // (2) // // customer preferences should be respected. sslParameters.setCipherSuites(cipherSuites); sslParameters.setApplicationProtocols(appProtocols); >> Therefore, personally, I think application may want a handy tool to sort >> the cipher suite for the strength for general purpose, but not for >> application protocol. > > Because HTTP/2 would probably be popular given the success of its > predecessor, it would be handy to have a HTTP/2 comparator to > influence the selection of the HTTP/2 protocol. > > Nothing forbids to offer a comparator by cipher strength too. > I think a general cipher strength comparator is sufficient for HTTP/2 preference too. What do you think? Maybe, need no extra comparator for HTTP2. Extra comparator would make behaviors pretty complicated and hard to get expected, as I described in the previous mail. Xuelei
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 1:54 PM, wrote: > Hello, > > Just want to mention that with explicite http/https URLs users and > applications are somewhat used to select the application protocol first. Well, kind of :) Some time ago, and still now, if you put "https" in a URL, you are actually talking SPDY over TLS. > In fact if I have a H2 client I would expect it to try H2 first (especially > given the fact that no weak ciphers could be negotiated anyway). So basically > cipher order would select if you want strong but fast or very strong but > slower crypto for H2. You could only mess that up by prefering blacklisted > ciphers. But even then the serrver can still pick H2 and skip all blacklisted > preferences, right? > No. Currently, the server is given a cipher and based on that cipher has to choose the application protocol. It cannot choose the cipher based on the application protocol. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
Hello, Just want to mention that with explicite http/https URLs users and applications are somewhat used to select the application protocol first. In fact if I have a H2 client I would expect it to try H2 first (especially given the fact that no weak ciphers could be negotiated anyway). So basically cipher order would select if you want strong but fast or very strong but slower crypto for H2. You could only mess that up by prefering blacklisted ciphers. But even then the serrver can still pick H2 and skip all blacklisted preferences, right? Gruss Bernd -- http://bernd.eckenfels.net -Original Message- From: Xuelei Fan To: Simone Bordet Cc: OpenJDK Dev list , "net-...@openjdk.java.net >> OpenJDK Network Dev list" Sent: Fr., 25 Sep. 2015 11:48 Subject: Re: TLS ALPN Proposal v5 On 9/25/2015 4:11 PM, Simone Bordet wrote: > Hi, > > On Fri, Sep 25, 2015 at 3:44 AM, Xuelei Fan wrote: >> For example, a client wants to negotiate {HTTP2, HTTP1.1} or {HTTP1.1, >> HTTP2} and {TLS_RSA_WITH_AES_128_CBC_SHA, >> TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}. >> HTTP1.1/TLS_RSA_WITH_AES_128_CBC_SHA should be negotiated per the TLS >> and HTTP2 specification. If the cipher suites are sorted, >> TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 would be negotiated, this is not >> what the customer really expected. The customer preference should be >> respected. >> >> I don't think we really need to re-order the cipher suites. > > "We" as in the OpenJDK implementation *must not* reorder the cipher suites. Yes. I agree with this point, OpenJDK MUST NOT reorder the cipher suites. > "We" as in an application that wants to use HTTP/2 *must* reorder the > cipher suites. In an application, the cipher suites preference MUST be used properly, but the "reorder" behavior may be not the application expected order. For some reasons, applications (or customers) may want the preference of {TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, rather than reordered to {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA}. Customers preference should be respected, application and OpenJDK MUST NOT reorder the cipher suites. If there are three roles, OpenJDK, application, customers, there are three result: 1. OpenJDK MUST NOT reorder the cipher suites if no application request. 2. Applications MUST NOT reorder the cipher suites if no customer request. 3. Customers can set the cipher suites order according to they requirements. > The comparator provided is only a help to the application to perform > this reordering. > >> Let's consider the following client requests (prefer cipher suite more >> than application protocol; blacklisted_CS are HTTP2 blacklisted cipher >> suite): >> >> 1. {HTTP2, HTTP1.1} {strong_cipher_site, blacklisted_CS} >> HTTP2 and strong_cipher_site should be negotiated. Need not to re-order >> cipher suites. >> >> 2. {HTTP1.1, HTTP2} {strong_cipher_site, blacklisted_CS} >> HTTP1.1 and strong_cipher_site should be negotiated. Need not to >> re-order cipher suites. >> >> 3. {HTTP2, HTTP1.1} {blacklisted_CS, strong_cipher_site} >> HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order >> cipher suites. > > Of course you need to re-order in this case. > The application has just provided a preference for HTTP/2 in the > application protocol list, it actually happens that HTTP/2 could be > negotiated because strong ciphers are present, but instead HTTP/1.1 is > chosen. > Here is the question to answer, which preference should be respected firstly between cipher suite and application protocol? If application protocol are preferred at first, of course, application preference should be respected at first; otherwise, cipher suite preference should be respected at first. Let's re-write the example, among {application_protocol_1, application_protocol_2} and {cipher_suite_for_AP2, cipher_suite_for_AP1}. If application protocol preference get respected, application_protocol_1/cipher_suite_for_AP1 would be negotiated; If cipher suite preference get respected, application_protocol_2/cipher_suite_for_AP2 should be negotiated. >From my understand, cipher suite preference should be preferred over application protocols. >> 4. {HTTP1.1, HTTP2} {blacklisted_CS, strong_cipher_site} >> HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order >> cipher suites. >> >> 5. {HTTP2} {strong_cipher_site, blacklisted_CS} >> HTTP2 and strong_cipher_site should be negotiated. Need not to re-order >> cipher suites. >> >> 6. {HTTP1.1} {strong_cipher_site, blacklisted_CS} >> HTTP1.1 and strong_cipher_site should be negotiated. Need not to >> re-order
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 11:47 AM, Xuelei Fan wrote: > Here is the question to answer, which preference should be respected > firstly between cipher suite and application protocol? If application > protocol are preferred at first, of course, application preference > should be respected at first; otherwise, cipher suite preference should > be respected at first. The answer to this question has been decided when the algorithm has been chosen to be: for each cipher for each application protocol end end All the rest being equal, ciphers dominate application protocol selection. Are you suggesting to change this to: for each application protocol for each cipher end end ? It's in the hands of the role that configures application protocols and ciphers to decide whether it's more important to prefer a protocol or a cipher. Put it in a different way: If the role prefers application protocols, it has to sort the ciphers to influence that. If the role prefers ciphers, it has to sort the ciphers. No matter what, it has to sort the ciphers. > Therefore, personally, I think application may want a handy tool to sort > the cipher suite for the strength for general purpose, but not for > application protocol. Because HTTP/2 would probably be popular given the success of its predecessor, it would be handy to have a HTTP/2 comparator to influence the selection of the HTTP/2 protocol. Nothing forbids to offer a comparator by cipher strength too. -- Simone Bordet http://cometd.org http://webtide.com Developer advice, training, services and support from the Jetty & CometD experts.
Re: TLS ALPN Proposal v5
New to ALPN and this thread, just my $0.02. On 09/25/2015 05:47 PM, Xuelei Fan wrote: Here is the question to answer, which preference should be respected firstly between cipher suite and application protocol? No concrete answer, but I think it's always better to "first respect what the user has configured". If user has explicitly requested {AP1, AP2} but has not configured cipher suites order himself, ALPN preference should be respected first. This might mean that for different ALPN requests the *default* cipher suite order should be different. --Max
Re: TLS ALPN Proposal v5
On 9/25/2015 4:11 PM, Simone Bordet wrote: > Hi, > > On Fri, Sep 25, 2015 at 3:44 AM, Xuelei Fan wrote: >> For example, a client wants to negotiate {HTTP2, HTTP1.1} or {HTTP1.1, >> HTTP2} and {TLS_RSA_WITH_AES_128_CBC_SHA, >> TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}. >> HTTP1.1/TLS_RSA_WITH_AES_128_CBC_SHA should be negotiated per the TLS >> and HTTP2 specification. If the cipher suites are sorted, >> TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 would be negotiated, this is not >> what the customer really expected. The customer preference should be >> respected. >> >> I don't think we really need to re-order the cipher suites. > > "We" as in the OpenJDK implementation *must not* reorder the cipher suites. Yes. I agree with this point, OpenJDK MUST NOT reorder the cipher suites. > "We" as in an application that wants to use HTTP/2 *must* reorder the > cipher suites. In an application, the cipher suites preference MUST be used properly, but the "reorder" behavior may be not the application expected order. For some reasons, applications (or customers) may want the preference of {TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, rather than reordered to {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA}. Customers preference should be respected, application and OpenJDK MUST NOT reorder the cipher suites. If there are three roles, OpenJDK, application, customers, there are three result: 1. OpenJDK MUST NOT reorder the cipher suites if no application request. 2. Applications MUST NOT reorder the cipher suites if no customer request. 3. Customers can set the cipher suites order according to they requirements. > The comparator provided is only a help to the application to perform > this reordering. > >> Let's consider the following client requests (prefer cipher suite more >> than application protocol; blacklisted_CS are HTTP2 blacklisted cipher >> suite): >> >> 1. {HTTP2, HTTP1.1} {strong_cipher_site, blacklisted_CS} >> HTTP2 and strong_cipher_site should be negotiated. Need not to re-order >> cipher suites. >> >> 2. {HTTP1.1, HTTP2} {strong_cipher_site, blacklisted_CS} >> HTTP1.1 and strong_cipher_site should be negotiated. Need not to >> re-order cipher suites. >> >> 3. {HTTP2, HTTP1.1} {blacklisted_CS, strong_cipher_site} >> HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order >> cipher suites. > > Of course you need to re-order in this case. > The application has just provided a preference for HTTP/2 in the > application protocol list, it actually happens that HTTP/2 could be > negotiated because strong ciphers are present, but instead HTTP/1.1 is > chosen. > Here is the question to answer, which preference should be respected firstly between cipher suite and application protocol? If application protocol are preferred at first, of course, application preference should be respected at first; otherwise, cipher suite preference should be respected at first. Let's re-write the example, among {application_protocol_1, application_protocol_2} and {cipher_suite_for_AP2, cipher_suite_for_AP1}. If application protocol preference get respected, application_protocol_1/cipher_suite_for_AP1 would be negotiated; If cipher suite preference get respected, application_protocol_2/cipher_suite_for_AP2 should be negotiated. >From my understand, cipher suite preference should be preferred over application protocols. >> 4. {HTTP1.1, HTTP2} {blacklisted_CS, strong_cipher_site} >> HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order >> cipher suites. >> >> 5. {HTTP2} {strong_cipher_site, blacklisted_CS} >> HTTP2 and strong_cipher_site should be negotiated. Need not to re-order >> cipher suites. >> >> 6. {HTTP1.1} {strong_cipher_site, blacklisted_CS} >> HTTP1.1 and strong_cipher_site should be negotiated. Need not to >> re-order cipher suites. >> >> 7. {HTTP2} {blacklisted_CS, strong_cipher_site} >> blacklisted_CS would be filtered out as it does not appy to HTTP2. Only >> strong_cipher_site presents in ClientHello message. >> >> HTTP2 and strong_cipher_site should be negotiated. Need not to re-order >> cipher suites. >> >> 8. {HTTP1.1} {blacklisted_CS, strong_cipher_site} >> HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order >> cipher suites. >> >> One concern may be that, the customer is not intent to negotiate HTTP2 >> blacklisted cipher suite. The customer just don't know which are the >> strong cipher suites among many cipher suites. I think we may need a >> handy tool to order the cipher suites before configuration. >> >> // there are a few cipher suites are available >> String[] cipherSuites = ... // a array of cipher suites. >> >> // Q: Don't know the strength of them >> // A: OK, there is a handy tool >> cipherSuites = cipherSuiteReorder.sort(cipherSuites); > > Or, with the comparator: > > cipherSuites = Arrays.sort(cipherSuites, > ApplicationProtocol.H2.CIPHER_COMPARATOR); > > The comparator is
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 3:44 AM, Xuelei Fan wrote: > For example, a client wants to negotiate {HTTP2, HTTP1.1} or {HTTP1.1, > HTTP2} and {TLS_RSA_WITH_AES_128_CBC_SHA, > TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}. > HTTP1.1/TLS_RSA_WITH_AES_128_CBC_SHA should be negotiated per the TLS > and HTTP2 specification. If the cipher suites are sorted, > TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 would be negotiated, this is not > what the customer really expected. The customer preference should be > respected. > > I don't think we really need to re-order the cipher suites. "We" as in the OpenJDK implementation *must not* reorder the cipher suites. "We" as in an application that wants to use HTTP/2 *must* reorder the cipher suites. The comparator provided is only a help to the application to perform this reordering. > Let's consider the following client requests (prefer cipher suite more > than application protocol; blacklisted_CS are HTTP2 blacklisted cipher > suite): > > 1. {HTTP2, HTTP1.1} {strong_cipher_site, blacklisted_CS} > HTTP2 and strong_cipher_site should be negotiated. Need not to re-order > cipher suites. > > 2. {HTTP1.1, HTTP2} {strong_cipher_site, blacklisted_CS} > HTTP1.1 and strong_cipher_site should be negotiated. Need not to > re-order cipher suites. > > 3. {HTTP2, HTTP1.1} {blacklisted_CS, strong_cipher_site} > HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order > cipher suites. Of course you need to re-order in this case. The application has just provided a preference for HTTP/2 in the application protocol list, it actually happens that HTTP/2 could be negotiated because strong ciphers are present, but instead HTTP/1.1 is chosen. > 4. {HTTP1.1, HTTP2} {blacklisted_CS, strong_cipher_site} > HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order > cipher suites. > > 5. {HTTP2} {strong_cipher_site, blacklisted_CS} > HTTP2 and strong_cipher_site should be negotiated. Need not to re-order > cipher suites. > > 6. {HTTP1.1} {strong_cipher_site, blacklisted_CS} > HTTP1.1 and strong_cipher_site should be negotiated. Need not to > re-order cipher suites. > > 7. {HTTP2} {blacklisted_CS, strong_cipher_site} > blacklisted_CS would be filtered out as it does not appy to HTTP2. Only > strong_cipher_site presents in ClientHello message. > > HTTP2 and strong_cipher_site should be negotiated. Need not to re-order > cipher suites. > > 8. {HTTP1.1} {blacklisted_CS, strong_cipher_site} > HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order > cipher suites. > > One concern may be that, the customer is not intent to negotiate HTTP2 > blacklisted cipher suite. The customer just don't know which are the > strong cipher suites among many cipher suites. I think we may need a > handy tool to order the cipher suites before configuration. > > // there are a few cipher suites are available > String[] cipherSuites = ... // a array of cipher suites. > > // Q: Don't know the strength of them > // A: OK, there is a handy tool > cipherSuites = cipherSuiteReorder.sort(cipherSuites); Or, with the comparator: cipherSuites = Arrays.sort(cipherSuites, ApplicationProtocol.H2.CIPHER_COMPARATOR); The comparator is the handy tool. > // configure the cipher suites > SSLParameters.setCipherSuites(cipherSuites); > > The order also apply to the normally cipher suites configuration, not > only to application protocols. The re-order should be called by > customers explicitly. JSSE would better not sort them automatically. > > I think, the handy sort tool cannot be simply bind to application > protocol. For example, HTTP2 has a blacklisted cipher suites. OK, > ApplicationProtocol.H2BLACKLISTCOMPARATOR is expected to make the sort. > If, in the future, a new application protocol (AP_NEW) has a different > blacklist cipher suites, a new > ApplicationProtocol.APNEWBLACKLISTCOMPARATOR would be defined. If both > {HTTP2, AP_NEW} would be requested, which comparator for the sorting > would be used? None of them can sort the cipher suite properly. The > comparator design will not work any more. Sure it does. Because you explicitly set a preference in the order of the application protocol, you only sort to favour the best protocol. In case you have [HTTP/2, AP_NEW, HTTP/1.1], then you can simply compose the comparators to sort first with the H2.CIPHER_COMPARATOR, then with AP_NEW.CIPHER_COMPARATOR. cipherSuites = Arrays.sort(cipherSuites, ApplicationProtocol.H2.CIPHER_COMPARATOR.thenComparing(AP_NEW.CIPHER_COMPARATOR)); > We may need a handy tool for the sorting for stronger cipher suites. > But, AFAIU, the tool does not belong to ALPN. Indeed, it belongs to ApplicationProtocol.H2, not to ApplicationProtocol. -- Simone Bordet http://cometd.org http://webtide.com Developer advice, training, services and support from the Jetty & CometD experts.
Re: TLS ALPN Proposal v5
On 9/25/2015 7:45 AM, Bradford Wetmore wrote: > > On 9/23/2015 2:33 AM, Simone Bordet wrote: >> Hi, >> >> On Wed, Sep 23, 2015 at 7:04 AM, Bradford Wetmore >> wrote: >>> This new proposal still requires that ciphers are sorted in a way that matches the ApplicationProtocol order. Would be nice if, along with the HTTP/2 blacklist, there is a HTTP/2 comparator that sorts ciphers putting the blacklisted ones at the end. >>> >>> Hm...is the sample code at the end of the initial class description >>> insufficient? Adding a comparator seems a little heavyweight in that it >>> could require access to the ciphersuite internals and would add a lot of >>> complexity for this one known use case. When TLSv1.3 is done, the >>> blacklist >>> stuff in HTTP/2 goes away. >> >> Sure, but until TLS 1.3 widely deployed, applications will have to >> sort the ciphers to put HTTP/2 ones before the blacklisted ones. >> Providing this comparator is as trivial as providing >> ApplicationProtocol.HTTP2BLACKLIST, so I thought to mention it. > > I learned something today: Collections/Arrays.sort()/others are stable. > (i.e. equal elements will not be reordered as a result of the sort) My > expectation of "equals" was .equals(), not return value == 0. > > I was concerned that such a Comparator might reorder valid H2 suites > from what was passed in. Thankfully, that's not the case, so I've added > this Comparator. There is a warning now about "consistency with > equals()", as the Strings obvioulsy won't be equals() and thus sorted > sets/maps just won't work. (See the Comparator pages for further > discussion.) It might be not customers expected behavior to re-order/sort their preference of cipher suites or preference. For example, a client wants to negotiate {HTTP2, HTTP1.1} or {HTTP1.1, HTTP2} and {TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}. HTTP1.1/TLS_RSA_WITH_AES_128_CBC_SHA should be negotiated per the TLS and HTTP2 specification. If the cipher suites are sorted, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 would be negotiated, this is not what the customer really expected. The customer preference should be respected. I don't think we really need to re-order the cipher suites. Let's consider the following client requests (prefer cipher suite more than application protocol; blacklisted_CS are HTTP2 blacklisted cipher suite): 1. {HTTP2, HTTP1.1} {strong_cipher_site, blacklisted_CS} HTTP2 and strong_cipher_site should be negotiated. Need not to re-order cipher suites. 2. {HTTP1.1, HTTP2} {strong_cipher_site, blacklisted_CS} HTTP1.1 and strong_cipher_site should be negotiated. Need not to re-order cipher suites. 3. {HTTP2, HTTP1.1} {blacklisted_CS, strong_cipher_site} HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order cipher suites. 4. {HTTP1.1, HTTP2} {blacklisted_CS, strong_cipher_site} HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order cipher suites. 5. {HTTP2} {strong_cipher_site, blacklisted_CS} HTTP2 and strong_cipher_site should be negotiated. Need not to re-order cipher suites. 6. {HTTP1.1} {strong_cipher_site, blacklisted_CS} HTTP1.1 and strong_cipher_site should be negotiated. Need not to re-order cipher suites. 7. {HTTP2} {blacklisted_CS, strong_cipher_site} blacklisted_CS would be filtered out as it does not appy to HTTP2. Only strong_cipher_site presents in ClientHello message. HTTP2 and strong_cipher_site should be negotiated. Need not to re-order cipher suites. 8. {HTTP1.1} {blacklisted_CS, strong_cipher_site} HTTP1.1 and blacklisted_CS should be negotiated. Need not to re-order cipher suites. One concern may be that, the customer is not intent to negotiate HTTP2 blacklisted cipher suite. The customer just don't know which are the strong cipher suites among many cipher suites. I think we may need a handy tool to order the cipher suites before configuration. // there are a few cipher suites are available String[] cipherSuites = ... // a array of cipher suites. // Q: Don't know the strength of them // A: OK, there is a handy tool cipherSuites = cipherSuiteReorder.sort(cipherSuites); // configure the cipher suites SSLParameters.setCipherSuites(cipherSuites); The order also apply to the normally cipher suites configuration, not only to application protocols. The re-order should be called by customers explicitly. JSSE would better not sort them automatically. I think, the handy sort tool cannot be simply bind to application protocol. For example, HTTP2 has a blacklisted cipher suites. OK, ApplicationProtocol.H2BLACKLISTCOMPARATOR is expected to make the sort. If, in the future, a new application protocol (AP_NEW) has a different blacklist cipher suites, a new ApplicationProtocol.APNEWBLACKLISTCOMPARATOR would be defined. If both {HTTP2, AP_NEW} would be requested, which comparator for the sorting would be used? None of them can sort the cipher suite properly. The comparator des
Re: TLS ALPN Proposal v5
Hi, On Fri, Sep 25, 2015 at 1:45 AM, Bradford Wetmore wrote: > I think that a textual name will be better than: > > // Output: javax.net.ssl.ApplicationProtocol$1@1b9e1916 > > System.out.println(ApplicationProtocol.H2); > > and there's no UTF-8 ambiguity. Sure, but then I would just keep getNetworkSequence(), and remove getProtocolName(), since toString() is sufficient. To have to implement getProtocolName(), I see it as a non-strictly-needed burden to developers that implement ApplicationProtocol. I know of companies that want to use ALPN extensively because they use many different communication protocols internally, so it won't be a rare occasion to implement ApplicationProtocol. > http://cr.openjdk.java.net/~wetmore/8051498/webrev.15/ I gather that the Map parameter can't be solved in other ways, right ? Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
On 9/23/2015 2:33 AM, Simone Bordet wrote: Hi, On Wed, Sep 23, 2015 at 7:04 AM, Bradford Wetmore wrote: This new proposal still requires that ciphers are sorted in a way that matches the ApplicationProtocol order. Would be nice if, along with the HTTP/2 blacklist, there is a HTTP/2 comparator that sorts ciphers putting the blacklisted ones at the end. Hm...is the sample code at the end of the initial class description insufficient? Adding a comparator seems a little heavyweight in that it could require access to the ciphersuite internals and would add a lot of complexity for this one known use case. When TLSv1.3 is done, the blacklist stuff in HTTP/2 goes away. Sure, but until TLS 1.3 widely deployed, applications will have to sort the ciphers to put HTTP/2 ones before the blacklisted ones. Providing this comparator is as trivial as providing ApplicationProtocol.HTTP2BLACKLIST, so I thought to mention it. I learned something today: Collections/Arrays.sort()/others are stable. (i.e. equal elements will not be reordered as a result of the sort) My expectation of "equals" was .equals(), not return value == 0. I was concerned that such a Comparator might reorder valid H2 suites from what was passed in. Thankfully, that's not the case, so I've added this Comparator. There is a warning now about "consistency with equals()", as the Strings obvioulsy won't be equals() and thus sorted sets/maps just won't work. (See the Comparator pages for further discussion.) I also don't understand why there are 2 methods for the protocol name ? What value does it bring to have 2 methods for the same thing ? Please see the IANA registry: http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids for RFC 7301: http://www.rfc-editor.org/info/rfc7301 getProtocolName() is the IANA/IETF textual representation of the protocol name (i.e. "Protocol" column), for example "HTTP/1.1", "SPDY/3", and "HTTP/2 over TLS". I suppose toString() could be used instead, but thought it might eventually output additional ALPN value state. I don't have any concrete plans at this point. getNetworkSequence() is the identification sequence for the protocol (i.e. "Identification Sequence" column), and represents the actual byte identifiers that will travel the network in an ALPN extension. 0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1") 0x73 0x70 0x64 0x79 0x2f 0x33 ("spdy/3") 0x68 0x32 ("h2") When client wants to send the extension over the network, it grabs the ApplicationProtocols values from the SSLParameters, then calls getNetworkSequence() on each ApplicationProtocol to obtain the actual opaque ProtocolName(1..2^8-1) to send. Likewise on the server side, we match the incoming active ALPN opaque values with the list of mutually agreeable ALPN values. And of course, send back the final selected value. Sure, but application will have to implement two methods instead of one, and AFAIU the JDK implementation is never calling getProtocolName() since it's just a description for humans. I think that a textual name will be better than: // Output: javax.net.ssl.ApplicationProtocol$1@1b9e1916 System.out.println(ApplicationProtocol.H2); and there's no UTF-8 ambiguity. I've updated the webrev to include an SSLSocket test variant, and added a few more comments. http://cr.openjdk.java.net/~wetmore/8051498/webrev.14/ Hopefully things are more clear now. Thanks for your review/comments. I see now, thanks for the pointers ! Indulge me a bit more below on the Map passed as parameter to ApplicationProtocol :) IIUC, by the time we are executing the code that calls ApplicationProtocol.match(), the TLS protocol is already chosen and it's available in SSLSession. Not necessarily. This could also be called before the connection has even been attempted, say if the client wants to determine if the proposed protocols or protocol/ciphersuites it wants to use are even allowed by an ApplicationProtocol. When remains is the transient value of cipher that is being chosen. Because we already have modified the API to support the application protocol transient value (by adding SSLEngine.getHandshakeApplicationProtocol()) to be used by KeyManagers, I was wondering if we cannot either: CipherSuite is more of a Session value, so it should probably be part of the handshakeSSLSession. We could set handshakeSSLSession.getCipherSuite() before calling the ALPN selector, or pass it in as part of the Map. > A) add: String SSLEngine.getHandshakeCipherSuite(), to be used by > ApplicationProtocol That's kind of what we are doing already, but just in the ApplicationProtocol matcher instead so that it doesn't add extra methods to SSLSocket/SSLEngine. And this doesn't really help the pre-connection situation where you want to query/filter out unacceptable values. http://cr.openjdk.java.net/~wetmore/8051498/webrev.15/ 1. New H2
Re: TLS ALPN Proposal v5
Hi, On Wed, Sep 23, 2015 at 7:04 AM, Bradford Wetmore wrote: > >> This new proposal still requires that ciphers are sorted in a way that >> matches the ApplicationProtocol order. >> Would be nice if, along with the HTTP/2 blacklist, there is a HTTP/2 >> comparator that sorts ciphers putting the blacklisted ones at the end. > > Hm...is the sample code at the end of the initial class description > insufficient? Adding a comparator seems a little heavyweight in that it > could require access to the ciphersuite internals and would add a lot of > complexity for this one known use case. When TLSv1.3 is done, the blacklist > stuff in HTTP/2 goes away. Sure, but until TLS 1.3 widely deployed, applications will have to sort the ciphers to put HTTP/2 ones before the blacklisted ones. Providing this comparator is as trivial as providing ApplicationProtocol.HTTP2BLACKLIST, so I thought to mention it. >> I also don't understand why there are 2 methods for the protocol name >> ? What value does it bring to have 2 methods for the same thing ? > > Please see the IANA registry: > > http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids > > for RFC 7301: > > http://www.rfc-editor.org/info/rfc7301 > > getProtocolName() is the IANA/IETF textual representation of the protocol > name (i.e. "Protocol" column), for example "HTTP/1.1", "SPDY/3", and "HTTP/2 > over TLS". I suppose toString() could be used instead, but thought it might > eventually output additional ALPN value state. I don't have any concrete > plans at this point. > > getNetworkSequence() is the identification sequence for the protocol (i.e. > "Identification Sequence" column), and represents the actual byte > identifiers that will travel the network in an ALPN extension. > > 0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1") > 0x73 0x70 0x64 0x79 0x2f 0x33 ("spdy/3") > 0x68 0x32 ("h2") > > When client wants to send the extension over the network, it grabs the > ApplicationProtocols values from the SSLParameters, then calls > getNetworkSequence() on each ApplicationProtocol to obtain the actual opaque > ProtocolName(1..2^8-1) to send. Likewise on the server side, we match the > incoming active ALPN opaque values with the list of mutually agreeable ALPN > values. And of course, send back the final selected value. Sure, but application will have to implement two methods instead of one, and AFAIU the JDK implementation is never calling getProtocolName() since it's just a description for humans. > I've updated the webrev to include an SSLSocket test variant, and added a > few more comments. > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.14/ > > Hopefully things are more clear now. Thanks for your review/comments. I see now, thanks for the pointers ! Indulge me a bit more below on the Map passed as parameter to ApplicationProtocol :) IIUC, by the time we are executing the code that calls ApplicationProtocol.match(), the TLS protocol is already chosen and it's available in SSLSession. When remains is the transient value of cipher that is being chosen. Because we already have modified the API to support the application protocol transient value (by adding SSLEngine.getHandshakeApplicationProtocol()) to be used by KeyManagers, I was wondering if we cannot either: A) add: String SSLEngine.getHandshakeCipherSuite(), to be used by ApplicationProtocol or B) add: Map SSLEngine.getHandshakeParameters() or perhaps: Map SSLParameters.getHandshakeParameters(). Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v5
> This new proposal still requires that ciphers are sorted in a way that > matches the ApplicationProtocol order. > Would be nice if, along with the HTTP/2 blacklist, there is a HTTP/2 > comparator that sorts ciphers putting the blacklisted ones at the end. Hm...is the sample code at the end of the initial class description insufficient? Adding a comparator seems a little heavyweight in that it could require access to the ciphersuite internals and would add a lot of complexity for this one known use case. When TLSv1.3 is done, the blacklist stuff in HTTP/2 goes away. > I don't like the first parameter of ApplicationProtocol.match() to be > a Map; I personally don't like the Map either, but for situations where we don't have a connection yet (e.g. trying to reduce the set of protocols and/or ciphersuites for setEnabledCiphersuites()), this worked. Xuelei suggested the String->String map for future expansion, making it easier to add new parameters in between major releases if new ALPN protocols are introduced. (For those who aren't aware, adding classes/methods/variables/etc. is pretty much forbidden in update (minor) releases, but simply adding a new string to a Map is generally OK.) > I would prefer a full blown class at this > point, that contains all the parameters, for example: > > inner class ApplicationProtocol.Info > { > tlsProtocol > cipher > sslEngine > sessionIsResuming > etc. > } The other problem here is having a way to get at all the parameters of a connection. Enumerating them all in such a class is essentially duplicating methods that are already currently available in the SSLSession (handshakeSession) + SSLSocket/SSLEngines classes. Any future enhancements to SSLSocket/SSLEngine would have to be added here again in such a class. > I also don't understand why there are 2 methods for the protocol name > ? What value does it bring to have 2 methods for the same thing ? Please see the IANA registry: http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids for RFC 7301: http://www.rfc-editor.org/info/rfc7301 getProtocolName() is the IANA/IETF textual representation of the protocol name (i.e. "Protocol" column), for example "HTTP/1.1", "SPDY/3", and "HTTP/2 over TLS". I suppose toString() could be used instead, but thought it might eventually output additional ALPN value state. I don't have any concrete plans at this point. getNetworkSequence() is the identification sequence for the protocol (i.e. "Identification Sequence" column), and represents the actual byte identifiers that will travel the network in an ALPN extension. 0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1") 0x73 0x70 0x64 0x79 0x2f 0x33 ("spdy/3") 0x68 0x32 ("h2") When client wants to send the extension over the network, it grabs the ApplicationProtocols values from the SSLParameters, then calls getNetworkSequence() on each ApplicationProtocol to obtain the actual opaque ProtocolName(1..2^8-1) to send. Likewise on the server side, we match the incoming active ALPN opaque values with the list of mutually agreeable ALPN values. And of course, send back the final selected value. > RFC 7301 hints that the bytes to send over the network are the UTF-8 > bytes from that string. Intentional, this ApplicationProtocol class and these two contained values eliminate that problem. There is no UTF-8 to network byte conversion needed. The network sequence is hard-coded into the ApplicationProtocol and is used directly as the network bytes. The protocolName string is for user clarity. > There are still a lot of details missing, such as where is the chosen > ALPN value stored In SSLSocket/SSLEngine. If the connection is in the middle of a handshake and you need the handshake value: getHandshakeApplicationProtocol() Once the connection has finished handshaking, you can get the final/active value: getApplicationProtocol() The ALPN value is no longer in SSLSession, since it needs to be per-connection, not per session. > (and how it can be retrieved by the KeyManager, for > example), JSSE makes calls to X509KeyManagers (for SSLSockets) and X509ExtendedKeyManager (for SSLEngines). The chooseServerAlias methods are passed SSLSocket/SSLEngines for the connection being negotiated. As above, SSLSocket/SSLEngine now have: getHandshakeApplicationProtocol(); // if handshaking getApplicationProtocol(); // if not handshaking So if chooseServerAlias is called, we're in the middle of a handshake, and can get the ALPN value thusly: chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { ...deleted... ApplicationProtocol alpn = socket.getHandshakeApplicationProtocol(); ...deleted... > as well as the webrev not showing any real implementation, Yes, I'm using pseudo-code at this po
Re: TLS ALPN Proposal v5
Hi, On Sat, Sep 19, 2015 at 7:15 AM, Bradford Wetmore wrote: > Here is the new webrev: > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.12/ > > Unless there are major objections, we need to get ALPN into JDK very soon to > make JDK 9. We can still tweak the APIs if something is found later. > > Major changes: > > 1. ApplicationProtocols interface + H2 + HTTP/1.1 impls > > Both client/server call SSLParameters.setApplicationProtocols(List<>) to set > their preferences. > > The matches method can be used for: > > . During server handshaking to determine an acceptable ALPN value. > > . potentially during client preparation to eliminate known bad > ciphersuites/protocols combos. If you are going to only request TLSv1.1 and > earlier, you can disable H2 because it won't match. > > In this second case, you may not have a SSLSocket/SSLEngine yet, but you > still want to do the checks based on ciphersuite/protocol, so the second > parameters can be null. > > 2. ApplicationProtocolSelector gone. > > 3. SSLParameters AP_HTTP_1_1/AP_H2 effectively moved to > ApplicationProtocol. Selection logic added to ApplicationProtocol. > > 4. Moved ALPN values from SSLSession to SSLSocket/SSLSEngine. Added a > "handshaking in progress" variant. > > 5. SSLSession.getPeerApplicationProtocols() and > getHandshakeCipherSuiteList() are gone. These are all handled internally. This new proposal still requires that ciphers are sorted in a way that matches the ApplicationProtocol order. Would be nice if, along with the HTTP/2 blacklist, there is a HTTP/2 comparator that sorts ciphers putting the blacklisted ones at the end. I don't like the first parameter of ApplicationProtocol.match() to be a Map; I would prefer a full blown class at this point, that contains all the parameters, for example: inner class ApplicationProtocol.Info { tlsProtocol cipher sslEngine sessionIsResuming etc. } I also don't understand why there are 2 methods for the protocol name ? What value does it bring to have 2 methods for the same thing ? I would just use: class ApplicationProtocol { public String getName() } RFC 7301 hints that the bytes to send over the network are the UTF-8 bytes from that string. There are still a lot of details missing, such as where is the chosen ALPN value stored (and how it can be retrieved by the KeyManager, for example), as well as the webrev not showing any real implementation, and how exactly the ApplicationProtocol instances are called, etc. For example, client sends ["h2"], server has ["http/1.1", "h2"]. Will the instance of ApplicationProtocol corresponding to "http/1.1" be invoked at all ? If not, there is a missing step in your algorithm above, where the implementation intersects the ALPN values from both peers. Finally, I think this API may be suitable for the server, but not much for the client, which is equally important. I don't see how a client application can figure out what protocol has been chosen by the server, because there is no final notification about that and the API seems totally geared towards server "matching" more than client notification. For me this is a blocker. Can you please provide an example of how a client application would use this new API to be notified that the server has chosen protocol "foo" ? I still remain convinced that - so far - the Jetty API proposal (or the similar version that was proposed here 2-3 proposals ago) is superior to the latest ones. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
TLS ALPN Proposal v5
Hi all, On 9/7/2015 7:18 AM, Simone Bordet wrote: On Mon, Sep 7, 2015 at 5:54 AM, Bradford Wetmore wrote: In general, if the ciphersuites aren't ordered properly, that should be considered a configuration error on the part of the application(s). However, this dynamic ALPN selection approach still allows for appropriate ALPN values to be selected for each possible ciphersuite. That is, if the suites were ordered H1/H2, the ALPN value should be H1. For an example of such a selector, please see the new H2/H2+H1/H1 ApplicationProtocolSelector implementions in ApplicationProtocolSelector.java, and how they are called in ServerHandshaker.java. Here is the latest: http://cr.openjdk.java.net/~wetmore/8051498/webrev.09 Are you sure this is the latest code ? The relevant changes in ServerHandshaker are commented out. Yes, sorry for not making this clear. We've had a lot of internal discussions about the API and how to implement it: the comments in the implementation classes (sun.security.ssl) are primarily for Vinnie who has been working on the implementation. But I thought they provide some explanation as to how things might be implemented internally so I left them in the webrev. I have the feeling that ApplicationProtocolSelector (APS) is not really an application protocol selector, but a cipher suite selector. It was *(note past tense)* primarily an application protocol selector. The fact that it could also influence ciphersuite selection was an optimization to avoid using suites known not to work with a particular ALPN value, but were going to be attempted anyway (say due to a server misconfiguration). However, that has changed as the API has taken a different direction. You mentioned "session resumption" in your email, which reminded me that ALPN values should be attached to connections (i.e. SSLSocket/SSLEngine), not SSLSessions. That simplified things in several areas, especially in the Protocol Selector. We no longer have an ApplicationProtocolSelector, but rather an interface called ApplicationProtocol. These are concrete implementations of each ALPN/NPN value, and are responsible for examining the state of the connection so far and to return true if the conditions are right. These instances are passed as List to SSLParameters and then to SSLSocket/SSLEngines. We have a similar but somewhat simpler server selection algorithm than what was described earlier: Select TLS version for each ciphersuite load ALPN query with: proposed TLS version + proposed ciphersuite SSLSocket/SSLEngine + handshaking state for each ALPN value if (ALPN.matches()) temporarily assign ALPN to the handshaking SSLSocket/SSLEngine approve ciphersuite calls KeyManager for alias (can use ALPN value above) checks cipher/MAC restrictions, etc break; if no errors assign ciphersuite to handshakeSession assign ALPN to SSLSocket/SSLEngine assign handshakeSesion as the actual Session to SSLSocket/SSLEngine APS seem to conflate cipher suite selection with application protocol selection: the return value of select() actually is a 2-tuple that means (ciphers[0], protocol) so that returning the empty string or null does not have any effect on protocol selection, but only on cipher selection. To restate the point I think you raising, "Should the ALPN selection mechanism influence the TLS protocol version selection mechanism?" We had a similar discussion internally. Why would we want to encourage/enable the selection of downrev'd TLS protocol versions based on ALPN values? If we actually support the higher/stronger TLS version, IMHO we should be using them. 1. I think the stronger security benefits from the later protocols should always take priority over ALPN values and that we shouldn't be encouraging downrev'ing at all. For example, if there is a TLSv1.2/1.1/1.0 server, and we negotiated down to 1.0 just to support some ALPN value (or due to a bug in the selector), we lose GCM (v1.2) and the explicit IV (v1.1). ALPN values are application values, which I would expect to not be as security sensitive as the protocol values. 2. The server hello's protocol version is supposed to be the lower of that suggested by the client in the client hello and the highest supported by the server. Returning a lower value just to satisfy an ALPN selection would indicate to anyone listening (proxy, other connection from same VM?) that the higher TLS values are not supported on this server, which I think is incorrect. Future connections to this server might cache this lower protocol value and lose the stronger protocols. 3. I would expect that "older" ALPN values will likely still be supported in later versions of the TLS protocol. I would be surprised if something like http/1.1 would be p
Re: TLS ALPN Proposal v4
Hi, On Mon, Sep 7, 2015 at 5:54 AM, Bradford Wetmore wrote: > IMHO, the following works well. I've added a new method that contains the > ordered list of ciphersuites still to be tried which is a hint for ALPNinboked > selection, but we delay the actual ciphersuite selection until after the > ALPN value is chosen. So the algorithm is now: > > 0. Applications (especially server) might order suites with h2 > first for TLSv1.2. sslParameters.setUseCipherSuitesOrder(true) > should be called on the server to ensure those suites are > tried first. > > 1. Start Handshake. > > 2. Internal server handshaker chooses the TLS version. > > 3. The internal server handshaker finds the client/server/protocol > version intersection of the suites, loads the initial ordered > list into a new method on a SSLSession (obtained by the > getHandshakeSSLSession()), then iterates through the > ordered list of ciphersuites as usual. > > 4. For each "candidate" ciphersuite, first call the > ApplicationProtocolSelector to choose an appropriate ALPN value. > The getHandshakeSSLSession() contains the negotiated TLS > protocol version and the ordered ciphersuite list with the > "candidate" suite as the first entry. > > Note: If the client sent unsupported ALPN values, the Selector > can throw a SSLHandshakeException at this point and generate the > "no_application_protocol" alert. >inboked > The Selector can also either choose to ignore/skip the suite, or > accept the suite but choose no ALPN value. > > 5. Continue the ciphersuite selection routine as usual (check for > appropriate Keys, etc). The KeyManager now has access to the > negotiated TLS version and ALPN value along with theit > ciphersuite via the same/usual > getHandshakeSSLSession(). > This satisfies the RFC 7301 goal of having > the certificate selection mechanism use the ALPN value. > > As ciphersuites are removed from consideration via the > internal iterator in 3, they are also removed from the > corresponding SSLSession entry. > > 6. When handshaking is complete, the applications should verify > that the session parameters (protocol version, ALPN value, and > ciphersuites, etc.) are suitable, and send a HTTP-level > INADEQUATE_SECURITY (H2) if there's a problem. > > In general, if the ciphersuites aren't ordered properly, that should be > considered a configuration error on the part of the application(s). However, > this dynamic ALPN selection approach still allows for appropriate ALPN > values to be selected for each possible ciphersuite. That is, if the suites > were ordered H1/H2, the ALPN value should be H1. > > For an example of such a selector, please see the new H2/H2+H1/H1 > ApplicationProtocolSelector implementions in > ApplicationProtocolSelector.java, and how they are called in > ServerHandshaker.java. > > > Here is the latest: > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.09 Are you sure this is the latest code ? The relevant changes in ServerHandshaker are commented out. I have the feeling that ApplicationProtocolSelector (APS) is not really an application protocol selector, but a cipher suite selector. APS seem to conflate cipher suite selection with application protocol selection: the return value of select() actually is a 2-tuple that means (ciphers[0], protocol) so that returning the empty string or null does not have any effect on protocol selection, but only on cipher selection. You can for example implement APS without even looking at the application protocol, just to exclude dynamically certain ciphers from selection (e.g. based on performance or remote IP). I don't understand exactly bullet 5 above. If APS chooses a cipher and a protocol, but this is not a valid combination for the KeyManager to select a certificate, what happens ? That APS is called again, right ? But what if that was the last cipher ? Then APS won't be called again. How can an application know that it is done trying to select a protocol and that the protocol it chose is actually used ? I guess this also brings to bullet 6: how can an application verify that the N-tuple chosen is actually a correct one ? Is there an additional callback that is being invoked (that applications can implement) before the ServerHello is actually sent to the client ? A very important point that I saw in the comments is support for TLS session resumption - this has been asked multiple times by Jetty users that were using Jetty's ALPN (and we implemented it). Just make sure that whatever proposal enters JDK 9, session resumption is supported. My preference would go to the previous proposal (akin to Jetty - I know I am biased) where protocol selection was happening in isolation *after* cipher selection. It is much simpler, and has
TLS ALPN Proposal v4
Hi all, Simone/Xuelei/I wrote: Per my understanding, application protocol should be negotiated before >>>cipher suite and protocol version negotiated. >> >>This is not possible for HTTP/2. >>Application protocol negotiation MUST happen*after* the TLS protocol >>and the TLS cipher are negotiated. > >Yes, that's my understanding as well. What are the behaviors of other vendors? Can we ask for a clarification from both HTTP/2 and TLS WG? and then Simone wrote: I support Xuelei in that you should ask confirmation to the HTTP/2 editor. Thanks for the encouragement, Simone. As you've probably heard, I did contact the IETF HTTP/2 working group and posed several questions about expected usage[1]. I'm combining those responses plus several other points that came up since the last discussion. This may be repeating some things already said, but serves as useful background info for those here that might not be following closely: 1. HTTP/2 (aka H2) and TLSv1.3 were developed in parallel. The H2 designers wanted the ciphersuite restrictions in the proposed TLSv1.3. But since TLSv1.3 wasn't ready, they compromised by allowing TLSv1.2 to be used but with the restriction that only those ciphersuites that were expected/allowed for TLSv1.3 could be used. That is, there is a blacklist of ciphersuites for TLSv1.2: if a suite is present, it can't be used in TLSv1.2. (e.g. no RSA KeyExchange, no CBC-based block ciphers, no stream ciphers, etc.) 2. RFC 7301 says in a couple places that it would be advantageous to have the chosen ALPN value used by the certificate selection mechanism (See sections 1 & 4). Without a radical rewrite of the current selection mechanism (n-tuple), that means ALPN selection should be done before the ciphersuite is selected. We could also check after, but I have a different approach (see below). 3. From the H2 working group discussion, a server instance will very likely support both H2 and legacy HTTP/1.1. This means for servers that prefer H2, any iterative cipher selection mechanisms needs to try the H2-specific ciphersuites first, then legacy non-H2 suites. That is, the suites must be ordered appropriately so that the ciphersuite selection mechanism won't attempt a blacklisted suite before exhausting all H2-acceptable suites. This ordering can be requested today in JSSE by the server calling sslParameters.setUseCipherSuitesOrder(true). This particular point won't matter when TLSv1.3 is in play, as we wouldn't try those suites at all. 4. Clients may not know whether a server will be H2 or HTTP/1.1, so they should also appropriately sort ciphersuites based on their ALPN preferences. (H2 first, H1 second.) 5. For our SunJSSE, while I think our current enabled list order is generally ok, we should probably reorder the ciphersuite priorities so that the TLSv1.3 acceptable suites are up front, with the others following. This prefers forward secrecy ciphersuites to our current ordering. I am thinking we should probably do this for JDK 9, and maybe backport as well. The current webrev (link below) doesn't have this yet. 6. To avoid downgrade attacks, applications should not provide for a fallback mechanism. This includes ALPN selection. Connection#1: {"h2", "http/1.1"} // Don't make two connections. Connection#2: {"http/1.1"} POODLE was a good example where allowing fallbacks bit hard. Of course, we can't control this at the JSSE layer, it's the application layer responsibility. Tradeoff between A) change radically the OpenJDK implementation to support an iterative processing of TLS protocols, extensions (all of them), ciphers, aliases, etc. that would be future proof (if that is even possible) and B) hack in just enough of what is needed to support H2 today (for which we already have working examples) ? Given where we are now schedule wise (integration currently due at the end of September), and that SunJSSE is such an iterative implementation, coming up with a multi-selector API is likely beyond what we can do at this point. (webrev link below). IMHO, the following works well. I've added a new method that contains the ordered list of ciphersuites still to be tried which is a hint for ALPN selection, but we delay the actual ciphersuite selection until after the ALPN value is chosen. So the algorithm is now: 0. Applications (especially server) might order suites with h2 first for TLSv1.2. sslParameters.setUseCipherSuitesOrder(true) should be called on the server to ensure those suites are tried first. 1. Start Handshake. 2. Internal server handshaker chooses the TLS version. 3. The internal server handshaker finds the client/server/protocol version intersection of the suites, loads the initial ordered list into a new method on a SSLSession (obtained by the getHandshakeSSLSession()), then iterates through the ordered list of ciph
Re: TLS ALPN Proposal v3
Hi, On Fri, Jul 24, 2015 at 9:38 PM, Jason Greene wrote: > The truth is that there is a gap between the current capabilities of TLS > stacks and what the specs are trying to achieve. Ultimately the desired > semantic the specs are trying to achieve is that every ALPN protocol can have > its own TLS requirements. In this case H2 wanted TLS 1.3 behavior before it > was released. This is basically social engineering, the newer protocol is the > carrot for updating your TLS stack. However there are other potential > scenarios, such as protocols which desire to be encrypted but unauthenticated. > > To truly resolve this gap in a future proof manner, TLS stacks need to > support cipher suite selection based on the combination of ALPN protocol and > TLS version. Had TLS 1.3 been released before H2, we would not need to choose the cipher suite based on ALPN + TLS version, because any TLS 1.3 cipher would do, and the support for ALPN would be much simpler (probably akin to SNI). The current situation is a temporary glitch produced by the H2 specification, and requires clients and servers to implement hacks to support H2 (sorting ciphers, etc.). Another thing to remember is that clients and servers may implement different ways of selecting the various TLS parameters. While server have to choose among TLS protocol versions, ciphers, application protocols, etc., the client can only react to what the server chose. For a TLS implementation, it may be simpler to implement a client (like browsers do) than a server; I think the server algorithm would work for clients, but not necessarily viceversa. Tradeoff between A) change radically the OpenJDK implementation to support an iterative processing of TLS protocols, extensions (all of them), ciphers, aliases, etc. that would be future proof (if that is even possible) and B) hack in just enough of what is needed to support H2 today (for which we already have working examples) ? Would it be possible to fit the ALPN solution that would have been implemented if TLS 1.3 was out before HTTP/2 to support the current situation ? -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v3
Am Fri, 24 Jul 2015 14:38:36 -0500 schrieb Jason Greene : > The truth is that there is a gap between the current capabilities of > TLS stacks and what the specs are trying to achieve. Ultimately the > desired semantic the specs are trying to achieve is that every ALPN > protocol can have its own TLS requirements. Not sure if this is desireable, it was I guess the motivation, but see below: > In this case H2 wanted > TLS 1.3 behavior before it was released. This is basically social > engineering, the newer protocol is the carrot for updating your TLS > stack. However there are other potential scenarios, such as protocols > which desire to be encrypted but unauthenticated. I think it is fine to define a minimum security level together with an application protocol. If the protocol is supported the TLS stack needs to provide the desired features, and given the fact that it will negotiate the "best" protocol version you can just deny H2 if the cipher is not good enough. However: > To truly resolve this gap in a future proof manner, TLS stacks need > to support cipher suite selection based on the combination of ALPN > protocol and TLS version. If each ALPN can select different security parameters, this would be a configuration and interop nightmare. Dont go that route. I would not provide any features to enable it, nor require them. Having said that H2 should really be less demanding. (not sure whats the best place to discuss it, not part of the H2 group). Gruss Bernd
Re: TLS ALPN Proposal v3
> On Jul 9, 2015, at 12:02 PM, Bradford Wetmore oracle.com> wrote: > > Ok, I'll check with the HTTP/2 group tomorrow. It appears the proper > list is: Hi Brad, Your post to the H2 group got my attention, so I thought as a user of JSSE for an H2 implementation I should reply additionally here. My responses are inline: -snip- > > On 7/9/2015 8:29 AM, Simone Bordet wrote: >> Hi, >> >> On Thu, Jul 9, 2015 at 1:42 AM, Bradford Wetmore >> wrote: >> >>> Xuelei/Simone wrote: > Per my understanding, application protocol should be negotiated before > cipher suite and protocol version negotiated. This is not possible for HTTP/2. Application protocol negotiation MUST happen *after* the TLS protocol and the TLS cipher are negotiated. >>> >>> Yes, that's my understanding as well. >> >> Well, to be precise, either the application protocol is negotiated >> after the cipher (and you need cipher sorting to influence the cipher >> selection towards the application protocol you would like to choose), >> or it must happen at the same time - that is, cipher and application >> protocol must be chosen at the same time - but this implies that the >> action of choosing that tuple may be invoked multiple times with the >> current OpenJDK implementation. >> >> Note that I don't know if the fact that cipher selection is an >> iterative process is an OpenJDK implementation detail. >> If other implementations are not iterative, then perhaps they have a >> single moment where the tuple is chosen. >> >> I support Xuelei in that you should ask confirmation to the HTTP/2 editor. >> Also, remember that Firefox, Chrome, OpenSSL, nghttp2, etc. are all >> open source and their code is available to verify the behavior. The truth is that there is a gap between the current capabilities of TLS stacks and what the specs are trying to achieve. Ultimately the desired semantic the specs are trying to achieve is that every ALPN protocol can have its own TLS requirements. In this case H2 wanted TLS 1.3 behavior before it was released. This is basically social engineering, the newer protocol is the carrot for updating your TLS stack. However there are other potential scenarios, such as protocols which desire to be encrypted but unauthenticated. To truly resolve this gap in a future proof manner, TLS stacks need to support cipher suite selection based on the combination of ALPN protocol and TLS version. Until then h2 implementations have to rely on both peers sorting, with many clients taking the additional step of post-validating the selected cipher. With NSS this is accomplished using an API that that categorizes cipher aspects (e.g. not a block cipher etc). This approach, which is arguably a hack can lead to interop errors if the administrator has tried to influence cipher suite selection for other reasons. As an example, its quite common to use an abstract indicator (e.g GNU TLS priority strings & openssl cipher strings), and these may inadvertently disable ciphers now required for h2 interop. >> >>> IIUC, the HTTP/2 blacklist is just strongly recommended ("...SHOULD NOT use >>> any of the cipher suites...black list"), but not required. Such potential >>> peers must also support such a configuration, but in general, it will not. >>> See section 9.2.2. I think it's still considered compliant to the spec tho. >> >> From experience, if a server breaks this SHOULD NOT, it won't work >> with any browser. >> We had our share of pain trying to figure out interoperability with >> browsers for Jetty :) >> Sure, it's a SHOULD NOT, but it's like a MUST NOT if you want a >> browser to talk to a Java server (or a Java client to talk to a >> current HTTP/2 server). Yes exactly. Firefox and Chrome enforce the SHOULDs, and if negotiation results in a cipher that violates the SHOULDs you not only fail to establish an h2 connection, you fail to establish any connection at all. >> >>> Simone wrote two different ways to do selection: >>> 1) ... so that TLS protocol, cipher (possibly the alias too) and application protocol are chosen together, or 2) we separate the TLS protocol and cipher negotiation (and alias) in one step, and we perform application protocol selection afterwards. >>> >>> Rather than completely redo the JSSE selection mechanism with the >>> (version/ciphersuite/ALPN)-tuple idea (which would be a much more involved >>> API and behavior change), I think the more straightforward solution (2) is >>> better. >> >> That's what we do in Jetty's ALPN implementation too. >> Be aware that it rules out some possibility such as those mentioned by >> Michael from RFC 7301. I’d highly recommend exploring 1) because its quite possible you will end up needing to go that route anyway based on the above reasoning. -snip- >> >>> http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/SSLEngineAlpnHttp2.java.html >>> >>> See the configuration in c
Re: TLS ALPN Proposal v3
Ok, I'll check with the HTTP/2 group tomorrow. It appears the proper list is: ietf-http...@w3.org Is that correct? Brad On 7/9/2015 8:29 AM, Simone Bordet wrote: Hi, On Thu, Jul 9, 2015 at 1:42 AM, Bradford Wetmore wrote: SSLParameters is a configuration class which is used to configure SSLSockets/SSLEngines. SSLSession/ExtendedSSLSession is a class which holds negotiated Session values. getReceivedApplicationProtocols() represents the Application Protocol values received from the peer, thus belongs in the SSLSession. I suggest to rename ExtendedSSLSession.getRequestedApplicationProtocols() to ExtendedSSLSession.getPeerApplicationProtocols() The protocols are not really "requested", they are more "offered", but IIUC the reason to add "Requested" to this method is to distinguish it from SSLParameters.getApplicationProtocols() which returns the local protocols, and in that spirit I think "Peer" is better for ExtendedSSLSession. Xuelei/Simone wrote: Per my understanding, application protocol should be negotiated before cipher suite and protocol version negotiated. This is not possible for HTTP/2. Application protocol negotiation MUST happen *after* the TLS protocol and the TLS cipher are negotiated. Yes, that's my understanding as well. Well, to be precise, either the application protocol is negotiated after the cipher (and you need cipher sorting to influence the cipher selection towards the application protocol you would like to choose), or it must happen at the same time - that is, cipher and application protocol must be chosen at the same time - but this implies that the action of choosing that tuple may be invoked multiple times with the current OpenJDK implementation. Note that I don't know if the fact that cipher selection is an iterative process is an OpenJDK implementation detail. If other implementations are not iterative, then perhaps they have a single moment where the tuple is chosen. I support Xuelei in that you should ask confirmation to the HTTP/2 editor. Also, remember that Firefox, Chrome, OpenSSL, nghttp2, etc. are all open source and their code is available to verify the behavior. IIUC, the HTTP/2 blacklist is just strongly recommended ("...SHOULD NOT use any of the cipher suites...black list"), but not required. Such potential peers must also support such a configuration, but in general, it will not. See section 9.2.2. I think it's still considered compliant to the spec tho. From experience, if a server breaks this SHOULD NOT, it won't work with any browser. We had our share of pain trying to figure out interoperability with browsers for Jetty :) Sure, it's a SHOULD NOT, but it's like a MUST NOT if you want a browser to talk to a Java server (or a Java client to talk to a current HTTP/2 server). Simone wrote two different ways to do selection: 1) ... so that TLS protocol, cipher (possibly the alias too) and application protocol are chosen together, or 2) we separate the TLS protocol and cipher negotiation (and alias) in one step, and we perform application protocol selection afterwards. Rather than completely redo the JSSE selection mechanism with the (version/ciphersuite/ALPN)-tuple idea (which would be a much more involved API and behavior change), I think the more straightforward solution (2) is better. That's what we do in Jetty's ALPN implementation too. Be aware that it rules out some possibility such as those mentioned by Michael from RFC 7301. Also, it is critical to detail how the mechanism work. Example implementations for SSLFunction would be great to have: the typical HTTP/2 case is to select the application protocol based on the TLS protocol and the already negotiated cipher. I have a "working" test example which shows how the ALPN APIs can be used for HTTP/2 clients and servers. It is a minor configuration tweak to the jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java test that we use as the basis for JSSE SSLEngine testing. Do you have a Java 9 server that can negotiate h2 with current browsers ? http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/SSLEngineAlpnHttp2.java.html See the configuration in createSSLEngines() around line 265 and 280. http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/Http2ApplicationSelector.java.html Note the HTTP/2 blacklist and reordering code. The code is not actually "working" yet (haven't merged API/impl repos yet), but shows how to configure/use this API. Just a reminder that the cipher blacklist is only valid for TLS 1.2. For example, if the negotiated TLS protocol is 1.3, there is no need to look at the ciphers (nor to sort them). Thanks !
Re: TLS ALPN Proposal v3
Hi, On Thu, Jul 9, 2015 at 1:42 AM, Bradford Wetmore wrote: > SSLParameters is a configuration class which is used to configure > SSLSockets/SSLEngines. SSLSession/ExtendedSSLSession is a class which holds > negotiated Session values. getReceivedApplicationProtocols() represents the > Application Protocol values received from the peer, thus belongs in the > SSLSession. I suggest to rename ExtendedSSLSession.getRequestedApplicationProtocols() to ExtendedSSLSession.getPeerApplicationProtocols() The protocols are not really "requested", they are more "offered", but IIUC the reason to add "Requested" to this method is to distinguish it from SSLParameters.getApplicationProtocols() which returns the local protocols, and in that spirit I think "Peer" is better for ExtendedSSLSession. > Xuelei/Simone wrote: >>> Per my understanding, application protocol should be negotiated before >>> cipher suite and protocol version negotiated. >> >> This is not possible for HTTP/2. >> Application protocol negotiation MUST happen *after* the TLS protocol >> and the TLS cipher are negotiated. > > Yes, that's my understanding as well. Well, to be precise, either the application protocol is negotiated after the cipher (and you need cipher sorting to influence the cipher selection towards the application protocol you would like to choose), or it must happen at the same time - that is, cipher and application protocol must be chosen at the same time - but this implies that the action of choosing that tuple may be invoked multiple times with the current OpenJDK implementation. Note that I don't know if the fact that cipher selection is an iterative process is an OpenJDK implementation detail. If other implementations are not iterative, then perhaps they have a single moment where the tuple is chosen. I support Xuelei in that you should ask confirmation to the HTTP/2 editor. Also, remember that Firefox, Chrome, OpenSSL, nghttp2, etc. are all open source and their code is available to verify the behavior. > IIUC, the HTTP/2 blacklist is just strongly recommended ("...SHOULD NOT use > any of the cipher suites...black list"), but not required. Such potential > peers must also support such a configuration, but in general, it will not. > See section 9.2.2. I think it's still considered compliant to the spec tho. >From experience, if a server breaks this SHOULD NOT, it won't work with any browser. We had our share of pain trying to figure out interoperability with browsers for Jetty :) Sure, it's a SHOULD NOT, but it's like a MUST NOT if you want a browser to talk to a Java server (or a Java client to talk to a current HTTP/2 server). > Simone wrote two different ways to do selection: > >> 1) ... so that TLS protocol, cipher (possibly the alias too) and >> application protocol are chosen together, or >> 2) we separate the TLS protocol and >> cipher negotiation (and alias) in one step, and we perform application >> protocol selection afterwards. > > Rather than completely redo the JSSE selection mechanism with the > (version/ciphersuite/ALPN)-tuple idea (which would be a much more involved > API and behavior change), I think the more straightforward solution (2) is > better. That's what we do in Jetty's ALPN implementation too. Be aware that it rules out some possibility such as those mentioned by Michael from RFC 7301. >> Also, it is critical to detail how the mechanism work. >> >> Example implementations for SSLFunction would be great to have: the >> typical HTTP/2 case is to select the application protocol based on the >> TLS protocol and the already negotiated cipher. > > I have a "working" test example which shows how the ALPN APIs can be used > for HTTP/2 clients and servers. It is a minor configuration tweak to the > jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java test that we use as > the basis for JSSE SSLEngine testing. Do you have a Java 9 server that can negotiate h2 with current browsers ? > http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/SSLEngineAlpnHttp2.java.html > > See the configuration in createSSLEngines() around line 265 and 280. > > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/Http2ApplicationSelector.java.html > > Note the HTTP/2 blacklist and reordering code. > > The code is not actually "working" yet (haven't merged API/impl repos yet), > but shows how to configure/use this API. Just a reminder that the cipher blacklist is only valid for TLS 1.2. For example, if the negotiated TLS protocol is 1.3, there is no need to look at the ciphers (nor to sort them). Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v3
On 7/9/2015 7:42 AM, Bradford Wetmore wrote: > Xuelei/Simone wrote: >>> Per my understanding, application protocol should be negotiated before >>> cipher suite and protocol version negotiated. >> >> This is not possible for HTTP/2. >> Application protocol negotiation MUST happen *after* the TLS protocol >> and the TLS cipher are negotiated. > > Yes, that's my understanding as well. What are the behaviors of other vendors? Can we ask for a clarification from both HTTP/2 and TLS WG? Thanks, Xuelei
TLS ALPN Proposal v3
Greetings, Xuelei wrote: > I think Brad would consider our information for his design. I did, and thanks for the all of the detailed discussion, Simone/Michael/Xuelei. I've taken into account the feedback from the previous discussion back in June. Here is v3 of the public ALPN API. http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/ Main points: 1. SSLBase/SSLFunction gone 2. New ApplicationProtocolSelector class with two select methods: select(SSLSocket), select(SSLEngine) throws SSLHandshakeException instead of SSLProtocolException (oops/sorry!) 3. "@since 1.9" changes to "@since 9" (changes for JDK 9) 4. SSLSession.getCipherSuite() a getHandshakeSession.getCipherSuite() no longer dynamic value ALPN Selector will be called after suite has been set. 5. Psuedo code in the SunJSSEimplementation for ALPN selection. 6. Working HTTP 2 & 1.1 client/server configuration example (test). Various responses, I'll try to attribute the original author correctly. :) If I missed a point you feel is important, please restate. Simone wrote: >> ExtendedSSLSession >> public List getReceivedApplicationProtocols() { > > This is a constant once the application protocols are received, so it > can be surely retrieved from SSLParameters. > I don't understand why it is replicated here ? SSLParameters is a configuration class which is used to configure SSLSockets/SSLEngines. SSLSession/ExtendedSSLSession is a class which holds negotiated Session values. getReceivedApplicationProtocols() represents the Application Protocol values received from the peer, thus belongs in the SSLSession. One other point that is not always obvious to folks is that a single SSLParameters object can be used to initialize multiple SSLEngine/SSLSocket objects. You can configure sockets as part of a customer SSLSocketFactory, or by using SSLParameters. Regarding the old SSLFunction/SSLBase: > I'm not sure about this one being a marker interface. > I could understand if it extracted the common functionality of > SSLEngine and SSLSocket, but a marker interface does not really add > much, and perhaps I would prefer it entirely gone. Previously it was suggested that the ALPN selector could be a @FunctionalInterface (Simone?) and generic (Sean?), so I was trying to accommodate that. Both are gone now. We could still introduce a SSLBase with these methods: ---begin--- public abstract String[] getEnabledCipherSuites() public abstract void setEnabledCipherSuites(String[] suites) public abstract String[] getEnabledProtocols() public abstract void setEnabledProtocols(String[] protocols) public abstract boolean getEnableSessionCreation() public abstract void setEnableSessionCreation(boolean flag) public SSLSession getHandshakeSession() minor tweak for SSLSocket about getSession() public abstract void setNeedClientAuth(boolean need) public abstract boolean getNeedClientAuth() public abstract SSLSession getSession() minor tweak needed in SSLSocket public abstract String[] getSupportedCipherSuites() public abstract String[] getSupportedProtocols() public abstract boolean getUseClientMode() public abstract void setUseClientMode(boolean mode) public abstract boolean getWantClientAuth() public abstract void setWantClientAuth(boolean want) public SSLParameters getSSLParameters() public void setSSLParameters(SSLParameters params) ---end--- which would eliminate the SSLEngine/SSLSocket-specific methods in ApplicationProtocolSelector.java, but I'm not sure it's worth the effort to isolate all these methods just to lose one method in the ALPN selector. To do this as a @FunctionInterface, I wanted to use java.util.function.Function, but needed it to return a checked Exception. Anyway, it's gone for now. > On the same note, why is SSLFunction generic at all ? This was an internal idea that in the future there might be additional SSL functions we could do as lambdas. Xuelei/Simone wrote: >> Per my understanding, application protocol should be negotiated before >> cipher suite and protocol version negotiated. > > This is not possible for HTTP/2. > Application protocol negotiation MUST happen *after* the TLS protocol > and the TLS cipher are negotiated. Yes, that's my understanding as well. Simone wrote: > Currently, IIUC, the cipher selection is an iterative process where a > cipher is attempted until one is negotiated. Yes. Simone wrote: > Yesterday a browser could open a page and browse the site over > http/1.1. From my readings of the RFC, I agree with Simone and think the intent of the RFC writers was that if a sufficient connection state does not exist for HTTP/2, then it should be possible to fallback to something else instead of killing the connection. If the implementation wants to insist on HTTP/2 only, the ALPN selector can certainly enforce that, but it needs to try the H2 ciphersuites first. With this API, we c
Re: TLS ALPN Proposal v2
On 6/5/2015 11:16 PM, Simone Bordet wrote: > Hi, > > On Fri, Jun 5, 2015 at 4:46 PM, Xuelei Fan wrote: >> If H2 is not supported, SPDY/3.1 would be attempted, of SPDY/3.1 is not >> supported HTTP/1.1 would be attempted. > > Correct. > >> If H2 is supported in both side, >> but H2 does not work, it is a H2 problem that need to be addressed in H2 >> layer. > > If both client and server have "h2" as a potentially supported > protocol, but the cipher to use h2 is not valid, then h2 is not > supported for that particular connection. > At that point, like you said above, spdy/3.1 is attempted, and so on. > ;-) That's the point we cannot agree with each other at present. >> No application protocol fallback in TLS layer if the application >> protocol is supported. > > Your interpretation of "supported" is not what browser and server > implementors mean :) > ;-) maybe. It's not my expertise. >> I understand your concerns now. I think we have different understanding >> of the ALPN protocols. It's a good thing to understand the actually >> requirements of the industry, I think. Thank you! > > So where does this leave us know ? > ;-) I think Brad would consider our information for his design. > By the way, while I have participated in the RFC 7540 discussions, and > implemented HTTP/2 in Jetty to be interoperable with a variety of > other clients and servers, feel free to ask clarifications to the RFC > 7540 and RFC 7301 mailing lists, or even directly to the editors of > those RFCs; they are typically open to answer questions, I guess > especially so if they come from the OpenJDK team that is implementing > those specification. > Yes. It would be help to know the implementation of other SSL/TLS vendors, too. Thanks, Xuelei
Re: TLS ALPN Proposal v2
Hi, On Fri, Jun 5, 2015 at 4:46 PM, Xuelei Fan wrote: > If H2 is not supported, SPDY/3.1 would be attempted, of SPDY/3.1 is not > supported HTTP/1.1 would be attempted. Correct. > If H2 is supported in both side, > but H2 does not work, it is a H2 problem that need to be addressed in H2 > layer. If both client and server have "h2" as a potentially supported protocol, but the cipher to use h2 is not valid, then h2 is not supported for that particular connection. At that point, like you said above, spdy/3.1 is attempted, and so on. > No application protocol fallback in TLS layer if the application > protocol is supported. Your interpretation of "supported" is not what browser and server implementors mean :) > I understand your concerns now. I think we have different understanding > of the ALPN protocols. It's a good thing to understand the actually > requirements of the industry, I think. Thank you! So where does this leave us know ? By the way, while I have participated in the RFC 7540 discussions, and implemented HTTP/2 in Jetty to be interoperable with a variety of other clients and servers, feel free to ask clarifications to the RFC 7540 and RFC 7301 mailing lists, or even directly to the editors of those RFCs; they are typically open to answer questions, I guess especially so if they come from the OpenJDK team that is implementing those specification. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
On 6/5/2015 10:11 PM, Simone Bordet wrote: > On Fri, Jun 5, 2015 at 2:36 PM, Xuelei Fan wrote: >> > See more inlines, please. >> > >> > Please help on one question I'm not sure of. Per HTTP/2 specification, >> > Does H2 server allow fallback to HTTP/1.1 if client requests a HTTP/2 >> > connection? I did not find the answer from RFC 7540. > Yes. > The intended behavior is exactly to fall back to http/1.1 if h2 cannot > be negotiated. > > This is implicitly explained in the ALPN spec, RFC 7301, see > http://tools.ietf.org/html/rfc7301#section-3.2. > This section says: "It is expected that a server will have a list of protocols that it supports, in preference order, and will only select a protocol if the client supports it." I may have different understanding. If server support H2, H2 should be used. No fallback is expected. Support does not means the protocol must work in any cases. Fallback to use HTTP/1.1 should be a spec of HTTP/2, rather than TLS protocols. I would like to see an evidence in HTTP/2 spec that H2 server allow fallback to HTTP/1.1. >> > In TLS, if client requests to negotiate TLS v1.2, and server supports >> > TLS 1.2, it is not allowed to fallback to TLS v1.1. If there is not >> > suitable cipher suite to negotiate TLS 1.2, the connection would be >> > terminated immediately. I'm not sure what's the spec for HTTP/2, >> > HTTP/1.1 and HTTP/1.0. > HTTP/2 does not behave like TLS in this sense. > > ALPN is for *application* protocol selection. > A client can send: > > ["h2", "spdy/3.1", "http/1.1"] > > Failing h2, spdy/3.1 is attempted, which is a completely different > protocol, with different restrictions, etc. > "Failing" is confusing. Support does not means the protocol must work in any cases. But failing means that. I would use "support" for the description as what RFC 7301 does. If H2 is not supported, SPDY/3.1 would be attempted, of SPDY/3.1 is not supported HTTP/1.1 would be attempted. If H2 is supported in both side, but H2 does not work, it is a H2 problem that need to be addressed in H2 layer. No application protocol fallback in TLS layer if the application protocol is supported. I understand your concerns now. I think we have different understanding of the ALPN protocols. It's a good thing to understand the actually requirements of the industry, I think. Thank you! Xuelei
Re: TLS ALPN Proposal v2
Hi, On Fri, Jun 5, 2015 at 2:36 PM, Xuelei Fan wrote: > See more inlines, please. > > Please help on one question I'm not sure of. Per HTTP/2 specification, > Does H2 server allow fallback to HTTP/1.1 if client requests a HTTP/2 > connection? I did not find the answer from RFC 7540. Yes. The intended behavior is exactly to fall back to http/1.1 if h2 cannot be negotiated. This is implicitly explained in the ALPN spec, RFC 7301, see http://tools.ietf.org/html/rfc7301#section-3.2. > In TLS, if client requests to negotiate TLS v1.2, and server supports > TLS 1.2, it is not allowed to fallback to TLS v1.1. If there is not > suitable cipher suite to negotiate TLS 1.2, the connection would be > terminated immediately. I'm not sure what's the spec for HTTP/2, > HTTP/1.1 and HTTP/1.0. HTTP/2 does not behave like TLS in this sense. ALPN is for *application* protocol selection. A client can send: ["h2", "spdy/3.1", "http/1.1"] Failing h2, spdy/3.1 is attempted, which is a completely different protocol, with different restrictions, etc. > Per RFC 7540, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 is a mandatory > cipher suite for H2. No. It's a mandatory cipher for *TLS 1.2 deployments only*. If the client uses TLS 1.4 does not have to have that cipher, and hence there can be an empty intersection of ciphers with the server. That cipher is only mentioned because all the mandatory TLS 1.2 ciphers have been blacklisted by HTTP/2. If TLS 1.3 was specified before HTTP/2, that cipher would not even be mentioned, and the HTTP/2 spec would have referenced only TLS 1.3 as mandatory: no black lists, no special cipher. The TLS and HTTP specifications will evolve independently, and there cannot be a requirement that whenever TLS changes, an update to HTTP/2 must be published. Hope this clarifies. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
See more inlines, please. Please help on one question I'm not sure of. Per HTTP/2 specification, Does H2 server allow fallback to HTTP/1.1 if client requests a HTTP/2 connection? I did not find the answer from RFC 7540. In TLS, if client requests to negotiate TLS v1.2, and server supports TLS 1.2, it is not allowed to fallback to TLS v1.1. If there is not suitable cipher suite to negotiate TLS 1.2, the connection would be terminated immediately. I'm not sure what's the spec for HTTP/2, HTTP/1.1 and HTTP/1.0. On 6/5/2015 4:05 PM, Simone Bordet wrote: > Hi, > > On Fri, Jun 5, 2015 at 6:11 AM, Xuelei Fan wrote: >> I think it should be true that if a server can negotiate h2, the server >> MUST support H2 and the enabled cipher suites MUST contains at least one >> H2 required cipher suite. Otherwise, it's bug in server side. >> >> It's instinctive that if a server support h2, and then the application >> protocol selector would select h2. If the server declare to support h2, >> but no suitable cipher suites, it may be a server bug. The connection >> should be terminated rather than downgrade to HTTP/1.1, I think. > > The server may support h2, but there is no valid h2 cipher in common > with the client, so it's not a server bug. Per RFC 7540, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 is a mandatory cipher suite for H2. The case is not expected that there is no cipher in common. It's a fatal error if there is no cipher in common. > In that case, client and server cannot speak h2, but nothing forbids > them to speak http/1.1. > It would be really bad for the user experience if both client and > server could speak http/1.1, but they don't just because they can't > speak h2. > They would appear like spoiled children :) > > The point of ALPN is to *negotiate* a protocol, not to give up on the > first failure. > I cannot agree, ALPN is not a mechanism to tolerant incorrect protocol implementation. If H2 is bad implemented or bad deployed, terminate the connection, rather than fallback to HTTP/1.1 is a better and safer user experience. >> Is it possible that client only request h2_valid_cipher_a, but server >> only support h2_valid_cipher_b, and as would result in that there is no >> common cipher suites between client and server for H2? It is possible, >> surely. Should the connection be terminated, or fall-back to HTTP/1.1? >> I think connection should be terminated immediately, rather than >> fall-back to HTTP/1.1. Per page 68, section 9.2.2, RFC 7540, there is >> an mandatory cipher suite (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) MUST >> be supported in both client and server. If there is no common cipher >> suites between client and server for H2, it is actually a bad >> deployments, and the connection should be terminated rather than >> fall-back to HTTP/1.1. Version downgrading is not a safe behavior, I think. > > That is not what the 7540 expert group thinks, certainly not what > browsers do, and certainly not what servers do. > The behavior is to speak http/1.1 (or the next protocol that fits). > Hm, that what I want to know. Do you mean that RFC 7540 expect a H2 server fall-back to HTTP/1.1 from HTTP/2 request? See also my question in the beginning. Per my understanding, if server does not support H2, downgrade to use HTTP/1.1 is allowed. But if the server supports H2, is it still allowed to use HTTP/1.1? That may be the key for our discussion. >> That's an interesting case. The question actually is: between requested >> application protocols and cipher suites, which preference should be >> respected at first. Because it is a application requirement that a >> certain cipher suite is not suitable to H2, I think requested >> application protocols should be respected at first. >> >> My scenarios look like: >> 1. client sends [h2_invalid_cipher, h2_valid_cipher] and h2/http/1.1 >> application protocol. >> 2. server selects h2 (we need an API for the selection). >> 3. server selects h2_valid_cipher because of h2 is selected previously >> (may need an API for the selection). > > Does not work. How do you know that server has h2_valid_cipher available ? > If it does not, you have picked h2, and an invalid cipher (breaks > 7540), or you terminate the connection while instead you could speak > http/1.1. > TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 is a mandatory cipher suite for H2. Per RFC 7540, "... To avoid this problem causing TLS handshake failures, deployments of HTTP/2 that use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE] with the P-256 elliptic curve" >> In #1, if there is no h2_valid_cipher requested, it is a bug in client side. >> In #3, if there is no h2_valid_cipher that can be negotiated, it is a >> bug in server side, or the client does not enabled the mandatory cipher >> suite (a bug in client). > > Does not work. > The client may be using TLS 1.4, where that mandatory cipher suite > (it's mandatory only for TLS 1.2 deployments) has been
Re: TLS ALPN Proposal v2
I've just noticed the SSLParameters.setUseCipherSuitesOrder() method. I guess this can be used to enforce a higher priority for the h2 compatible ciphers on the server side. On the new API, I'm not sure about the SSLBase, SSLFunction construct either. I don't think it is very clear, and if its purpose is just to allow use of lambdas, then I think the original approach was better. Michael. On 05/06/15 05:11, Xuelei Fan wrote: Hi, See inlines, please. On 6/5/2015 5:30 AM, Simone Bordet wrote: Hi, On Thu, Jun 4, 2015 at 6:50 PM, Xuelei Fan wrote: Hm, I see your point now. But I may not agree with your ALPN "MUST happen after" protocol/cipher suite negotiation conclusion. I parse this section as, a H2 server must be strong enough(comply to RFC7540), and a H2 client must also be strong enough (comply to RFC7540). Otherwise, both side may terminated the connection, and cannot declare as complying to H2. It is not necessary for an application protocol selector to detect whether a H2 server/client comply to H2 or not. If "H2" is requested, it means that the client supports H2. Otherwise, it's a client application bug. Not that simple, see below. If "H2" is selected by a selected, it means that the selected server supports H2. Otherwise, it is a selector implementation bug. If something wrong in either client or server, it is expected to terminate the connection immediately, rather than downgrade to a not-strong enough level. From the points above, I think an application protocol selector may not need to know the negotiated protocol version and cipher suite. No. The client may send ciphers that are valid for http/1.1 (but invalid for h2), along with ciphers that are good for h2 (as well as http/1.1 of course), plus the list of protocols it supports. The client has no idea what the server supports. I think it should be true that if a client requests h2, the client MUST support H2 and the requested cipher suites MUST contains at least one H2 required cipher suite. Otherwise, it's bug in client side. When the server sees that the client supports h2, it MUST pick a cipher that is valid for h2. Alternatively, the ciphers on the server are sorted so that those valid for h2 have higher priority (they are attempted before all the others), so that there is a high chance that a h2 valid cipher is chosen (but no guarantee) before choosing the application protocol. When the application protocol selector callback is invoked, it can only pick h2 IFF the cipher is h2 valid, otherwise it has to fallback to http/1.1. I think it should be true that if a server can negotiate h2, the server MUST support H2 and the enabled cipher suites MUST contains at least one H2 required cipher suite. Otherwise, it's bug in server side. It's instinctive that if a server support h2, and then the application protocol selector would select h2. If the server declare to support h2, but no suitable cipher suites, it may be a server bug. The connection should be terminated rather than downgrade to HTTP/1.1, I think. Is it possible that client only request h2_valid_cipher_a, but server only support h2_valid_cipher_b, and as would result in that there is no common cipher suites between client and server for H2? It is possible, surely. Should the connection be terminated, or fall-back to HTTP/1.1? I think connection should be terminated immediately, rather than fall-back to HTTP/1.1. Per page 68, section 9.2.2, RFC 7540, there is an mandatory cipher suite (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) MUST be supported in both client and server. If there is no common cipher suites between client and server for H2, it is actually a bad deployments, and the connection should be terminated rather than fall-back to HTTP/1.1. Version downgrading is not a safe behavior, I think. With your reasoning, the client can send [h2_invalid_cipher, h2_valid_cipher], the server may pick h2_invalid_cipher, then the application protocol selector is invoked, which will only look at the protocols, pick h2 since it's supported by client and server, and now you have an invalid connection: the h2 protocol with h2_invalid_cipher. That's an interesting case. The question actually is: between requested application protocols and cipher suites, which preference should be respected at first. Because it is a application requirement that a certain cipher suite is not suitable to H2, I think requested application protocols should be respected at first. My scenarios look like: 1. client sends [h2_invalid_cipher, h2_valid_cipher] and h2/http/1.1 application protocol. 2. server selects h2 (we need an API for the selection). 3. server selects h2_valid_cipher because of h2 is selected previously (may need an API for the selection). In #1, if there is no h2_valid_cipher requested, it is a bug in client side. In #3, if there is no h2_valid_cipher that can be negotiated, it is a bug in server side, or the client does not enabled the mandatory cipher
Re: TLS ALPN Proposal v2
Hi, On Fri, Jun 5, 2015 at 6:11 AM, Xuelei Fan wrote: > I think it should be true that if a server can negotiate h2, the server > MUST support H2 and the enabled cipher suites MUST contains at least one > H2 required cipher suite. Otherwise, it's bug in server side. > > It's instinctive that if a server support h2, and then the application > protocol selector would select h2. If the server declare to support h2, > but no suitable cipher suites, it may be a server bug. The connection > should be terminated rather than downgrade to HTTP/1.1, I think. The server may support h2, but there is no valid h2 cipher in common with the client, so it's not a server bug. In that case, client and server cannot speak h2, but nothing forbids them to speak http/1.1. It would be really bad for the user experience if both client and server could speak http/1.1, but they don't just because they can't speak h2. They would appear like spoiled children :) The point of ALPN is to *negotiate* a protocol, not to give up on the first failure. > Is it possible that client only request h2_valid_cipher_a, but server > only support h2_valid_cipher_b, and as would result in that there is no > common cipher suites between client and server for H2? It is possible, > surely. Should the connection be terminated, or fall-back to HTTP/1.1? > I think connection should be terminated immediately, rather than > fall-back to HTTP/1.1. Per page 68, section 9.2.2, RFC 7540, there is > an mandatory cipher suite (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) MUST > be supported in both client and server. If there is no common cipher > suites between client and server for H2, it is actually a bad > deployments, and the connection should be terminated rather than > fall-back to HTTP/1.1. Version downgrading is not a safe behavior, I think. That is not what the 7540 expert group thinks, certainly not what browsers do, and certainly not what servers do. The behavior is to speak http/1.1 (or the next protocol that fits). > That's an interesting case. The question actually is: between requested > application protocols and cipher suites, which preference should be > respected at first. Because it is a application requirement that a > certain cipher suite is not suitable to H2, I think requested > application protocols should be respected at first. > > My scenarios look like: > 1. client sends [h2_invalid_cipher, h2_valid_cipher] and h2/http/1.1 > application protocol. > 2. server selects h2 (we need an API for the selection). > 3. server selects h2_valid_cipher because of h2 is selected previously > (may need an API for the selection). Does not work. How do you know that server has h2_valid_cipher available ? If it does not, you have picked h2, and an invalid cipher (breaks 7540), or you terminate the connection while instead you could speak http/1.1. > In #1, if there is no h2_valid_cipher requested, it is a bug in client side. > In #3, if there is no h2_valid_cipher that can be negotiated, it is a > bug in server side, or the client does not enabled the mandatory cipher > suite (a bug in client). Does not work. The client may be using TLS 1.4, where that mandatory cipher suite (it's mandatory only for TLS 1.2 deployments) has been removed because insecure. There is no bug on either side, just no cipher in common. > I still cannot understand the outcome. I think, if there is no h2 valid > cipher in common, the connection should be terminated as there is a bug > in client or server side (see above). No, see above. > I'm not familiar with HTTP/2 protocol, can you share more scenarios that > application protocol selection depends on the cipher? It is evident. In all examples, yours and mines, every time we pick "h2" we have to look at the ciphers to see if it is a valid one for h2 or not. You cannot pick "h2" without looking at the cipher so there is an evident dependency. If it's not the right cipher, you say "close the connection", while the implemented behavior of browsers and servers is to fallback to http/1.1. Either case, you have looked at the cipher and taken a decision based on the tuple (app_proto, cipher). In contrast, you can pick "http/1.1" and *any* cipher you want, you don't need to look at the cipher. >> A bit of warning here: we are designing an API for ALPN, not for HTTP/2. >> The ALPN API should be flexible enough to implement *at least* HTTP/2, >> possibly even more complex scenarios (for example alias selection), >> but IMHO it should not be tied to HTTP/2. >> > Yes. That's what I intended to do now. It's very bad if application > protocol selection depends on the negotiation of TLS protocols, cipher > suites, or other handshake attributes, or other Chicken/Eggs dependence. > As would make the JSSE provider hard to be implemented, and the API hard > to be used. That's what I want to avoid in JSSE layer. > >> Again, I see 2 cases: either the JDK implementation picks the TLS >> protocol, the cipher and the alias like
Re: TLS ALPN Proposal v2
On 6/5/2015 8:37 AM, Bradford Wetmore wrote: >> I'd like to use: >> >> - * Gets the application protocol value(s) received from the peer >> - * for this connection. >> + * Gets a {@link List} of requested application protocol value(s) >> + * for this connection. > > I've never seen a link inside an opening sentence. I have seen @code, > but there's only 6 in the entire java namespace. Better to use @code. Xuelei
Re: TLS ALPN Proposal v2
Hi, See inlines, please. On 6/5/2015 5:30 AM, Simone Bordet wrote: > Hi, > > On Thu, Jun 4, 2015 at 6:50 PM, Xuelei Fan wrote: >> Hm, I see your point now. But I may not agree with your ALPN "MUST >> happen after" protocol/cipher suite negotiation conclusion. >> >> I parse this section as, a H2 server must be strong enough(comply to >> RFC7540), and a H2 client must also be strong enough (comply to >> RFC7540). Otherwise, both side may terminated the connection, and >> cannot declare as complying to H2. It is not necessary for an >> application protocol selector to detect whether a H2 server/client >> comply to H2 or not. >> >> If "H2" is requested, it means that the client supports H2. Otherwise, >> it's a client application bug. > > Not that simple, see below. > >> If "H2" is selected by a selected, it >> means that the selected server supports H2. Otherwise, it is a selector >> implementation bug. If something wrong in either client or server, it >> is expected to terminate the connection immediately, rather than >> downgrade to a not-strong enough level. >> >> From the points above, I think an application protocol selector may not >> need to know the negotiated protocol version and cipher suite. > > No. > > The client may send ciphers that are valid for http/1.1 (but invalid > for h2), along with ciphers that are good for h2 (as well as http/1.1 > of course), plus the list of protocols it supports. > The client has no idea what the server supports. > I think it should be true that if a client requests h2, the client MUST support H2 and the requested cipher suites MUST contains at least one H2 required cipher suite. Otherwise, it's bug in client side. > When the server sees that the client supports h2, it MUST pick a > cipher that is valid for h2. > Alternatively, the ciphers on the server are sorted so that those > valid for h2 have higher priority (they are attempted before all the > others), so that there is a high chance that a h2 valid cipher is > chosen (but no guarantee) before choosing the application protocol. > When the application protocol selector callback is invoked, it can > only pick h2 IFF the cipher is h2 valid, otherwise it has to fallback > to http/1.1. > I think it should be true that if a server can negotiate h2, the server MUST support H2 and the enabled cipher suites MUST contains at least one H2 required cipher suite. Otherwise, it's bug in server side. It's instinctive that if a server support h2, and then the application protocol selector would select h2. If the server declare to support h2, but no suitable cipher suites, it may be a server bug. The connection should be terminated rather than downgrade to HTTP/1.1, I think. Is it possible that client only request h2_valid_cipher_a, but server only support h2_valid_cipher_b, and as would result in that there is no common cipher suites between client and server for H2? It is possible, surely. Should the connection be terminated, or fall-back to HTTP/1.1? I think connection should be terminated immediately, rather than fall-back to HTTP/1.1. Per page 68, section 9.2.2, RFC 7540, there is an mandatory cipher suite (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) MUST be supported in both client and server. If there is no common cipher suites between client and server for H2, it is actually a bad deployments, and the connection should be terminated rather than fall-back to HTTP/1.1. Version downgrading is not a safe behavior, I think. > With your reasoning, the client can send [h2_invalid_cipher, > h2_valid_cipher], the server may pick h2_invalid_cipher, then the > application protocol selector is invoked, which will only look at the > protocols, pick h2 since it's supported by client and server, and now > you have an invalid connection: the h2 protocol with > h2_invalid_cipher. > That's an interesting case. The question actually is: between requested application protocols and cipher suites, which preference should be respected at first. Because it is a application requirement that a certain cipher suite is not suitable to H2, I think requested application protocols should be respected at first. My scenarios look like: 1. client sends [h2_invalid_cipher, h2_valid_cipher] and h2/http/1.1 application protocol. 2. server selects h2 (we need an API for the selection). 3. server selects h2_valid_cipher because of h2 is selected previously (may need an API for the selection). In #1, if there is no h2_valid_cipher requested, it is a bug in client side. In #3, if there is no h2_valid_cipher that can be negotiated, it is a bug in server side, or the client does not enabled the mandatory cipher suite (a bug in client). > We have been through these issues for months in the RFC 7540 expert > group, and the outcome is that protocol selection, for h2, depends on > the cipher. > We have also been through a number of scenarios where both the client > and the server send h2 valid ciphers, but their intersection is empty > (
Re: TLS ALPN Proposal v2
On 6/2/2015 11:23 PM, Xuelei Fan wrote: src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java = List getReceivedApplicationProtocols() -- C1. It might be useful to know the client requested application protocols in some circumstance. Better to set the application protocols in client side either. For ALPN, the client supplies the list, the server chooses. For NPN, the server supplies the list, the client chooses. So it's a list of received (requested) protocols. I've changed it for now, not a big deal to me. I'd like to use: - * Gets the application protocol value(s) received from the peer - * for this connection. + * Gets a {@link List} of requested application protocol value(s) + * for this connection. I've never seen a link inside an opening sentence. I have seen @code, but there's only 6 in the entire java namespace. The -public List getReceivedApplicationProtocols() { +public List getRequesedApplicationProtocols() { I'll assume that was supposed to be requested. :) C2. The return value would better to be immutable, and better to describe the preference per RFC 7301. Maybe looks like: -* @return the non-null list of application protocol names +* @return the non-null immutable list of application protocol +* names, in descending order of preference. The returned +* list may be empty if no application protocols were +* requested. Done. src/java.base/share/classes/javax/net/ssl/SSLParameters.java List getApplicationProtocols() -- C3. Better to indicate explicitly that this method only apply to client mode. See above. C4. The method description is not instinctive enough for an application developer. Can we use words to indicate the purpose of the setting? For example: - * Gets the list of application-level protocol names that could - * be sent to the SSL/TLS peer. + * Gets the {@link List} of application layer protocol names that + * can be negotiated over SSL/TLS/DTLS protocols. Changed, except for the @link. C5. Prefer to use immutable return value: - * @return a non-null list of application protocol names. + * @return a non-null immutable list of application protocol names. Changed. C6. Nice to have a link for the standard protocol names. I wasn't planning on having a list of standard protocol names. See below. void setApplicationProtocols(List protocols) C7. see C3. C8. see C4. Changed. s/getApplicationProtocolSelector() -- C9. The use of SSLFunction make the implementation of protocol selector and JSSE provider implementation complicated. From the spec, looks like the selector may want to know address/ports, SSL protocol versions or the negotiated cipher suit. As would require that before use this selector, the handshaking must negotiate the protocol version and the cipher suite. That's a specific JSSE implementation requirement. It does not sound like a reasonable behavior. The implement of the selector is not straightforward, I think. Per section 4, RFC 7301: "... The "application_layer_protocol_negotiation" ServerHello extension is intended to be definitive for the connection (until the connection is renegotiated) and is sent in plaintext to permit network elements to provide differentiated service for the connection when the TCP or UDP port number is not definitive for the application-layer protocol to be used in the connection. By placing ownership of protocol selection on the server, ALPN facilitates scenarios in which certificate selection or connection rerouting may be based on the negotiated protocol." Per my understanding, application protocol should be negotiated before cipher suite and protocol version negotiated. And the connection may be rerouted (even to different machines) for further operation. The requested application protocols list should be the only information for the selection of a suitable application protocol. Based on that, I think it is more simple to use Simone's proposal: @FunctionalInterface interface ApplicationProtocolSelector { String select(List protocols) throws SSLException; } Hence, no need for a SSLBase any more. There's been a lot of discussion this morning, I'll return to this later when I've had a chance to parse it. public static final String AP_HTTP_1_1 = "http/1.1"; public static final String AP_H2 = "h2"; C10. I understand why the constants are defined here. However, usually, we don't define standard names in JSSE APIs. Instead, we normally use Oracle standard names documentation. This is not really a Standard Name in our normal sense/usage. Usuall
Re: TLS ALPN Proposal v2
Hi, On Thu, Jun 4, 2015 at 6:50 PM, Xuelei Fan wrote: > Hm, I see your point now. But I may not agree with your ALPN "MUST > happen after" protocol/cipher suite negotiation conclusion. > > I parse this section as, a H2 server must be strong enough(comply to > RFC7540), and a H2 client must also be strong enough (comply to > RFC7540). Otherwise, both side may terminated the connection, and > cannot declare as complying to H2. It is not necessary for an > application protocol selector to detect whether a H2 server/client > comply to H2 or not. > > If "H2" is requested, it means that the client supports H2. Otherwise, > it's a client application bug. Not that simple, see below. > If "H2" is selected by a selected, it > means that the selected server supports H2. Otherwise, it is a selector > implementation bug. If something wrong in either client or server, it > is expected to terminate the connection immediately, rather than > downgrade to a not-strong enough level. > > From the points above, I think an application protocol selector may not > need to know the negotiated protocol version and cipher suite. No. The client may send ciphers that are valid for http/1.1 (but invalid for h2), along with ciphers that are good for h2 (as well as http/1.1 of course), plus the list of protocols it supports. The client has no idea what the server supports. When the server sees that the client supports h2, it MUST pick a cipher that is valid for h2. Alternatively, the ciphers on the server are sorted so that those valid for h2 have higher priority (they are attempted before all the others), so that there is a high chance that a h2 valid cipher is chosen (but no guarantee) before choosing the application protocol. When the application protocol selector callback is invoked, it can only pick h2 IFF the cipher is h2 valid, otherwise it has to fallback to http/1.1. With your reasoning, the client can send [h2_invalid_cipher, h2_valid_cipher], the server may pick h2_invalid_cipher, then the application protocol selector is invoked, which will only look at the protocols, pick h2 since it's supported by client and server, and now you have an invalid connection: the h2 protocol with h2_invalid_cipher. We have been through these issues for months in the RFC 7540 expert group, and the outcome is that protocol selection, for h2, depends on the cipher. We have also been through a number of scenarios where both the client and the server send h2 valid ciphers, but their intersection is empty (this may happen when a very old client talks to a very new server, think TLS 1.2 vs TLS 1.4, or viceversa). Same outcome: to pick h2 you MUST have a h2 valid cipher in common between client and server, so application protocol selection, for h2, depends on the cipher. A bit of warning here: we are designing an API for ALPN, not for HTTP/2. The ALPN API should be flexible enough to implement *at least* HTTP/2, possibly even more complex scenarios (for example alias selection), but IMHO it should not be tied to HTTP/2. Again, I see 2 cases: either the JDK implementation picks the TLS protocol, the cipher and the alias like it does now, and then invokes the "callback" to pick the application protocol (current Jetty ALPN behavior), or the implementation must be reviewed to perform TLS protocol, cipher, alias and application protocol selection at once, with a "callback" that will be invoked possibly multiple times until it can find the right tuple to return. The latter would be the optimal solution, the former has certainly working implementations. Hope this clarified. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
On 6/5/2015 12:12 AM, Simone Bordet wrote: > Hi, > > On Thu, Jun 4, 2015 at 5:53 PM, Xuelei Fan wrote: >> On 6/4/2015 8:19 PM, Simone Bordet wrote: >>> This is not possible for HTTP/2. >>> Application protocol negotiation MUST happen *after* the TLS protocol >>> and the TLS cipher are negotiated. >>> >> Why? Is it a spec of HTTP/2? It is a point I don't understand now. >> Please help with more details. > > http://tools.ietf.org/html/rfc7540#section-9.2 > > You can only speak h2 if the cipher is strong enough as defined by RFC 7540. > Hm, I see your point now. But I may not agree with your ALPN "MUST happen after" protocol/cipher suite negotiation conclusion. I parse this section as, a H2 server must be strong enough(comply to RFC7540), and a H2 client must also be strong enough (comply to RFC7540). Otherwise, both side may terminated the connection, and cannot declare as complying to H2. It is not necessary for an application protocol selector to detect whether a H2 server/client comply to H2 or not. If "H2" is requested, it means that the client supports H2. Otherwise, it's a client application bug. If "H2" is selected by a selected, it means that the selected server supports H2. Otherwise, it is a selector implementation bug. If something wrong in either client or server, it is expected to terminate the connection immediately, rather than downgrade to a not-strong enough level. >From the points above, I think an application protocol selector may not need to know the negotiated protocol version and cipher suite. Thanks, Xuelei
Re: TLS ALPN Proposal v2
Hi, On Thu, Jun 4, 2015 at 5:53 PM, Xuelei Fan wrote: > On 6/4/2015 8:19 PM, Simone Bordet wrote: >> This is not possible for HTTP/2. >> Application protocol negotiation MUST happen *after* the TLS protocol >> and the TLS cipher are negotiated. >> > Why? Is it a spec of HTTP/2? It is a point I don't understand now. > Please help with more details. http://tools.ietf.org/html/rfc7540#section-9.2 You can only speak h2 if the cipher is strong enough as defined by RFC 7540. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
On 04/06/15 15:18, Simone Bordet wrote: Hi, On Thu, Jun 4, 2015 at 3:08 PM, Michael McMahon wrote: On 04/06/15 13:19, Simone Bordet wrote: Hi, On Wed, Jun 3, 2015 at 8:23 AM, Xuelei Fan wrote: Per section 4, RFC 7301: "... The "application_layer_protocol_negotiation" ServerHello extension is intended to be definitive for the connection (until the connection is renegotiated) and is sent in plaintext to permit network elements to provide differentiated service for the connection when the TCP or UDP port number is not definitive for the application-layer protocol to be used in the connection. By placing ownership of protocol selection on the server, ALPN facilitates scenarios in which certificate selection or connection rerouting may be based on the negotiated protocol." Per my understanding, application protocol should be negotiated before cipher suite and protocol version negotiated. This is not possible for HTTP/2. Application protocol negotiation MUST happen *after* the TLS protocol and the TLS cipher are negotiated. What do you mean by "after"? As far as TLS is concerned, all of this negotiation happens in one negotiation. The client proposes a list of ciphers and application protocols. The server chooses a cipher and application protocol and sends back its choices. Currently, IIUC, the cipher selection is an iterative process where a cipher is attempted until one is negotiated. In this process, there is no looking at the application protocol. Here we're trying to find a solution for ALPN, and either we 1) look the application protocol in this iterative process (and therefore the SSLFunction is invoked multiple times), so that TLS protocol, cipher (possibly the alias too) and application protocol are chosen together, at once (for each iteration); or 2) we separate the TLS protocol and cipher negotiation (and alias) in one step, and we perform application protocol selection afterwards. The latter is how Jetty's ALPN works, and that's what I mean with *after*. For HTTP/2 it won't work to pick the application protocol before the cipher. Either at the same time, or after. That is why I asked to specify how the mechanism worked. Okay. I've been looking at it from the client point of view, and as far as I understand it, all of the information is available to the client at the right time. The HTTP/2 RFC specifically warns against splitting this negotiation with the example that a client could propose a mandatory TLS 1.2 cipher, but which is black-listed by HTTP/2. If (internally) the server chooses that cipher first, without knowing the application protocol is going to be HTTP/2 then you end up with a non-compliant connection that will probably have to be closed for reason of insufficient security. If the server chooses a blacklisted cipher, and then "h2" as protocol, it's a non compliant server. Communication of clients with compliant (and properly configured) servers is guaranteed if the application protocol is chosen after (or at the same time of) the cipher. If I understand you correctly, you are proposing to rework the internal JDK code to perform TLS protocol, cipher, alias and application protocol in one point, which is then possibly iterated multiple times until a satisfactory tuple is selected ? I am fine with this approach too, but I guess the API will be very different from Jetty's ALPN and this current proposal (which is fine as well - does not have to be similar to Jetty's). I don't know enough about the TLS implementation to say how much work it is. Thanks ! Actually, I'm not proposing anything at this stage. But, I wonder if it might be simpler to just make all relevant information available to the existing negotiation API, rather than splitting it into separate calls - Michael.
Re: TLS ALPN Proposal v2
On 6/4/2015 8:19 PM, Simone Bordet wrote: > Hi, > > On Wed, Jun 3, 2015 at 8:23 AM, Xuelei Fan wrote: >> Per section 4, RFC 7301: >> "... The >>"application_layer_protocol_negotiation" ServerHello extension is >>intended to be definitive for the connection (until the connection is >>renegotiated) and is sent in plaintext to permit network elements to >>provide differentiated service for the connection when the TCP or UDP >>port number is not definitive for the application-layer protocol to >>be used in the connection. By placing ownership of protocol >>selection on the server, ALPN facilitates scenarios in which >>certificate selection or connection rerouting may be based on the >>negotiated protocol." >> >> Per my understanding, application protocol should be negotiated before >> cipher suite and protocol version negotiated. > > This is not possible for HTTP/2. > Application protocol negotiation MUST happen *after* the TLS protocol > and the TLS cipher are negotiated. > Why? Is it a spec of HTTP/2? It is a point I don't understand now. Please help with more details. >> And the connection may be >> rerouted (even to different machines) for further operation. The >> requested application protocols list should be the only information for >> the selection of a suitable application protocol. > > Not sure what you exactly mean here, Here is an example to explain the "rerouting". For example, there a four entities, an TLS client, a router, an http/2 over TLS server, and an http/1.1 over TLS server. 1. the client request a connection to the http/2 server, the TCP connection is established between the client the router at first. 2. the router analysis the ClientHello message, and reroute the connection to the http/2 server. 3. the client and http/2 server negotiate the TLS connection, including the SSL protocol and cipher suite. The router should not be able to play man-in-the-middle negotiation if it does not know the server credentials. > but you can't pick the HTTP/2 > protocol unless you have the TLS protocol and TLS cipher available. > So *only* the list of protocol sent by the client is not enough for > HTTP/2, we would need additional contextual information. > See my question above. > What a HTTP/2 aware load balancer written in Java that offloads TLS > would need to do is to negotiate the TLS protocol, negotiate the TLS > cipher, *then* negotiate the application protocol (whether "h2" or > "http/1.1"), and with the last information pick a backend server, > typically forwarding clear text bytes to the backend. > See my question above. Thanks, Xuelei
Re: TLS ALPN Proposal v2
Hi, On Thu, Jun 4, 2015 at 3:08 PM, Michael McMahon wrote: > On 04/06/15 13:19, Simone Bordet wrote: >> >> Hi, >> >> On Wed, Jun 3, 2015 at 8:23 AM, Xuelei Fan wrote: >>> >>> Per section 4, RFC 7301: >>>"... The >>> "application_layer_protocol_negotiation" ServerHello extension is >>> intended to be definitive for the connection (until the connection is >>> renegotiated) and is sent in plaintext to permit network elements to >>> provide differentiated service for the connection when the TCP or UDP >>> port number is not definitive for the application-layer protocol to >>> be used in the connection. By placing ownership of protocol >>> selection on the server, ALPN facilitates scenarios in which >>> certificate selection or connection rerouting may be based on the >>> negotiated protocol." >>> >>> Per my understanding, application protocol should be negotiated before >>> cipher suite and protocol version negotiated. >> >> This is not possible for HTTP/2. >> Application protocol negotiation MUST happen *after* the TLS protocol >> and the TLS cipher are negotiated. > > > What do you mean by "after"? As far as TLS is concerned, all of this > negotiation happens in one negotiation. The client proposes a list of > ciphers and application protocols. The server chooses a cipher > and application protocol and sends back its choices. Currently, IIUC, the cipher selection is an iterative process where a cipher is attempted until one is negotiated. In this process, there is no looking at the application protocol. Here we're trying to find a solution for ALPN, and either we 1) look the application protocol in this iterative process (and therefore the SSLFunction is invoked multiple times), so that TLS protocol, cipher (possibly the alias too) and application protocol are chosen together, at once (for each iteration); or 2) we separate the TLS protocol and cipher negotiation (and alias) in one step, and we perform application protocol selection afterwards. The latter is how Jetty's ALPN works, and that's what I mean with *after*. For HTTP/2 it won't work to pick the application protocol before the cipher. Either at the same time, or after. That is why I asked to specify how the mechanism worked. > The HTTP/2 RFC specifically warns against splitting this negotiation > with the example that a client could propose a mandatory TLS 1.2 cipher, > but which is black-listed by HTTP/2. If (internally) the server chooses that > cipher first, > without knowing the application protocol is going to be HTTP/2 > then you end up with a non-compliant connection that will probably have > to be closed for reason of insufficient security. If the server chooses a blacklisted cipher, and then "h2" as protocol, it's a non compliant server. Communication of clients with compliant (and properly configured) servers is guaranteed if the application protocol is chosen after (or at the same time of) the cipher. If I understand you correctly, you are proposing to rework the internal JDK code to perform TLS protocol, cipher, alias and application protocol in one point, which is then possibly iterated multiple times until a satisfactory tuple is selected ? I am fine with this approach too, but I guess the API will be very different from Jetty's ALPN and this current proposal (which is fine as well - does not have to be similar to Jetty's). I don't know enough about the TLS implementation to say how much work it is. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
On 04/06/15 13:19, Simone Bordet wrote: Hi, On Wed, Jun 3, 2015 at 8:23 AM, Xuelei Fan wrote: Per section 4, RFC 7301: "... The "application_layer_protocol_negotiation" ServerHello extension is intended to be definitive for the connection (until the connection is renegotiated) and is sent in plaintext to permit network elements to provide differentiated service for the connection when the TCP or UDP port number is not definitive for the application-layer protocol to be used in the connection. By placing ownership of protocol selection on the server, ALPN facilitates scenarios in which certificate selection or connection rerouting may be based on the negotiated protocol." Per my understanding, application protocol should be negotiated before cipher suite and protocol version negotiated. This is not possible for HTTP/2. Application protocol negotiation MUST happen *after* the TLS protocol and the TLS cipher are negotiated. What do you mean by "after"? As far as TLS is concerned, all of this negotiation happens in one negotiation. The client proposes a list of ciphers and application protocols. The server chooses a cipher and application protocol and sends back its choices. The HTTP/2 RFC specifically warns against splitting this negotiation with the example that a client could propose a mandatory TLS 1.2 cipher, but which is black-listed by HTTP/2. If (internally) the server chooses that cipher first, without knowing the application protocol is going to be HTTP/2 then you end up with a non-compliant connection that will probably have to be closed for reason of insufficient security. - Michael And the connection may be rerouted (even to different machines) for further operation. The requested application protocols list should be the only information for the selection of a suitable application protocol. Not sure what you exactly mean here, but you can't pick the HTTP/2 protocol unless you have the TLS protocol and TLS cipher available. So *only* the list of protocol sent by the client is not enough for HTTP/2, we would need additional contextual information. What a HTTP/2 aware load balancer written in Java that offloads TLS would need to do is to negotiate the TLS protocol, negotiate the TLS cipher, *then* negotiate the application protocol (whether "h2" or "http/1.1"), and with the last information pick a backend server, typically forwarding clear text bytes to the backend. Thanks !
Re: TLS ALPN Proposal v2
Hi, On Wed, Jun 3, 2015 at 8:23 AM, Xuelei Fan wrote: > Per section 4, RFC 7301: > "... The >"application_layer_protocol_negotiation" ServerHello extension is >intended to be definitive for the connection (until the connection is >renegotiated) and is sent in plaintext to permit network elements to >provide differentiated service for the connection when the TCP or UDP >port number is not definitive for the application-layer protocol to >be used in the connection. By placing ownership of protocol >selection on the server, ALPN facilitates scenarios in which >certificate selection or connection rerouting may be based on the >negotiated protocol." > > Per my understanding, application protocol should be negotiated before > cipher suite and protocol version negotiated. This is not possible for HTTP/2. Application protocol negotiation MUST happen *after* the TLS protocol and the TLS cipher are negotiated. > And the connection may be > rerouted (even to different machines) for further operation. The > requested application protocols list should be the only information for > the selection of a suitable application protocol. Not sure what you exactly mean here, but you can't pick the HTTP/2 protocol unless you have the TLS protocol and TLS cipher available. So *only* the list of protocol sent by the client is not enough for HTTP/2, we would need additional contextual information. What a HTTP/2 aware load balancer written in Java that offloads TLS would need to do is to negotiate the TLS protocol, negotiate the TLS cipher, *then* negotiate the application protocol (whether "h2" or "http/1.1"), and with the last information pick a backend server, typically forwarding clear text bytes to the backend. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
Hi, On Wed, Jun 3, 2015 at 2:56 AM, Bradford Wetmore wrote: > Hi, > > I have just posted the second iteration of the ALPN proposal which hopefully > addresses all of the comments raised here. It is in javadoc format, but > things can certainly be adjusted: > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.00/ > > Please see the archive [1] for previous design discussion. I will be > writing up usage examples in the next few days. > > The significant changes: > > ExtendedSSLSession > public List getReceivedApplicationProtocols() { > > This will allow applications to examine which protocol names were > sent. This is a constant once the application protocols are received, so it can be surely retrieved from SSLParameters. I don't understand why it is replicated here ? > SSLParameters > mentions both ALPN/NPN as possible protocols. I removed the > discussion about "server" and "client" since ALPN/NPN essentially > reverse the roles. > > mentions "appropriate character sets" for String-byte[] conversions > such as UTF-8 for ALPN. > > The application protocol selector is now a @FunctionalInterface > (i.e. lambda-ready) called SSLFunction. It is to throw an > SSLException if no values are supported, or null if you want to > treat as an unknown extension. > > Defined constants for HTTP/1.1 and HTTP/2. > > SSLSession > > Called out that getHandshakeSession's ciphersuite may vary until > selected. > > SSLBase > > A new marker interface that SSLEngine/SSLSocket will implement. > This will allow for a single SSLFunction instead of having > SSLFunctionSSLEngine and SSLFunctionSSLSocket. It does require > that the lambda do a instanceof, unless we were to move the common > Socket/Engine APIs into this class. I'm not sure about this one being a marker interface. I could understand if it extracted the common functionality of SSLEngine and SSLSocket, but a marker interface does not really add much, and perhaps I would prefer it entirely gone. On the same note, why is SSLFunction generic at all ? Also, it is critical to detail how the mechanism work. Will SSLFunction be invoked multiple times, or only once ? When, exactly, with respect to cipher selection and alias selection ? Example implementations for SSLFunction would be great to have: the typical HTTP/2 case is to select the application protocol based on the TLS protocol and the already negotiated cipher. Thanks ! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal v2
src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java = List getReceivedApplicationProtocols() -- C1. It might be useful to know the client requested application protocols in some circumstance. Better to set the application protocols in client side either. I'd like to use: - * Gets the application protocol value(s) received from the peer - * for this connection. + * Gets a {@link List} of requested application protocol value(s) + * for this connection. -public List getReceivedApplicationProtocols() { +public List getRequesedApplicationProtocols() { C2. The return value would better to be immutable, and better to describe the preference per RFC 7301. Maybe looks like: -* @return the non-null list of application protocol names +* @return the non-null immutable list of application protocol +* names, in descending order of preference. The returned +* list may be empty if no application protocols were +* requested. src/java.base/share/classes/javax/net/ssl/SSLParameters.java List getApplicationProtocols() -- C3. Better to indicate explicitly that this method only apply to client mode. C4. The method description is not instinctive enough for an application developer. Can we use words to indicate the purpose of the setting? For example: - * Gets the list of application-level protocol names that could - * be sent to the SSL/TLS peer. + * Gets the {@link List} of application layer protocol names that + * can be negotiated over SSL/TLS/DTLS protocols. C5. Prefer to use immutable return value: - * @return a non-null list of application protocol names. + * @return a non-null immutable list of application protocol names. C6. Nice to have a link for the standard protocol names. void setApplicationProtocols(List protocols) C7. see C3. C8. see C4. s/getApplicationProtocolSelector() -- C9. The use of SSLFunction make the implementation of protocol selector and JSSE provider implementation complicated. >From the spec, looks like the selector may want to know address/ports, SSL protocol versions or the negotiated cipher suit. As would require that before use this selector, the handshaking must negotiate the protocol version and the cipher suite. That's a specific JSSE implementation requirement. It does not sound like a reasonable behavior. The implement of the selector is not straightforward, I think. Per section 4, RFC 7301: "... The "application_layer_protocol_negotiation" ServerHello extension is intended to be definitive for the connection (until the connection is renegotiated) and is sent in plaintext to permit network elements to provide differentiated service for the connection when the TCP or UDP port number is not definitive for the application-layer protocol to be used in the connection. By placing ownership of protocol selection on the server, ALPN facilitates scenarios in which certificate selection or connection rerouting may be based on the negotiated protocol." Per my understanding, application protocol should be negotiated before cipher suite and protocol version negotiated. And the connection may be rerouted (even to different machines) for further operation. The requested application protocols list should be the only information for the selection of a suitable application protocol. Based on that, I think it is more simple to use Simone's proposal: @FunctionalInterface interface ApplicationProtocolSelector { String select(List protocols) throws SSLException; } Hence, no need for a SSLBase any more. public static final String AP_HTTP_1_1 = "http/1.1"; public static final String AP_H2 = "h2"; C10. I understand why the constants are defined here. However, usually, we don't define standard names in JSSE APIs. Instead, we normally use Oracle standard names documentation. src/java.base/share/classes/javax/net/ssl/SSLSession.java = String getCipherSuite() --- Pretty hard to use this method with the new specification. It's not a necessary update, see #C9. Hope it helps! Xuelei On 6/3/2015 8:56 AM, Bradford Wetmore wrote: > Hi, > > I have just posted the second iteration of the ALPN proposal which > hopefully addresses all of the comments raised here. It is in javadoc > format, but things can certainly be adjusted: > > http://cr.openjdk.java.net/~wetmore/8051498/webrev.00/ > > Please see the archive [1] for previous design discussion. I will be > writing up usage examples in the next few days. > > The significant changes: > > ExtendedSSLSession > public List getReceivedA
TLS ALPN Proposal v2
Hi, I have just posted the second iteration of the ALPN proposal which hopefully addresses all of the comments raised here. It is in javadoc format, but things can certainly be adjusted: http://cr.openjdk.java.net/~wetmore/8051498/webrev.00/ Please see the archive [1] for previous design discussion. I will be writing up usage examples in the next few days. The significant changes: ExtendedSSLSession public List getReceivedApplicationProtocols() { This will allow applications to examine which protocol names were sent. SSLParameters mentions both ALPN/NPN as possible protocols. I removed the discussion about "server" and "client" since ALPN/NPN essentially reverse the roles. mentions "appropriate character sets" for String-byte[] conversions such as UTF-8 for ALPN. The application protocol selector is now a @FunctionalInterface (i.e. lambda-ready) called SSLFunction. It is to throw an SSLException if no values are supported, or null if you want to treat as an unknown extension. Defined constants for HTTP/1.1 and HTTP/2. SSLSession Called out that getHandshakeSession's ciphersuite may vary until selected. SSLBase A new marker interface that SSLEngine/SSLSocket will implement. This will allow for a single SSLFunction instead of having SSLFunctionSSLEngine and SSLFunctionSSLSocket. It does require that the lambda do a instanceof, unless we were to move the common Socket/Engine APIs into this class. Thanks, Brad [1] http://mail.openjdk.java.net/pipermail/security-dev/2015-May/012183.html
Re: TLS ALPN Proposal
Simone, I'm sorry for the delay in responding, I've been getting familiar with lambdas the last couple days, and how we might be able to apply it to the ALPNSelector code. Interesting stuff. To the question in this email. I'll leave the previous discussion for context. See my responses inline. On 5/27/2015 4:47 AM, Simone Bordet wrote: Hi, On Tue, May 26, 2015 at 8:46 PM, Bradford Wetmore wrote: I am not sure I follow this. Can you please sketch the steps/algorithm that will be done in your proposed solution ? I'm assuming you are talking about 1a and not 1b. Sure, most of the heavy lifting takes place in ServerHandshaker. ServerHandshaker.java = In the SunJSSE code: // currently line 330. private void clientHello(ClientHello mesg) throws IOException { // Was an ALPNExtension received? ALPNExtension alpnExt = (ALPNExtension) mesg.extensions.get(ExtensionTyp.EXT_ALPN); ... // Currently line 706 in JDK9. session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL, getLocalSupportedSignAlgs(), sslContext.getSecureRandom(), getHostAddressSE(), getPortSE()); ... session.setALPNNames(alpnExt.getNames()); ... // choose cipher suite and corresponding private key // This function is at 987 currently. chooseCipherSuite(mesg); ... // Only adds an ALPN extension if non-empty. m1.extensions.add(applicationProtocolSelector.select(...)); ... Above, chooseCipherSuite() iterates through the collection of suites. Inside that, trySetCipherSuite() attempts to verify that the suite is acceptable to use. Inside that, setupPrivateKeyAndChain() does the actual KeyManager calls. if (conn != null) { alias = km.chooseServerAlias(algorithm, null, conn); } else { alias = km.chooseEngineServerAlias(algorithm, null, engine); } Now in the Application's Code: If you want the KeyManager to take this info into account, you need to create your own customer KM. public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { ExtendedSSLSession session = engine.getHandshakeSession(); String protocol = session.getProtocol(); String ciphersuite = session.getCipherSuite(); List alpns = session.getRequestedApplicationProtocolNames(); // Some logic for which key to use... return choose(protocol, ciphersuite, alpns); } And then your actual ALPN selector: public String select(...) throws SSLProtocolException { ExtendedSSLSession session = engine.getHandshakeSession() String ciphersuite = session.getCipherSuite(); List alpns = session.getRequestedApplicationProtocolNames(); // Some logic for which key to use... return choose(protocol, ciphersuite, alpns); } Hopefully that is clear. Let me see if I understand correctly. In chooseEngineServerAlias() I will have a proposed cipher and the list of app protos from the client. The goal would be to choose the alias based on the app proto, as stated by 7301. However, the app proto is not yet chosen here. If I don't have other constraints to choose the app proto (e.g. SNI), the usual algorithm applies: pick the first server app proto that is in common with the client. Let's assume this is h2; but looking at the cipher, it's not good, so we have to pick another app proto, say http/1.1. Now the cipher is good and we return the alias. This is similar to what happens now with Jetty's ALPN: the cipher will be chosen, then the ALPN callback invoked and there, by looking at the cipher, we know we have to use http/1.1. Let's assume now I have the constraint to choose h2 (e.g. I have a SNI of http2.domain.com). In chooseEngineServerAlias() I will look at SNI, and therefore choose h2, then look at the proposed cipher, which is not good, so return null. Method chooseEngineServerAlias() will be called repeatedly for other ciphers, until a cipher good for h2 is found, otherwise it's an alert 120. Correct. To expand a bit... You will have the SSLSocket/SSLEngine which will give you access to the Socket's attributes (e.g. local/remote IP address/ports), along with the handshakeSession which is being negotiated. The handshakeSession will give access to the selected TLS protocol version number plus the received SNI and ALPN names. With my change to the ciphersuites, it will now give you to the "proposed" ciphersuite, the one being probed for valid key material. If your custom KeyManager don't like this combination of protocol/ciphersuite/sni/alpn/Socket attributes, the KeyManager can report back no valid key material is available, thus meeting that constraint. Are you propos
Re: TLS ALPN Proposal
Hi, On Tue, May 26, 2015 at 8:46 PM, Bradford Wetmore wrote: >> I am not sure I follow this. Can you please sketch the steps/algorithm >> that will be done in your proposed solution ? > > I'm assuming you are talking about 1a and not 1b. > > Sure, most of the heavy lifting takes place in ServerHandshaker. > > ServerHandshaker.java > = > > In the SunJSSE code: > > // currently line 330. > private void clientHello(ClientHello mesg) throws IOException { > > // Was an ALPNExtension received? > ALPNExtension alpnExt = (ALPNExtension) > mesg.extensions.get(ExtensionTyp.EXT_ALPN); > ... > // Currently line 706 in JDK9. > session = new SSLSessionImpl(protocolVersion, > CipherSuite.C_NULL, > getLocalSupportedSignAlgs(), > sslContext.getSecureRandom(), > getHostAddressSE(), getPortSE()); > ... > session.setALPNNames(alpnExt.getNames()); > ... > // choose cipher suite and corresponding private key > // This function is at 987 currently. > chooseCipherSuite(mesg); > ... > // Only adds an ALPN extension if non-empty. > m1.extensions.add(applicationProtocolSelector.select(...)); > ... > > Above, chooseCipherSuite() iterates through the collection of suites. Inside > that, trySetCipherSuite() attempts to verify that the suite is acceptable to > use. Inside that, setupPrivateKeyAndChain() does the actual KeyManager > calls. > > if (conn != null) { > alias = km.chooseServerAlias(algorithm, null, conn); > } else { > alias = km.chooseEngineServerAlias(algorithm, null, engine); > } > > Now in the Application's Code: > > If you want the KeyManager to take this info into account, you need to > create your own customer KM. > > public String chooseEngineServerAlias(String keyType, > Principal[] issuers, > SSLEngine engine) { > > ExtendedSSLSession session = engine.getHandshakeSession(); > String protocol = session.getProtocol(); > String ciphersuite = session.getCipherSuite(); > List alpns = > session.getRequestedApplicationProtocolNames(); > > // Some logic for which key to use... > return choose(protocol, ciphersuite, alpns); > } > > And then your actual ALPN selector: > > public String select(...) throws SSLProtocolException { > ExtendedSSLSession session = engine.getHandshakeSession() > String ciphersuite = session.getCipherSuite(); > List alpns = > session.getRequestedApplicationProtocolNames(); > > // Some logic for which key to use... > return choose(protocol, ciphersuite, alpns); > } > > Hopefully that is clear. Let me see if I understand correctly. In chooseEngineServerAlias() I will have a proposed cipher and the list of app protos from the client. The goal would be to choose the alias based on the app proto, as stated by 7301. However, the app proto is not yet chosen here. If I don't have other constraints to choose the app proto (e.g. SNI), the usual algorithm applies: pick the first server app proto that is in common with the client. Let's assume this is h2; but looking at the cipher, it's not good, so we have to pick another app proto, say http/1.1. Now the cipher is good and we return the alias. This is similar to what happens now with Jetty's ALPN: the cipher will be chosen, then the ALPN callback invoked and there, by looking at the cipher, we know we have to use http/1.1. Let's assume now I have the constraint to choose h2 (e.g. I have a SNI of http2.domain.com). In chooseEngineServerAlias() I will look at SNI, and therefore choose h2, then look at the proposed cipher, which is not good, so return null. Method chooseEngineServerAlias() will be called repeatedly for other ciphers, until a cipher good for h2 is found, otherwise it's an alert 120. Are you proposing to call select(...) from chooseEngineServerAlias(), and give the ALPN callback a semantic that it may be called multiple times, each time with a different cipher, and give access to the ALPN callback implementation to SNI to choose the right protocol based on that ? Thanks! -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
> I am not sure I follow this. Can you please sketch the steps/algorithm > that will be done in your proposed solution ? I'm assuming you are talking about 1a and not 1b. Sure, most of the heavy lifting takes place in ServerHandshaker. ServerHandshaker.java = In the SunJSSE code: // currently line 330. private void clientHello(ClientHello mesg) throws IOException { // Was an ALPNExtension received? ALPNExtension alpnExt = (ALPNExtension) mesg.extensions.get(ExtensionTyp.EXT_ALPN); ... // Currently line 706 in JDK9. session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL, getLocalSupportedSignAlgs(), sslContext.getSecureRandom(), getHostAddressSE(), getPortSE()); ... session.setALPNNames(alpnExt.getNames()); ... // choose cipher suite and corresponding private key // This function is at 987 currently. chooseCipherSuite(mesg); ... // Only adds an ALPN extension if non-empty. m1.extensions.add(applicationProtocolSelector.select(...)); ... Above, chooseCipherSuite() iterates through the collection of suites. Inside that, trySetCipherSuite() attempts to verify that the suite is acceptable to use. Inside that, setupPrivateKeyAndChain() does the actual KeyManager calls. if (conn != null) { alias = km.chooseServerAlias(algorithm, null, conn); } else { alias = km.chooseEngineServerAlias(algorithm, null, engine); } Now in the Application's Code: If you want the KeyManager to take this info into account, you need to create your own customer KM. public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { ExtendedSSLSession session = engine.getHandshakeSession(); String protocol = session.getProtocol(); String ciphersuite = session.getCipherSuite(); List alpns = session.getRequestedApplicationProtocolNames(); // Some logic for which key to use... return choose(protocol, ciphersuite, alpns); } And then your actual ALPN selector: public String select(...) throws SSLProtocolException { ExtendedSSLSession session = engine.getHandshakeSession() String ciphersuite = session.getCipherSuite(); List alpns = session.getRequestedApplicationProtocolNames(); // Some logic for which key to use... return choose(protocol, ciphersuite, alpns); } Hopefully that is clear. Brad On 5/26/2015 1:00 AM, Simone Bordet wrote: Hi, On Tue, May 26, 2015 at 2:30 AM, Bradford Wetmore wrote: Darn those Chicken/Eggs [1]! Yes, you are correct. The steps for the current server code: 1. The ClientHello is parsed, and the SNI matcher callback is called. It does not return which value was matched in the ServerHello, just whether a SNI name was matched or not: The "extension_data" field of this extension SHALL be empty. 2. Begin generating the ServerHello, choose the Protocol Version. 3. Iterate through the list of client's ciphersuites and call the Server's KeyManager (KM) callback until the KM returns key material we can use. A return string selects the proposed ciphersuite. So we currently don't know the selected ciphersuite until the KM has been called (possibly multiple times). If we choose the ALPN before the ciphersuite, the ciphersuite selection may end up being inappropriate (HTTP/2 blacklist). If we choose the ciphersuite first, then the ALPN value wasn't used to drive the certificate selection. Two suggestions in preferred order below. In each of these cases, unfortunately there is currently no indication of the proposed Ciphersuite, so we need to modify the behavior of getHandshakeSession().getCipherSuite() to fill in the proposed CipherSuite before the call to the KM. This seems ok with the current wording, but we'd need to make that explicit. This value will change for each ciphersuite/KM choice attempt. Each suggestion below is followed by our previously proposed ALPN callback to make the actual ALPN value selection: 1a. Add a parallel method to ExtendedSSLSession: public List getRequestedApplicationProtocolNames(); along with the previously proposed selected name: public String getApplicationProtocol() (I'll be changing these names. I'm open to suggestions). When the KM is called, the TLS protocol (e.g. TLSv1.2) has already been selected. Both of the major selection parameters (protocol/proposed ciphersuite) are now available, and applications have access to the ordered ALPN list to see what the client's requested values were. -or- 1b. Keep API as is, and make two callbacks. This first is an advisory value, the TLS protocol version and proposed ciphersuite will be available in getHandshakeSes
Re: TLS ALPN Proposal
Hi, On Tue, May 26, 2015 at 2:30 AM, Bradford Wetmore wrote: > Darn those Chicken/Eggs [1]! > > Yes, you are correct. The steps for the current server code: > > 1. The ClientHello is parsed, and the SNI matcher callback is called. It > does not return which value was matched in the ServerHello, just whether a > SNI name was matched or not: > > The "extension_data" field of this extension SHALL be > empty. > > 2. Begin generating the ServerHello, choose the Protocol Version. > > 3. Iterate through the list of client's ciphersuites and call the Server's > KeyManager (KM) callback until the KM returns key material we can use. A > return string selects the proposed ciphersuite. > > So we currently don't know the selected ciphersuite until the KM has been > called (possibly multiple times). > > If we choose the ALPN before the ciphersuite, the ciphersuite selection may > end up being inappropriate (HTTP/2 blacklist). If we choose the ciphersuite > first, then the ALPN value wasn't used to drive the certificate selection. > > Two suggestions in preferred order below. > > In each of these cases, unfortunately there is currently no indication of > the proposed Ciphersuite, so we need to modify the behavior of > getHandshakeSession().getCipherSuite() to fill in the proposed CipherSuite > before the call to the KM. This seems ok with the current wording, but we'd > need to make that explicit. This value will change for each ciphersuite/KM > choice attempt. > > Each suggestion below is followed by our previously proposed ALPN callback > to make the actual ALPN value selection: > > > 1a. Add a parallel method to ExtendedSSLSession: > > public List getRequestedApplicationProtocolNames(); > > along with the previously proposed selected name: > > public String getApplicationProtocol() > > (I'll be changing these names. I'm open to suggestions). > > When the KM is called, the TLS protocol (e.g. TLSv1.2) has already been > selected. > > Both of the major selection parameters (protocol/proposed ciphersuite) are > now available, and applications have access to the ordered ALPN list to see > what the client's requested values were. > > -or- > > 1b. Keep API as is, and make two callbacks. This first is an advisory > value, the TLS protocol version and proposed ciphersuite will be available > in getHandshakeSession(). The second callback sets the final value that > will be sent. > > > I think 1.a is my preference. I am not sure I follow this. Can you please sketch the steps/algorithm that will be done in your proposed solution ? -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
Darn those Chicken/Eggs [1]! Yes, you are correct. The steps for the current server code: 1. The ClientHello is parsed, and the SNI matcher callback is called. It does not return which value was matched in the ServerHello, just whether a SNI name was matched or not: The "extension_data" field of this extension SHALL be empty. 2. Begin generating the ServerHello, choose the Protocol Version. 3. Iterate through the list of client's ciphersuites and call the Server's KeyManager (KM) callback until the KM returns key material we can use. A return string selects the proposed ciphersuite. So we currently don't know the selected ciphersuite until the KM has been called (possibly multiple times). If we choose the ALPN before the ciphersuite, the ciphersuite selection may end up being inappropriate (HTTP/2 blacklist). If we choose the ciphersuite first, then the ALPN value wasn't used to drive the certificate selection. Two suggestions in preferred order below. In each of these cases, unfortunately there is currently no indication of the proposed Ciphersuite, so we need to modify the behavior of getHandshakeSession().getCipherSuite() to fill in the proposed CipherSuite before the call to the KM. This seems ok with the current wording, but we'd need to make that explicit. This value will change for each ciphersuite/KM choice attempt. Each suggestion below is followed by our previously proposed ALPN callback to make the actual ALPN value selection: 1a. Add a parallel method to ExtendedSSLSession: public List getRequestedApplicationProtocolNames(); along with the previously proposed selected name: public String getApplicationProtocol() (I'll be changing these names. I'm open to suggestions). When the KM is called, the TLS protocol (e.g. TLSv1.2) has already been selected. Both of the major selection parameters (protocol/proposed ciphersuite) are now available, and applications have access to the ordered ALPN list to see what the client's requested values were. -or- 1b. Keep API as is, and make two callbacks. This first is an advisory value, the TLS protocol version and proposed ciphersuite will be available in getHandshakeSession(). The second callback sets the final value that will be sent. I think 1.a is my preference. To answer some of the other questions. On 5/25/2015 3:08 AM, Michael McMahon wrote: 2) The notion of client preference needs to be made explicit. This could just be a matter of javadoc given that List is ordered. So, it could be enough to say the same order is used in the protocol. Yes, I'll add that. 3) It's a shame that the RFC didn't mandate UTF8 encoded byte sequences for the protocol name, because it's theoretically possible that non UTF8 byte sequences could get registered, but that's not a concern for HTTP/2 at least. No. Not sure what we can do about that, short of going back to the byte[] option. Given that IANA operates mainly in English, I would expect the namespaces will probably be ASCII, but that is just conjecture. > This would be possible, IIUC, using > sslEngine.getHandshakeSession().getRequestedServerNames() in the > ApplicationProtocolSelector implementation. Yes. > but I understand it's mentioned in RFC 7301. Yes, see the last sentence section 1. Brad [1] https://www.youtube.com/watch?v=ixgf5SlvOB4&feature=youtu.be&t=27
Re: TLS ALPN Proposal
On 5/22/2015 8:28 PM, Weijun Wang wrote: On 5/23/2015 9:13 AM, Bradford Wetmore wrote: Weijun wrote: > But in the RFC the name is in uppercase and chars in string are all > lowercases. > ...deleted... > - Compare with equalsIgnoreCase() Not following here, the spec is specific about the over-the-wire byte values, and http/1.1 != Http/1.1. Because the spec says o Identification Sequence: The precise set of octet values that identifies the protocol. This could be the UTF-8 encoding [RFC3629] of the protocol name. and the name is uppercase. What if someone really sends "HTTP/1.1".getBytes("UTF-8")? I'm sorry, but I'm still not understanding your point. Looking at an existing ALPN directory entry: Protocol: HTTP/1.1 Identification Sequence: 0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1") Reference: [RFC7230] The name of the "Protocol" is HTTP/1.1, but the "Identification Sequence" is "0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1")". I am proposing that the List be the values of the Identification Sequence, not the IANA Protocol Names. Is your opinion that the ALPN API String "Protocol" be the "Protocol:" and that we should internally map from HTTP/1.1 to http/1.1 before sending? Or that Identification Sequence "HTTP/1.1" SHOULD BE treated the same as "http/1.1"? I think that's what you're saying, since I think you want to compare it using equalsIgnoreCase(). That will make future ALPN protocol name addition challenging. > What if someone really sends "HTTP/1.1".getBytes("UTF-8")? In my proposal, then they should send "HTTP/1.1" instead of "http/1.1". I'm really sorry if I'm still missing something. Brad
Re: TLS ALPN Proposal
Hi, On Mon, May 25, 2015 at 3:57 PM, Michael McMahon wrote: > Perhaps, though it seems there are specific ALPNs for HTTP/1.1 ("http/1.1") > and for HTTP/2 ("h2"). So, I think you would use ALPN itself to do that > negotiation. > An incoming TLS connection without the ALPN extension is just assumed to be > HTTP/1.1 Sure, but I can see a client looping over a list of domain names (e.g. to check whether the sites support HTTP/2) and therefore not having any knowledge of whether it should or not add the ALPN extension. This client will always add it, but the server must force http/1.1 for http1.domain.com. > There aren't very many different "applications" envisaged yet. There are > a couple of NAT related protocols registered. But, actually having thought > about it > again, client certificate selection happens in the X509ExtendedKeyManager > class > and that implementation could presumably call > sslEngine.getHandshakeSession().getApplicationProtocol() > and select the client cert using that information. It doesn't do that now > obviously > but I think it could in future if necessary. Sure, unless the protocol is not available because ALPN code has not run yet. For what I understand, currently cipher selection and certificate selection happen at the same time, please correct me if I am wrong. If that's the case, then we have a chicken-egg problem: you can't call ALPN code before the cipher is selected, but you need ALPN to select the certificate. If those two steps can be split, then ALPN code could be put in between and all is solved. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
On 25/05/15 12:34, Simone Bordet wrote: Hi, On Mon, May 25, 2015 at 12:08 PM, Michael McMahon wrote: Hi Brad, A couple of initial comments/questions. 1) Certificate selection is one feature envisaged by ALPN. ie a client or a server ought to be able to choose a different certificate depending on the application name that gets negotiated. Is that possible with this API? Interesting. I can definitely see choosing the ALPN protocol based on the SNI name sent by the client. For example, a server able to speak http/1.1 and h2 receiving a request for http1.domain.com wants to force http/1.1. This would be possible, IIUC, using sslEngine.getHandshakeSession().getRequestedServerNames() in the ApplicationProtocolSelector implementation. Perhaps, though it seems there are specific ALPNs for HTTP/1.1 ("http/1.1") and for HTTP/2 ("h2"). So, I think you would use ALPN itself to do that negotiation. An incoming TLS connection without the ALPN extension is just assumed to be HTTP/1.1 I see less common choosing the certificate given the application protocol, but I understand it's mentioned in RFC 7301. There aren't very many different "applications" envisaged yet. There are a couple of NAT related protocols registered. But, actually having thought about it again, client certificate selection happens in the X509ExtendedKeyManager class and that implementation could presumably call sslEngine.getHandshakeSession().getApplicationProtocol() and select the client cert using that information. It doesn't do that now obviously but I think it could in future if necessary. ALPN definitely needs the cipher to be negotiated to support HTTP/2, so I hope it's not a chicken-egg problem. I've been assuming that (by default) we just need to avoid using the black-listed ciphers and make sure to propose at least the one mandatory cipher; then we shouldn't have any problem. HTTP/2 apps can still create their own SSLContexts and configure them any way they want. - Michael.
Re: TLS ALPN Proposal
Hi, On Mon, May 25, 2015 at 12:08 PM, Michael McMahon wrote: > Hi Brad, > > A couple of initial comments/questions. > > 1) Certificate selection is one feature envisaged by ALPN. ie a client or a > server > ought to be able to choose a different certificate depending on the > application name > that gets negotiated. Is that possible with this API? Interesting. I can definitely see choosing the ALPN protocol based on the SNI name sent by the client. For example, a server able to speak http/1.1 and h2 receiving a request for http1.domain.com wants to force http/1.1. This would be possible, IIUC, using sslEngine.getHandshakeSession().getRequestedServerNames() in the ApplicationProtocolSelector implementation. I see less common choosing the certificate given the application protocol, but I understand it's mentioned in RFC 7301. ALPN definitely needs the cipher to be negotiated to support HTTP/2, so I hope it's not a chicken-egg problem. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
Hi Brad, A couple of initial comments/questions. 1) Certificate selection is one feature envisaged by ALPN. ie a client or a server ought to be able to choose a different certificate depending on the application name that gets negotiated. Is that possible with this API? 2) The notion of client preference needs to be made explicit. This could just be a matter of javadoc given that List is ordered. So, it could be enough to say the same order is used in the protocol. 3) It's a shame that the RFC didn't mandate UTF8 encoded byte sequences for the protocol name, because it's theoretically possible that non UTF8 byte sequences could get registered, but that's not a concern for HTTP/2 at least. Thanks, Michael On 22/05/15 01:55, Bradford Wetmore wrote: This is a fork of the previous thread: Subject: TLS Handshake Message Proposal (Was: Re: JEP 244: TLS Application-Layer Protocol Negotiation Extension) I broke this thread off to keep this proposal discussion together, but if you're interested in the history, please see the previous thread. This approach combines different suggestions from security-dev in a new way, and simplifies the ALPN selection process quite a bit. I think it addresses most of the concerns about selection that were raised. This approach can be completely separated from the Handshake mechanism I discussed in the previous message, so I'm thinking of this approach for JDK 9 and targeting the more general handshake approach for JDK 10. Here's the summary of API additions: SSLParameters: -- Client-side: gets/sets the list of protocol names to send. Server-side: gets/sets a ApplicationProtocolSelector which is a user-defined callback mechanism. ApplicationProtocolSelector: Server-side: callback methods for SSLSocket/SSLEngine which are provided with handshake information for making the selection ExtendedSSLSession: --- gets the negotiated protocol String Specifics below. The javadoc obviously needs work. class SSLParameters { ...deleted... /** * Gets the list of application protocols that will sent by * the client. * * The list could be empty, in which case no protocols will be * sent. * * @returns a list of application protocol names. */ public List getApplicationProtocols() { }; /** * Sets the list of application protocols that will sent by * the client. * * protocols could be empty, in which case no protocols will be * sent. * * @param protocols a list of application protocol names * @throws IllegalArgumentException if protocols is null. */ public void setApplicationProtocols(List protocols); /** * Gets the current server-side application layer protocol selector. * * @param the selector mechanism. * @return the current application protocol selector, or null if * there is not one. */ public ApplicationProtocolSelector getApplicationProtocolSelector() {}; /** * Sets the server-side application layer protocol selector. * * @param the selector mechanism, or null if protocol selection * should not be done. */ public void setApplicationProtocolSelector( ApplicationProtocolSelector selector) {}; } /* * A callback class on the server side that is responsible for * choosing which Application Protocol should be used in a SSL/TLS * connection. */ public abstract class ApplicationProtocolSelector { /* * SSLSocket callback to choose which Application Protocol value * to return to a SSL/TLS client * * @param sslSocket the SSLSocket for this connection * @param protocols the list of protocols advertised by the client * @param protocolVersion the negotiated protocol version * @param ciphersuite the negotiated ciphersuite * @return a non-empty protocol String to send to the client, * or null if no protocol value (i.e. extension) should be sent. * @throws SSLProtocolException if the connection should be aborted * because the the server supports none of the protocols that * the client advertised. */ public String select(SSLSocket sslSocket, String[] protocols, String protocolVersion, String ciphersuite) throws SSLProtocolException; /* * SSLEngine callback to choose which Application Protocol to return * to a SSL/TLS client. * * @param sslEngine the SSLEngine for this connection * @param protocols the list of protocols advertised by the client * @param protocolVersion the negotiated protocol version * @param ciphersuite the negotiated ciphersuite * @return a non-empty protocol String to send to the client, * or null if no protocol value should b
Re: TLS ALPN Proposal
Hi, On Sat, May 23, 2015 at 3:13 AM, Bradford Wetmore wrote: > Thanks for the thorough reviews and comments, I really appreciate it and > always learn something. FunctionalInterface (@since 1.8) is something I > haven't really explored yet, so off to the books. Just to be clear, this is what I am proposing: class SSLParameters { ... List getApplicationProtocols(); void setApplicationProtocols(List protocols); void setApplicationProtocolSelector(ApplicationProtocolSelector selector); ApplicationProtocolSelector getApplicationProtocolSelector(); } @FunctionalInterface interface ApplicationProtocolSelector { String select(List protocols) throws SSLException; } In this way, there is no need for a SSLBase to converge SSLSocket and SSLEngine, the ApplicationProtocolSelector can be specified as a lambda expression on SSLParameters, and everything is much simpler. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
On 5/23/2015 9:13 AM, Bradford Wetmore wrote: Weijun wrote: > But in the RFC the name is in uppercase and chars in string are all > lowercases. > ...deleted... > - Compare with equalsIgnoreCase() Not following here, the spec is specific about the over-the-wire byte values, and http/1.1 != Http/1.1. Because the spec says o Identification Sequence: The precise set of octet values that identifies the protocol. This could be the UTF-8 encoding [RFC3629] of the protocol name. and the name is uppercase. What if someone really sends "HTTP/1.1".getBytes("UTF-8")? --Max
Re: TLS ALPN Proposal
Thanks for the thorough reviews and comments, I really appreciate it and always learn something. FunctionalInterface (@since 1.8) is something I haven't really explored yet, so off to the books. I'm glad this ALPN approach seems worth pursing. I have several different comments I'll combine into this single message. On 5/22/2015 9:12 AM, Simone Bordet wrote: ExtendedSSLSession: --- gets the negotiated protocol String If I understand correctly, SSLParameters will have methods that can only be used by one side of the TLS protocol (e.g. client or server, but not both). It's already like this for other things (e.g. SNI) so it will work, but I had hoped for some kind of reworking in this area too, but I'm digressing. I don't have a better idea/suggestion for this, protocol advertisement and selection are two very different things. At this point, I am thinking it should remain in SSLParameters. I considered putting the selector into the SSLContext initialization: sslContext.init(KeyManager, TrustManager, SecureRandom, Selector); but that means 1 selector for all SSLSockets/SSLEngines that get generated from that SSLContext. That is constricting if the selector wanted to keep any connection-specific values. It could go into SSLSocket/SSLEngine, but starting in JDK 6, we've been lumping all set* configuration parameters into SSLParameters, so that once configured, devs can reuse one SSLParameters object without having to reconstruct it (source code or at runtime) from scratch. BTW, there was a previous question about when to use SSLSocket.set*() and sslSocket.setSSLParameters(params). I gave a partial answer in: http://mail.openjdk.java.net/pipermail/security-dev/2014-November/011430.html I recently filed: https://bugs.openjdk.java.net/browse/JDK-8080799 Provide guidance on repeated configuration parameter APIs to address this. I don't think we need to deprecate the set() methods, but having a note here will alleviate confusion. /* * A callback class on the server side that is responsible for * choosing which Application Protocol should be used in a SSL/TLS * connection. */ public abstract class ApplicationProtocolSelector { /* * SSLSocket callback to choose which Application Protocol value * to return to a SSL/TLS client * * @param sslSocket the SSLSocket for this connection * @param protocols the list of protocols advertised by the client * @param protocolVersion the negotiated protocol version Egads, this is confusing. protocols is the ALPN protocols, protocolVersion is the TLS version number. I'll fix this. * @param ciphersuite the negotiated ciphersuite * @return a non-empty protocol String to send to the client, * or null if no protocol value (i.e. extension) should be sent. * @throws SSLProtocolException if the connection should be aborted * because the the server supports none of the protocols that * the client advertised. Whoops, I put exactly the Exception I didn't want to use! I was originally thinking SSLHandshakeException. See below for more comments. */ public String select(SSLSocket sslSocket, String[] protocols, String protocolVersion, String ciphersuite) throws SSLProtocolException; We are currently getting the protocolVersion and the cipherSuite via: [sslSocket|sslEngine].getHandshakeSession().get[Protocol|CipherSuite]() If this is correct, perhaps there is no need to pass those 2 parameters to select() ? Good point. Yes, those are no longer needed. There was a suggestion to have access to the clientHello information in order to guide ciphersuite/protocol selection, however, there isn't a way to control that part of the internals at this time, so I didn't include it. As an aside, if we do develop the Handshake API (other mail) and allow for handshake message modification (not currently proposed, but hinted at), the protocols/ciphersuites values could be adjusted before they are handled. e.g. INBOUND callbacks would be triggered after the message has been parsed and added to the handshake hash calculation, but before clientHello() is actually called. I would suggest that if SSLParameters.setApplicationProtocols() takes a List, then also select() should take a List, rather than a String[]. Since it's the server picking the protocols, would be handy to have the client protocols in a List in order to call contains(), etc. on it. Good points. I would suggest to throw SSLException rather than the too specific SSLProtocolException (which may also be misleading, since its javadoc hints at a "flaw in one of the protocol implementations", while in this case it is just a failure to negotiate an *application* protocol - perfectly fine from the point of view of the TLS protocol). See above. I'll change it to SSLException for now, but I think it probably should
Re: TLS ALPN Proposal
On 5/23/2015 3:20 AM, Simone Bordet wrote: Hi, On Fri, May 22, 2015 at 9:14 PM, Bernd Eckenfels wrote: I would suggest to make this encoded in latin1 instead. This is supposed to be a 8bit clean encoding (and will be compatible to all ASCII only strings). It is still ugly and needs to be documanted cleanly that the string you get back might not be a string at all. RFC 7301 hints that protocol string could be UTF-8 encoded: http://tools.ietf.org/html/rfc7301#section-6 But in the RFC the name is in uppercase and chars in string are all lowercases. So maybe the preferred impl will be like this? - Fields use String - on the wire UTF-8 - Compare with equalsIgnoreCase() --Max
Re: TLS ALPN Proposal
Hi, On Fri, May 22, 2015 at 9:14 PM, Bernd Eckenfels wrote: > I would suggest to make this encoded in latin1 instead. This is > supposed to be a 8bit clean encoding (and will be compatible to all > ASCII only strings). It is still ugly and needs to be documanted > cleanly that the string you get back might not be a string at all. RFC 7301 hints that protocol string could be UTF-8 encoded: http://tools.ietf.org/html/rfc7301#section-6 -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
Hi, On Fri, May 22, 2015 at 8:54 PM, Sean Mullan wrote: > There's actually a bunch of methods in common, so one possibility is to > create a new interface containing the common methods (say SSLBase for now > for lack of a better name). Then you could change SSLEngine and SSLSocket to > implement SSLBase (which should be a compatible change), and then have a > single method on ApplicationProtocolSelector. Question is if there are > enough common methods to do what you want? I don't know enough about ALPN to > answer that question. There are 2 things that conflate here: one is to provide the mechanism to support ALPN, and the second is to make sure that it is possible to support HTTP/2. ALPN per se, for example, does not need any information about SSLEngine or TLS protocol versions or ciphers. It just needs the protocol strings, so the ApplicationProtocolSelector would just need select(List). For HTTP/2, however, the choice of the protocol will depend on the TLS version and the cipher, so we will need a way to obtain that information. Typically, in the code where you pass the ApplicationProtocolSelector you have the SSLEngine available, e.g.: sslEngine.getSSLParameters().setApplicationProtocolSelector(new ApplicationProtocolSelector() { public String select(List clientProtocols) { // Here sslEngine will be in lexical scope } }); In this way, ApplicationProtocolSelector won't depend on SSLEngine or SSLSocket, and can be reduced to a FunctionalInterface. -- Simone Bordet http://bordet.blogspot.com --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz
Re: TLS ALPN Proposal
> > There was also some internal discussion about whether the values > > should be Strings or byte arrays. The ALPN RFC only discusses > > bytes, and a String.toBytes("US-ASCII") would limit the API to > > ASCII strings. > > > > Lastly, we could also add some convenience values for well-known > > values. e.g.: > > > > public static final AP_HTTP_1.1 = "http/1.1"; > > > > or in byte form: > > > > public static final AP_H2 = "h2".getBytes(""US-ASCII"); > > > > I refrained from including SPDY/*, since they are on their way out > > now, and NAT/STUN since there hasn't been any call for it so far. > > I agree that only http/1.1 and h2 deserve a constant. I would suggest to make this encoded in latin1 instead. This is supposed to be a 8bit clean encoding (and will be compatible to all ASCII only strings). It is still ugly and needs to be documanted cleanly that the string you get back might not be a string at all. Gruss Bernd
Re: TLS ALPN Proposal
On 05/22/2015 12:12 PM, Simone Bordet wrote: Would be great if we could make this class a FunctionalInterface Yes, that would be nice. , but I guess it's not easy due to lack of commonality between SSLSocket and SSLEngine. Unless there is a way to abstract something out of those 2:) There's actually a bunch of methods in common, so one possibility is to create a new interface containing the common methods (say SSLBase for now for lack of a better name). Then you could change SSLEngine and SSLSocket to implement SSLBase (which should be a compatible change), and then have a single method on ApplicationProtocolSelector. Question is if there are enough common methods to do what you want? I don't know enough about ALPN to answer that question. --Sean
Re: TLS ALPN Proposal
Hi, On Fri, May 22, 2015 at 2:55 AM, Bradford Wetmore wrote: > This is a fork of the previous thread: > > Subject: TLS Handshake Message Proposal > (Was: Re: JEP 244: TLS Application-Layer Protocol > Negotiation Extension) > > I broke this thread off to keep this proposal discussion together, but if > you're interested in the history, please see the previous thread. > > This approach combines different suggestions from security-dev in a new way, > and simplifies the ALPN selection process quite a bit. I think it addresses > most of the concerns about selection that were raised. > > This approach can be completely separated from the Handshake mechanism I > discussed in the previous message, so I'm thinking of this approach for JDK > 9 and targeting the more general handshake approach for JDK 10. > > Here's the summary of API additions: > > > SSLParameters: > -- > Client-side: gets/sets the list of protocol names to send. > Server-side: gets/sets a ApplicationProtocolSelector which is a > user-defined callback mechanism. > > ApplicationProtocolSelector: > > Server-side: callback methods for SSLSocket/SSLEngine which > are provided with handshake information for making > the selection > > ExtendedSSLSession: > --- > gets the negotiated protocol String If I understand correctly, SSLParameters will have methods that can only be used by one side of the TLS protocol (e.g. client or server, but not both). It's already like this for other things (e.g. SNI) so it will work, but I had hoped for some kind of reworking in this area too, but I'm digressing. > /* > * A callback class on the server side that is responsible for > * choosing which Application Protocol should be used in a SSL/TLS > * connection. > */ > public abstract class ApplicationProtocolSelector { > > /* > * SSLSocket callback to choose which Application Protocol value > * to return to a SSL/TLS client > * > * @param sslSocket the SSLSocket for this connection > * @param protocols the list of protocols advertised by the client > * @param protocolVersion the negotiated protocol version > * @param ciphersuite the negotiated ciphersuite > * @return a non-empty protocol String to send to the client, > * or null if no protocol value (i.e. extension) should be sent. > * @throws SSLProtocolException if the connection should be aborted > * because the the server supports none of the protocols that > * the client advertised. > */ > public String select(SSLSocket sslSocket, String[] protocols, > String protocolVersion, String ciphersuite) > throws SSLProtocolException; We are currently getting the protocolVersion and the cipherSuite via: [sslSocket|sslEngine].getHandshakeSession().get[Protocol|CipherSuite]() If this is correct, perhaps there is no need to pass those 2 parameters to select() ? I would suggest that if SSLParameters.setApplicationProtocols() takes a List, then also select() should take a List, rather than a String[]. Since it's the server picking the protocols, would be handy to have the client protocols in a List in order to call contains(), etc. on it. I would suggest to throw SSLException rather than the too specific SSLProtocolException (which may also be misleading, since its javadoc hints at a "flaw in one of the protocol implementations", while in this case it is just a failure to negotiate an *application* protocol - perfectly fine from the point of view of the TLS protocol). Would be great if we could make this class a FunctionalInterface, but I guess it's not easy due to lack of commonality between SSLSocket and SSLEngine. Unless there is a way to abstract something out of those 2 :) > public class ExtendedSSLSession implements SSLSession { > > ...deleted... > > /** >* Gets the application protocol negotiated for this connection. >* >* @returns the application protocol name or null if none was >* negotiated. >*/ > public String getApplicationProtocol() { }; > } How would this case be covered: * client sends protocol list "foo","bar" * server sends back "bax". * client has to decide what to do. The only chance to call ExtendedSSLSession.getApplicationProtocol() would be *after* the handshake is completed, right ? Do you plan to hardcode the abort of the handshake with an alert_120, or give the application a chance (just asking) ? > There was also some internal discussion about whether the values should be > Strings or byte arrays. The ALPN RFC only discusses bytes, and a > String.toBytes("US-ASCII") would limit the API to ASCII strings. > > Lastly, we could also add some convenience values for well-known values. > e.g.: > > public static final AP_HTTP_1.1 = "http/1.1"; > > or in byte form: > > public static fin
TLS ALPN Proposal
This is a fork of the previous thread: Subject: TLS Handshake Message Proposal (Was: Re: JEP 244: TLS Application-Layer Protocol Negotiation Extension) I broke this thread off to keep this proposal discussion together, but if you're interested in the history, please see the previous thread. This approach combines different suggestions from security-dev in a new way, and simplifies the ALPN selection process quite a bit. I think it addresses most of the concerns about selection that were raised. This approach can be completely separated from the Handshake mechanism I discussed in the previous message, so I'm thinking of this approach for JDK 9 and targeting the more general handshake approach for JDK 10. Here's the summary of API additions: SSLParameters: -- Client-side: gets/sets the list of protocol names to send. Server-side: gets/sets a ApplicationProtocolSelector which is a user-defined callback mechanism. ApplicationProtocolSelector: Server-side: callback methods for SSLSocket/SSLEngine which are provided with handshake information for making the selection ExtendedSSLSession: --- gets the negotiated protocol String Specifics below. The javadoc obviously needs work. class SSLParameters { ...deleted... /** * Gets the list of application protocols that will sent by * the client. * * The list could be empty, in which case no protocols will be * sent. * * @returns a list of application protocol names. */ public List getApplicationProtocols() { }; /** * Sets the list of application protocols that will sent by * the client. * * protocols could be empty, in which case no protocols will be * sent. * * @param protocols a list of application protocol names * @throws IllegalArgumentException if protocols is null. */ public void setApplicationProtocols(List protocols); /** * Gets the current server-side application layer protocol selector. * * @param the selector mechanism. * @return the current application protocol selector, or null if * there is not one. */ public ApplicationProtocolSelector getApplicationProtocolSelector() {}; /** * Sets the server-side application layer protocol selector. * * @param the selector mechanism, or null if protocol selection * should not be done. */ public void setApplicationProtocolSelector( ApplicationProtocolSelector selector) {}; } /* * A callback class on the server side that is responsible for * choosing which Application Protocol should be used in a SSL/TLS * connection. */ public abstract class ApplicationProtocolSelector { /* * SSLSocket callback to choose which Application Protocol value * to return to a SSL/TLS client * * @param sslSocket the SSLSocket for this connection * @param protocols the list of protocols advertised by the client * @param protocolVersion the negotiated protocol version * @param ciphersuite the negotiated ciphersuite * @return a non-empty protocol String to send to the client, * or null if no protocol value (i.e. extension) should be sent. * @throws SSLProtocolException if the connection should be aborted * because the the server supports none of the protocols that * the client advertised. */ public String select(SSLSocket sslSocket, String[] protocols, String protocolVersion, String ciphersuite) throws SSLProtocolException; /* * SSLEngine callback to choose which Application Protocol to return * to a SSL/TLS client. * * @param sslEngine the SSLEngine for this connection * @param protocols the list of protocols advertised by the client * @param protocolVersion the negotiated protocol version * @param ciphersuite the negotiated ciphersuite * @return a non-empty protocol String to send to the client, * or null if no protocol value should be sent. * @throws SSLProtocolException if the connection should be aborted * because the the server supports none of the protocols that * the client advertised. */ public String select(SSLEngine sslEngine, String[] protocols, String protocolVersion, String ciphersuite) throws SSLProtocolException; } If need be, we could include the received extensions or in a future version of this class. public class ExtendedSSLSession implements SSLSession { ...deleted... /** * Gets the application protocol negotiated for this connection. * * @returns the application protocol name or null if none was * negotiated. */ public String getApplicationProtocol() { }; } There was also some