%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(engine_SUITE).
-include_lib("common_test/include/ct.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{seconds, 10}}
].
all() ->
[
get_all_possible_methods,
engine_load_all_methods,
engine_load_some_methods,
multiple_engine_load,
engine_list,
get_id_and_name,
engine_by_id,
bad_arguments,
unknown_engine,
pre_command_fail_bad_value,
pre_command_fail_bad_key,
failed_engine_init,
ctrl_cmd_string,
ctrl_cmd_string_optional,
ensure_load,
{group, engine_stored_key},
{group, engine_fakes_rsa}
].
groups() ->
[{engine_stored_key, [],
[
sign_verify_rsa,
sign_verify_dsa,
sign_verify_ecdsa,
sign_verify_rsa_pwd,
sign_verify_rsa_pwd_bad_pwd,
priv_encrypt_pub_decrypt_rsa,
priv_encrypt_pub_decrypt_rsa_pwd,
pub_encrypt_priv_decrypt_rsa,
pub_encrypt_priv_decrypt_rsa_pwd,
get_pub_from_priv_key_rsa,
get_pub_from_priv_key_rsa_pwd,
get_pub_from_priv_key_rsa_pwd_no_pwd,
get_pub_from_priv_key_rsa_pwd_bad_pwd,
get_pub_from_priv_key_dsa,
get_pub_from_priv_key_ecdsa
]},
{engine_fakes_rsa, [], [sign_verify_rsa_fake
]}
].
init_per_suite(Config) ->
case {os:type(), crypto:info_lib()} of
{_, [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}]} ->
{skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
{{unix,darwin}, _} ->
{skip, "Engine unsupported on Darwin"};
{{win32,_}, _} ->
{skip, "Engine unsupported on Windows"};
{OS, Res} ->
ct:log("crypto:info_lib() -> ~p\nos:type() -> ~p", [Res,OS]),
try crypto:start() of
ok ->
Config;
{error,{already_started,crypto}} ->
Config
catch _:_ ->
{skip, "Crypto did not start"}
end
end.
end_per_suite(_Config) ->
ok.
%%--------------------------------------------------------------------
init_per_group(engine_stored_key, Config) ->
group_load_engine(Config, [engine_method_rsa]);
init_per_group(engine_fakes_rsa, Config) ->
case crypto:info_lib() of
[{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer), LibVer >= 16#10100000 ->
group_load_engine(Config, []);
_ ->
{skip, "Too low OpenSSL cryptolib version"}
end;
init_per_group(_Group, Config0) ->
Config0.
group_load_engine(Config, ExcludeMthds) ->
case load_storage_engine(Config, ExcludeMthds) of
{ok, E} ->
KeyDir = key_dir(Config),
[{storage_engine,E}, {storage_dir,KeyDir} | Config];
{error, notexist} ->
{skip, "OTP Test engine not found"};
{error, notsup} ->
{skip, "Engine not supported on this SSL version"};
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"};
Other ->
ct:log("Engine load failed: ~p",[Other]),
{fail, "Engine load failed"}
end.
end_per_group(_, Config) ->
case proplists:get_value(storage_engine, Config) of
undefined ->
ok;
E ->
ok = crypto:engine_unload(E)
end.
%%--------------------------------------------------------------------
init_per_testcase(_Case, Config) ->
Config.
end_per_testcase(_Case, _Config) ->
ok.
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
get_all_possible_methods() ->
[{doc, "Just fetch all possible engine methods supported."}].
get_all_possible_methods(Config) when is_list(Config) ->
try
List = crypto:engine_get_all_methods(),
true = erlang:is_list(List),
ct:log("crypto:engine_get_all_methods() -> ~p\n", [List]),
ok
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
engine_load_all_methods()->
[{doc, "Use a dummy md5 engine that does not implement md5"
"but rather returns a static binary to test that crypto:engine_load "
"functions works."}].
engine_load_all_methods(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]) of
{ok, E} ->
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_still_original_engine);
Md5Hash2 ->
ok;
_ ->
ct:fail(fail_to_load_engine)
end,
ok = crypto:engine_unload(E),
case crypto:hash(md5, "Don't panic") of
Md5Hash2 ->
ct:fail(fail_to_unload_still_test_engine);
Md5Hash1 ->
ok;
_ ->
ct:fail(fail_to_unload_engine)
end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
engine_load_some_methods()->
[{doc, "Use a dummy md5 engine that does not implement md5"
"but rather returns a static binary to test that crypto:engine_load "
"functions works."}].
engine_load_some_methods(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
EngineMethods = crypto:engine_get_all_methods() --
[engine_method_dh, engine_method_rand,
engine_method_ciphers, engine_method_store,
engine_method_pkey_meths, engine_method_pkey_asn1_meths],
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[],
EngineMethods) of
{ok, E} ->
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_engine_still_original);
Md5Hash2 ->
ok;
_ ->
ct:fail(fail_to_load_engine)
end,
ok = crypto:engine_unload(E),
case crypto:hash(md5, "Don't panic") of
Md5Hash2 ->
ct:fail(fail_to_unload_still_test_engine);
Md5Hash1 ->
ok;
_ ->
ct:fail(fail_to_unload_engine)
end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
multiple_engine_load()->
[{doc, "Use a dummy md5 engine that does not implement md5"
"but rather returns a static binary to test that crypto:engine_load "
"functions works when called multiple times."}].
multiple_engine_load(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]) of
{ok, E} ->
{ok, E1} = crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]),
{ok, E2} = crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]),
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_still_original_engine);
Md5Hash2 ->
ok;
_ ->
ct:fail(fail_to_load_engine)
end,
ok = crypto:engine_unload(E2),
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_still_original_engine);
Md5Hash2 ->
ok;
_ ->
ct:fail(fail_to_load_engine)
end,
ok = crypto:engine_unload(E),
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_still_original_engine);
Md5Hash2 ->
ok;
_ ->
ct:fail(fail_to_load_engine)
end,
ok = crypto:engine_unload(E1),
case crypto:hash(md5, "Don't panic") of
Md5Hash2 ->
ct:fail(fail_to_unload_still_test_engine);
Md5Hash1 ->
ok;
_ ->
ct:fail(fail_to_unload_engine)
end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
engine_list()->
[{doc, "Test add and remove engine ID to the SSL internal engine list."}].
engine_list(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
EngineList0 = crypto:engine_list(),
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]) of
{ok, E} ->
EngineList0 = crypto:engine_list(),
ok = crypto:engine_add(E),
[<<"MD5">>] = lists:subtract(crypto:engine_list(), EngineList0),
ok = crypto:engine_remove(E),
EngineList0 = crypto:engine_list(),
ok = crypto:engine_unload(E);
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
get_id_and_name()->
[{doc, "Test fetching id and name from an engine."}].
get_id_and_name(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]) of
{ok, E} ->
<<"MD5">> = crypto:engine_get_id(E),
<<"MD5 test engine">> = crypto:engine_get_name(E),
ok = crypto:engine_unload(E);
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
engine_by_id()->
[{doc, "Test fetching a new reference the the engine when the"
"engine id is added to the SSL engine list."}].
engine_by_id(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[]) of
{ok, E} ->
case crypto:engine_by_id(<<"MD5">>) of
{error,bad_engine_id} ->
ok;
{ok, _} ->
ct:fail(fail_engine_found)
end,
ok = crypto:engine_add(E),
{ok, _E1} = crypto:engine_by_id(<<"MD5">>),
ok = crypto:engine_remove(E),
ok = crypto:engine_unload(E);
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
%%-------------------------------------------------------------------------
%% Error cases
bad_arguments()->
[{doc, "Test different arguments in bad format."}].
bad_arguments(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
try
crypto:engine_load(fail_engine, [], [])
of
X1 ->
ct:fail("1 Got ~p",[X1])
catch
error:badarg ->
ok
end,
try
crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
1,
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[])
of
{error,bad_engine_id} ->
throw(dynamic_engine_unsupported);
X2 ->
ct:fail("2 Got ~p",[X2])
catch
error:badarg ->
ok
end,
try
crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
{'ID', <<"MD5">>},
<<"LOAD">>],
[])
of
{error,bad_engine_id} -> % should have happend in the previous try...catch end!
throw(dynamic_engine_unsupported);
X3 ->
ct:fail("3 Got ~p",[X3])
catch
error:badarg ->
ok
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"};
throw:dynamic_engine_unsupported ->
{skip, "Dynamic Engine not supported"}
end
end.
unknown_engine() ->
[{doc, "Try to load a non existent engine."}].
unknown_engine(Config) when is_list(Config) ->
try
{error, bad_engine_id} = crypto:engine_load(<<"fail_engine">>, [], []),
ok
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
pre_command_fail_bad_value() ->
[{doc, "Test pre command due to bad value"}].
pre_command_fail_bad_value(Config) when is_list(Config) ->
DataDir = unicode:characters_to_binary(code:priv_dir(crypto)),
try
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>,
<<DataDir/binary, <<"/libfail_engine.so">>/binary >>},
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
{error, ctrl_cmd_failed} ->
ok;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
pre_command_fail_bad_key() ->
[{doc, "Test pre command due to bad key"}].
pre_command_fail_bad_key(Config) when is_list(Config) ->
try
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_WRONG_PATH">>, Engine},
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
{error, ctrl_cmd_failed} ->
ok;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
failed_engine_init()->
[{doc, "Test failing engine init due to missed pre command"}].
failed_engine_init(Config) when is_list(Config) ->
try
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
{<<"ID">>, <<"MD5">>}],
[]) of
{error, engine_init_failed} ->
ok;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
%%-------------------------------------------------------------------------
%% Test the optional flag in ctrl comands
ctrl_cmd_string()->
[{doc, "Test that a not known optional ctrl comand do not fail"}].
ctrl_cmd_string(Config) when is_list(Config) ->
try
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
{ok, E} ->
case crypto:engine_ctrl_cmd_string(E, <<"TEST">>, <<"17">>) of
ok ->
ok = crypto:engine_unload(E),
ct:fail(fail_ctrl_cmd_should_fail);
{error,ctrl_cmd_failed} ->
ok = crypto:engine_unload(E)
end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
ctrl_cmd_string_optional()->
[{doc, "Test that a not known optional ctrl comand do not fail"}].
ctrl_cmd_string_optional(Config) when is_list(Config) ->
try
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
{ok, E} ->
case crypto:engine_ctrl_cmd_string(E, <<"TEST">>, <<"17">>, true) of
ok ->
ok = crypto:engine_unload(E);
Err ->
ct:log("Error: ~p",[Err]),
ok = crypto:engine_unload(E),
ct:fail(fail_ctrl_cmd_string)
end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end.
ensure_load()->
[{doc, "Test the special ensure load function."}].
ensure_load(Config) when is_list(Config) ->
case crypto:get_test_engine() of
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
case crypto:ensure_engine_loaded(<<"MD5">>, Engine) of
{ok, E} ->
{ok, _E1} = crypto:ensure_engine_loaded(<<"MD5">>, Engine),
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_still_original_engine);
Md5Hash2 ->
ok;
_ ->
ct:fail(fail_to_load_engine)
end,
ok = crypto:ensure_engine_unloaded(E),
case crypto:hash(md5, "Don't panic") of
Md5Hash2 ->
ct:fail(fail_to_unload_still_test_engine);
Md5Hash1 ->
ok;
_ ->
ct:fail(fail_to_unload_engine)
end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
catch
error:notsup ->
{skip, "Engine not supported on this SSL version"}
end
end.
%%%----------------------------------------------------------------
%%% Pub/priv key storage tests. Thoose are for testing the crypto.erl
%%% support for using priv/pub keys stored in an engine.
sign_verify_rsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key.pem")},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key.pem")},
sign_verify(rsa, sha, Priv, Pub).
sign_verify_rsa_fake(Config) ->
%% Use fake engine rsa implementation
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key.pem")},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key.pem")},
sign_verify_fake(rsa, sha256, Priv, Pub).
sign_verify_dsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "dsa_private_key.pem")},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "dsa_public_key.pem")},
sign_verify(dss, sha, Priv, Pub).
sign_verify_ecdsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "ecdsa_private_key.pem")},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "ecdsa_public_key.pem")},
sign_verify(ecdsa, sha, Priv, Pub).
sign_verify_rsa_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem"),
password => "password"},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key_pwd.pem")},
sign_verify(rsa, sha, Priv, Pub).
sign_verify_rsa_pwd_bad_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem"),
password => "Bad password"},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key_pwd.pem")},
try sign_verify(rsa, sha, Priv, Pub) of
_ -> {fail, "PWD prot pubkey sign succeded with no pwd!"}
catch
error:badarg -> ok
end.
priv_encrypt_pub_decrypt_rsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key.pem")},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key.pem")},
priv_enc_pub_dec(rsa, Priv, Pub, rsa_pkcs1_padding).
priv_encrypt_pub_decrypt_rsa_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem"),
password => "password"},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key_pwd.pem")},
priv_enc_pub_dec(rsa, Priv, Pub, rsa_pkcs1_padding).
pub_encrypt_priv_decrypt_rsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key.pem")},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key.pem")},
pub_enc_priv_dec(rsa, Pub, Priv, rsa_pkcs1_padding).
pub_encrypt_priv_decrypt_rsa_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem"),
password => "password"},
Pub = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_public_key_pwd.pem")},
pub_enc_priv_dec(rsa, Pub, Priv, rsa_pkcs1_padding).
get_pub_from_priv_key_rsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key.pem")},
case crypto:privkey_to_pubkey(rsa, Priv) of
{error, not_found} ->
{fail, "Key not found"};
{error, notsup} ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
Pub ->
ct:log("rsa Pub = ~p",[Pub]),
sign_verify(rsa, sha, Priv, Pub)
end.
get_pub_from_priv_key_rsa_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem"),
password => "password"},
case crypto:privkey_to_pubkey(rsa, Priv) of
{error, not_found} ->
{fail, "Key not found"};
{error, notsup} ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
Pub ->
ct:log("rsa Pub = ~p",[Pub]),
sign_verify(rsa, sha, Priv, Pub)
end.
get_pub_from_priv_key_rsa_pwd_no_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem")},
case crypto:privkey_to_pubkey(rsa, Priv) of
{error, not_found} ->
ok;
{error, notsup} ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
Pub ->
ct:log("rsa Pub = ~p",[Pub]),
{fail, "PWD prot pubkey fetch succeded although no pwd!"}
end.
get_pub_from_priv_key_rsa_pwd_bad_pwd(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "rsa_private_key_pwd.pem"),
password => "Bad password"},
case crypto:privkey_to_pubkey(rsa, Priv) of
{error, not_found} ->
ok;
{error, notsup} ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
Pub ->
ct:log("rsa Pub = ~p",[Pub]),
{fail, "PWD prot pubkey fetch succeded with bad pwd!"}
end.
get_pub_from_priv_key_dsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "dsa_private_key.pem")},
case crypto:privkey_to_pubkey(dss, Priv) of
{error, not_found} ->
{fail, "Key not found"};
{error, notsup} ->
{skip, "DSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
Pub ->
ct:log("dsa Pub = ~p",[Pub]),
sign_verify(dss, sha, Priv, Pub)
end.
get_pub_from_priv_key_ecdsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "ecdsa_private_key.pem")},
case crypto:privkey_to_pubkey(ecdsa, Priv) of
{error, not_found} ->
{fail, "Key not found"};
{error, notsup} ->
{skip, "ECDSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
Pub ->
ct:log("ecdsa Pub = ~p",[Pub]),
sign_verify(ecdsa, sha, Priv, Pub)
end.
%%%================================================================
%%% Help for engine_stored_pub_priv_keys* test cases
%%%
load_storage_engine(Config) ->
load_storage_engine(Config, []).
load_storage_engine(_Config, ExcludeMthds) ->
case crypto:get_test_engine() of
{ok, Engine} ->
try crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
[],
crypto:engine_get_all_methods() -- ExcludeMthds
)
catch
error:notsup ->
{error, notsup}
end;
{error, Error} ->
{error, Error}
end.
key_dir(Config) ->
DataDir = unicode:characters_to_binary(proplists:get_value(data_dir, Config)),
filename:join(DataDir, "pkcs8").
engine_ref(Config) ->
proplists:get_value(storage_engine, Config).
key_id(Config, File) ->
filename:join(proplists:get_value(storage_dir,Config), File).
pubkey_alg_supported(Alg) ->
lists:member(Alg,
proplists:get_value(public_keys, crypto:supports())).
pub_enc_priv_dec(Alg, KeyEnc, KeyDec, Padding) ->
case pubkey_alg_supported(Alg) of
true ->
PlainText = <<"Hej på dig">>,
CryptoText = crypto:public_encrypt(Alg, PlainText, KeyEnc, Padding),
case crypto:private_decrypt(Alg, CryptoText, KeyDec, Padding) of
PlainText -> ok;
_ -> {fail, "Encrypt-decrypt error"}
end;
false ->
{skip, lists:concat([Alg," is not supported by cryptolib"])}
end.
priv_enc_pub_dec(Alg, KeyEnc, KeyDec, Padding) ->
case pubkey_alg_supported(Alg) of
true ->
PlainText = <<"Hej på dig">>,
CryptoText = crypto:private_encrypt(Alg, PlainText, KeyEnc, Padding),
case crypto:public_decrypt(Alg, CryptoText, KeyDec, Padding) of
PlainText -> ok;
_ -> {fail, "Encrypt-decrypt error"}
end;
false ->
{skip, lists:concat([Alg," is not supported by cryptolib"])}
end.
sign_verify(Alg, Sha, KeySign, KeyVerify) ->
case pubkey_alg_supported(Alg) of
true ->
PlainText = <<"Hej på dig">>,
Signature = crypto:sign(Alg, Sha, PlainText, KeySign),
case is_fake(Signature) of
true ->
ct:pal("SIG ~p ~p size ~p~n~p",[Alg,Sha,size(Signature),Signature]),
{fail, "Faked RSA impl used!!"};
false ->
case crypto:verify(Alg, Sha, PlainText, Signature, KeyVerify) of
true -> ok;
_ -> {fail, "Sign-verify error"}
end
end;
false ->
{skip, lists:concat([Alg," is not supported by cryptolib"])}
end.
%%% Use fake engine rsa implementation
sign_verify_fake(Alg, Sha, KeySign, KeyVerify) ->
case pubkey_alg_supported(Alg) of
true ->
PlainText = <<"Fake me!">>,
Signature = crypto:sign(Alg, Sha, PlainText, KeySign),
case is_fake(Signature) of
true ->
case crypto:verify(Alg, Sha, PlainText, Signature, KeyVerify) of
true -> ok;
_ -> {fail, "Sign-verify error"}
end;
false ->
ct:pal("SIG ~p ~p size ~p~n~p",[Alg,Sha,size(Signature),Signature]),
{fail, "Faked impl not used"}
end;
false ->
{skip, lists:concat([Alg," is not supported by cryptolib"])}
end.
is_fake(Sig) -> is_fake(Sig, 0).
is_fake(<<>>, _) -> true;
is_fake(<<B,Rest/binary>>, B) -> is_fake(Rest, B+1);
is_fake(_, _) -> false.