From 5a593e4b540c26e7eba3bd44527d929b99c999cb Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Fri, 30 Mar 2012 12:56:08 +0100 Subject: Accept a cacertsdir option in ssl_options; scan this for certificates when an SSL connection is attempted. NB ssl_opts/1 goes in rabbit_net so it can be used for the erlang client too. --- src/rabbit_net.erl | 21 ++++++++++++++++++++- src/rabbit_networking.erl | 3 ++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/rabbit_net.erl b/src/rabbit_net.erl index e6a05335..914c99d6 100644 --- a/src/rabbit_net.erl +++ b/src/rabbit_net.erl @@ -17,7 +17,7 @@ -module(rabbit_net). -include("rabbit.hrl"). --export([is_ssl/1, ssl_info/1, controlling_process/2, getstat/2, +-export([is_ssl/1, ssl_info/1, ssl_opts/1, controlling_process/2, getstat/2, recv/1, async_recv/3, port_command/2, setopts/2, send/2, close/1, maybe_fast_close/1, sockname/1, peername/1, peercert/1, connection_string/2]). @@ -39,6 +39,7 @@ -spec(ssl_info/1 :: (socket()) -> 'nossl' | ok_val_or_error( {atom(), {atom(), atom(), atom()}})). +-spec(ssl_opts/1 :: (rabbit_types:infos()) -> rabbit_types:infos()). -spec(controlling_process/2 :: (socket(), pid()) -> ok_or_any_error()). -spec(getstat/2 :: (socket(), [stat_option()]) @@ -80,6 +81,14 @@ ssl_info(Sock) when ?IS_SSL(Sock) -> ssl_info(_Sock) -> nossl. +ssl_opts(SslOpts0) -> + case proplists:lookup(cacertdir, SslOpts0) of + {cacertdir, Dir} -> + [{cacerts, load_cacerts_dir(Dir)} | SslOpts0]; + none -> + SslOpts0 + end. + controlling_process(Sock, Pid) when ?IS_SSL(Sock) -> ssl:controlling_process(Sock#ssl_socket.ssl, Pid); controlling_process(Sock, Pid) when is_port(Sock) -> @@ -164,3 +173,13 @@ connection_string(Sock, Direction) -> {_, {error, _Reason} = Error} -> Error end. + +load_cacerts_dir(Dir) -> + filelib:fold_files( + Dir, ".*\\.pem", false, + fun (F, Certs) -> + {ok, PemBin} = file:read_file(F), + Ders = [Cert || {'Certificate', Cert, not_encrypted} + <- public_key:pem_decode(PemBin)], + Ders ++ Certs + end, []). diff --git a/src/rabbit_networking.erl b/src/rabbit_networking.erl index 825d1bb1..f77073cc 100644 --- a/src/rabbit_networking.erl +++ b/src/rabbit_networking.erl @@ -160,8 +160,9 @@ ensure_ssl() -> | SslOptsConfig] end. -ssl_transform_fun(SslOpts) -> +ssl_transform_fun(SslOpts0) -> fun (Sock) -> + SslOpts = rabbit_net:ssl_opts(SslOpts0), case catch ssl:ssl_accept(Sock, SslOpts, ?SSL_TIMEOUT * 1000) of {ok, SslSock} -> {ok, #ssl_socket{tcp = Sock, ssl = SslSock}}; -- cgit v1.2.1 From 4f2bdcf7a08409d1c2c16337096626b562c7ae7f Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Tue, 10 Apr 2012 17:04:47 +0100 Subject: Instead of reading the directory and parsing the certificates every time a connection opens, make a file with all the certificates every time the directory contents change. The aggregate file is named for the /expected/ mtime of the directory once it's been written (to a resolution of one second). This avoids the memory blowout caused by supplying the certificate binaries with every connection -- those don't get garbage collected -- and is much faster, much the same as just using a static cacertfile. --- src/rabbit_net.erl | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/rabbit_net.erl b/src/rabbit_net.erl index 914c99d6..3c1ad6c2 100644 --- a/src/rabbit_net.erl +++ b/src/rabbit_net.erl @@ -84,7 +84,7 @@ ssl_info(_Sock) -> ssl_opts(SslOpts0) -> case proplists:lookup(cacertdir, SslOpts0) of {cacertdir, Dir} -> - [{cacerts, load_cacerts_dir(Dir)} | SslOpts0]; + [{cacertfile, load_cacerts_dir(Dir)} | SslOpts0]; none -> SslOpts0 end. @@ -175,11 +175,35 @@ connection_string(Sock, Direction) -> end. load_cacerts_dir(Dir) -> - filelib:fold_files( - Dir, ".*\\.pem", false, - fun (F, Certs) -> - {ok, PemBin} = file:read_file(F), - Ders = [Cert || {'Certificate', Cert, not_encrypted} - <- public_key:pem_decode(PemBin)], - Ders ++ Certs - end, []). + LastModified = filelib:last_modified(Dir), + Stamp = integer_to_list( + calendar:datetime_to_gregorian_seconds(LastModified)), + CurrentFilename = filename:join(Dir, Stamp ++ ".ca"), + case filelib:is_file(CurrentFilename) of + true -> + CurrentFilename; + false -> + NewContents = + filelib:fold_files( + Dir, ".*\\.pem", false, + fun (F, Certs) -> + {ok, PemBin} = file:read_file(F), + [PemBin | Certs] + end, []), + %% Remove old files + filelib:fold_files( + Dir, "[0-9]*\\.ca", false, + fun (F, _) -> + file:delete(F) + end, undefined), + %% Create a new file name with the expected mtime of the + %% directory once we've written to it. This will + %% occasionally miss; this assumes it's not a huge deal to + %% re-generate it. + NewStamp = integer_to_list( + calendar:datetime_to_gregorian_seconds( + calendar:local_time())), + NewFilename = filename:join(Dir, NewStamp ++ ".ca"), + file:write_file(NewFilename, NewContents), + NewFilename + end. -- cgit v1.2.1 From 9a47e34280e9db29d3986e108fc435d0d81bc313 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Wed, 11 Apr 2012 13:47:12 +0100 Subject: Factor out CA file name generation --- src/rabbit_net.erl | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/rabbit_net.erl b/src/rabbit_net.erl index 3c1ad6c2..c77eb789 100644 --- a/src/rabbit_net.erl +++ b/src/rabbit_net.erl @@ -174,14 +174,16 @@ connection_string(Sock, Direction) -> Error end. +ca_tmp_filename(Dir, DateTime) -> + SecondsStr = integer_to_list( + calendar:datetime_to_gregorian_seconds(DateTime)), + filename:join(Dir, SecondsStr ++ ".tmp"). + load_cacerts_dir(Dir) -> - LastModified = filelib:last_modified(Dir), - Stamp = integer_to_list( - calendar:datetime_to_gregorian_seconds(LastModified)), - CurrentFilename = filename:join(Dir, Stamp ++ ".ca"), - case filelib:is_file(CurrentFilename) of + ExpectedFilename = ca_tmp_filename(Dir, filelib:last_modified(Dir)), + case filelib:is_file(ExpectedFilename) of true -> - CurrentFilename; + ExpectedFilename; false -> NewContents = filelib:fold_files( @@ -192,7 +194,7 @@ load_cacerts_dir(Dir) -> end, []), %% Remove old files filelib:fold_files( - Dir, "[0-9]*\\.ca", false, + Dir, "[0-9]*\\.tmp", false, fun (F, _) -> file:delete(F) end, undefined), @@ -200,10 +202,7 @@ load_cacerts_dir(Dir) -> %% directory once we've written to it. This will %% occasionally miss; this assumes it's not a huge deal to %% re-generate it. - NewStamp = integer_to_list( - calendar:datetime_to_gregorian_seconds( - calendar:local_time())), - NewFilename = filename:join(Dir, NewStamp ++ ".ca"), + NewFilename = ca_tmp_filename(Dir, calendar:local_time()), file:write_file(NewFilename, NewContents), NewFilename end. -- cgit v1.2.1