Posted by: fdmanana | September 24, 2010

The new SSL implementation in Erlang OTP

Recently, I was trying the new SSL implementation of OTP. This new implementation appeared in the R12 series and is now the default one in R14. Unlike the “old” implementation, this one is mostly done in Erlang (instead of being basically a wrapper around the OpenSSL library) and only uses the cryptographic functions that the OpenSSL library provides.

The motivation to try it out, was that I was having often (but not very often) errors like the following from the “old” SSL implementation:


** {error,{badinfo,{tcp,#Port,
                        <<"\r\n6d\r\n,\n{\"seq\":70,\"id\":\"97b36d5003934d0c9dd58057b05fa167
\",\"changes\":[{\"rev\":\"1-0d6deda5b380ae207ba87a7a3a32d0a1\"}]}\r\n6d\r\n,\n{\"seq\":71,\"id\":
\"8a1c475b8dc5426e9172d6b970ae7c03\",\"changes\":[{\"rev
\":\"1-72851f645fb6ab77f36866cbe505d82c\"}]}\r\n6d\r\n,\n{\"seq\":72,\"id\":
\"fdb1d5b1c5b24ce481463ad668c13c40\",\"changes\":[{\"rev\":\"1-
c37b5444eec8375631c326a0e77ca427\"}]}\r\n6d\r\n,\n{\"seq\":73,\"id\":
\"b612465dafc44699b09d8bef5d4d4d8d\",\"changes\":[{\"rev\":\"1-
be951f78ba830f5a1002abe0ce479c2d\"}]}\r\n6d\r\n,\n{\"seq\":74,\"id\":
\"d2c2b5a771ef4b57b6d58fce2808cf7c\",\"changes\":[{\"rev\":\"1-
c628443ff4dd7c3d9b4fd226727e2841\"}]}\r\n6d\r\n,\n{\"seq\":75,\"id\":
\"8d669c377f08442981ce2d18a21d920b\",\"changes\":[{\"rev
\":\"1-6db3a14c76701b87b0686412093ac103\"}]}\r\n6d\r\n,\n{\"seq\":76,\"id\":
\"367bf0948d9d459582d187c9232844b8\",\"changes\":[{\"rev
\":\"1-16ae7cf1c04c4f7c024493de1f18c8ed\"}]}\r\n6d\r\n,\n{\"seq\":77,\"id\":
\"f2c805327ae740098e5db221c3f27b4b\",\"changes\":[{\"rev\":\"1-
b22aa541f7e353a4cd430a9293239c77\"}]}\r\n6d\r\n,\n{\"seq\":78,\"id\":
\"6ddf8033cec845c8986ee4bd03ff8ed6\",\"changes\":[{\"rev
\":\"1-23f5957d250f5079277e6e4a86def1f1\"}]}\r\n6d\r\n,\n{\"seq\":79,\"id\":
\"738365bd4fed44158516211847c13616\",\"changes\":[{\"rev
\":\"1-6dcd375366f107fb2575c8eda6c6bdec\"}]}\r\n6d\r\n,\n{\"seq\":80,\"id\":
\"2d66c797761b4506934d00b2fd260f90\",\"changes\":[{\"rev\":\"1-
cc7dddd31fd753a9b4577607ce321cef\"}]}\r\n6d\r\n,\n{\"seq\":81,\"id\":
\"0c01c012d4f540a3a015d57681a0af4f\",\"changes\":[{\"rev\":\"1-
ff288fbba546fbfbf78c602e2fa39ea2\"}]}\r\n6d\r\n,\n{\"seq\":82,\"id\":
\"dc8a7ff04d37428ea83c3515a801bd32\",\"changes\":[{\"rev\":\"1-2">>}}}

(Yes, this was CouchDB related). So I tried the following code in OTP R13B03 and R13B04:


test() ->
    Body = iolist_to_binary([
        "GET / HTTP/1.1\r\n",
        "Host: ", ?HOST, "\r\n",
        "Accept: */*\r\n",
        "Connection: close\r\n", "\r\n"
    ]),
    application:start(crypto),
    application:start(public_key),
    application:start(ssl),
    Options = [
                {ssl_imp, new},
                binary,
                {nodelay, true},
                {active, false},
                {verify, verify_peer},
                {depth, 3},
                {cacertfile, "/etc/ssl/certs/ca-certificates.crt"}
    ],
    {ok, S} = ssl:connect(?HOST, 443, Options),
    ok = ssl:send(S, Body),
    loop(S),
    ssl:close(S).

loop(S) ->
    ssl:setopts(S, [{active, once}]),
    receive
    {ssl, S, Data} ->
        io:format("received data:  ~p~n", [Data]),
        loop(S);
    {ssl_closed, S} ->
        io:format("socket closed", []);
    {ssl_error, S, Error} ->
        io:format("socket error:  ~p", [Error])
    end.

And I was getting the following stack trace when ssl:connect/3 was called:


=ERROR REPORT==== 17-Sep-2010::18:33:04 ===
SSL: 1056: error:{error,
                  {badmatch,
                   {error,
                    {asn1,
                     {'Type not compatible with table constraint',
                      {{badmatch,{error,{asn1,{wrong_tag,{5,16}}}}},
                       [{'OTP-PUB-KEY','dec_Dss-Parms',2},
                        {'OTP-PUB-KEY',dec_SignatureAlgorithm,2},
                        {'OTP-PUB-KEY',dec_OTPTBSCertificate,2},
                        {'OTP-PUB-KEY',dec_OTPCertificate,2},
                        {'OTP-PUB-KEY',decode,2},
                        {pubkey_cert_records,decode_cert,1},
                        {public_key,pkix_decode_cert,2},
                        {ssl_certificate_db,add_certs,3}]}}}}}} /etc/ssl/certs/ca-certificates.crt
  [{ssl_connection,init_certificates,2},
   {ssl_connection,ssl_init,2},
   {ssl_connection,init,1},
   {gen_fsm,init_it,6},
   {proc_lib,init_p_do_apply,3}]

I was finding it weird, since the trusted certificates files I was providing was in the PEM format (supported according to the man page) and it worked with the “old” SSL implementation.

I posted a message to the erlang-bugs mailing list reporting the issue, since it seemed to me that it was a regression:

http://www.erlang.org/cgi-bin/ezmlm-cgi?2:sss:2031:201009:nkpigljldefpimkjppbn#b

It turned out to be a true regression.
Fortunatelly, Ingela Anderton Andin, from the OTP team, quickly responded and worked on a few patches against the R14B release that I tried out until it worked. Those patches are all available at her github account: http://github.com/IngelaAndin

(I must say github is one of my favourite free services on the Web, congratulations to the creators and maintainers).

A special thanks to Ingela for her quick response.
I squashed the relevant commits into a single patch to apply against R14B and it’s available here:


http://gist.github.com/594325

Since Ubuntu is using R13B03 and can not update to R14B so soon (it’s a very recent release and besides desktopcouch/couchdb, they have other Erlang OTP dependents), I prepared them an equivalent patch to apply against R13B03 (the ssl and public_key code has quite a lot of diferences between R13 and R14), available in the following github gist:

http://gist.github.com/594316

Also, as part of that same erlang-bugs thread, it was also proposed a suggestion for adding an extra possible value passed to the certificate validation chain function (option verify_fun) that allows for distinguishing between unknown CAs (not listed in the trusted certificates file) and certificates self-signed by the peer (something common in intranets). This because currently, as of R14B, the term {bad_term, unknown_ca} is used to signal both cases (unknown CA and self-signed ceritificate.

It turns out that the suggestion was accepted by the OTP team and is now available in development branches (will make it into the next OTP R14 series release):

http://github.com/IngelaAndin/otp/commit/3962e4f5d7a496c32862b05eeab026837a6ff681

After that commit, an unknown CA error is still represented by the term {bad_cert, unknown_ca} and a self-signed certificate is now represented by the term {bad_cert, selfsigned_peer} (the “old” SSL implementation allowed to distinguish both cases as well).

Conclusion:

If you use the new SSL implementation (default on R14), don’t except to be able to use the certificates file in a Ubuntu system (and also in a Linux Caixa Mágica system). You’ll have to apply one of those patches available in the gists mentioned above.

I’m a bit surprised that I was the first one finding and reporting this issue/regression.

A big thanks to Ingela Andin from the OTP team for the quick response.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: