Description of the Issue:
Chromium Android fails when SSL server gives a empty protocol list in NPN
extension in a ServerHello message.
When visiting https://www.ossifrage.net/ by using Chromium Android,
gets "Error 2 (net::ERR_FAILED): Unknown error". The site works fine in
desktop chrome and in the android browser.
After investigation. the failure is caused by server doesn't give any
advertised protocols in TLS "Next Protocol Negotiation" extension in a
ServerHello message.
In the specification of NPN, it says "The extension_data field of a
next_protocol_negotiation extension in a ServerHello contains an optional
list of protocols advertised by the server.", which means the server may
not send the protocol list in NPN extension in a ServerHello message. Then
in "Protocol selection" phase, the spec says
"It's expected that a client will have a list of protocols that it
supports, in preference order, and will only select a protocol if the
server supports it. In that case, the client SHOULD select the first
protocol advertised by the server that it also supports. In the event that
the client doesn't support any of server's protocols, or the server doesn't
advertise any, it SHOULD select the first protocol that it supports."
Seems Chromium NSS implementation handles the case that the server doesn't
advertise any protocols, but Chromium openssl implementation doesn't.
jnd: could you find out where Chrome sets the net::ERR_FAILED error code?
This won't help fix this bug. I just wanted to improve Chrome's error
reporting. net::ERR_FAILED is the default error code and is not
informative.
The call sequence was (in ssl_client_socket_openssl.cc)
SSLClientSocketOpenSSL::DoHandshake() ->
MapOpenSSLError(int err, const crypto::OpenSSLErrStackTracer& tracer)->
MapOpenSSLErrorSSL().
In MapOpenSSLErrorSSL, the OpenSSL error SSL_R_PARSE_TLSEXT(227) maps to
ERR_FAILED in default switch.
Select the first protocol from the next protocol list of SSLConfig if If we
didn't find a protocol.
It's possible that there is no overlap between the server advertised
protocols and SSL client advertised protocols. And Server even can give a
empty protocol list in NPN extension in a ServerHello message.
In this case, the SSL client should pick up the first protocol from the
next protocol list of SSLConfig.
info: yes, it appears to be the same problem. The server's behaviour is
suboptimal, but not strictly invalid. The client should tolerate it but I
suspect that the fix just hasn't made it into a Chrome Android release yet.
If it helps, here's my SSL configuration. Server is Apache 2.4. Works on
everything I've tested with (Android stock browser, Chromium desktop,
Chrome desktop, Firefox desktop, Firefox mobile, Lynx, cURL, wget, httpie).
SSLEngine on
SSLProtocol -ALL +TLSv1.2 +TLSv1.1 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite
ECDHE-RSA-AES256-SHA384:AES256-GCM-SHA384:RC4-SHA:!ADH:!MD5:!aNULL:!EDH
SSLCompression Off