Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade crypto functions to support OTP 23 #231

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ language: erlang
notifications:
email: false
otp_release:
- 23.0
- 22.0
- 21.3
- 21.2.3
Expand Down
Binary file modified rebar
Binary file not shown.
1 change: 1 addition & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{erl_opts, [debug_info,
{platform_define, "^R15", 'gen_tcp_r15b_workaround'},
{platform_define, "^(R14|R15|R16B-)", 'crypto_compatibility'},
{platform_define, "^(R14|R15|R16|17|18|19|20|21|22)", new_crypto_unavailable},
{platform_define, "^(R14|R15|R16B|17)", 'rand_mod_unavailable'},
{platform_define, "^(R14|R15|R16B|17)", 'sni_unavailable'},
{platform_define, "^(R14|R15|R16)", 'map_unavailable'},
Expand Down
25 changes: 23 additions & 2 deletions src/mochiweb_session.erl
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,15 @@ decrypt_data(<<IV:16/binary, Crypt/binary>>, Key) ->
crypto:aes_cfb_128_decrypt(Key, IV, Crypt).

-spec gen_key(iolist(), iolist()) -> binary().
gen_key(ExpirationTime, ServerKey)->
gen_key(ExpirationTime, ServerKey) ->
crypto:md5_mac(ServerKey, [ExpirationTime]).

-spec gen_hmac(iolist(), binary(), iolist(), binary()) -> binary().
gen_hmac(ExpirationTime, Data, SessionKey, Key) ->
crypto:sha_mac(Key, [ExpirationTime, Data, SessionKey]).

-else.
-ifdef(new_crypto_unavailable).
-spec encrypt_data(binary(), binary()) -> binary().
encrypt_data(Data, Key) ->
IV = crypto:strong_rand_bytes(16),
Expand All @@ -150,13 +151,33 @@ decrypt_data(<<IV:16/binary, Crypt/binary>>, Key) ->
crypto:block_decrypt(aes_cfb128, Key, IV, Crypt).

-spec gen_key(iolist(), iolist()) -> binary().
gen_key(ExpirationTime, ServerKey)->
gen_key(ExpirationTime, ServerKey) ->
crypto:hmac(md5, ServerKey, [ExpirationTime]).

-spec gen_hmac(iolist(), binary(), iolist(), binary()) -> binary().
gen_hmac(ExpirationTime, Data, SessionKey, Key) ->
crypto:hmac(sha, Key, [ExpirationTime, Data, SessionKey]).

-else. % new crypto available (OTP 23+)
-spec encrypt_data(binary(), binary()) -> binary().
encrypt_data(Data, Key) ->
IV = crypto:strong_rand_bytes(16),
Crypt = crypto:crypto_one_time(aes_128_cfb128, Key, IV, Data, true),
<<IV/binary, Crypt/binary>>.

-spec decrypt_data(binary(), binary()) -> binary().
decrypt_data(<<IV:16/binary, Crypt/binary>>, Key) ->
crypto:crypto_one_time(aes_128_cfb128, Key, IV, Crypt, false).

-spec gen_key(iolist(), iolist()) -> binary().
gen_key(ExpirationTime, ServerKey) ->
crypto:mac(hmac, md5, ServerKey, [ExpirationTime]).

-spec gen_hmac(iolist(), binary(), iolist(), binary()) -> binary().
gen_hmac(ExpirationTime, Data, SessionKey, Key) ->
crypto:mac(hmac, sha, Key, [ExpirationTime, Data, SessionKey]).

-endif.
-endif.

-ifdef(TEST).
Expand Down
40 changes: 30 additions & 10 deletions src/mochiweb_socket.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
listen(Ssl, Port, Opts, SslOpts) ->
case Ssl of
true ->
Opts1 = add_unbroken_ciphers_default(Opts ++ SslOpts),
Opts2 = add_safe_protocol_versions(Opts1),
Opts1 = add_safe_protocol_versions(Opts),
Opts2 = add_unbroken_ciphers_default(Opts1 ++ SslOpts),
case ssl:listen(Port, Opts2) of
{ok, ListenSocket} ->
{ok, {ssl, ListenSocket}};
Expand All @@ -29,11 +29,39 @@ listen(Ssl, Port, Opts, SslOpts) ->
gen_tcp:listen(Port, Opts)
end.

-ifdef(new_crypto_unavailable).
add_unbroken_ciphers_default(Opts) ->
Default = filter_unsecure_cipher_suites(ssl:cipher_suites()),
Ciphers = filter_broken_cipher_suites(proplists:get_value(ciphers, Opts, Default)),
[{ciphers, Ciphers} | proplists:delete(ciphers, Opts)].

%% Filter old map style cipher suites
filter_unsecure_cipher_suites(Ciphers) ->
lists:filter(fun
({_,des_cbc,_}) -> false;
({_,_,md5}) -> false;
(_) -> true
end,
Ciphers).

-else.
add_unbroken_ciphers_default(Opts) ->
%% add_safe_protocol_versions/1 must have been called to ensure a {versions, _} tuple is present
Versions = proplists:get_value(versions, Opts),
CipherSuites = lists:append([ssl:cipher_suites(all, Version) || Version <- Versions]),
Default = filter_unsecure_cipher_suites(CipherSuites),
Ciphers = filter_broken_cipher_suites(proplists:get_value(ciphers, Opts, Default)),
[{ciphers, Ciphers} | proplists:delete(ciphers, Opts)].

%% Filter new map style cipher suites
filter_unsecure_cipher_suites(Ciphers) ->
ssl:filter_cipher_suites(Ciphers, [
{key_exchange, fun(des_cbc) -> false; (_) -> true end},
{mac, fun(md5) -> false; (_) -> true end}
]).

-endif.

filter_broken_cipher_suites(Ciphers) ->
case proplists:get_value(ssl_app, ssl:versions()) of
"5.3" ++ _ ->
Expand All @@ -44,14 +72,6 @@ filter_broken_cipher_suites(Ciphers) ->
Ciphers
end.

filter_unsecure_cipher_suites(Ciphers) ->
lists:filter(fun
({_,des_cbc,_}) -> false;
({_,_,md5}) -> false;
(_) -> true
end,
Ciphers).

add_safe_protocol_versions(Opts) ->
case proplists:is_defined(versions, Opts) of
true ->
Expand Down