\o Hi all, I saw that ALPN support from JEP 244 was backported to JDK8 and I've recently had the time to take a closer look at it. For context, I'm one of the maintainers of JSS, a NSS wrapper for Java. I've been discussing this with another contributor, Fraser (cc'd).
One of the concerns we have with the implementation (and its exposure in the corresponding SSLEngine/SSLSocket/SSLParameters interface) is that protocols are passed in as Strings. However, RFC 7301 says in section 6: > 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. When applied with GREASE'd values from RFC 8701, Strings don't work well. In particular, most of the registered values [0] are non-UTF-8, which can't be easily round-tripped in Java. This means that while precise octet values are specified by IANA, they cannot be properly specified in Java. In particular: byte[] desired = new byte[]{ (byte) 0xFA, (byte) 0xFA }; String encoded = new String(desired, StandardCharsets.UTF_8); byte[] wire = encoded.getBytes(StandardCharsets.UTF_8); String round = new String(wire, StandardCharsets.UTF_8); fails, as does choosing US_ASCII for the encoding: byte[] desired = new byte[]{ (byte) 0xFA, (byte) 0xFA }; String encoded = new String(desired, StandardCharsets.US_ASCII); byte[] wire = encoded.getBytes(StandardCharsets.UTF_8); String round = new String(wire, StandardCharsets.UTF_8); Note that we (at the application level) can't control the final (wire / round-tripped) encoding to UTF_8 as this is done within the SunJSSE implementation: https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java#L100 https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java#L170 https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java#L223 https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java#L425 and perhaps other files I'm missing. This decreases interoperability with other TLS implementations. OpenSSL [1], NSS [2], and GnuTLS [3] support setting opaque blobs as the ALPN protocol list, meaning the caller is free to supply GREASE'd values. Go on the other hand still uses its string [4], but that string class supports round-tripping non-UTF8 values correctly [5]. Additionally, it means that GREASE'd values sent by Java applications aren't compliant with the RFC 8701/IANA wire values. Is there some workaround I'm missing? I believe that setting US_ASCII internally in SunJSSE isn't sufficient to ensure the right wire encoding gets used. I'm thinking the only real fix is to deprecate the String methods and provide byte[] methods for all identifiers. Thanks in advanced, Alex [0]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids [1]: https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_alpn_protos.html [2]: https://github.com/nss-dev/nss/blob/master/lib/ssl/ssl.h#L392-L409 [3]: https://gnutls.org/manual/html_node/Application-Layer-Protocol-Negotiation-_0028ALPN_0029.html [4]: https://golang.org/pkg/crypto/tls/#ClientHelloInfo [5]: https://play.golang.org/p/PjyZ-NZmKQe