Erlang Mailing Lists

Author Message

<  Erlang bugs mailing list  ~  SSL 3.11.1 : Certificate-based authentication fails with Fir

Guest
Posted: Tue Jun 01, 2010 3:31 pm Reply with quote
Guest
Hello,

Certificate-based authentication fails with Firefox (on MacOS X), while the same setup succeeds with Safari, Chrome and curl (which probably use OpenSSL). The server is a very simple erlang SSL server that verifies the peer certificate :

ssl:ssl_accept(ClientTransportSocket, [{ssl_imp, new}, {active, false}, {fail_if_no_peer_cert, true}, {verify, verify_peer}, {cacertfile, ?ALL_CERTIFICATES}, {certfile, ?SERVER_CERT_FILE}, {keyfile, ?SERVER_KEY_FILE}, {validate_extensions_fun, fun validate_extensions/4}, {verify_fun, fun(ErrorList) -> case ErrorList of [] -> true; _ -> io:format("ErrorList is ~p~n", [ErrorList]), false end end}], infinity)

The bug seems to be in next_state/3, for the handshake case, around line 1766 of ssl_connection.erl (from the dev branch on github).

{Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0, KeyAlg,Version),
Start = {next_state, StateName, State0#state{tls_handshake_buffer = Buf}},
lists:foldl(Handle, Start, Packets)

Handlers (invoked from Handle) can call next_record to get the next packet. For example, handle_peer_cert/3 (line 1148), is as follows :

handle_peer_cert(PeerCert, PublicKeyInfo,
#state{session = Session} = State0) ->
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
{Record, State} = next_record(State1),
next_state(certify, Record, State).

next_record/1 will then attempt to get the next record, ignoring Packets list:

next_record(#state{tls_cipher_texts = [], socket = Socket} = State) ->
inet:setopts(Socket, [{active,once}]),
{no_record, State};
next_record(#state{tls_cipher_texts = [CT | Rest],
connection_states = ConnStates0} = State) ->
case ssl_record:decode_cipher_text(CT, ConnStates0) of
{Plain, ConnStates} ->
{Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}};
#alert{} = Alert ->
{Alert, State}
end.

If the client sends a single packet in the handshake buffer (i.e. lists:foldl only runs once), everything is fine. The handler will call next_record that will either serve the packet from tls_cipher_texts or handshake with the transport layer with {active, once}.

If the client sends more than one packet in the handshake buffer (Data + Buf0 above), and more data to the socket that can get returned by next_record, events end up being processed in wrong order.

This is typically what happens with Firefox.

Packets is composed of three elements :

[{{certificate, [<<48,130,5,6,48,...>>]}, <<11, ...>>},
{{client_key_exchange, {client_diffie_hellman_public, <<...>>}}, <<16,...>>},
{{certificate_verify, <<120, ...>>}, <<15,...>>}]

While at the same time, a record is present in tls_cipher_texts.

Eventually, the process fails with a function_clause error because the state isn't what is expected (in this very case, there is no cipher_state defined here since no client_key_exchange packet was processed):

** Reason for termination =
** {function_clause,[{ssl_cipher,block_decipher,
[#Fun<ssl_cipher.3.32442245>,undefined,20,
<<120,5,167,147,201,226,3,57,134,28,129,147,
41,178,143,254,181,2,49,7,140,13,191,3,135,
237,179,175,167,41,239,235,34,22,61,214,
228,77,124,198,115,53,25,153,151,63,51,197>>,
{3,1}]},
{ssl_record,decipher,2},
{ssl_record,decode_cipher_text,2},
{ssl_connection,next_record,1},
{ssl_connection,next_state,3},
{lists,foldl,3}, <--- this is the lists:foldl above
{ssl_connection,next_state,3},
{gen_fsm,handle_msg,7}]}

Paul


________________________________________________________________
erlang-bugs (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-bugs-unsubscribe@erlang.org

Post received from mailinglist
Guest
Posted: Wed Jun 02, 2010 3:52 pm Reply with quote
Guest
Hi !

Thank you for reporting this bug. I have created a fix could you please
try it out.

git fetch git://github.com/IngelaAndin/otp.git
ia/ssl_many_handshake_packages_at_once

Regards Ingela Erlang/OTP team, Ericsson AB

Paul Guyot wrote:
> Hello,
>
> Certificate-based authentication fails with Firefox (on MacOS X), while the same setup succeeds with Safari, Chrome and curl (which probably use OpenSSL). The server is a very simple erlang SSL server that verifies the peer certificate :
>
> ssl:ssl_accept(ClientTransportSocket, [{ssl_imp, new}, {active, false}, {fail_if_no_peer_cert, true}, {verify, verify_peer}, {cacertfile, ?ALL_CERTIFICATES}, {certfile, ?SERVER_CERT_FILE}, {keyfile, ?SERVER_KEY_FILE}, {validate_extensions_fun, fun validate_extensions/4}, {verify_fun, fun(ErrorList) -> case ErrorList of [] -> true; _ -> io:format("ErrorList is ~p~n", [ErrorList]), false end end}], infinity)
>
> The bug seems to be in next_state/3, for the handshake case, around line 1766 of ssl_connection.erl (from the dev branch on github).
>
> {Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0, KeyAlg,Version),
> Start = {next_state, StateName, State0#state{tls_handshake_buffer = Buf}},
> lists:foldl(Handle, Start, Packets)
>
> Handlers (invoked from Handle) can call next_record to get the next packet. For example, handle_peer_cert/3 (line 1148), is as follows :
>
> handle_peer_cert(PeerCert, PublicKeyInfo,
> #state{session = Session} = State0) ->
> State1 = State0#state{session =
> Session#session{peer_certificate = PeerCert},
> public_key_info = PublicKeyInfo},
> {Record, State} = next_record(State1),
> next_state(certify, Record, State).
>
> next_record/1 will then attempt to get the next record, ignoring Packets list:
>
> next_record(#state{tls_cipher_texts = [], socket = Socket} = State) ->
> inet:setopts(Socket, [{active,once}]),
> {no_record, State};
> next_record(#state{tls_cipher_texts = [CT | Rest],
> connection_states = ConnStates0} = State) ->
> case ssl_record:decode_cipher_text(CT, ConnStates0) of
> {Plain, ConnStates} ->
> {Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}};
> #alert{} = Alert ->
> {Alert, State}
> end.
>
> If the client sends a single packet in the handshake buffer (i.e. lists:foldl only runs once), everything is fine. The handler will call next_record that will either serve the packet from tls_cipher_texts or handshake with the transport layer with {active, once}.
>
> If the client sends more than one packet in the handshake buffer (Data + Buf0 above), and more data to the socket that can get returned by next_record, events end up being processed in wrong order.
>
> This is typically what happens with Firefox.
>
> Packets is composed of three elements :
>
> [{{certificate, [<<48,130,5,6,48,...>>]}, <<11, ...>>},
> {{client_key_exchange, {client_diffie_hellman_public, <<...>>}}, <<16,...>>},
> {{certificate_verify, <<120, ...>>}, <<15,...>>}]
>
> While at the same time, a record is present in tls_cipher_texts.
>
> Eventually, the process fails with a function_clause error because the state isn't what is expected (in this very case, there is no cipher_state defined here since no client_key_exchange packet was processed):
>
> ** Reason for termination =
> ** {function_clause,[{ssl_cipher,block_decipher,
> [#Fun<ssl_cipher.3.32442245>,undefined,20,
> <<120,5,167,147,201,226,3,57,134,28,129,147,
> 41,178,143,254,181,2,49,7,140,13,191,3,135,
> 237,179,175,167,41,239,235,34,22,61,214,
> 228,77,124,198,115,53,25,153,151,63,51,197>>,
> {3,1}]},
> {ssl_record,decipher,2},
> {ssl_record,decode_cipher_text,2},
> {ssl_connection,next_record,1},
> {ssl_connection,next_state,3},
> {lists,foldl,3}, <--- this is the lists:foldl above
> {ssl_connection,next_state,3},
> {gen_fsm,handle_msg,7}]}
>
> Paul
>
>
> ________________________________________________________________
> erlang-bugs (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:erlang-bugs-unsubscribe@erlang.org
>
>
>


________________________________________________________________
erlang-bugs (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-bugs-unsubscribe@erlang.org

Post received from mailinglist
Guest
Posted: Wed Jun 02, 2010 4:25 pm Reply with quote
Guest
Hello,

Thank you for your quick fix. I confirm that SSL 3.11.1 from your branch works as expected with Firefox and other Gecko-based browsers, as well as with Safari/Chrome/curl.

Thanks again !

Regards,

Paul

Le 2 juin 2010

Display posts from previous:  

All times are GMT
Page 1 of 1
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum