aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto
diff options
context:
space:
mode:
authorDániel Szoboszlay <[email protected]>2014-05-06 17:45:48 +0200
committerMagnus Henoch <[email protected]>2016-09-28 15:09:42 +0100
commit01222faf161cf656062144d01d0f93146215736b (patch)
treeb192e5b14bb96627038f70463ed6119ff6506cc9 /lib/crypto
parent0a1feff48388c8430f5eebd1531f769605601fab (diff)
downloadotp-01222faf161cf656062144d01d0f93146215736b.tar.gz
otp-01222faf161cf656062144d01d0f93146215736b.tar.bz2
otp-01222faf161cf656062144d01d0f93146215736b.zip
Update test suites with FIPS mode support
Every algorithm is now tested in both FIPS and non-FIPS modes (when crypto is compiled with FIPS support). In FIPS mode non-FIPS algorithms are disabled and the tests verify that they crash with notsup error as expected. In FIPS mode RSA and EC algorithms don't work if the key sizes are below a minimum required value - which happened to be the case with most keys used in the tests. These tests were changed to use longer keys (even in non-FIPS mode for simplicity). Conflicts: lib/crypto/test/crypto_SUITE.erl
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/test/blowfish_SUITE.erl72
-rw-r--r--lib/crypto/test/crypto_SUITE.erl299
2 files changed, 311 insertions, 60 deletions
diff --git a/lib/crypto/test/blowfish_SUITE.erl b/lib/crypto/test/blowfish_SUITE.erl
index d7c50dc6de..c45aae6916 100644
--- a/lib/crypto/test/blowfish_SUITE.erl
+++ b/lib/crypto/test/blowfish_SUITE.erl
@@ -107,11 +107,33 @@ end_per_testcase(_TestCase, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
-[ecb, cbc, cfb64, ofb64].
+[{group, fips},
+ {group, non_fips}].
groups() ->
- [].
+ [{fips, [], [no_ecb, no_cbc, no_cfb64, no_ofb64]},
+ {non_fips, [], [ecb, cbc, cfb64, ofb64]}].
+init_per_group(fips, Config) ->
+ case crypto:info_fips() of
+ enabled ->
+ Config;
+ not_enabled ->
+ true = crypto:enable_fips_mode(true),
+ enabled = crypto:info_fips(),
+ Config;
+ not_supported ->
+ {skip, "FIPS mode not supported"}
+ end;
+init_per_group(non_fips, Config) ->
+ case crypto:info_fips() of
+ enabled ->
+ true = crypto:enable_fips_mode(false),
+ not_enabled = crypto:info_fips(),
+ Config;
+ _NotEnabled ->
+ Config
+ end;
init_per_group(_GroupName, Config) ->
Config.
@@ -196,8 +218,54 @@ ofb64(Config) when is_list(Config) ->
to_bin("E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"),
ok.
+no_ecb(doc) ->
+ "Test that ECB mode is disabled";
+no_ecb(suite) ->
+ [];
+no_ecb(Config) when is_list(Config) ->
+ notsup(fun crypto:blowfish_ecb_encrypt/2,
+ [to_bin("0000000000000000"),
+ to_bin("FFFFFFFFFFFFFFFF")]).
+
+no_cbc(doc) ->
+ "Test that CBC mode is disabled";
+no_cbc(suite) ->
+ [];
+no_cbc(Config) when is_list(Config) ->
+ notsup(fun crypto:blowfish_cbc_encrypt/3,
+ [?KEY, ?IVEC, ?DATA_PADDED]).
+
+no_cfb64(doc) ->
+ "Test that CFB64 mode is disabled";
+no_cfb64(suite) ->
+ [];
+no_cfb64(Config) when is_list(Config) ->
+ notsup(fun crypto:blowfish_cfb64_encrypt/3,
+ [?KEY, ?IVEC, ?DATA]),
+ ok.
+
+no_ofb64(doc) ->
+ "Test that OFB64 mode is disabled";
+no_ofb64(suite) ->
+ [];
+no_ofb64(Config) when is_list(Config) ->
+ notsup(fun crypto:blowfish_ofb64_encrypt/3,
+ [?KEY, ?IVEC, ?DATA]).
+
%% Helper functions
+%% Assert function fails with notsup error
+notsup(Fun, Args) ->
+ ok = try
+ {error, {return, apply(Fun, Args)}}
+ catch
+ error:notsup ->
+ ok;
+ Class:Error ->
+ {error, {Class, Error}}
+ end.
+
+
%% Convert a hexadecimal string to a binary.
-spec(to_bin(L::string()) -> binary()).
to_bin(L) ->
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index f0811c3e4f..ec8c157d37 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -29,52 +29,88 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
+all() ->
[app,
appup,
- {group, md4},
- {group, md5},
- {group, ripemd160},
- {group, sha},
- {group, sha224},
- {group, sha256},
- {group, sha384},
- {group, sha512},
- {group, rsa},
- {group, dss},
- {group, ecdsa},
- {group, dh},
- {group, ecdh},
- {group, srp},
- {group, des_cbc},
- {group, des_cfb},
- {group, des3_cbc},
- {group, des3_cbf},
- {group, des3_cfb},
- {group, des_ede3},
- {group, blowfish_cbc},
- {group, blowfish_ecb},
- {group, blowfish_cfb64},
- {group, blowfish_ofb64},
- {group, aes_cbc128},
- {group, aes_cfb8},
- {group, aes_cfb128},
- {group, aes_cbc256},
- {group, aes_ecb},
- {group, aes_ige256},
- {group, rc2_cbc},
- {group, rc4},
- {group, aes_ctr},
- {group, aes_gcm},
- {group, chacha20_poly1305},
- {group, aes_cbc},
+ {group, fips},
+ {group, non_fips},
mod_pow,
exor,
rand_uniform
].
-groups() ->
- [{md4, [], [hash]},
+groups() ->
+ [{non_fips, [], [{group, md4},
+ {group, md5},
+ {group, ripemd160},
+ {group, sha},
+ {group, sha224},
+ {group, sha256},
+ {group, sha384},
+ {group, sha512},
+ {group, rsa},
+ {group, dss},
+ {group, ecdsa},
+ {group, dh},
+ {group, ecdh},
+ {group, srp},
+ {group, des_cbc},
+ {group, des_cfb},
+ {group, des3_cbc},
+ {group, des3_cbf},
+ {group, des3_cfb},
+ {group, des_ede3},
+ {group, blowfish_cbc},
+ {group, blowfish_ecb},
+ {group, blowfish_cfb64},
+ {group, blowfish_ofb64},
+ {group, aes_cbc128},
+ {group, aes_cfb8},
+ {group, aes_cfb128},
+ {group, aes_cbc256},
+ {group, aes_ige256},
+ {group, rc2_cbc},
+ {group, rc4},
+ {group, aes_ctr},
+ {group, aes_gcm},
+ {group, chacha20_poly1305},
+ {group, aes_cbc}]},
+ {fips, [], [{group, no_md4},
+ {group, no_md5},
+ {group, no_ripemd160},
+ {group, sha},
+ {group, sha224},
+ {group, sha256},
+ {group, sha384},
+ {group, sha512},
+ {group, rsa},
+ {group, dss},
+ {group, ecdsa},
+ {group, dh},
+ {group, ecdh},
+ {group, no_srp},
+ {group, no_des_cbc},
+ {group, no_des_cfb},
+ {group, des3_cbc},
+ {group, des3_cbf},
+ {group, des3_cfb},
+ {group, des_ede3},
+ {group, no_blowfish_cbc},
+ {group, no_blowfish_ecb},
+ {group, no_blowfish_cfb64},
+ {group, no_blowfish_ofb64},
+ {group, aes_cbc128},
+ {group, aes_cfb8},
+ {group, aes_cfb128},
+ {group, aes_cbc256},
+ {group, no_aes_ige256},
+ {group, no_rc2_cbc},
+ {group, no_rc4},
+ {group, aes_ctr},
+ {group, aes_gcm},
+ {group, no_chacha20_poly1305},
+ {group, aes_cbc}]},
+ {md4, [], [hash]},
{md5, [], [hash, hmac]},
{ripemd160, [], [hash]},
{sha, [], [hash, hmac]},
@@ -82,9 +118,9 @@ groups() ->
{sha256, [], [hash, hmac]},
{sha384, [], [hash, hmac]},
{sha512, [], [hash, hmac]},
- {rsa, [], [sign_verify,
- public_encrypt
- ]},
+ {rsa, [], [sign_verify,
+ public_encrypt
+ ]},
{dss, [], [sign_verify]},
{ecdsa, [], [sign_verify]},
{dh, [], [generate_compute]},
@@ -107,11 +143,25 @@ groups() ->
{blowfish_ecb, [], [block]},
{blowfish_cfb64, [], [block]},
{blowfish_ofb64,[], [block]},
- {rc4, [], [stream]},
+ {rc4, [], [stream]},
{aes_ctr, [], [stream]},
{aes_gcm, [], [aead]},
{chacha20_poly1305, [], [aead]},
- {aes_cbc, [], [block]}
+ {aes_cbc, [], [block]},
+ {no_md4, [], [no_support, no_hash]},
+ {no_md5, [], [no_support, no_hash, no_hmac]},
+ {no_ripemd160, [], [no_support, no_hash]},
+ {no_srp, [], [no_support, no_generate_compute]},
+ {no_des_cbc, [], [no_support, no_block]},
+ {no_des_cfb, [], [no_support, no_block]},
+ {no_blowfish_cbc, [], [no_support, no_block]},
+ {no_blowfish_ecb, [], [no_support, no_block]},
+ {no_blowfish_cfb64, [], [no_support, no_block]},
+ {no_blowfish_ofb64, [], [no_support, no_block]},
+ {no_aes_ige256, [], [no_support, no_block]},
+ {no_chacha20_poly1305, [], [no_support, no_block]},
+ {no_rc2_cbc, [], [no_support, no_block]},
+ {no_rc4, [], [no_support, no_stream]}
].
%%-------------------------------------------------------------------
@@ -141,12 +191,42 @@ end_per_suite(_Config) ->
application:stop(crypto).
%%-------------------------------------------------------------------
+init_per_group(fips, Config) ->
+ FIPSConfig = [{fips, true} | Config],
+ case crypto:info_fips() of
+ enabled ->
+ FIPSConfig;
+ not_enabled ->
+ true = crypto:enable_fips_mode(true),
+ enabled = crypto:info_fips(),
+ FIPSConfig;
+ not_supported ->
+ {skip, "FIPS mode not supported"}
+ end;
+init_per_group(non_fips, Config) ->
+ NonFIPSConfig = [{fips, false} | Config],
+ case crypto:info_fips() of
+ enabled ->
+ true = crypto:enable_fips_mode(false),
+ not_enabled = crypto:info_fips(),
+ NonFIPSConfig;
+ _NotEnabled ->
+ NonFIPSConfig
+ end;
init_per_group(GroupName, Config) ->
- case is_supported(GroupName) of
- true ->
- group_config(GroupName, Config);
- false ->
- {skip, "Group not supported"}
+ case atom_to_list(GroupName) of
+ "no_" ++ TypeStr ->
+ %% Negated test case: check the algorithm is not supported
+ %% (e.g. due to FIPS mode limitations)
+ [{type, list_to_atom(TypeStr)} | Config];
+ _Other ->
+ %% Regular test case: skip if the algorithm is not supported
+ case is_supported(GroupName) of
+ true ->
+ [{type, GroupName} | group_config(GroupName, Config)];
+ false ->
+ {skip, "Group not supported"}
+ end
end.
end_per_group(_GroupName, Config) ->
@@ -183,6 +263,12 @@ appup() ->
appup(Config) when is_list(Config) ->
ok = ?t:appup_test(crypto).
%%--------------------------------------------------------------------
+no_support() ->
+ [{doc, "Test an algorithm is not reported in the supported list"}].
+no_support(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ false = is_supported(Type).
+%%--------------------------------------------------------------------
hash() ->
[{doc, "Test all different hash functions"}].
hash(Config) when is_list(Config) ->
@@ -194,7 +280,14 @@ hash(Config) when is_list(Config) ->
hash(Type, Msgs, Digests),
hash(Type, lists:map(fun iolistify/1, Msgs), Digests),
hash_increment(Type, Inc, IncrDigest).
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+no_hash() ->
+ [{doc, "Test all disabled hash functions"}].
+no_hash(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ notsup(fun crypto:hash/2, [Type, <<"Hi There">>]),
+ notsup(fun crypto:hash_init/1, [Type]).
+%%--------------------------------------------------------------------
hmac() ->
[{doc, "Test all different hmac functions"}].
hmac(Config) when is_list(Config) ->
@@ -204,6 +297,13 @@ hmac(Config) when is_list(Config) ->
hmac(Type, lists:map(fun iolistify/1, Keys), lists:map(fun iolistify/1, Data), Expected),
hmac_increment(Type).
%%--------------------------------------------------------------------
+no_hmac() ->
+ [{doc, "Test all disabled hmac functions"}].
+no_hmac(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ notsup(fun crypto:hmac/3, [Type, <<"Key">>, <<"Hi There">>]),
+ notsup(fun crypto:hmac_init/2, [Type, <<"Key">>]).
+%%--------------------------------------------------------------------
cmac() ->
[{doc, "Test all different cmac functions"}].
cmac(Config) when is_list(Config) ->
@@ -214,12 +314,41 @@ cmac(Config) when is_list(Config) ->
block() ->
[{doc, "Test block ciphers"}].
block(Config) when is_list(Config) ->
+ Fips = proplists:get_bool(fips, Config),
+ Type = ?config(type, Config),
+ %% See comment about EVP_CIPHER_CTX_set_key_length in
+ %% block_crypt_nif in crypto.c.
+ case {Fips, Type} of
+ {true, aes_cfb8} ->
+ throw({skip, "Cannot test aes_cfb8 in FIPS mode because of key length issue"});
+ {true, aes_cfb128} ->
+ throw({skip, "Cannot test aes_cfb128 in FIPS mode because of key length issue"});
+ _ ->
+ ok
+ end,
+
Blocks = proplists:get_value(block, Config),
lists:foreach(fun block_cipher/1, Blocks),
lists:foreach(fun block_cipher/1, block_iolistify(Blocks)),
lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)).
%%--------------------------------------------------------------------
+no_block() ->
+ [{doc, "Test disabled block ciphers"}].
+no_block(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ Args = case Type of
+ des_ecb ->
+ [Type, <<"Key">>, <<"Hi There">>];
+ blowfish_ecb ->
+ [Type, <<"Key">>, <<"Hi There">>];
+ _ ->
+ [Type, <<"Key">>, <<"Ivec">>, <<"Hi There">>]
+ end,
+ N = length(Args),
+ notsup(fun crypto:block_encrypt/N, Args),
+ notsup(fun crypto:block_decrypt/N, Args).
+%%--------------------------------------------------------------------
stream() ->
[{doc, "Test stream ciphers"}].
stream(Config) when is_list(Config) ->
@@ -228,6 +357,12 @@ stream(Config) when is_list(Config) ->
lists:foreach(fun stream_cipher/1, Streams),
lists:foreach(fun stream_cipher/1, stream_iolistify(Streams)),
lists:foreach(fun stream_cipher_incment/1, stream_iolistify(Streams)).
+%%--------------------------------------------------------------------
+no_stream() ->
+ [{doc, "Test disabled stream ciphers"}].
+no_stream(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ notsup(fun crypto:stream_init/2, [Type, <<"Key">>]).
%%--------------------------------------------------------------------
aead() ->
@@ -259,6 +394,24 @@ generate_compute(Config) when is_list(Config) ->
GenCom = proplists:get_value(generate_compute, Config),
lists:foreach(fun do_generate_compute/1, GenCom).
%%--------------------------------------------------------------------
+no_generate_compute() ->
+ [{doc, "Test crypto:genarate_key and crypto:compute_key "
+ "for disabled algorithms"}].
+no_generate_compute(Config) when is_list(Config) ->
+ %% This test is specific to the SRP protocol
+ srp = ?config(type, Config),
+ {srp,
+ UserPrivate, UserGenParams, UserComParams,
+ HostPublic, HostPrivate, HostGenParams, HostComParams,
+ _SessionKey} = srp3(),
+ UserPublic = HostPublic, % use a fake public key
+ notsup(fun crypto:generate_key/3, [srp, UserGenParams, UserPrivate]),
+ notsup(fun crypto:generate_key/3, [srp, HostGenParams, HostPrivate]),
+ notsup(fun crypto:compute_key/4,
+ [srp, HostPublic, {UserPublic, UserPrivate}, UserComParams]),
+ notsup(fun crypto:compute_key/4,
+ [srp, UserPublic, {HostPublic, HostPrivate}, HostComParams]).
+%%--------------------------------------------------------------------
compute() ->
[{doc, " Test crypto:compute_key"}].
compute(Config) when is_list(Config) ->
@@ -577,6 +730,25 @@ do_generate({ecdh = Type, Curve, Priv, Pub}) ->
ct:fail({{crypto, generate_key, [Type, Priv, Curve]}, {expected, Pub}, {got, Other}})
end.
+notsup(Fun, Args) ->
+ Result =
+ try
+ {error, {return, apply(Fun, Args)}}
+ catch
+ error:notsup ->
+ ok;
+ Class:Error ->
+ {error, {Class, Error}}
+ end,
+ case Result of
+ ok ->
+ ok;
+ {error, Value} ->
+ {module, Module} = erlang:fun_info(Fun, module),
+ {name, Name} = erlang:fun_info(Fun, name),
+ ct:fail({{Module, Name, Args}, {expected, {error, notsup}}, {got, Value}})
+ end.
+
hexstr2point(X, Y) ->
<<4:8, (hexstr2bin(X))/binary, (hexstr2bin(Y))/binary>>.
@@ -791,12 +963,23 @@ group_config(rsa = Type, Config) ->
Private = rsa_private(),
PublicS = rsa_public_stronger(),
PrivateS = rsa_private_stronger(),
- SignVerify = sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS),
+ SignVerify =
+ case ?config(fips, Config) of
+ true ->
+ %% Use only the strong keys in FIPS mode
+ sign_verify_tests(Type, Msg,
+ PublicS, PrivateS,
+ PublicS, PrivateS);
+ false ->
+ sign_verify_tests(Type, Msg,
+ Public, Private,
+ PublicS, PrivateS)
+ end,
MsgPubEnc = <<"7896345786348 Asldi">>,
- PubPrivEnc = [{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_padding},
- rsa_oaep(),
- no_padding()
- ],
+ PubPrivEnc = [{rsa, PublicS, PrivateS, MsgPubEnc, rsa_pkcs1_padding},
+ rsa_oaep(),
+ no_padding()
+ ],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
group_config(dss = Type, Config) ->
Msg = dss_plain(),
@@ -2335,7 +2518,7 @@ ecdh() ->
TestCases).
dh() ->
- {dh, 0087761979513264537414556992123116644042638206717762626089877284926656954974893442000747478454809111207351620687968672207938731607963470779396984752680274820156266685080223616226905101126463253150237669547023934604953898814222890239130021414026118792251620881355456432549881723310342870016961804255746630219, 2}.
+ {dh, 90970053988169282502023478715631717259407236400413906591937635666709823903223997309250405131675572047545403771567755831138144089197560332757755059848492919215391041119286178688014693040542889497092308638580104031455627238700168892909539193174537248629499995652186913900511641708112112482297874449292467498403, 2}.
rsa_oaep() ->
%% ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
@@ -2423,8 +2606,8 @@ cmac_nist(aes_cbc256 = Type) ->
no_padding() ->
- Public = [_, Mod] = rsa_public(),
- Private = rsa_private(),
+ Public = [_, Mod] = rsa_public_stronger(),
+ Private = rsa_private_stronger(),
MsgLen = erlang:byte_size(int_to_bin(Mod)),
Msg = list_to_binary(lists:duplicate(MsgLen, $X)),
{rsa, Public, Private, Msg, rsa_no_padding}.