Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ALPN support in SSLSocket #640

Closed
wants to merge 4 commits into from

Conversation

frasertweedale
Copy link
Contributor

This is a prerequisite for ACME tls-alpn-01 challenge verification.
See https://gist.github.com/frasertweedale/dfac386579cb2d1fe892f39d22c2975d
for usage / testbed.

ab29dd6c (Fraser Tweedale, 7 minutes ago)
   alpn: support via new SSLSocket constructor

   Add a new SSLSocket constructor that allows the caller to specify ALPN
   protocols.

555134db (Fraser Tweedale, 2 hours ago)
   alpn: add SSLSocket.getNegotiatedProtocol()

   Add a method to retrieve the identifier of the negotiated protocol, if
   available.

465ac1d9 (Fraser Tweedale, 4 days ago)
   alpn: format and supply ALPN data if user provides it

   Update the private SSLSocket constructor to accept a String[] of ALPN
   protocol names in preferred order.  When given, it will prepare the ALPN
   extension data in the required format and pass it along to the
   socketConnect method.

   The change to publicly expose this capability will occur in a subsequent
   commit.

6f5a0cf8 (Fraser Tweedale, 4 days ago)
   alpn: add support in native socketConnect method

   Update the private native socketConnect method to receive optional ALPN
   data to include in handshake.  The value is performatted per 
   SSL_SetNextProtoNego().

   Support for library users to supply the ALPN data will follow in subsequent
   commits.

Update the private native socketConnect method to receive optional
ALPN data to include in handshake.  The value is performatted per
SSL_SetNextProtoNego().

Support for library users to supply the ALPN data will follow in
subsequent commits.
Update the private SSLSocket constructor to accept a String[] of
ALPN protocol names in preferred order.  When given, it will prepare
the ALPN extension data in the required format and pass it along to
the socketConnect method.

The change to publicly expose this capability will occur in a
subsequent commit.
Add a method to retrieve the identifier of the negotiated protocol,
if available.
Add a new SSLSocket constructor that allows the caller to specify
ALPN protocols.
@frasertweedale
Copy link
Contributor Author

@cipherboy ahaha whups, I did not even see #526 :S

@frasertweedale
Copy link
Contributor Author

@cipherboy ah, looks like #526 is about the server side anyway, whereas this PR is for the client side and is mostly orthogonal.

Copy link
Member

@cipherboy cipherboy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is largely fine.

What's missing is a ALPN selection routine on the server. I'm not sure if you wanted to add that; this is purely client side support, as is mine in #526 (it doesn't do server selection at all--that requires a call to SSL_SetNextProtoCallback).

My only thing is... this is the legacy SSLSocket... We should really be adding features its replacement, org.mozilla.jss.ssl.javax.JSSSocket.

I guess, what's the use case for still using this one? The other one is compliant with standard JDK interfaces and I'd prefer to push #526 (and then a later one adding server-side ALPN support) rather than continuing to add new features to the old one.

It is on my TODO list to rip out all of this old SSLSocket, including from PKI.

My 2c. I'll merge if there's a compelling reason to not use the new one for something.

* After the handshake, returns the negotiated protocol
* or null (e.g. when the server does not support ALPN).
*/
public native byte[] getNegotiatedProtocol() throws SocketException;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that we have any hope of making org.mozilla.jss.ssl.SSLSocket comply with javax.net.ssl.SSLSocket at this point in time (I've tried, twice!)... But how about we at least comply when the functions do the same thing? :-)

https://docs.oracle.com/javase/9/docs/api/javax/net/ssl/SSLSocket.html#getApplicationProtocol--

(return String and getNegotiatedProtocol -> getApplicationProtocol since they do the same thing).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the name sure. Return String I am less sure about (discussed elsewhere).

*/
public SSLSocket(
InetAddress address, int port,
String hostname, byte[][]alpn,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your commit message you wrote:

Update the private SSLSocket constructor to accept a String[] of ALPN

But I only see byte[][] of ALPNs. I'd prefer we stick with JCA-standard types here rather than introducing our own in general... But at minimum, the commit message should match the code. :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just saw your comment on the other PR. Bravo Java, bravo. What if the sequence of bytes is not valid UTF-8? What do you know, there are ALPN GREASE values that are not valid UTF-8 (see https://tools.ietf.org/html/rfc8701, e.g. {0xFA, 0xFA}. If you want to set them, you cannot. If you want to read them, you cannot (the UTF-8 reader converts them to ��.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-)

if (alpn != NULL) {
JSS_RefByteArray(env, alpn, (jbyte**)&alpnData, &alpnLength);
if (alpnLength > 0) {
SSL_SetNextProtoNego(sock->fd, alpnData, alpnLength);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ALPN data only really needs to be provided before the handshake is performed. Not that I mind the extra constructors, but should we add a separate setApplicationProtocols(...) function to add this after construction? This would let us set it after construction from a JSSSocketFactory (which I think we have in ldap-jdk and/or PKI).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(And IIRC, it can be used with TLSv1.2 and can be provided on later handshakes. Under TLSv1.3 there's only the initial one so I guess it doesn't matter too much.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to worry about the renegotiation use case. But if it does turn out to be important we could add the extra function then.

Or now... I do prefer supplying as much "config" in the constructor rather than afterwards. Having to call extra functions to do more setup is something I find distasteful (I use that word in acknowledgement that it is indeed a matter of taste ^_^). Ideally there would be a single configuration record type that can supply SNI, ALPN and be extensible as new knobs are needed, so that there is not a combinatorial explosion in the number of possible constructors :)

Copy link
Member

@cipherboy cipherboy Oct 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also turns out (I had forgotten until I made changes in my other PR) -- NSS doesn't support changing ALPN values on renegotiation. Even 0RTT assumes (and validates!) ALPN doesn't change any.

"single configuration record type"

... So ... JSSParameters? :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cipherboy yep :D

@frasertweedale
Copy link
Contributor Author

This is largely fine.

What's missing is a ALPN selection routine on the server. I'm not sure if you wanted to add that; this is purely client side support, as is mine in #526 (it doesn't do server selection at all--that requires a call to SSL_SetNextProtoCallback).

My only thing is... this is the legacy SSLSocket... We should really be adding features its replacement, org.mozilla.jss.ssl.javax.JSSSocket.

I guess, what's the use case for still using this one? The other one is compliant with standard JDK interfaces and I'd prefer to push #526 (and then a later one adding server-side ALPN support) rather than continuing to add new features to the old one.

It is on my TODO list to rip out all of this old SSLSocket, including from PKI.

My 2c. I'll merge if there's a compelling reason to not use the new one for something.

I'll have a closer review of #526. I don't mind to abandon this #526 satisfies the client side use case of ACME tls-alpn-01 challenge.

@frasertweedale
Copy link
Contributor Author

Abandoning in favour of #526 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants