From af287d7b242b27a05084580f110db2f4a6667e54 Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Fri, 4 May 2012 19:08:03 +0200 Subject: Fix timetrap error in pre-hooks --- lib/common_test/src/ct_framework.erl | 77 +++++++++++++++++++++++------------- lib/common_test/src/ct_hooks.erl | 3 +- 2 files changed, 51 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 11575cd0fb..e53383e038 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -204,7 +204,7 @@ init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) -> data={Mod,FuncSpec}}), case catch configure(MergedInfo,MergedInfo,SuiteInfo, - FuncSpec,Config) of + FuncSpec,[],Config) of {suite0_failed,Reason} -> ct_util:set_testdata({curr_tc,{Mod,{suite0_failed,{require,Reason}}}}), {skip,{require_failed_in_suite0,Reason}}; @@ -212,12 +212,14 @@ init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) -> {auto_skip,{require_failed,Reason}}; {'EXIT',Reason} -> {auto_skip,Reason}; - {ok,Config1} -> + {ok,PostInitHook,Config1} -> case get('$test_server_framework_test') of undefined -> - ct_suite_init(Suite, FuncSpec, Config1); + ct_suite_init(Suite, FuncSpec, PostInitHook, Config1); Fun -> - case Fun(init_tc, Config1) of + PostInitHookResult = do_post_init_hook(PostInitHook, + Config1), + case Fun(init_tc, [PostInitHookResult ++ Config1]) of NewConfig when is_list(NewConfig) -> {ok,NewConfig}; Else -> @@ -226,14 +228,28 @@ init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) -> end end. -ct_suite_init(Suite, Func, [Config]) when is_list(Config) -> +ct_suite_init(Suite, Func, PostInitHook, Config) when is_list(Config) -> case ct_hooks:init_tc(Suite, Func, Config) of NewConfig when is_list(NewConfig) -> - {ok, [NewConfig]}; + PostInitHookResult = do_post_init_hook(PostInitHook, NewConfig), + {ok, [PostInitHookResult ++ NewConfig]}; Else -> Else end. +do_post_init_hook(PostInitHook, Config) -> + lists:flatmap(fun({Tag,Fun}) -> + case lists:keysearch(Tag,1,Config) of + {value,_} -> + []; + false -> + case Fun() of + {error,_} -> []; + Result -> [{Tag,Result}] + end + end + end, PostInitHook). + add_defaults(Mod,Func, GroupPath) -> Suite = get_suite_name(Mod, GroupPath), case (catch Suite:suite()) of @@ -453,15 +469,16 @@ timetrap_first([],Info,[]) -> timetrap_first([],Info,Found) -> ?rev(Found) ++ ?rev(Info). -configure([{require,Required}|Rest],Info,SuiteInfo,Scope,Config) -> +configure([{require,Required}|Rest], + Info,SuiteInfo,Scope,PostInitHook,Config) -> case ct:require(Required) of ok -> - configure(Rest,Info,SuiteInfo,Scope,Config); + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,Config); Error = {error,Reason} -> case required_default('_UNDEF',Required,Info, SuiteInfo,Scope) of ok -> - configure(Rest,Info,SuiteInfo,Scope,Config); + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,Config); _ -> case lists:keymember(Required,2,SuiteInfo) of true -> @@ -471,14 +488,15 @@ configure([{require,Required}|Rest],Info,SuiteInfo,Scope,Config) -> end end end; -configure([{require,Name,Required}|Rest],Info,SuiteInfo,Scope,Config) -> +configure([{require,Name,Required}|Rest], + Info,SuiteInfo,Scope,PostInitHook,Config) -> case ct:require(Name,Required) of ok -> - configure(Rest,Info,SuiteInfo,Scope,Config); + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,Config); Error = {error,Reason} -> case required_default(Name,Required,Info,SuiteInfo,Scope) of ok -> - configure(Rest,Info,SuiteInfo,Scope,Config); + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,Config); _ -> case lists:keymember(Name,2,SuiteInfo) of true -> @@ -488,17 +506,24 @@ configure([{require,Name,Required}|Rest],Info,SuiteInfo,Scope,Config) -> end end end; -configure([{timetrap,off}|Rest],Info,SuiteInfo,Scope,Config) -> - configure(Rest,Info,SuiteInfo,Scope,Config); -configure([{timetrap,Time}|Rest],Info,SuiteInfo,Scope,Config) -> - Dog = test_server:timetrap(Time), - configure(Rest,Info,SuiteInfo,Scope,[{watchdog,Dog}|Config]); -configure([{ct_hooks, Hook} | Rest], Info, SuiteInfo, Scope, Config) -> - configure(Rest, Info, SuiteInfo, Scope, [{ct_hooks, Hook} | Config]); -configure([_|Rest],Info,SuiteInfo,Scope,Config) -> - configure(Rest,Info,SuiteInfo,Scope,Config); -configure([],_,_,_,Config) -> - {ok,[Config]}. +configure([{timetrap,off}|Rest],Info,SuiteInfo,Scope,PostInitHook,Config) -> + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,Config); +configure([{timetrap,Time}|Rest],Info,SuiteInfo,Scope,PostInitHook,Config) -> + PostInitHook1 = + [{watchdog,fun() -> case test_server:get_timetrap_info() of + undefined -> + test_server:timetrap(Time); + _ -> + {error,already_set} + end + end} | PostInitHook], + configure(Rest,Info,SuiteInfo,Scope,PostInitHook1,Config); +configure([{ct_hooks,Hook}|Rest],Info,SuiteInfo,Scope,PostInitHook,Config) -> + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,[{ct_hooks,Hook}|Config]); +configure([_|Rest],Info,SuiteInfo,Scope,PostInitHook,Config) -> + configure(Rest,Info,SuiteInfo,Scope,PostInitHook,Config); +configure([],_,_,_,PostInitHook,Config) -> + {ok,PostInitHook,Config}. %% the require element in Info may come from suite/0 and %% should be scoped 'suite', or come from the group info @@ -562,10 +587,8 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> %% in case Mod == ct_framework, lookup the suite name Suite = get_suite_name(Mod, Args), - case lists:keysearch(watchdog,1,Args) of - {value,{watchdog,Dog}} -> test_server:timetrap_cancel(Dog); - false -> ok - end, + test_server:timetrap_cancel(), + %% save the testcase process pid so that it can be used %% to look up the attached trace window later case ct_util:get_testdata(interpret) of diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index 0fe6e03079..e53ef9f202 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -125,7 +125,7 @@ end_tc(_Mod, TC, Config, Result, _Return) -> on_tc_skip(How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, {How, Reason}, [on_tc_skip, Suite, Case]). -on_tc_fail(_How, {Suite, Case, Reason}) -> +on_tc_fail(How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, Reason, [on_tc_fail, Suite, Case]). %% ------------------------------------------------------------------------- @@ -353,7 +353,6 @@ pos(Id,[_|Rest],Num) -> pos(Id,Rest,Num+1). - catch_apply(M,F,A, Default) -> try apply(M,F,A) -- cgit v1.2.3 From e711632042d1538fce80d565a2add309a88efa1b Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Tue, 8 May 2012 17:47:21 +0200 Subject: Fix IO printout crash caused by hook function --- lib/common_test/src/ct_hooks.erl | 4 ++-- lib/common_test/src/ct_logs.erl | 14 ++++++++++++-- lib/common_test/src/cth_surefire.erl | 13 +++++++++---- 3 files changed, 23 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index e53ef9f202..98b74665de 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -125,7 +125,7 @@ end_tc(_Mod, TC, Config, Result, _Return) -> on_tc_skip(How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, {How, Reason}, [on_tc_skip, Suite, Case]). -on_tc_fail(How, {Suite, Case, Reason}) -> +on_tc_fail(_How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, Reason, [on_tc_fail, Suite, Case]). %% ------------------------------------------------------------------------- @@ -356,7 +356,7 @@ pos(Id,[_|Rest],Num) -> catch_apply(M,F,A, Default) -> try apply(M,F,A) - catch error:Reason -> + catch _:Reason -> case erlang:get_stacktrace() of %% Return the default if it was the CTH module which did not have the function. [{M,F,A,_}|_] when Reason == undef -> diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 1ccbdc3718..8359dcee98 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -659,13 +659,23 @@ create_io_fun(FromPid, State) -> print_to_log(sync, FromPid, TCGL, List, State) -> IoFun = create_io_fun(FromPid, State), - io:format(TCGL, "~s", [lists:foldl(IoFun, [], List)]), + %% in some situations (exceptions), the printout is made from the + %% test server IO process and there's no valid group leader to send to + IoProc = if FromPid /= TCGL -> TCGL; + true -> State#logger_state.ct_log_fd + end, + io:format(IoProc, "~s", [lists:foldl(IoFun, [], List)]), State; print_to_log(async, FromPid, TCGL, List, State) -> IoFun = create_io_fun(FromPid, State), + %% in some situations (exceptions), the printout is made from the + %% test server IO process and there's no valid group leader to send to + IoProc = if FromPid /= TCGL -> TCGL; + true -> State#logger_state.ct_log_fd + end, Printer = fun() -> - io:format(TCGL, "~s", [lists:foldl(IoFun, [], List)]) + io:format(IoProc, "~s", [lists:foldl(IoFun, [], List)]) end, case State#logger_state.async_print_jobs of [] -> diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl index c42f956b3a..ef7fe6c455 100644 --- a/lib/common_test/src/cth_surefire.erl +++ b/lib/common_test/src/cth_surefire.erl @@ -83,16 +83,21 @@ pre_init_per_testcase(_TC,Config,State) -> {Config, init_tc(State, Config)}. post_end_per_testcase(TC,Config,Result,State) -> {Result, end_tc(TC,Config, Result,State)}. +on_tc_fail(_TC, _Res, State = #state{test_cases = []}) -> + State; on_tc_fail(_TC, Res, State) -> TCs = State#state.test_cases, - TC = hd(State#state.test_cases), - NewTC = TC#testcase{ failure = - {fail,lists:flatten(io_lib:format("~p",[Res]))} }, + TC = hd(TCs), + NewTC = TC#testcase{ + failure = + {fail,lists:flatten(io_lib:format("~p",[Res]))} }, State#state{ test_cases = [NewTC | tl(TCs)]}. +on_tc_skip(_Tc, _Res, State = #state{test_cases = []}) -> + State; on_tc_skip(_Tc, Res, State) -> TCs = State#state.test_cases, - TC = hd(State#state.test_cases), + TC = hd(TCs), NewTC = TC#testcase{ failure = {skipped,lists:flatten(io_lib:format("~p",[Res]))} }, -- cgit v1.2.3 From 17a8416f2ccbcda98c5d28af2b007aaca2b333fe Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 21 Aug 2012 11:12:20 +0200 Subject: Fix bug in ets:test_ms/2. copy_shallow was called when using '$_' --- lib/stdlib/test/ets_SUITE.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 97ac433cb9..95f10b1df3 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -1026,6 +1026,8 @@ t_test_ms(Config) when is_list(Config) -> [{{'$1','$2'},[{'<','$1','$2'}],['$$']}]), ?line {ok,false} = ets:test_ms({a,b}, [{{'$1','$2'},[{'>','$1','$2'}],['$$']}]), + Tpl = {a,gb_sets:new()}, + ?line {ok,Tpl} = ets:test_ms(Tpl, [{{'_','_'}, [], ['$_']}]), % OTP-10190 ?line {error,[{error,String}]} = ets:test_ms({a,b}, [{{'$1','$2'}, [{'flurp','$1','$2'}], -- cgit v1.2.3 From 2702f65e834a65d05d82cebf77bc7385becbf3a7 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 31 May 2012 13:08:03 +0200 Subject: crypto: Add rsa and dss hash signing support --- lib/crypto/c_src/crypto.c | 139 +++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 30 +++++++-- lib/crypto/test/crypto_SUITE.erl | 63 +++++++++++++++++- 3 files changed, 227 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 4be593e208..62e745db6c 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -168,6 +168,7 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -175,7 +176,9 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -256,6 +259,7 @@ static ErlNifFunc nif_funcs[] = { {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, {"rsa_verify_nif", 4, rsa_verify_nif}, + {"rsa_verify_hash_nif", 4, rsa_verify_hash_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, {"exor", 2, exor}, {"rc4_encrypt", 2, rc4_encrypt}, @@ -263,7 +267,9 @@ static ErlNifFunc nif_funcs[] = { {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, {"rc2_cbc_crypt", 4, rc2_cbc_crypt}, {"rsa_sign_nif", 3, rsa_sign_nif}, + {"rsa_sign_hash_nif", 3, rsa_sign_hash_nif}, {"dss_sign_nif", 3, dss_sign_nif}, + {"dss_sign_hash_nif", 3, dss_sign_hash_nif}, {"rsa_public_crypt", 4, rsa_public_crypt}, {"rsa_private_crypt", 4, rsa_private_crypt}, {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif}, @@ -1327,6 +1333,46 @@ done: return ret; } +static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data, Signature, Key=[E,N]) */ + ErlNifBinary data_bin, sign_bin; + ERL_NIF_TERM head, tail, ret; + int i, type; + RSA* rsa = RSA_new(); + + if (!enif_inspect_binary(env,argv[1],&data_bin)) { + ret = enif_make_badarg(env); + goto done; + } + + if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; + else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; + else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; + else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; + else { + ret = enif_make_badarg(env); + goto done; + } + + if (!inspect_mpint(env, argv[2], &sign_bin) + || !enif_get_list_cell(env, argv[3], &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->e) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->n) + || !enif_is_empty_list(env, tail)) { + + ret = enif_make_badarg(env); + } + else { + i = RSA_verify(type, data_bin.data, data_bin.size, + sign_bin.data+4, sign_bin.size-4, rsa); + ret = (i==1 ? atom_true : atom_false); + } +done: + RSA_free(rsa); + return ret; +} + static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, IVec, Data, IsEncrypt) */ ErlNifBinary key_bin, ivec_bin, data_bin; @@ -1530,6 +1576,52 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } } +static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type,Data,Key=[E,N,D]) */ + ErlNifBinary data_bin, ret_bin; + ERL_NIF_TERM head, tail; + unsigned rsa_s_len; + RSA *rsa = RSA_new(); + int i, type; + + if (!enif_inspect_binary(env,argv[1],&data_bin)) + goto badarg; + + if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; + else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; + else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; + else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; + else goto badarg; + + if (!enif_get_list_cell(env, argv[2], &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->e) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->n) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->d) + || !enif_is_empty_list(env,tail)) { + badarg: + RSA_free(rsa); + return enif_make_badarg(env); + } + enif_alloc_binary(RSA_size(rsa), &ret_bin); + i = RSA_sign(type, data_bin.data, data_bin.size, + ret_bin.data, &rsa_s_len, rsa); + RSA_free(rsa); + if (i) { + ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); + if (rsa_s_len != data_bin.size) { + enif_realloc_binary(&ret_bin, rsa_s_len); + ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len); + } + return enif_make_binary(env,&ret_bin); + } + else { + enif_release_binary(&ret_bin); + return atom_error; + } +} + static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ ErlNifBinary data_bin, ret_bin; @@ -1579,6 +1671,53 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } } +static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ + ErlNifBinary data_bin, ret_bin; + ERL_NIF_TERM head, tail; + unsigned int dsa_s_len; + DSA* dsa = DSA_new(); + int i, type; + + if (!enif_inspect_binary(env,argv[1],&data_bin)) + goto badarg; + + if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; + else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; + else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; + else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; + else goto badarg; + + dsa->pub_key = NULL; + if (!enif_get_list_cell(env, argv[2], &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->p) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->q) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->g) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->priv_key) + || !enif_is_empty_list(env,tail)) { + badarg: + DSA_free(dsa); + return enif_make_badarg(env); + } + + enif_alloc_binary(DSA_size(dsa), &ret_bin); + i = DSA_sign(type, data_bin.data, data_bin.size, + ret_bin.data, &dsa_s_len, dsa); + DSA_free(dsa); + if (i) { + if (dsa_s_len != ret_bin.size) { + enif_realloc_binary(&ret_bin, dsa_s_len); + } + return enif_make_binary(env, &ret_bin); + } + else { + return atom_error; + } +} + static int rsa_pad(ERL_NIF_TERM term, int* padding) { if (term == atom_rsa_pkcs1_padding) { diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index d7aac27825..f4f4e20b4d 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -43,8 +43,8 @@ -export([exor/2]). -export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). -export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). --export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). +-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4, rsa_verify_hash/4]). +-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3, dss_sign_hash/3, rsa_sign_hash/3]). -export([rsa_public_encrypt/3, rsa_private_decrypt/3]). -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). @@ -80,8 +80,8 @@ strong_rand_mpint, rand_uniform, mod_exp, - dss_verify,dss_sign, - rsa_verify,rsa_sign, + dss_verify,dss_sign,dss_sign_hash, + rsa_verify,rsa_verify_hash,rsa_sign,rsa_sign_hash, rsa_public_encrypt,rsa_private_decrypt, rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, @@ -581,6 +581,8 @@ mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub. -spec rsa_verify(binary(), binary(), [binary()]) -> boolean(). -spec rsa_verify(rsa_digest_type(), binary(), binary(), [binary()]) -> boolean(). +-spec rsa_verify_hash(rsa_digest_type(), binary(), binary(), [binary()]) -> + boolean(). %% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey dss_verify(Data,Signature,Key) -> @@ -595,8 +597,14 @@ rsa_verify(Type, Data, Signature, Key) -> notsup -> erlang:error(notsup); Bool -> Bool end. +rsa_verify_hash(Type, Hash, Signature, Key) -> + case rsa_verify_hash_nif(Type, Hash, Signature, Key) of + notsup -> erlang:error(notsup); + Bool -> Bool + end. rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +rsa_verify_hash_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. %% @@ -605,8 +613,10 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. %% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey -spec dss_sign(binary(), [binary()]) -> binary(). -spec dss_sign(dss_digest_type(), binary(), [binary()]) -> binary(). +-spec dss_sign_hash(dss_digest_type(), binary(), [binary()]) -> binary(). -spec rsa_sign(binary(), [binary()]) -> binary(). -spec rsa_sign(rsa_digest_type(), binary(), [binary()]) -> binary(). +-spec rsa_sign_hash(rsa_digest_type(), binary(), [binary()]) -> binary(). dss_sign(Data,Key) -> dss_sign(sha,Data,Key). @@ -615,8 +625,14 @@ dss_sign(Type, Data, Key) -> error -> erlang:error(badkey, [Data, Key]); Sign -> Sign end. +dss_sign_hash(Type, Hash, Key) -> + case dss_sign_hash_nif(Type,Hash,Key) of + error -> erlang:error(badkey, [Hash, Key]); + Sign -> Sign + end. dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +dss_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent rsa_sign(Data,Key) -> @@ -626,8 +642,14 @@ rsa_sign(Type, Data, Key) -> error -> erlang:error(badkey, [Type,Data,Key]); Sign -> Sign end. +rsa_sign_hash(Type, Hash, Key) -> + case rsa_sign_hash_nif(Type,Hash,Key) of + error -> erlang:error(badkey, [Type,Hash,Key]); + Sign -> Sign + end. rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +rsa_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 627c966dfb..a399511de0 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -61,7 +61,9 @@ rsa_verify_test/1, dsa_verify_test/1, rsa_sign_test/1, + rsa_sign_hash_test/1, dsa_sign_test/1, + dsa_sign_hash_test/1, rsa_encrypt_decrypt/1, dh/1, exor_test/1, @@ -88,7 +90,8 @@ groups() -> aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, - dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, + rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test, + rsa_encrypt_decrypt, dh, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, smp]}]. @@ -1207,6 +1210,33 @@ rsa_sign_test(Config) when is_list(Config) -> ok. +rsa_sign_hash_test(doc) -> + "rsa_sign_hash testing"; +rsa_sign_hash_test(suite) -> + []; +rsa_sign_hash_test(Config) when is_list(Config) -> + PubEx = 65537, + PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945, + Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123, + Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" + "09812312908312378623487263487623412039812 huagasd">>, + + PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], + PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], + MD5 = crypto:md5(sized_binary(Msg)), + SHA = crypto:sha(sized_binary(Msg)), + ?line Sig1 = crypto:rsa_sign_hash(sha, SHA, PrivKey), + ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig1),PubKey), true), + + ?line Sig2 = crypto:rsa_sign_hash(md5, MD5, PrivKey), + ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig2),PubKey), true), + + ?line m(Sig1 =:= Sig2, false), + ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig1),PubKey), false), + ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig2),PubKey), false), + + ok. + dsa_sign_test(doc) -> "dsa_sign testing"; dsa_sign_test(suite) -> @@ -1237,6 +1267,37 @@ dsa_sign_test(Config) when is_list(Config) -> ok. +dsa_sign_hash_test(doc) -> + "dsa_sign_hash testing"; +dsa_sign_hash_test(suite) -> + []; +dsa_sign_hash_test(Config) when is_list(Config) -> + Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" + "09812312908312378623487263487623412039812 huagasd">>, + SHA = crypto:sha(sized_binary(Msg)), + + PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978, + PrivKey = _X = 441502407453038284293378221372000880210588566361, + ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797, + ParamQ = 1349199015905534965792122312016505075413456283393, + ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669, + + Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)], + ?line Sig1 = crypto:dss_sign_hash(sha, SHA, Params ++ [crypto:mpint(PrivKey)]), + + ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1), + Params ++ [crypto:mpint(PubKey)]), true), + + ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1), + Params ++ [crypto:mpint(PubKey)]), false), + + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)), + Params ++ [crypto:mpint(PubKey)]), false), + + %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]), + + ok. + rsa_encrypt_decrypt(doc) -> ["Test rsa_public_encrypt and rsa_private_decrypt functions."]; -- cgit v1.2.3 From 90167202a4ce3dc6d4822fad04c51cc35913d796 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 15:35:26 +0200 Subject: crypto: Redo interface for rsa and dss hash signing Replace _hash functions with {digest,_} argument to existing sign/verify functions. --- lib/crypto/c_src/crypto.c | 435 ++++++++++++++++++++------------------- lib/crypto/doc/src/crypto.xml | 66 +++--- lib/crypto/src/crypto.erl | 73 +++---- lib/crypto/test/crypto_SUITE.erl | 14 +- 4 files changed, 292 insertions(+), 296 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 62e745db6c..25616410be 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -168,7 +168,6 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -176,9 +175,7 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -204,6 +201,7 @@ static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, #endif /* OPENSSL_THREADS */ /* helpers */ +static void init_digest_types(ErlNifEnv* env); static void hmac_md5(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); @@ -259,7 +257,6 @@ static ErlNifFunc nif_funcs[] = { {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, {"rsa_verify_nif", 4, rsa_verify_nif}, - {"rsa_verify_hash_nif", 4, rsa_verify_hash_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, {"exor", 2, exor}, {"rc4_encrypt", 2, rc4_encrypt}, @@ -267,9 +264,7 @@ static ErlNifFunc nif_funcs[] = { {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, {"rc2_cbc_crypt", 4, rc2_cbc_crypt}, {"rsa_sign_nif", 3, rsa_sign_nif}, - {"rsa_sign_hash_nif", 3, rsa_sign_hash_nif}, {"dss_sign_nif", 3, dss_sign_nif}, - {"dss_sign_hash_nif", 3, dss_sign_hash_nif}, {"rsa_public_crypt", 4, rsa_public_crypt}, {"rsa_private_crypt", 4, rsa_private_crypt}, {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif}, @@ -326,6 +321,7 @@ static ERL_NIF_TERM atom_check_failed; static ERL_NIF_TERM atom_unknown; static ERL_NIF_TERM atom_none; static ERL_NIF_TERM atom_notsup; +static ERL_NIF_TERM atom_digest; static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) @@ -399,6 +395,9 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_unknown = enif_make_atom(env,"unknown"); atom_none = enif_make_atom(env,"none"); atom_notsup = enif_make_atom(env,"notsup"); + atom_digest = enif_make_atom(env,"digest"); + + init_digest_types(env); *priv_data = NULL; library_refc++; @@ -1214,14 +1213,43 @@ static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin) } static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigestType,Data,Signature,Key=[P, Q, G, Y]) */ +{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */ ErlNifBinary data_bin, sign_bin; BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; + unsigned char* digest; ERL_NIF_TERM head, tail; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; DSA *dsa; int i; + if (argv[0] == atom_sha) { + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != SHA_DIGEST_LENGTH) { + + return enif_make_badarg(env); + } + digest = data_bin.data; + } + else { + if (!inspect_mpint(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + digest = hmacbuf; + } + } + else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin) + && data_bin.size == SHA_DIGEST_LENGTH) { + digest = data_bin.data; + } + else { + return enif_make_badarg(env); + } + if (!inspect_mpint(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) || !get_bn_from_mpint(env, head, &dsa_p) @@ -1232,23 +1260,13 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_mpint(env, head, &dsa_y) || !enif_is_empty_list(env,tail)) { - badarg: + if (dsa_p) BN_free(dsa_p); if (dsa_q) BN_free(dsa_q); if (dsa_g) BN_free(dsa_g); if (dsa_y) BN_free(dsa_y); return enif_make_badarg(env); } - if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - } - else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin) - && data_bin.size == SHA_DIGEST_LENGTH) { - memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH); - } - else { - goto badarg; - } dsa = DSA_new(); dsa->p = dsa_p; @@ -1256,23 +1274,121 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv dsa->g = dsa_g; dsa->priv_key = NULL; dsa->pub_key = dsa_y; - i = DSA_verify(0, hmacbuf, SHA_DIGEST_LENGTH, + i = DSA_verify(0, digest, SHA_DIGEST_LENGTH, sign_bin.data+4, sign_bin.size-4, dsa); DSA_free(dsa); return(i > 0) ? atom_true : atom_false; } + +static void md5_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + MD5(in, in_len, out); +} +static void sha1_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA1(in, in_len, out); +} +#ifdef HAVE_SHA256 +static void sha256_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA256(in, in_len, out); +} +#endif +#ifdef HAVE_SHA384 +static void sha384_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA384(in, in_len, out); +} +#endif +#ifdef HAVE_SHA512 +static void sha512_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA512(in, in_len, out); +} +#endif + +struct digest_type_t { + const char* type_str; + unsigned len; /* 0 if notsup */ + int NID_type; + void (*funcp)(unsigned char* in, unsigned int in_len, unsigned char* out); + ERL_NIF_TERM type_atom; +}; + +struct digest_type_t digest_types[] = +{ + {"md5", MD5_DIGEST_LENGTH, NID_md5, md5_digest}, + {"sha", SHA_DIGEST_LENGTH, NID_sha1, sha1_digest}, + {"sha256", +#ifdef HAVE_SHA256 + SHA256_LEN, NID_sha256, sha256_digest +#else + 0 +#endif + }, + {"sha384", +#ifdef HAVE_SHA384 + SHA384_LEN, NID_sha384, sha384_digest +#else + 0 +#endif + }, + {"sha512", +#ifdef HAVE_SHA512 + SHA512_LEN, NID_sha512, sha512_digest +#else + 0 +#endif + }, + {NULL} +}; + +static void init_digest_types(ErlNifEnv* env) +{ + struct digest_type_t* p = digest_types; + + for (p = digest_types; p->type_str; p++) { + p->type_atom = enif_make_atom(env, p->type_str); + } + +} + +static struct digest_type_t* get_digest_type(ERL_NIF_TERM type) +{ + struct digest_type_t* p = NULL; + for (p = digest_types; p->type_str; p++) { + if (type == p->type_atom) { + return p; + } + } + return NULL; +} + static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data, Signature, Key=[E,N]) */ +{/* (Type, Data|{digest,Digest}, Signature, Key=[E,N]) */ ErlNifBinary data_bin, sign_bin; unsigned char hmacbuf[SHA512_LEN]; ERL_NIF_TERM head, tail, ret; int i; - RSA* rsa = RSA_new(); + RSA* rsa; const ERL_NIF_TERM type = argv[0]; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t* digp = NULL; + unsigned char* digest = NULL; + + digp = get_digest_type(type); + if (!digp) { + return enif_make_badarg(env); + } + if (!digp->len) { + return atom_notsup; + } + + rsa = RSA_new(); - if (!inspect_mpint(env, argv[1], &data_bin) - || !inspect_mpint(env, argv[2], &sign_bin) + if (!inspect_mpint(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) || !get_bn_from_mpint(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) @@ -1280,99 +1396,38 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM || !enif_is_empty_list(env, tail)) { ret = enif_make_badarg(env); + goto done; } - else { - if (type == atom_sha) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, rsa); - } - else if (type == atom_sha256) { - #ifdef HAVE_SHA256 - SHA256(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha256, hmacbuf, SHA256_LEN, - sign_bin.data+4, sign_bin.size-4, rsa); - #else - ret = atom_notsup; - goto done; - #endif - } - else if (type == atom_sha384) { - #ifdef HAVE_SHA384 - SHA384(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha384, hmacbuf, SHA384_LEN, - sign_bin.data+4, sign_bin.size-4, rsa); - #else - ret = atom_notsup; - goto done; - #endif - } - else if (type == atom_sha512) { - #ifdef HAVE_SHA512 - SHA512(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha512, hmacbuf, SHA512_LEN, - sign_bin.data+4, sign_bin.size-4, rsa); - #else - ret = atom_notsup; - goto done; - #endif - } - else if (type == atom_md5) { - MD5(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, rsa); - } - else { + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != digp->len) { + ret = enif_make_badarg(env); goto done; } - ret = (i==1 ? atom_true : atom_false); - } -done: - RSA_free(rsa); - return ret; -} - -static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data, Signature, Key=[E,N]) */ - ErlNifBinary data_bin, sign_bin; - ERL_NIF_TERM head, tail, ret; - int i, type; - RSA* rsa = RSA_new(); - - if (!enif_inspect_binary(env,argv[1],&data_bin)) { - ret = enif_make_badarg(env); - goto done; + digest = data_bin.data; + } + else if (inspect_mpint(env, argv[1], &data_bin)) { + digest = hmacbuf; + digp->funcp(data_bin.data+4, data_bin.size-4, digest); } - - if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; - else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; - else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; - else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; else { ret = enif_make_badarg(env); goto done; } - if (!inspect_mpint(env, argv[2], &sign_bin) - || !enif_get_list_cell(env, argv[3], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) - || !enif_is_empty_list(env, tail)) { + i = RSA_verify(digp->NID_type, digest, digp->len, + sign_bin.data+4, sign_bin.size-4, rsa); + + ret = (i==1 ? atom_true : atom_false); - ret = enif_make_badarg(env); - } - else { - i = RSA_verify(type, data_bin.data, data_bin.size, - sign_bin.data+4, sign_bin.size-4, rsa); - ret = (i==1 ? atom_true : atom_false); - } done: RSA_free(rsa); return ret; } + static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, IVec, Data, IsEncrypt) */ ErlNifBinary key_bin, ivec_bin, data_bin; @@ -1531,86 +1586,59 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) } static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Data,Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ +{/* (Type, Data|{digest,Digest}, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ ErlNifBinary data_bin, ret_bin; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned rsa_s_len; - RSA *rsa = RSA_new(); - int i, is_sha; - - if (argv[0] == atom_sha) is_sha = 1; - else if (argv[0] == atom_md5) is_sha = 0; - else goto badarg; + RSA* rsa; + int i; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t *digp; + unsigned char* digest; - if (!inspect_mpint(env,argv[1],&data_bin) - || !get_rsa_private_key(env, argv[2], rsa)) { - badarg: - RSA_free(rsa); + digp = get_digest_type(argv[0]); + if (!digp) { return enif_make_badarg(env); } - enif_alloc_binary(RSA_size(rsa), &ret_bin); - if (is_sha) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH); - i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - ret_bin.data, &rsa_s_len, rsa); - } - else { - MD5(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH); - i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH, - ret_bin.data, &rsa_s_len, rsa); + if (!digp->len) { + return atom_notsup; } - RSA_free(rsa); - if (i) { - ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); - if (rsa_s_len != data_bin.size) { - enif_realloc_binary(&ret_bin, rsa_s_len); - ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len); + + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != digp->len) { + + return enif_make_badarg(env); } - return enif_make_binary(env,&ret_bin); + digest = data_bin.data; } else { - enif_release_binary(&ret_bin); - return atom_error; + if (!inspect_mpint(env,argv[1],&data_bin)) { + return enif_make_badarg(env); + } + digest = hmacbuf; + digp->funcp(data_bin.data+4, data_bin.size-4, digest); } -} -static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Data,Key=[E,N,D]) */ - ErlNifBinary data_bin, ret_bin; - ERL_NIF_TERM head, tail; - unsigned rsa_s_len; - RSA *rsa = RSA_new(); - int i, type; - - if (!enif_inspect_binary(env,argv[1],&data_bin)) - goto badarg; - - if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; - else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; - else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; - else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; - else goto badarg; - - if (!enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->d) - || !enif_is_empty_list(env,tail)) { - badarg: + rsa = RSA_new(); + if (!get_rsa_private_key(env, argv[2], rsa)) { RSA_free(rsa); return enif_make_badarg(env); } + + enif_alloc_binary(RSA_size(rsa), &ret_bin); - i = RSA_sign(type, data_bin.data, data_bin.size, + + ERL_VALGRIND_ASSERT_MEM_DEFINED(digest, digp->len); + i = RSA_sign(digp->NID_type, digest, digp->len, ret_bin.data, &rsa_s_len, rsa); + RSA_free(rsa); if (i) { ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); - if (rsa_s_len != data_bin.size) { + if (rsa_s_len != ret_bin.size) { enif_realloc_binary(&ret_bin, rsa_s_len); ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len); } @@ -1622,71 +1650,48 @@ static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE } } + static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ +{/* (DigesType|none, Data|{digest,Digest}, Key=[P,Q,G,PrivKey]) */ ErlNifBinary data_bin, ret_bin; ERL_NIF_TERM head, tail; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned int dsa_s_len; - DSA* dsa = DSA_new(); + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + unsigned char* digest = NULL; + DSA* dsa; int i; - dsa->pub_key = NULL; - if (!enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->q) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->g) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->priv_key) - || !enif_is_empty_list(env,tail)) { - goto badarg; - } - if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + if (argv[0] == atom_sha) { + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != SHA_DIGEST_LENGTH) { + + return enif_make_badarg(env); + } + digest = data_bin.data; + } + else { + if (!inspect_mpint(env,argv[1],&data_bin)) { + return enif_make_badarg(env); + } + SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + digest = hmacbuf; + } } - else if (argv[0] == atom_none && enif_inspect_binary(env,argv[1],&data_bin) + else if (argv[0] == atom_none + && enif_inspect_binary(env,argv[1],&data_bin) && data_bin.size == SHA_DIGEST_LENGTH) { - memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH); - } - else { - badarg: - DSA_free(dsa); - return enif_make_badarg(env); - } - enif_alloc_binary(DSA_size(dsa), &ret_bin); - i = DSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - ret_bin.data, &dsa_s_len, dsa); - DSA_free(dsa); - if (i) { - if (dsa_s_len != ret_bin.size) { - enif_realloc_binary(&ret_bin, dsa_s_len); - } - return enif_make_binary(env, &ret_bin); + digest = data_bin.data; } else { - return atom_error; + return enif_make_badarg(env); } -} -static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ - ErlNifBinary data_bin, ret_bin; - ERL_NIF_TERM head, tail; - unsigned int dsa_s_len; - DSA* dsa = DSA_new(); - int i, type; - - if (!enif_inspect_binary(env,argv[1],&data_bin)) - goto badarg; - - if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; - else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; - else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; - else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; - else goto badarg; + dsa = DSA_new(); dsa->pub_key = NULL; if (!enif_get_list_cell(env, argv[2], &head, &tail) @@ -1698,13 +1703,12 @@ static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_mpint(env, head, &dsa->priv_key) || !enif_is_empty_list(env,tail)) { - badarg: - DSA_free(dsa); - return enif_make_badarg(env); + DSA_free(dsa); + return enif_make_badarg(env); } enif_alloc_binary(DSA_size(dsa), &ret_bin); - i = DSA_sign(type, data_bin.data, data_bin.size, + i = DSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, ret_bin.data, &dsa_s_len, dsa); DSA_free(dsa); if (i) { @@ -1718,6 +1722,7 @@ static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE } } + static int rsa_pad(ERL_NIF_TERM term, int* padding) { if (term == atom_rsa_pkcs1_padding) { diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 19db6c9dd4..36f8bc6deb 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -865,11 +865,13 @@ Mpint() = >]]> - rsa_sign(Data, Key) -> Signature - rsa_sign(DigestType, Data, Key) -> Signature + rsa_sign(DataOrDigest, Key) -> Signature + rsa_sign(DigestType, DataOrDigest, Key) -> Signature Sign the data using rsa with the given key. + DataOrDigest = Data | {digest,Digest} Data = Mpint + Digest = binary() Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] E, N, D = Mpint Where E is the public exponent, N is public modulus and @@ -879,37 +881,40 @@ Mpint() = >]]> the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C is the CRT coefficient. Terminology is taken from RFC 3447. - DigestType = md5 | sha + DigestType = md5 | sha | sha256 | sha384 | sha512 The default DigestType is sha. Mpint = binary() Signature = binary() -

Calculates a DigestType digest of the Data - and creates a RSA signature with the private key Key - of the digest.

+

Creates a RSA signature with the private key Key + of a digest. The digest is either calculated as a + DigestType digest of Data or a precalculated + binary Digest.

- rsa_verify(Data, Signature, Key) -> Verified - rsa_verify(DigestType, Data, Signature, Key) -> Verified + rsa_verify(DataOrDigest, Signature, Key) -> Verified + rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified Verify the digest and signature using rsa with given public key. Verified = boolean() + DataOrDigest = Data | {digest|Digest} Data, Signature = Mpint + Digest = binary() Key = [E, N] E, N = Mpint Where E is the public exponent and N is public modulus. DigestType = md5 | sha | sha256 | sha384 | sha512 - The default DigestType is sha. + The default DigestType is sha. Mpint = binary() -

Calculates a DigestType digest of the Data - and verifies that the digest matches the RSA signature using the +

Verifies that a digest matches the RSA signature using the signer's public key Key. -

+ The digest is either calculated as a DigestType + digest of Data or a precalculated binary Digest.

May throw exception notsup in case the chosen DigestType is not supported by the underlying OpenSSL implementation.

@@ -1022,45 +1027,52 @@ Mpint() = >]]>
- dss_sign(Data, Key) -> Signature - dss_sign(DigestType, Data, Key) -> Signature + dss_sign(DataOrDigest, Key) -> Signature + dss_sign(DigestType, DataOrDigest, Key) -> Signature Sign the data using dsa with given private key. - DigestType = sha | none (default is sha) - Data = Mpint | ShaDigest + DigestType = sha + DataOrDigest = Mpint | {digest,Digest} Key = [P, Q, G, X] P, Q, G, X = Mpint Where P, Q and G are the dss parameters and X is the private key. - ShaDigest = binary() with length 20 bytes + Digest = binary() with length 20 bytes Signature = binary() -

Creates a DSS signature with the private key Key of a digest. - If DigestType is 'sha', the digest is calculated as SHA1 of Data. - If DigestType is 'none', Data is the precalculated SHA1 digest.

+

Creates a DSS signature with the private key Key of + a digest. The digest is either calculated as a SHA1 + digest of Data or a precalculated binary Digest.

+

A deprecated feature is having DigestType = 'none' + in which case DataOrDigest is a precalculated SHA1 + digest.

- dss_verify(Data, Signature, Key) -> Verified - dss_verify(DigestType, Data, Signature, Key) -> Verified + dss_verify(DataOrDigest, Signature, Key) -> Verified + dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified Verify the data and signature using dsa with given public key. Verified = boolean() - DigestType = sha | none + DigestType = sha + DataOrDigest = Mpint | {digest,Digest} Data = Mpint | ShaDigest Signature = Mpint Key = [P, Q, G, Y] P, Q, G, Y = Mpint Where P, Q and G are the dss parameters and Y is the public key. - ShaDigest = binary() with length 20 bytes + Digest = binary() with length 20 bytes -

Verifies that a digest matches the DSS signature using the public key Key. - If DigestType is 'sha', the digest is calculated as SHA1 of Data. - If DigestType is 'none', Data is the precalculated SHA1 digest.

+

Verifies that a digest matches the DSS signature using the + public key Key. The digest is either calculated as a SHA1 + digest of Data or is a precalculated binary Digest.

+

A deprecated feature is having DigestType = 'none' + in which case DataOrDigest is a precalculated SHA1 + digest binary.

diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index f4f4e20b4d..69ab51d11e 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -43,8 +43,8 @@ -export([exor/2]). -export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). -export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4, rsa_verify_hash/4]). --export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3, dss_sign_hash/3, rsa_sign_hash/3]). +-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). +-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). -export([rsa_public_encrypt/3, rsa_private_decrypt/3]). -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). @@ -80,8 +80,8 @@ strong_rand_mpint, rand_uniform, mod_exp, - dss_verify,dss_sign,dss_sign_hash, - rsa_verify,rsa_verify_hash,rsa_sign,rsa_sign_hash, + dss_verify,dss_sign, + rsa_verify,rsa_sign, rsa_public_encrypt,rsa_private_decrypt, rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, @@ -97,6 +97,7 @@ -type rsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. +-type data_or_digest() :: binary() | {digest, binary()}. -type crypto_integer() :: binary() | integer(). -define(nif_stub,nif_stub_error(?LINE)). @@ -576,12 +577,10 @@ mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub. %% %% DSS, RSA - verify %% --spec dss_verify(binary(), binary(), [binary()]) -> boolean(). --spec dss_verify(dss_digest_type(), binary(), binary(), [binary()]) -> boolean(). --spec rsa_verify(binary(), binary(), [binary()]) -> boolean(). --spec rsa_verify(rsa_digest_type(), binary(), binary(), [binary()]) -> - boolean(). --spec rsa_verify_hash(rsa_digest_type(), binary(), binary(), [binary()]) -> +-spec dss_verify(data_or_digest(), binary(), [binary()]) -> boolean(). +-spec dss_verify(dss_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean(). +-spec rsa_verify(data_or_digest(), binary(), [binary()]) -> boolean(). +-spec rsa_verify(rsa_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean(). %% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey @@ -592,64 +591,44 @@ dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub. % Key = [E,N] E=PublicExponent N=PublicModulus rsa_verify(Data,Signature,Key) -> rsa_verify_nif(sha, Data,Signature,Key). -rsa_verify(Type, Data, Signature, Key) -> - case rsa_verify_nif(Type, Data, Signature, Key) of +rsa_verify(Type, DataOrDigest, Signature, Key) -> + case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of notsup -> erlang:error(notsup); Bool -> Bool end. -rsa_verify_hash(Type, Hash, Signature, Key) -> - case rsa_verify_hash_nif(Type, Hash, Signature, Key) of - notsup -> erlang:error(notsup); - Bool -> Bool - end. rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. -rsa_verify_hash_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. %% %% DSS, RSA - sign %% %% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey --spec dss_sign(binary(), [binary()]) -> binary(). --spec dss_sign(dss_digest_type(), binary(), [binary()]) -> binary(). --spec dss_sign_hash(dss_digest_type(), binary(), [binary()]) -> binary(). --spec rsa_sign(binary(), [binary()]) -> binary(). --spec rsa_sign(rsa_digest_type(), binary(), [binary()]) -> binary(). --spec rsa_sign_hash(rsa_digest_type(), binary(), [binary()]) -> binary(). - -dss_sign(Data,Key) -> - dss_sign(sha,Data,Key). -dss_sign(Type, Data, Key) -> - case dss_sign_nif(Type,Data,Key) of - error -> erlang:error(badkey, [Data, Key]); - Sign -> Sign - end. -dss_sign_hash(Type, Hash, Key) -> - case dss_sign_hash_nif(Type,Hash,Key) of - error -> erlang:error(badkey, [Hash, Key]); +-spec dss_sign(data_or_digest(), [binary()]) -> binary(). +-spec dss_sign(dss_digest_type(), data_or_digest(), [binary()]) -> binary(). +-spec rsa_sign(data_or_digest(), [binary()]) -> binary(). +-spec rsa_sign(rsa_digest_type(), data_or_digest(), [binary()]) -> binary(). + +dss_sign(DataOrDigest,Key) -> + dss_sign(sha,DataOrDigest,Key). +dss_sign(Type, DataOrDigest, Key) -> + case dss_sign_nif(Type,DataOrDigest,Key) of + error -> erlang:error(badkey, [DataOrDigest, Key]); Sign -> Sign end. dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -dss_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent -rsa_sign(Data,Key) -> - rsa_sign(sha, Data, Key). -rsa_sign(Type, Data, Key) -> - case rsa_sign_nif(Type,Data,Key) of - error -> erlang:error(badkey, [Type,Data,Key]); - Sign -> Sign - end. -rsa_sign_hash(Type, Hash, Key) -> - case rsa_sign_hash_nif(Type,Hash,Key) of - error -> erlang:error(badkey, [Type,Hash,Key]); +rsa_sign(DataOrDigest,Key) -> + rsa_sign(sha, DataOrDigest, Key). +rsa_sign(Type, DataOrDigest, Key) -> + case rsa_sign_nif(Type,DataOrDigest,Key) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); Sign -> Sign end. rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -rsa_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index a399511de0..6cc00d85ad 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1225,15 +1225,15 @@ rsa_sign_hash_test(Config) when is_list(Config) -> PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], MD5 = crypto:md5(sized_binary(Msg)), SHA = crypto:sha(sized_binary(Msg)), - ?line Sig1 = crypto:rsa_sign_hash(sha, SHA, PrivKey), - ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig1),PubKey), true), + ?line Sig1 = crypto:rsa_sign(sha, {digest,SHA}, PrivKey), + ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig1),PubKey), true), - ?line Sig2 = crypto:rsa_sign_hash(md5, MD5, PrivKey), - ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig2),PubKey), true), + ?line Sig2 = crypto:rsa_sign(md5, {digest,MD5}, PrivKey), + ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig2),PubKey), true), ?line m(Sig1 =:= Sig2, false), - ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig1),PubKey), false), - ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig2),PubKey), false), + ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig1),PubKey), false), + ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig2),PubKey), false), ok. @@ -1283,7 +1283,7 @@ dsa_sign_hash_test(Config) when is_list(Config) -> ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669, Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)], - ?line Sig1 = crypto:dss_sign_hash(sha, SHA, Params ++ [crypto:mpint(PrivKey)]), + ?line Sig1 = crypto:dss_sign(sha, {digest,SHA}, Params ++ [crypto:mpint(PrivKey)]), ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1), Params ++ [crypto:mpint(PubKey)]), true), -- cgit v1.2.3 From 95b2d97ecfeb4f1f254e4b7c16ea2ec8b4698dd0 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 31 May 2012 13:08:16 +0200 Subject: public_key: Add rsa and dss hash signing support --- lib/public_key/src/public_key.erl | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'lib') diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 9f1a0b3af5..1c5c6d1d2e 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -34,6 +34,7 @@ decrypt_private/2, decrypt_private/3, encrypt_public/2, encrypt_public/3, decrypt_public/2, decrypt_public/3, + sign_hash/3, verify_hash/4, sign/3, verify/4, pkix_sign/2, pkix_verify/2, pkix_is_self_signed/1, @@ -331,6 +332,25 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D}) -> [crypto:mpint(K) || K <- [E, N, D]]. +%%-------------------------------------------------------------------- +-spec sign_hash(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), + rsa_private_key() | + dsa_private_key()) -> Signature :: binary(). +%% +%% Description: Create a PKCS digital signature. +%%-------------------------------------------------------------------- +sign_hash(Hash, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) + when is_binary(Hash) -> + crypto:rsa_sign_hash(DigestType, Hash, [crypto:mpint(E), + crypto:mpint(N), + crypto:mpint(D)]); +sign_hash(Hash, DigestType, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) + when is_binary(Hash)-> + crypto:dss_sign_hash(DigestType, Hash, + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(X)]). + %%-------------------------------------------------------------------- -spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), rsa_private_key() | @@ -358,6 +378,23 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) [crypto:mpint(P), crypto:mpint(Q), crypto:mpint(G), crypto:mpint(X)]). +%%-------------------------------------------------------------------- +-spec verify_hash(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), + Signature :: binary(), rsa_public_key() + | dsa_public_key()) -> boolean(). +%% +%% Description: Verifies a PKCS digital signature. +%%-------------------------------------------------------------------- +verify_hash(Hash, DigestType, Signature, + #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) + when is_binary (Hash) and (DigestType == sha orelse + DigestType == sha256 orelse + DigestType == sha512 orelse + DigestType == md5) -> + crypto:rsa_verify_hash(DigestType, Hash, + sized_binary(Signature), + [crypto:mpint(Exp), crypto:mpint(Mod)]). + %%-------------------------------------------------------------------- -spec verify(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), Signature :: binary(), rsa_public_key() -- cgit v1.2.3 From 3cde11a94c2761aa8980931f455734d8870446b3 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 12 Jun 2012 16:26:35 +0200 Subject: public_key: Generalised API --- lib/public_key/doc/src/public_key.xml | 12 ++-- lib/public_key/src/public_key.erl | 116 ++++++++++++++++------------------ 2 files changed, 59 insertions(+), 69 deletions(-) (limited to 'lib') diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 0b6673e826..0c9e0c9013 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -5,7 +5,7 @@
2008 - 2011 + 2012 Ericsson AB, All Rights Reserved @@ -84,7 +84,7 @@

rsa_digest_type() = 'md5' | 'sha'

-

dss_digest_type() = 'none' | 'sha'

+

dss_digest_type() = 'sha'

ssh_file() = openssh_public_key | rfc4716_public_key | known_hosts | auth_keys

@@ -398,9 +398,9 @@ Msg = binary() The msg is either the binary "plain text" data to be - signed or in the case that digest type is none + signed or in the case that digest type is {digest, DigestType} it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dsa_digest_type() + DigestType = rsa_digest_type() | dsa_digest_type() | {digest, rsa_digest_type() | dsa_digest_type()} Key = rsa_private_key() | dsa_private_key() @@ -463,9 +463,9 @@ Msg = binary() The msg is either the binary "plain text" data - or in the case that digest type is none + or in the case that digest type is {digest, DigestType} it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dsa_digest_type() + DigestType = rsa_digest_type() | dsa_digest_type() | {digest, rsa_digest_type() | dsa_digest_type()} Signature = binary() Key = rsa_public_key() | dsa_public_key() diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 1c5c6d1d2e..9c87c9505e 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -34,7 +34,6 @@ decrypt_private/2, decrypt_private/3, encrypt_public/2, encrypt_public/3, decrypt_public/2, decrypt_public/3, - sign_hash/3, verify_hash/4, sign/3, verify/4, pkix_sign/2, pkix_verify/2, pkix_is_self_signed/1, @@ -50,7 +49,7 @@ | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. -type rsa_digest_type() :: 'md5' | 'sha'| 'sha256' | 'sha512'. --type dss_digest_type() :: 'none' | 'sha'. +-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility -define(UINT32(X), X:32/unsigned-big-integer). -define(DER_NULL, <<5, 0>>). @@ -333,76 +332,55 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, [crypto:mpint(K) || K <- [E, N, D]]. %%-------------------------------------------------------------------- --spec sign_hash(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), - rsa_private_key() | - dsa_private_key()) -> Signature :: binary(). -%% -%% Description: Create a PKCS digital signature. -%%-------------------------------------------------------------------- -sign_hash(Hash, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) - when is_binary(Hash) -> - crypto:rsa_sign_hash(DigestType, Hash, [crypto:mpint(E), - crypto:mpint(N), - crypto:mpint(D)]); -sign_hash(Hash, DigestType, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) - when is_binary(Hash)-> - crypto:dss_sign_hash(DigestType, Hash, - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]). - -%%-------------------------------------------------------------------- --spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), - rsa_private_key() | +-spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type() | + {digest, rsa_digest_type() | dss_digest_type()}, + rsa_private_key() | dsa_private_key()) -> Signature :: binary(). -%% %% Description: Create digital signature. %%-------------------------------------------------------------------- -sign(PlainText, DigestType, - #'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D} = Key) +sign(Digest, {digest, DigestType}, #'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) + when is_binary(Digest), + (DigestType == sha orelse + DigestType == sh256 orelse + DigestType == sha512 orelse + DigestType == md5) -> + crypto:rsa_sign_hash(DigestType, Digest, [crypto:mpint(E), crypto:mpint(N), crypto:mpint(D)]); + +sign(PlainText,DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) when is_binary(PlainText), - (DigestType == md5 orelse DigestType == sha), - is_integer(N), is_integer(E), is_integer(D) -> - crypto:rsa_sign(DigestType, sized_binary(PlainText), - format_rsa_private_key(Key)); - -sign(Digest, none, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) - when is_binary(Digest)-> - crypto:dss_sign(none, Digest, - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]); - -sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) + (DigestType == sha orelse + DigestType == sh256 orelse + DigestType == sha512 orelse + DigestType == md5) -> + crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), + crypto:mpint(N), + crypto:mpint(D)]); + +sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) when is_binary(PlainText) -> - crypto:dss_sign(sized_binary(PlainText), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]). + crypto:dss_sign(sized_binary(PlainText), + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(X)]); -%%-------------------------------------------------------------------- --spec verify_hash(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), - Signature :: binary(), rsa_public_key() - | dsa_public_key()) -> boolean(). -%% -%% Description: Verifies a PKCS digital signature. -%%-------------------------------------------------------------------- -verify_hash(Hash, DigestType, Signature, - #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) - when is_binary (Hash) and (DigestType == sha orelse - DigestType == sha256 orelse - DigestType == sha512 orelse - DigestType == md5) -> - crypto:rsa_verify_hash(DigestType, Hash, - sized_binary(Signature), - [crypto:mpint(Exp), crypto:mpint(Mod)]). +sign(Digest, {digest, DigestType}, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) + when is_binary(Digest)-> + crypto:dss_sign_hash(DigestType, Digest, + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(X)]); +%% Backwards compatible +sign(Digest, none, #'DSAPrivateKey'{} = Key) -> + sign(Digest, {digest, sha}, Key). %%-------------------------------------------------------------------- --spec verify(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), - Signature :: binary(), rsa_public_key() +-spec verify(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type() | + {digest, rsa_digest_type() | dss_digest_type()}, + Signature :: binary(), rsa_public_key() | dsa_public_key()) -> boolean(). -%% %% Description: Verifies a digital signature. %%-------------------------------------------------------------------- -verify(PlainText, DigestType, Signature, +verify(PlainText, DigestType, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) when is_binary (PlainText) and (DigestType == sha orelse DigestType == sha256 orelse @@ -413,14 +391,26 @@ verify(PlainText, DigestType, Signature, sized_binary(Signature), [crypto:mpint(Exp), crypto:mpint(Mod)]); -verify(Digest, none, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) +verify(Digest, {digest, DigestType}, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) + when is_binary (Digest) and (DigestType == sha orelse + DigestType == sha256 orelse + DigestType == sha512 orelse + DigestType == md5) -> + crypto:rsa_verify_hash(DigestType, Digest, + sized_binary(Signature), + [crypto:mpint(Exp), crypto:mpint(Mod)]); + +verify(Digest, {digest, sha}, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) when is_integer(Key), is_binary(Digest), is_binary(Signature) -> crypto:dss_verify(none, Digest, sized_binary(Signature), [crypto:mpint(P), crypto:mpint(Q), crypto:mpint(G), crypto:mpint(Key)]); - +%% Backwards compatibility +verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> + verify(Digest, {digest, sha}, Signature, Key); + verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) when is_integer(Key), is_binary(PlainText), is_binary(Signature) -> crypto:dss_verify(sized_binary(PlainText), -- cgit v1.2.3 From fe18efc0c82cc55e44bbc5d6ca465dff76e5287e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 19:58:08 +0200 Subject: public_key: Align the interface of sign and verify with crypto --- lib/public_key/doc/src/public_key.xml | 15 +++---- lib/public_key/src/public_key.erl | 84 ++++++++++++----------------------- 2 files changed, 36 insertions(+), 63 deletions(-) (limited to 'lib') diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 0c9e0c9013..f64274d608 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -396,11 +396,11 @@ sign(Msg, DigestType, Key) -> binary() Create digital signature. - Msg = binary() + Msg = binary() | {digest,binary()} The msg is either the binary "plain text" data to be - signed or in the case that digest type is {digest, DigestType} - it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dsa_digest_type() | {digest, rsa_digest_type() | dsa_digest_type()} + signed or it is the hashed value of "plain text" i.e. the + digest. + DigestType = rsa_digest_type() | dsa_digest_type() Key = rsa_private_key() | dsa_private_key() @@ -461,11 +461,10 @@ verify(Msg, DigestType, Signature, Key) -> boolean() Verifies a digital signature. - Msg = binary() + Msg = binary() | {digest,binary()} The msg is either the binary "plain text" data - or in the case that digest type is {digest, DigestType} - it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dsa_digest_type() | {digest, rsa_digest_type() | dsa_digest_type()} + or it is the hashed value of "plain text" i.e. the digest. + DigestType = rsa_digest_type() | dsa_digest_type() Signature = binary() Key = rsa_public_key() | dsa_public_key() diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 9c87c9505e..686a11a7b2 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -48,7 +48,7 @@ -type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. --type rsa_digest_type() :: 'md5' | 'sha'| 'sha256' | 'sha512'. +-type rsa_digest_type() :: 'md5' | 'sha'| 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility -define(UINT32(X), X:32/unsigned-big-integer). @@ -332,87 +332,61 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, [crypto:mpint(K) || K <- [E, N, D]]. %%-------------------------------------------------------------------- --spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type() | - {digest, rsa_digest_type() | dss_digest_type()}, +-spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), rsa_private_key() | dsa_private_key()) -> Signature :: binary(). %% Description: Create digital signature. %%-------------------------------------------------------------------- -sign(Digest, {digest, DigestType}, #'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) - when is_binary(Digest), - (DigestType == sha orelse - DigestType == sh256 orelse - DigestType == sha512 orelse - DigestType == md5) -> - crypto:rsa_sign_hash(DigestType, Digest, [crypto:mpint(E), crypto:mpint(N), crypto:mpint(D)]); - -sign(PlainText,DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) - when is_binary(PlainText), - (DigestType == sha orelse - DigestType == sh256 orelse - DigestType == sha512 orelse - DigestType == md5) -> - crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), - crypto:mpint(N), - crypto:mpint(D)]); - -sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) - when is_binary(PlainText) -> +sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) -> + crypto:rsa_sign(DigestType, Digest, format_rsa_private_key(Key)); + +sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) -> + crypto:rsa_sign(DigestType, sized_binary(PlainText), format_rsa_private_key(Key)); + +sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> + crypto:dss_sign(Digest, + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(X)]); + +sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> crypto:dss_sign(sized_binary(PlainText), [crypto:mpint(P), crypto:mpint(Q), crypto:mpint(G), crypto:mpint(X)]); -sign(Digest, {digest, DigestType}, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) - when is_binary(Digest)-> - crypto:dss_sign_hash(DigestType, Digest, - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> - sign(Digest, {digest, sha}, Key). + sign({digest,Digest}, sha, Key). %%-------------------------------------------------------------------- --spec verify(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type() | - {digest, rsa_digest_type() | dss_digest_type()}, +-spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), Signature :: binary(), rsa_public_key() | dsa_public_key()) -> boolean(). %% Description: Verifies a digital signature. %%-------------------------------------------------------------------- +verify({digest,_}=Digest, DigestType, Signature, + #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> + crypto:rsa_verify(DigestType, Digest, + sized_binary(Signature), + [crypto:mpint(Exp), crypto:mpint(Mod)]); + verify(PlainText, DigestType, Signature, - #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) - when is_binary (PlainText) and (DigestType == sha orelse - DigestType == sha256 orelse - DigestType == sha512 orelse - DigestType == md5) -> + #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> crypto:rsa_verify(DigestType, sized_binary(PlainText), sized_binary(Signature), [crypto:mpint(Exp), crypto:mpint(Mod)]); -verify(Digest, {digest, DigestType}, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) - when is_binary (Digest) and (DigestType == sha orelse - DigestType == sha256 orelse - DigestType == sha512 orelse - DigestType == md5) -> - crypto:rsa_verify_hash(DigestType, Digest, - sized_binary(Signature), - [crypto:mpint(Exp), crypto:mpint(Mod)]); - -verify(Digest, {digest, sha}, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) - when is_integer(Key), is_binary(Digest), is_binary(Signature) -> - crypto:dss_verify(none, - Digest, - sized_binary(Signature), +verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) + when is_integer(Key), is_binary(Signature) -> + crypto:dss_verify(Digest, sized_binary(Signature), [crypto:mpint(P), crypto:mpint(Q), crypto:mpint(G), crypto:mpint(Key)]); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> - verify(Digest, {digest, sha}, Signature, Key); + verify({digest,Digest}, sha, Signature, Key); verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) - when is_integer(Key), is_binary(PlainText), is_binary(Signature) -> + when is_integer(Key), is_binary(PlainText), is_binary(Signature) -> crypto:dss_verify(sized_binary(PlainText), sized_binary(Signature), [crypto:mpint(P), crypto:mpint(Q), -- cgit v1.2.3 From 208f9ad3828313f6c659a501d53f5534ec1bdf2e Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 15 Jun 2012 17:34:28 +0200 Subject: crypto: Add SHA256 and SHA512 based MACs --- lib/crypto/c_src/crypto.c | 144 ++++++++++++++++++++++++++++++++++++++- lib/crypto/src/crypto.erl | 63 ++++++++++++++++- lib/crypto/test/crypto_SUITE.erl | 49 +++++++++++-- 3 files changed, 249 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 25616410be..a1f2614f69 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2011. All Rights Reserved. + * Copyright Ericsson AB 2010-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -149,6 +149,8 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -208,6 +210,16 @@ static void hmac_md5(unsigned char *key, int klen, static void hmac_sha1(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); +#ifdef HAVE_SHA256 +static void hmac_sha256(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif +#ifdef HAVE_SHA512 +static void hmac_sha512(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif static int library_refc = 0; /* number of users of this dynamic library */ @@ -235,6 +247,8 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, + {"sha256_mac_n_nif", 3, sha256_mac_n_nif}, + {"sha512_mac_n_nif", 3, sha512_mac_n_nif}, {"hmac_init", 2, hmac_init}, {"hmac_update", 2, hmac_update}, {"hmac_final", 1, hmac_final}, @@ -292,6 +306,7 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) #define SHA384_LEN (384/8) #define SHA512_LEN (512/8) #define HMAC_INT_LEN 64 +#define HMAC_INT2_LEN 128 #define HMAC_IPAD 0x36 #define HMAC_OPAD 0x5c @@ -765,6 +780,50 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA256 + unsigned char hmacbuf[SHA256_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA256_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + +static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA512 + unsigned char hmacbuf[SHA512_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA512_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type, Key) */ ErlNifBinary key; @@ -773,6 +832,8 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ const EVP_MD *md; if (argv[0] == atom_sha) md = EVP_sha1(); + else if (argv[0] == atom_sha256) md = EVP_sha256(); + else if (argv[0] == atom_sha512) md = EVP_sha512(); else if (argv[0] == atom_md5) md = EVP_md5(); else if (argv[0] == atom_ripemd160) md = EVP_ripemd160(); else goto badarg; @@ -2184,3 +2245,84 @@ static void hmac_sha1(unsigned char *key, int klen, SHA1_Final((unsigned char *) hmacbuf, &ctx); } +#ifdef HAVE_SHA256 +static void hmac_sha256(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA256_CTX ctx; + char ipad[HMAC_INT_LEN]; + char opad[HMAC_INT_LEN]; + unsigned char nkey[SHA256_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT_LEN) { + SHA256(key, klen, nkey); + key = nkey; + klen = SHA256_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA256_Init(&ctx); + SHA256_Update(&ctx, ipad, HMAC_INT_LEN); + SHA256_Update(&ctx, dbuf, dlen); + SHA256_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA256_Init(&ctx); + SHA256_Update(&ctx, opad, HMAC_INT_LEN); + SHA256_Update(&ctx, hmacbuf, SHA256_DIGEST_LENGTH); + SHA256_Final((unsigned char *) hmacbuf, &ctx); +} +#endif + +#ifdef HAVE_SHA512 +static void hmac_sha512(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA512_CTX ctx; + char ipad[HMAC_INT2_LEN]; + char opad[HMAC_INT2_LEN]; + unsigned char nkey[SHA512_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT2_LEN) { + SHA512(key, klen, nkey); + key = nkey; + klen = SHA512_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT2_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA512_Init(&ctx); + SHA512_Update(&ctx, ipad, HMAC_INT2_LEN); + SHA512_Update(&ctx, dbuf, dlen); + SHA512_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA512_Init(&ctx); + SHA512_Update(&ctx, opad, HMAC_INT2_LEN); + SHA512_Update(&ctx, hmacbuf, SHA512_DIGEST_LENGTH); + SHA512_Final((unsigned char *) hmacbuf, &ctx); +} +#endif diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 69ab51d11e..0f14092f87 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,12 +22,14 @@ -module(crypto). -export([start/0, stop/0, info/0, info_lib/0, version/0]). +-export([hash/2]). -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). +-export([sha256_mac/2, sha256_mac_96/2, sha512_mac/2, sha512_mac/3, sha512_mac_96/2]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). @@ -68,6 +70,8 @@ sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, + sha256_mac, sha256_mac_96, + sha512_mac, sha512_mac_96, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -172,7 +176,7 @@ info_lib() -> ?nif_stub. %% (no version): Driver implementation %% 2.0 : NIF implementation, requires OTP R14 version() -> ?CRYPTO_VSN. - + %% Below Key and Data are binaries or IO-lists. IVec is a binary. %% Output is always a binary. Context is a binary. @@ -180,6 +184,15 @@ version() -> ?CRYPTO_VSN. %% MESSAGE DIGESTS %% +-spec hash(_, iodata()) -> binary(). +hash(md5, Data) -> md5(Data); +hash(md4, Data) -> md4(Data); +hash(sha, Data) -> sha(Data); +hash(sha1, Data) -> sha(Data); +hash(sha256, Data) -> sha256(Data); +hash(sha512, Data) -> sha512(Data). + + %% %% MD5 %% @@ -336,6 +349,52 @@ sha_mac_96(Key, Data) -> sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. +%% +%% SHA256_MAC +%% +-spec sha256_mac(iodata(), iodata()) -> binary(). +-spec sha256_mac_96(iodata(), iodata()) -> binary(). + +sha256_mac(Key, Data) -> + sha256_mac_n(Key,Data,32). + +sha256_mac(Key, Data, Size) -> + sha256_mac_n(Key, Data, Size). + +sha256_mac_96(Key, Data) -> + sha256_mac_n(Key,Data,12). + +sha256_mac_n(Key, Data, MacSz) -> + case sha256_mac_n_nif(Key, Data, MacSz) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha256_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. + +%% +%% SHA512_MAC +%% +-spec sha512_mac(iodata(), iodata()) -> binary(). +-spec sha512_mac_96(iodata(), iodata()) -> binary(). + +sha512_mac(Key, Data) -> + sha512_mac_n(Key,Data,64). + +sha512_mac(Key, Data, Size) -> + sha512_mac_n(Key, Data, Size). + +sha512_mac_96(Key, Data) -> + sha512_mac_n(Key,Data,12). + +sha512_mac_n(Key, Data, MacSz) -> + case sha512_mac_n_nif(Key, Data, MacSz) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha512_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. + %% %% CRYPTO FUNCTIONS %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 6cc00d85ad..01cdf9f001 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -33,6 +33,8 @@ sha_update/1, hmac_update_sha/1, hmac_update_sha_n/1, + hmac_update_sha256/1, + hmac_update_sha512/1, hmac_update_md5/1, hmac_update_md5_io/1, hmac_update_md5_n/1, @@ -84,8 +86,8 @@ groups() -> {rest, [], [md5, md5_update, md4, md4_update, md5_mac, md5_mac_io, sha, sha_update, - hmac_update_sha, hmac_update_sha_n, hmac_update_md5_n, - hmac_update_md5_io, hmac_update_md5, + hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512, + hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, des_cbc, aes_cfb, aes_cbc, aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, @@ -338,6 +340,44 @@ hmac_update_sha(Config) when is_list(Config) -> ?line Mac = crypto:hmac_final(Ctx3), ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). + +hmac_update_sha256(doc) -> + ["Generate an SHA256 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:sha256_mac." ]; +hmac_update_sha256(suite) -> + []; +hmac_update_sha256(Config) when is_list(Config) -> + ?line Key = hexstr2bin("00010203101112132021222330313233" + "04050607141516172425262734353637" + "08090a0b18191a1b28292a2b38393a3b" + "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"), + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(sha256, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final(Ctx3), + ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). + +hmac_update_sha512(doc) -> + ["Generate an SHA512 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:sha512_mac." ]; +hmac_update_sha512(suite) -> + []; +hmac_update_sha512(Config) when is_list(Config) -> + ?line Key = hexstr2bin("00010203101112132021222330313233" + "04050607141516172425262734353637" + "08090a0b18191a1b28292a2b38393a3b" + "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"), + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(sha512, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final(Ctx3), + ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). hmac_update_md5(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -1482,7 +1522,8 @@ worker_loop(N, Config) -> Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc, aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test, - hmac_update_md5, hmac_update_sha, aes_ctr_stream }, + hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512, + aes_ctr_stream }, F = element(random:uniform(size(Funcs)),Funcs), %%io:format("worker ~p calling ~p\n",[self(),F]), -- cgit v1.2.3 From 807fc6ec56e3e7a65d9de5884cf6ac9927e5c1aa Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 20:53:34 +0200 Subject: crypto: Cleanup code for sha256 and sha512 --- lib/crypto/c_src/crypto.c | 16 ++++++++++------ lib/crypto/src/crypto.erl | 35 +++++++++++++---------------------- 2 files changed, 23 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index a1f2614f69..3b412e3c1b 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -149,8 +149,8 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -247,8 +247,8 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, - {"sha256_mac_n_nif", 3, sha256_mac_n_nif}, - {"sha512_mac_n_nif", 3, sha512_mac_n_nif}, + {"sha256_mac_nif", 3, sha256_mac_nif}, + {"sha512_mac_nif", 3, sha512_mac_nif}, {"hmac_init", 2, hmac_init}, {"hmac_update", 2, hmac_update}, {"hmac_final", 1, hmac_final}, @@ -780,7 +780,7 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } -static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA256 unsigned char hmacbuf[SHA256_DIGEST_LENGTH]; @@ -802,7 +802,7 @@ static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER #endif } -static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA512 unsigned char hmacbuf[SHA512_DIGEST_LENGTH]; @@ -832,8 +832,12 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ const EVP_MD *md; if (argv[0] == atom_sha) md = EVP_sha1(); +#ifdef HAVE_SHA256 else if (argv[0] == atom_sha256) md = EVP_sha256(); +#endif +#ifdef HAVE_SHA512 else if (argv[0] == atom_sha512) md = EVP_sha512(); +#endif else if (argv[0] == atom_md5) md = EVP_md5(); else if (argv[0] == atom_ripemd160) md = EVP_ripemd160(); else goto badarg; diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 0f14092f87..cb1173f6be 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -29,7 +29,8 @@ -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). --export([sha256_mac/2, sha256_mac_96/2, sha512_mac/2, sha512_mac/3, sha512_mac_96/2]). +-export([sha256_mac/2, sha256_mac/3]). +-export([sha512_mac/2, sha512_mac/3]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). @@ -70,8 +71,7 @@ sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha256_mac, sha256_mac_96, - sha512_mac, sha512_mac_96, + sha256_mac, sha512_mac, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -353,47 +353,38 @@ sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. %% SHA256_MAC %% -spec sha256_mac(iodata(), iodata()) -> binary(). --spec sha256_mac_96(iodata(), iodata()) -> binary(). sha256_mac(Key, Data) -> - sha256_mac_n(Key,Data,32). + sha256_mac(Key, Data, 256 div 8). sha256_mac(Key, Data, Size) -> - sha256_mac_n(Key, Data, Size). + case sha256_mac_nif(Key, Data, Size) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. -sha256_mac_96(Key, Data) -> - sha256_mac_n(Key,Data,12). +sha256_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. -sha256_mac_n(Key, Data, MacSz) -> - case sha256_mac_n_nif(Key, Data, MacSz) of notsup -> erlang:error(notsup); Bin -> Bin end. -sha256_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% %% SHA512_MAC %% -spec sha512_mac(iodata(), iodata()) -> binary(). --spec sha512_mac_96(iodata(), iodata()) -> binary(). sha512_mac(Key, Data) -> - sha512_mac_n(Key,Data,64). - -sha512_mac(Key, Data, Size) -> - sha512_mac_n(Key, Data, Size). - -sha512_mac_96(Key, Data) -> - sha512_mac_n(Key,Data,12). + sha512_mac(Key, Data, 512 div 8). -sha512_mac_n(Key, Data, MacSz) -> - case sha512_mac_n_nif(Key, Data, MacSz) of +sha512_mac(Key, Data, MacSz) -> + case sha512_mac_nif(Key, Data, MacSz) of notsup -> erlang:error(notsup); Bin -> Bin end. -sha512_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. +sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% %% CRYPTO FUNCTIONS -- cgit v1.2.3 From 7553817a73f8409a789496964a5292627002e785 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 20:55:04 +0200 Subject: crypto: Add sha384 --- lib/crypto/c_src/crypto.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 51 ++++++++++++++++- 2 files changed, 193 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 3b412e3c1b..2ae34c9741 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -139,6 +139,10 @@ static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -150,6 +154,7 @@ static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -215,6 +220,11 @@ static void hmac_sha256(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); #endif +#ifdef HAVE_SHA384 +static void hmac_sha384(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif #ifdef HAVE_SHA512 static void hmac_sha512(unsigned char *key, int klen, unsigned char *dbuf, int dlen, @@ -237,6 +247,10 @@ static ErlNifFunc nif_funcs[] = { {"sha256_init_nif", 0, sha256_init_nif}, {"sha256_update_nif", 2, sha256_update_nif}, {"sha256_final_nif", 1, sha256_final_nif}, + {"sha384_nif", 1, sha384_nif}, + {"sha384_init_nif", 0, sha384_init_nif}, + {"sha384_update_nif", 2, sha384_update_nif}, + {"sha384_final_nif", 1, sha384_final_nif}, {"sha512_nif", 1, sha512_nif}, {"sha512_init_nif", 0, sha512_init_nif}, {"sha512_update_nif", 2, sha512_update_nif}, @@ -248,6 +262,7 @@ static ErlNifFunc nif_funcs[] = { {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, {"sha256_mac_nif", 3, sha256_mac_nif}, + {"sha384_mac_nif", 3, sha384_mac_nif}, {"sha512_mac_nif", 3, sha512_mac_nif}, {"hmac_init", 2, hmac_init}, {"hmac_update", 2, hmac_update}, @@ -638,6 +653,67 @@ static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER #endif } +static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Data) */ +#ifdef HAVE_SHA384 + ErlNifBinary ibin; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { + return enif_make_badarg(env); + } + SHA384((unsigned char *) ibin.data, ibin.size, + enif_make_new_binary(env,SHA384_LEN, &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* () */ +#ifdef HAVE_SHA384 + ERL_NIF_TERM ret; + SHA384_Init((SHA512_CTX *) enif_make_new_binary(env, sizeof(SHA512_CTX), &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ +#ifdef HAVE_SHA384 + SHA512_CTX* new_ctx; + ErlNifBinary ctx_bin, data_bin; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX) + || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret); + memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX)); + SHA384_Update(new_ctx, data_bin.data, data_bin.size); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context) */ +#ifdef HAVE_SHA384 + ErlNifBinary ctx_bin; + SHA512_CTX ctx_clone; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) { + return enif_make_badarg(env); + } + memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA512_CTX)); /* writable */ + SHA384_Final(enif_make_new_binary(env, SHA384_LEN, &ret), &ctx_clone); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Data) */ #ifdef HAVE_SHA512 @@ -802,6 +878,29 @@ static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM #endif } +static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA384 + unsigned char hmacbuf[SHA384_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA384_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + + static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA512 @@ -835,6 +934,9 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ #ifdef HAVE_SHA256 else if (argv[0] == atom_sha256) md = EVP_sha256(); #endif +#ifdef HAVE_SHA384 + else if (argv[0] == atom_sha384) md = EVP_sha384(); +#endif #ifdef HAVE_SHA512 else if (argv[0] == atom_sha512) md = EVP_sha512(); #endif @@ -2290,6 +2392,47 @@ static void hmac_sha256(unsigned char *key, int klen, } #endif +#ifdef HAVE_SHA384 +static void hmac_sha384(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA512_CTX ctx; + char ipad[HMAC_INT_LEN]; + char opad[HMAC_INT_LEN]; + unsigned char nkey[SHA384_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT_LEN) { + SHA384(key, klen, nkey); + key = nkey; + klen = SHA384_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA384_Init(&ctx); + SHA384_Update(&ctx, ipad, HMAC_INT_LEN); + SHA384_Update(&ctx, dbuf, dlen); + SHA384_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA384_Init(&ctx); + SHA384_Update(&ctx, opad, HMAC_INT_LEN); + SHA384_Update(&ctx, hmacbuf, SHA384_DIGEST_LENGTH); + SHA384_Final((unsigned char *) hmacbuf, &ctx); +} +#endif + #ifdef HAVE_SHA512 static void hmac_sha512(unsigned char *key, int klen, unsigned char *dbuf, int dlen, diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index cb1173f6be..177ccfeef7 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -27,9 +27,11 @@ -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). +-export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). -export([sha256_mac/2, sha256_mac/3]). +-export([sha384_mac/2, sha384_mac/3]). -export([sha512_mac/2, sha512_mac/3]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). @@ -68,10 +70,11 @@ md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, sha256, sha256_init, sha256_update, sha256_final, + sha384, sha384_init, sha384_update, sha384_final, sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha256_mac, sha512_mac, + sha256_mac, sha384_mac, sha512_mac, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -190,6 +193,7 @@ hash(md4, Data) -> md4(Data); hash(sha, Data) -> sha(Data); hash(sha1, Data) -> sha(Data); hash(sha256, Data) -> sha256(Data); +hash(sha384, Data) -> sha384(Data); hash(sha512, Data) -> sha512(Data). @@ -267,6 +271,40 @@ sha256_init_nif() -> ?nif_stub. sha256_update_nif(_Context, _Data) -> ?nif_stub. sha256_final_nif(_Context) -> ?nif_stub. +% +%% SHA384 +%% +-spec sha384(iodata()) -> binary(). +-spec sha384_init() -> binary(). +-spec sha384_update(binary(), iodata()) -> binary(). +-spec sha384_final(binary()) -> binary(). + +sha384(Data) -> + case sha384_nif(Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha384_init() -> + case sha384_init_nif() of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha384_update(Context, Data) -> + case sha384_update_nif(Context, Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha384_final(Context) -> + case sha384_final_nif(Context) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha384_nif(_Data) -> ?nif_stub. +sha384_init_nif() -> ?nif_stub. +sha384_update_nif(_Context, _Data) -> ?nif_stub. +sha384_final_nif(_Context) -> ?nif_stub. + % %% SHA512 %% @@ -365,10 +403,21 @@ sha256_mac(Key, Data, Size) -> sha256_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. +%% +%% SHA384_MAC +%% +-spec sha384_mac(iodata(), iodata()) -> binary(). + +sha384_mac(Key, Data) -> + sha384_mac(Key, Data, 384 div 8). + +sha384_mac(Key, Data, Size) -> + case sha384_mac_nif(Key, Data, Size) of notsup -> erlang:error(notsup); Bin -> Bin end. +sha384_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% %% SHA512_MAC -- cgit v1.2.3 From 29ecf2ad4b046b6b76b9cefb18fcc1d635a06037 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 19 Jul 2012 12:12:17 +0200 Subject: crypto: fix hmac_sha384 and add hmac test cases from RFC-4231 --- lib/crypto/c_src/crypto.c | 12 +-- lib/crypto/test/crypto_SUITE.erl | 214 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 2ae34c9741..c64ad2b82d 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -2398,13 +2398,13 @@ static void hmac_sha384(unsigned char *key, int klen, unsigned char *hmacbuf) { SHA512_CTX ctx; - char ipad[HMAC_INT_LEN]; - char opad[HMAC_INT_LEN]; + char ipad[HMAC_INT2_LEN]; + char opad[HMAC_INT2_LEN]; unsigned char nkey[SHA384_DIGEST_LENGTH]; int i; /* Change key if longer than 64 bytes */ - if (klen > HMAC_INT_LEN) { + if (klen > HMAC_INT2_LEN) { SHA384(key, klen, nkey); key = nkey; klen = SHA384_DIGEST_LENGTH; @@ -2415,19 +2415,19 @@ static void hmac_sha384(unsigned char *key, int klen, memcpy(ipad, key, klen); memcpy(opad, key, klen); - for (i = 0; i < HMAC_INT_LEN; i++) { + for (i = 0; i < HMAC_INT2_LEN; i++) { ipad[i] ^= HMAC_IPAD; opad[i] ^= HMAC_OPAD; } /* inner SHA */ SHA384_Init(&ctx); - SHA384_Update(&ctx, ipad, HMAC_INT_LEN); + SHA384_Update(&ctx, ipad, HMAC_INT2_LEN); SHA384_Update(&ctx, dbuf, dlen); SHA384_Final((unsigned char *) hmacbuf, &ctx); /* outer SHA */ SHA384_Init(&ctx); - SHA384_Update(&ctx, opad, HMAC_INT_LEN); + SHA384_Update(&ctx, opad, HMAC_INT2_LEN); SHA384_Update(&ctx, hmacbuf, SHA384_DIGEST_LENGTH); SHA384_Final((unsigned char *) hmacbuf, &ctx); } diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 01cdf9f001..a21b74d5ae 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -38,6 +38,7 @@ hmac_update_md5/1, hmac_update_md5_io/1, hmac_update_md5_n/1, + hmac_rfc4231/1, sha256/1, sha256_update/1, sha512/1, @@ -88,6 +89,7 @@ groups() -> md5_mac_io, sha, sha_update, hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512, hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, + hmac_rfc4231, des_cbc, aes_cfb, aes_cbc, aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, @@ -397,7 +399,218 @@ hmac_update_md5(Config) when is_list(Config) -> ?line Mac2 = crypto:hmac_final(CtxD), ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])), ?line m(Exp2, Mac2). + +hmac_rfc4231(doc) -> + ["Generate an HMAC using crypto:shaXXX_mac and hmac_init, hmac_update, and hmac_final. " + "Testvectors are take from RFC4231." ]; +hmac_rfc4231(suite) -> + []; +hmac_rfc4231(Config) when is_list(Config) -> + %% Test Case 1 + Case1Key = binary:copy(<<16#0b>>, 20), + Case1Data = <<"Hi There">>, + Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" + "881dc200c9833da726e9376c2e32cff7"), + Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f" + "15f9dadbe4101ec682aa034c7cebc59c" + "faea9ea9076ede7f4af152e8b2fa9cb6"), + Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0" + "2379f4e2ce4ec2787ad0b30545e17cde" + "daa833b7d6b8a702038b274eaea3f4e4" + "be9d914eeb61f1702e696c203a126854"), + + ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key), + ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data), + ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2), + ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data), + ?line m(Case1Exp256, Case1Mac256_1), + ?line m(Case1Exp256, Case1Mac256_2), + + ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key), + ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data), + ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2), + ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data), + ?line m(Case1Exp384, Case1Mac384_1), + ?line m(Case1Exp384, Case1Mac384_2), + + ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key), + ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data), + ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2), + ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data), + ?line m(Case1Exp512, Case1Mac512_1), + ?line m(Case1Exp512, Case1Mac512_2), + + %% Test Case 2 + Case2Key = <<"Jefe">>, + Case2Data = <<"what do ya want for nothing?">>, + Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843"), + Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b" + "9c7ef464f5a01b47e42ec3736322445e" + "8e2240ca5e69e2c78b3239ecfab21649"), + Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3" + "87bd64222e831fd610270cd7ea250554" + "9758bf75c05a994a6d034f65f8f0e6fd" + "caeab1a34d4a6b4b636e070a38bce737"), + + ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key), + ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data), + ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2), + ?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data), + ?line m(Case2Exp256, Case2Mac256_1), + ?line m(Case2Exp256, Case2Mac256_2), + + ?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key), + ?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data), + ?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2), + ?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data), + ?line m(Case2Exp384, Case2Mac384_1), + ?line m(Case2Exp384, Case2Mac384_2), + + ?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key), + ?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data), + ?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2), + ?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data), + ?line m(Case2Exp512, Case2Mac512_1), + ?line m(Case2Exp512, Case2Mac512_2), + + %% Test Case 3 + Case3Key = binary:copy(<<16#aa>>, 20), + Case3Data = binary:copy(<<16#dd>>, 50), + Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7" + "2959098b3ef8c122d9635514ced565fe"), + Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f" + "0aa635d947ac9febe83ef4e55966144b" + "2a5ab39dc13814b94e3ab6e101a34f27"), + Case3Exp512 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9" + "b1b5dbdd8ee81a3655f83e33b2279d39" + "bf3e848279a722c806b485a47e67c807" + "b946a337bee8942674278859e13292fb"), + + ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key), + ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data), + ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2), + ?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data), + ?line m(Case3Exp256, Case3Mac256_1), + ?line m(Case3Exp256, Case3Mac256_2), + + ?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key), + ?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data), + ?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2), + ?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data), + ?line m(Case3Exp384, Case3Mac384_1), + ?line m(Case3Exp384, Case3Mac384_2), + + ?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key), + ?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data), + ?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2), + ?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data), + ?line m(Case3Exp512, Case3Mac512_1), + ?line m(Case3Exp512, Case3Mac512_2), + + %% Test Case 4 + Case4Key = list_to_binary(lists:seq(1, 16#19)), + Case4Data = binary:copy(<<16#cd>>, 50), + Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a" + "85f0faa3e578f8077a2e3ff46729665b"), + Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7" + "7a9981480850009cc5577c6e1f573b4e" + "6801dd23c4a7d679ccf8a386c674cffb"), + Case4Exp512 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7" + "e576d97ff94b872de76f8050361ee3db" + "a91ca5c11aa25eb4d679275cc5788063" + "a5f19741120c4f2de2adebeb10a298dd"), + + ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key), + ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data), + ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2), + ?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data), + ?line m(Case4Exp256, Case4Mac256_1), + ?line m(Case4Exp256, Case4Mac256_2), + + ?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key), + ?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data), + ?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2), + ?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data), + ?line m(Case4Exp384, Case4Mac384_1), + ?line m(Case4Exp384, Case4Mac384_2), + + ?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key), + ?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data), + ?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2), + ?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data), + ?line m(Case4Exp512, Case4Mac512_1), + ?line m(Case4Exp512, Case4Mac512_2), + + %% Test Case 6 + Case6Key = binary:copy(<<16#aa>>, 131), + Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, + Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f" + "8e0bc6213728c5140546040f0ee37f54"), + Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4" + "4f9ef1012a2b588f3cd11f05033ac4c6" + "0c2ef6ab4030fe8296248df163f44952"), + Case6Exp512 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4" + "9b46d1f41b4aeec1121b013783f8f352" + "6b56d037e05f2598bd0fd2215d6a1e52" + "95e64f73f63f0aec8b915a985d786598"), + + ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key), + ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data), + ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2), + ?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data), + ?line m(Case6Exp256, Case6Mac256_1), + ?line m(Case6Exp256, Case6Mac256_2), + + ?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key), + ?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data), + ?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2), + ?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data), + ?line m(Case6Exp384, Case6Mac384_1), + ?line m(Case6Exp384, Case6Mac384_2), + + ?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key), + ?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data), + ?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2), + ?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data), + ?line m(Case6Exp512, Case6Mac512_1), + ?line m(Case6Exp512, Case6Mac512_2), + %% Test Case 7 + Case7Key = binary:copy(<<16#aa>>, 131), + Case7Data = <<"This is a test using a larger than block-size key and a larger t", + "han block-size data. The key needs to be hashed before being use", + "d by the HMAC algorithm.">>, + Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" + "bfdc63644f0713938a7f51535c3a35e2"), + Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" + "602420feb0b8fb9adccebb82461e99c5" + "a678cc31e799176d3860e6110c46523e"), + Case7Exp512 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd" + "debd71f8867289865df5a32d20cdc944" + "b6022cac3c4982b10d5eeb55c3e4de15" + "134676fb6de0446065c97440fa8c6a58"), + + ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key), + ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data), + ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2), + ?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data), + ?line m(Case7Exp256, Case7Mac256_1), + ?line m(Case7Exp256, Case7Mac256_2), + + ?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key), + ?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data), + ?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2), + ?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data), + ?line m(Case7Exp384, Case7Mac384_1), + ?line m(Case7Exp384, Case7Mac384_2), + + ?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key), + ?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data), + ?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2), + ?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data), + ?line m(Case7Exp512, Case7Mac512_1), + ?line m(Case7Exp512, Case7Mac512_2). hmac_update_md5_io(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -1523,6 +1736,7 @@ worker_loop(N, Config) -> aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test, hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512, + hmac_rfc4231, aes_ctr_stream }, F = element(random:uniform(size(Funcs)),Funcs), -- cgit v1.2.3 From d830b644d86f07dbebd9c12926c22867442e1726 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 17 Aug 2012 19:28:08 +0200 Subject: crypto: Add sha224 --- lib/crypto/c_src/crypto.c | 149 +++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 59 +++++++++++++++- lib/crypto/test/crypto_SUITE.erl | 54 ++++++++++++++ 3 files changed, 259 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index c64ad2b82d..d9ae8a87a3 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -53,6 +53,10 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224)\ + && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */ +# define HAVE_SHA224 +#endif #if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256) # define HAVE_SHA256 #endif @@ -135,6 +139,10 @@ static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -153,6 +161,7 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -215,6 +224,11 @@ static void hmac_md5(unsigned char *key, int klen, static void hmac_sha1(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); +#ifdef HAVE_SHA224 +static void hmac_sha224(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif #ifdef HAVE_SHA256 static void hmac_sha256(unsigned char *key, int klen, unsigned char *dbuf, int dlen, @@ -243,6 +257,10 @@ static ErlNifFunc nif_funcs[] = { {"sha_init", 0, sha_init}, {"sha_update", 2, sha_update}, {"sha_final", 1, sha_final}, + {"sha224_nif", 1, sha224_nif}, + {"sha224_init_nif", 0, sha224_init_nif}, + {"sha224_update_nif", 2, sha224_update_nif}, + {"sha224_final_nif", 1, sha224_final_nif}, {"sha256_nif", 1, sha256_nif}, {"sha256_init_nif", 0, sha256_init_nif}, {"sha256_update_nif", 2, sha256_update_nif}, @@ -261,6 +279,7 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, + {"sha224_mac_nif", 3, sha224_mac_nif}, {"sha256_mac_nif", 3, sha256_mac_nif}, {"sha384_mac_nif", 3, sha384_mac_nif}, {"sha512_mac_nif", 3, sha512_mac_nif}, @@ -317,6 +336,7 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) #define SHA_CTX_LEN (sizeof(SHA_CTX)) #define SHA_LEN 20 #define SHA_LEN_96 12 +#define SHA224_LEN (224/8) #define SHA256_LEN (256/8) #define SHA384_LEN (384/8) #define SHA512_LEN (512/8) @@ -331,6 +351,7 @@ static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */ static ERL_NIF_TERM atom_true; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_sha; +static ERL_NIF_TERM atom_sha224; static ERL_NIF_TERM atom_sha256; static ERL_NIF_TERM atom_sha384; static ERL_NIF_TERM atom_sha512; @@ -406,6 +427,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_true = enif_make_atom(env,"true"); atom_false = enif_make_atom(env,"false"); atom_sha = enif_make_atom(env,"sha"); + atom_sha224 = enif_make_atom(env,"sha224"); atom_sha256 = enif_make_atom(env,"sha256"); atom_sha384 = enif_make_atom(env,"sha384"); atom_sha512 = enif_make_atom(env,"sha512"); @@ -592,6 +614,67 @@ static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Data) */ +#ifdef HAVE_SHA224 + ErlNifBinary ibin; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { + return enif_make_badarg(env); + } + SHA224((unsigned char *) ibin.data, ibin.size, + enif_make_new_binary(env,SHA224_LEN, &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* () */ +#ifdef HAVE_SHA224 + ERL_NIF_TERM ret; + SHA224_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ +#ifdef HAVE_SHA224 + SHA256_CTX* new_ctx; + ErlNifBinary ctx_bin, data_bin; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX) + || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret); + memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX)); + SHA224_Update(new_ctx, data_bin.data, data_bin.size); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context) */ +#ifdef HAVE_SHA224 + ErlNifBinary ctx_bin; + SHA256_CTX ctx_clone; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) { + return enif_make_badarg(env); + } + memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA256_CTX)); /* writable */ + SHA224_Final(enif_make_new_binary(env, SHA224_LEN, &ret), &ctx_clone); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Data) */ #ifdef HAVE_SHA256 @@ -856,6 +939,28 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA224 + unsigned char hmacbuf[SHA224_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA224_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA256 @@ -931,6 +1036,9 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ const EVP_MD *md; if (argv[0] == atom_sha) md = EVP_sha1(); +#ifdef HAVE_SHA224 + else if (argv[0] == atom_sha224) md = EVP_sha224(); +#endif #ifdef HAVE_SHA256 else if (argv[0] == atom_sha256) md = EVP_sha256(); #endif @@ -2351,6 +2459,47 @@ static void hmac_sha1(unsigned char *key, int klen, SHA1_Final((unsigned char *) hmacbuf, &ctx); } +#ifdef HAVE_SHA224 +static void hmac_sha224(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA256_CTX ctx; + char ipad[HMAC_INT_LEN]; + char opad[HMAC_INT_LEN]; + unsigned char nkey[SHA224_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT_LEN) { + SHA224(key, klen, nkey); + key = nkey; + klen = SHA224_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA224_Init(&ctx); + SHA224_Update(&ctx, ipad, HMAC_INT_LEN); + SHA224_Update(&ctx, dbuf, dlen); + SHA224_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA224_Init(&ctx); + SHA224_Update(&ctx, opad, HMAC_INT_LEN); + SHA224_Update(&ctx, hmacbuf, SHA224_DIGEST_LENGTH); + SHA224_Final((unsigned char *) hmacbuf, &ctx); +} +#endif + #ifdef HAVE_SHA256 static void hmac_sha256(unsigned char *key, int klen, unsigned char *dbuf, int dlen, diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 177ccfeef7..a07e7a30b4 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -26,10 +26,12 @@ -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). +-export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]). -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). -export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). +-export([sha224_mac/2, sha224_mac/3]). -export([sha256_mac/2, sha256_mac/3]). -export([sha384_mac/2, sha384_mac/3]). -export([sha512_mac/2, sha512_mac/3]). @@ -69,12 +71,13 @@ -define(FUNC_LIST, [md4, md4_init, md4_update, md4_final, md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, - sha256, sha256_init, sha256_update, sha256_final, + sha224, sha224_init, sha224_update, sha224_final, + sha256, sha256_init, sha256_update, sha256_final, sha384, sha384_init, sha384_update, sha384_final, - sha512, sha512_init, sha512_update, sha512_final, + sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha256_mac, sha384_mac, sha512_mac, + sha224_mac, sha256_mac, sha384_mac, sha512_mac, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -237,6 +240,40 @@ sha_init() -> ?nif_stub. sha_update(_Context, _Data) -> ?nif_stub. sha_final(_Context) -> ?nif_stub. +% +%% SHA224 +%% +-spec sha224(iodata()) -> binary(). +-spec sha224_init() -> binary(). +-spec sha224_update(binary(), iodata()) -> binary(). +-spec sha224_final(binary()) -> binary(). + +sha224(Data) -> + case sha224_nif(Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha224_init() -> + case sha224_init_nif() of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha224_update(Context, Data) -> + case sha224_update_nif(Context, Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha224_final(Context) -> + case sha224_final_nif(Context) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha224_nif(_Data) -> ?nif_stub. +sha224_init_nif() -> ?nif_stub. +sha224_update_nif(_Context, _Data) -> ?nif_stub. +sha224_final_nif(_Context) -> ?nif_stub. + % %% SHA256 %% @@ -387,6 +424,22 @@ sha_mac_96(Key, Data) -> sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. +%% +%% SHA224_MAC +%% +-spec sha224_mac(iodata(), iodata()) -> binary(). + +sha224_mac(Key, Data) -> + sha224_mac(Key, Data, 224 div 8). + +sha224_mac(Key, Data, Size) -> + case sha224_mac_nif(Key, Data, Size) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha224_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. + %% %% SHA256_MAC %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index a21b74d5ae..bcd80c5a0f 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -409,6 +409,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 1 Case1Key = binary:copy(<<16#0b>>, 20), Case1Data = <<"Hi There">>, + Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f" + "47b4b1169912ba4f53684b22"), Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" "881dc200c9833da726e9376c2e32cff7"), Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f" @@ -419,6 +421,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "daa833b7d6b8a702038b274eaea3f4e4" "be9d914eeb61f1702e696c203a126854"), + ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key), + ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data), + ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2), + ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data), + ?line m(Case1Exp224, Case1Mac224_1), + ?line m(Case1Exp224, Case1Mac224_2), + ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key), ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data), ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2), @@ -443,6 +452,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 2 Case2Key = <<"Jefe">>, Case2Data = <<"what do ya want for nothing?">>, + Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f" + "8bbea2a39e6148008fd05e44"), Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7" "5a003f089d2739839dec58b964ec3843"), Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b" @@ -453,6 +464,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "9758bf75c05a994a6d034f65f8f0e6fd" "caeab1a34d4a6b4b636e070a38bce737"), + ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key), + ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data), + ?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2), + ?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data), + ?line m(Case2Exp224, Case2Mac224_1), + ?line m(Case2Exp224, Case2Mac224_2), + ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key), ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data), ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2), @@ -477,6 +495,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 3 Case3Key = binary:copy(<<16#aa>>, 20), Case3Data = binary:copy(<<16#dd>>, 50), + Case3Exp224 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264" + "9365b0c1f65d69d1ec8333ea"), Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7" "2959098b3ef8c122d9635514ced565fe"), Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f" @@ -487,6 +507,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "bf3e848279a722c806b485a47e67c807" "b946a337bee8942674278859e13292fb"), + ?line Case3Ctx224 = crypto:hmac_init(sha224, Case3Key), + ?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data), + ?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2), + ?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data), + ?line m(Case3Exp224, Case3Mac224_1), + ?line m(Case3Exp224, Case3Mac224_2), + ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key), ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data), ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2), @@ -511,6 +538,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 4 Case4Key = list_to_binary(lists:seq(1, 16#19)), Case4Data = binary:copy(<<16#cd>>, 50), + Case4Exp224 = hexstr2bin("6c11506874013cac6a2abc1bb382627c" + "ec6a90d86efc012de7afec5a"), Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a" "85f0faa3e578f8077a2e3ff46729665b"), Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7" @@ -521,6 +550,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "a91ca5c11aa25eb4d679275cc5788063" "a5f19741120c4f2de2adebeb10a298dd"), + ?line Case4Ctx224 = crypto:hmac_init(sha224, Case4Key), + ?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data), + ?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2), + ?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data), + ?line m(Case4Exp224, Case4Mac224_1), + ?line m(Case4Exp224, Case4Mac224_2), + ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key), ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data), ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2), @@ -545,6 +581,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 6 Case6Key = binary:copy(<<16#aa>>, 131), Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, + Case6Exp224 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2" + "d499f112f2d2b7273fa6870e"), Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f" "8e0bc6213728c5140546040f0ee37f54"), Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4" @@ -555,6 +593,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "6b56d037e05f2598bd0fd2215d6a1e52" "95e64f73f63f0aec8b915a985d786598"), + ?line Case6Ctx224 = crypto:hmac_init(sha224, Case6Key), + ?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data), + ?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2), + ?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data), + ?line m(Case6Exp224, Case6Mac224_1), + ?line m(Case6Exp224, Case6Mac224_2), + ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key), ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data), ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2), @@ -581,6 +626,8 @@ hmac_rfc4231(Config) when is_list(Config) -> Case7Data = <<"This is a test using a larger than block-size key and a larger t", "han block-size data. The key needs to be hashed before being use", "d by the HMAC algorithm.">>, + Case7Exp224 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd" + "946770db9c2b95c9f6f565d1"), Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" "bfdc63644f0713938a7f51535c3a35e2"), Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" @@ -591,6 +638,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "b6022cac3c4982b10d5eeb55c3e4de15" "134676fb6de0446065c97440fa8c6a58"), + ?line Case7Ctx224 = crypto:hmac_init(sha224, Case7Key), + ?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data), + ?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2), + ?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data), + ?line m(Case7Exp224, Case7Mac224_1), + ?line m(Case7Exp224, Case7Mac224_2), + ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key), ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data), ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2), -- cgit v1.2.3 From 42e65ffe5f2659d998ff0a7e5ebea2573c23a86f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 16 Aug 2012 16:38:31 +0200 Subject: crypto: Add more generic hash interface --- lib/crypto/doc/src/crypto.xml | 51 +++++++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 33 ++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 36f8bc6deb..0d78dbc426 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -255,6 +255,57 @@ Mpint() = >]]> the computed SHA message digest.

+ + hash(Type, Data) -> Digest + + + Type = md4 | md5 | sha | sha224 | sha256 | sha384 | sha512 + Data = iodata() + Digest = binary() + + +

Computes a message digest of type Type from Data.

+
+
+ + hash_init(Type) -> Context + + + Type = md4 | md5 | sha | sha224 | sha256 | sha384 | sha512 + + +

Initializes the context for streaming hash operations. Type determines + which digest to use. The returned context should be used as argument + to hash_update.

+
+
+ + hash_update(Context, Data) -> NewContext + + + Data = iodata() + + +

Updates the digest represented by Context using the given Data. Context + must have been generated using hash_init + or a previous call to this function. Data can be any length. NewContext + must be passed into the next call to hash_update + or hash_final.

+
+
+ + hash_final(Context) -> Digest + + + Digest = binary() + + +

Finalizes the hash operation referenced by Context returned + from a previous call to hash_update. + The size of Digest is determined by the type of hash + function used to generate it.

+
+
md5_mac(Key, Data) -> Mac Compute an MD5 MACmessage authentification code diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index a07e7a30b4..63043888b9 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -22,7 +22,7 @@ -module(crypto). -export([start/0, stop/0, info/0, info_lib/0, version/0]). --export([hash/2]). +-export([hash/2, hash_init/1, hash_update/2, hash_final/1]). -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). @@ -194,11 +194,40 @@ version() -> ?CRYPTO_VSN. hash(md5, Data) -> md5(Data); hash(md4, Data) -> md4(Data); hash(sha, Data) -> sha(Data); -hash(sha1, Data) -> sha(Data); +hash(sha224, Data) -> sha224(Data); hash(sha256, Data) -> sha256(Data); hash(sha384, Data) -> sha384(Data); hash(sha512, Data) -> sha512(Data). +-spec hash_init('md5'|'md4'|'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any(). + +hash_init(md5) -> {md5, md5_init()}; +hash_init(md4) -> {md4, md4_init()}; +hash_init(sha) -> {sha, sha_init()}; +hash_init(sha224) -> {sha224, sha224_init()}; +hash_init(sha256) -> {sha256, sha256_init()}; +hash_init(sha384) -> {sha384, sha384_init()}; +hash_init(sha512) -> {sha512, sha512_init()}. + +-spec hash_update(_, iodata()) -> any(). + +hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)}; +hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)}; +hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)}; +hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)}; +hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)}; +hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)}; +hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}. + +-spec hash_final(_) -> binary(). + +hash_final({md5,Context}) -> md5_final(Context); +hash_final({md4,Context}) -> md4_final(Context); +hash_final({sha,Context}) -> sha_final(Context); +hash_final({sha224,Context}) -> sha224_final(Context); +hash_final({sha256,Context}) -> sha256_final(Context); +hash_final({sha384,Context}) -> sha384_final(Context); +hash_final({sha512,Context}) -> sha512_final(Context). %% %% MD5 -- cgit v1.2.3 From c5541a4c03b89fcbcb0dd1bfab8460b1287cc6cb Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 20 Aug 2012 12:31:28 +0200 Subject: crypto: Add sha224 for rsa sign/verify --- lib/crypto/c_src/crypto.c | 13 +++++++++++++ lib/crypto/doc/src/crypto.xml | 4 ++-- lib/crypto/src/crypto.erl | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index d9ae8a87a3..9a1a6f6c55 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1564,6 +1564,12 @@ static void sha1_digest(unsigned char* in, unsigned int in_len, unsigned char* o { SHA1(in, in_len, out); } +#ifdef HAVE_SHA224 +static void sha224_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA224(in, in_len, out); +} +#endif #ifdef HAVE_SHA256 static void sha256_digest(unsigned char* in, unsigned int in_len, unsigned char* out) { @@ -1595,6 +1601,13 @@ struct digest_type_t digest_types[] = { {"md5", MD5_DIGEST_LENGTH, NID_md5, md5_digest}, {"sha", SHA_DIGEST_LENGTH, NID_sha1, sha1_digest}, + {"sha224", +#ifdef HAVE_SHA224 + SHA224_LEN, NID_sha224, sha224_digest +#else + 0 +#endif + }, {"sha256", #ifdef HAVE_SHA256 SHA256_LEN, NID_sha256, sha256_digest diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 0d78dbc426..48e35f8093 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -932,7 +932,7 @@ Mpint() = >]]> the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C is the CRT coefficient. Terminology is taken from RFC 3447. - DigestType = md5 | sha | sha256 | sha384 | sha512 + DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512 The default DigestType is sha. Mpint = binary() Signature = binary() @@ -957,7 +957,7 @@ Mpint() = >]]> Key = [E, N] E, N = Mpint Where E is the public exponent and N is public modulus. - DigestType = md5 | sha | sha256 | sha384 | sha512 + DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512 The default DigestType is sha. Mpint = binary() diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 63043888b9..0089e79a4f 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -105,7 +105,7 @@ aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, info_lib]). --type rsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'. +-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. -type data_or_digest() :: binary() | {digest, binary()}. -type crypto_integer() :: binary() | integer(). -- cgit v1.2.3 From 18581081644018b4a77234f68b6c67e789bc943b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 20 Aug 2012 15:29:26 +0200 Subject: public_key: Add sha224 to RSA sign/verify --- lib/public_key/doc/src/public_key.xml | 2 +- lib/public_key/src/public_key.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index f64274d608..2d455e4e15 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -82,7 +82,7 @@

rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'

-

rsa_digest_type() = 'md5' | 'sha'

+

rsa_digest_type() = 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'

dss_digest_type() = 'sha'

diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 686a11a7b2..d5df53e848 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -48,7 +48,7 @@ -type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. --type rsa_digest_type() :: 'md5' | 'sha'| 'sha256' | 'sha384' | 'sha512'. +-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility -define(UINT32(X), X:32/unsigned-big-integer). -- cgit v1.2.3 From 0c692262d9be40ba1d2565ee5f663c70e9c630b1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 20 Aug 2012 15:30:18 +0200 Subject: public_key: Fix documentation typo dsa -> dss --- lib/public_key/doc/src/public_key.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 2d455e4e15..5c227557f2 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -400,10 +400,10 @@ The msg is either the binary "plain text" data to be signed or it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dsa_digest_type() + DigestType = rsa_digest_type() | dss_digest_type() Key = rsa_private_key() | dsa_private_key() - - + +

Creates a digital signature.

@@ -464,7 +464,7 @@ Msg = binary() | {digest,binary()} The msg is either the binary "plain text" data or it is the hashed value of "plain text" i.e. the digest. - DigestType = rsa_digest_type() | dsa_digest_type() + DigestType = rsa_digest_type() | dss_digest_type() Signature = binary() Key = rsa_public_key() | dsa_public_key() -- cgit v1.2.3 From 571133751287d93598dc90fe90b58ab4580f4836 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 15 Jun 2012 17:35:58 +0200 Subject: ssl: Calculate handshake hash only when needed TLS/SSL version before 1.2 always used a MD5/SHA combination for the handshake hashes. With TLS 1.2 the default hash is SHA256 and it is possible to negotiate a different hash. This change delays the calculation of the handshake hashes until they are really needed. At that point the hash to use should be known. For now MD5/SHA is still hard coded. --- lib/ssl/src/ssl_connection.erl | 186 +++++++++++++++++++++-------------------- lib/ssl/src/ssl_handshake.erl | 93 ++++++++++----------- lib/ssl/src/ssl_handshake.hrl | 3 +- lib/ssl/src/ssl_ssl3.erl | 49 ++++------- lib/ssl/src/ssl_tls1.erl | 25 +++--- 5 files changed, 166 insertions(+), 190 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index c57930e821..965b396353 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -67,8 +67,7 @@ tls_packets = [], % Not yet handled decode ssl/tls packets. tls_record_buffer, % binary() buffer of incomplete records tls_handshake_buffer, % binary() buffer of incomplete handshakes - %% {{md5_hash, sha_hash}, {prev_md5, prev_sha}} (binary()) - tls_handshake_hashes, % see above + tls_handshake_history, % tls_handshake_history() tls_cipher_texts, % list() received but not deciphered yet cert_db, % session, % #session{} from ssl_handshake.hrl @@ -301,12 +300,13 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) -> State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), - Hashes0 = ssl_handshake:init_hashes(), + Handshake = ssl_handshake:init_handshake_history(), TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), try ssl_init(SSLOpts0, Role) of {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} -> Session = State0#state.session, - State = State0#state{tls_handshake_hashes = Hashes0, + State = State0#state{ + tls_handshake_history = Handshake, session = Session#session{own_certificate = OwnCert, time_stamp = TimeStamp}, file_ref_db = FileRefHandle, @@ -344,15 +344,15 @@ hello(start, #state{host = Host, port = Port, role = client, Cache, CacheCb, Renegotiation, Cert), Version = Hello#client_hello.client_version, - Hashes0 = ssl_handshake:init_hashes(), - {BinMsg, ConnectionStates, Hashes} = - encode_handshake(Hello, Version, ConnectionStates0, Hashes0), + Handshake0 = ssl_handshake:init_handshake_history(), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Hello, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State1 = State0#state{connection_states = ConnectionStates, - negotiated_version = Version, %% Requested version at this point + negotiated_version = Version, %% Requested version session = Session0#session{session_id = Hello#client_hello.session_id}, - tls_handshake_hashes = Hashes}, + tls_handshake_history = Handshake}, {Record, State} = next_record(State1), next_state(hello, hello, Record, State); @@ -431,12 +431,13 @@ abbreviated(#hello_request{}, State0) -> abbreviated(#finished{verify_data = Data} = Finished, #state{role = server, negotiated_version = Version, - tls_handshake_hashes = Hashes, + tls_handshake_history = Handshake, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State) -> +%%CHECKME case ssl_handshake:verify_connection(Version, Finished, client, - MasterSecret, Hashes) of + MasterSecret, Handshake) of verified -> ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), next_state_connection(abbreviated, @@ -447,18 +448,18 @@ abbreviated(#finished{verify_data = Data} = Finished, end; abbreviated(#finished{verify_data = Data} = Finished, - #state{role = client, tls_handshake_hashes = Hashes0, + #state{role = client, tls_handshake_history = Handshake0, session = #session{master_secret = MasterSecret}, negotiated_version = Version, connection_states = ConnectionStates0} = State) -> case ssl_handshake:verify_connection(Version, Finished, server, - MasterSecret, Hashes0) of + MasterSecret, Handshake0) of verified -> ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0), - {ConnectionStates, Hashes} = + {ConnectionStates, Handshake} = finalize_handshake(State#state{connection_states = ConnectionStates1}, abbreviated), next_state_connection(abbreviated, - ack_connection(State#state{tls_handshake_hashes = Hashes, + ack_connection(State#state{tls_handshake_history = Handshake, connection_states = ConnectionStates})); #alert{} = Alert -> @@ -641,10 +642,10 @@ cipher(#certificate_verify{signature = Signature}, public_key_info = PublicKeyInfo, negotiated_version = Version, session = #session{master_secret = MasterSecret}, - tls_handshake_hashes = Hashes + tls_handshake_history = Handshake } = State0) -> case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, - Version, MasterSecret, Hashes) of + Version, MasterSecret, Handshake) of valid -> {Record, State} = next_record(State0), next_state(cipher, cipher, Record, State); @@ -660,10 +661,10 @@ cipher(#finished{verify_data = Data} = Finished, role = Role, session = #session{master_secret = MasterSecret} = Session0, - tls_handshake_hashes = Hashes0} = State) -> + tls_handshake_history = Handshake0} = State) -> case ssl_handshake:verify_connection(Version, Finished, opposite_role(Role), - MasterSecret, Hashes0) of + MasterSecret, Handshake0) of verified -> Session = register_session(Role, Host, Port, Session0), cipher_role(Role, Data, Session, State); @@ -691,17 +692,17 @@ connection(#hello_request{}, #state{host = Host, port = Port, transport_cb = Transport, connection_states = ConnectionStates0, renegotiation = {Renegotiation, _}, - tls_handshake_hashes = Hashes0} = State0) -> + tls_handshake_history = Handshake0} = State0) -> Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Cache, CacheCb, Renegotiation, Cert), - {BinMsg, ConnectionStates, Hashes} = - encode_handshake(Hello, Version, ConnectionStates0, Hashes0), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Hello, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), {Record, State} = next_record(State0#state{connection_states = - ConnectionStates, + ConnectionStates, session = Session0#session{session_id = Hello#client_hello.session_id}, - tls_handshake_hashes = Hashes}), + tls_handshake_history = Handshake}), next_state(connection, hello, Record, State); connection(#client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) -> %% Mitigate Computational DoS attack @@ -1224,13 +1225,13 @@ certify_client(#state{client_certificate_requested = true, role = client, cert_db_ref = CertDbRef, session = #session{own_certificate = OwnCert}, socket = Socket, - tls_handshake_hashes = Hashes0} = State) -> + tls_handshake_history = Handshake0} = State) -> Certificate = ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client), - {BinCert, ConnectionStates, Hashes} = - encode_handshake(Certificate, Version, ConnectionStates0, Hashes0), + {BinCert, ConnectionStates, Handshake} = + encode_handshake(Certificate, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinCert), State#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}; + tls_handshake_history = Handshake}; certify_client(#state{client_certificate_requested = false} = State) -> State. @@ -1242,17 +1243,17 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, private_key = PrivateKey, session = #session{master_secret = MasterSecret, own_certificate = OwnCert}, - tls_handshake_hashes = Hashes0} = State) -> + tls_handshake_history = Handshake0} = State) -> case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, - Version, PrivateKey, Hashes0) of + Version, PrivateKey, Handshake0) of #certificate_verify{} = Verified -> - {BinVerified, ConnectionStates, Hashes} = + {BinVerified, ConnectionStates, Handshake} = encode_handshake(Verified, Version, - ConnectionStates0, Hashes0), + ConnectionStates0, Handshake0), Transport:send(Socket, BinVerified), State#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}; + tls_handshake_history = Handshake}; ignore -> State; #alert{} = Alert -> @@ -1308,11 +1309,11 @@ resumed_server_hello(#state{session = Session, {_, ConnectionStates1} -> State1 = State0#state{connection_states = ConnectionStates1, session = Session}, - {ConnectionStates, Hashes} = + {ConnectionStates, Handshake} = finalize_handshake(State1, abbreviated), State2 = State1#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}, + tls_handshake_history = Handshake}, {Record, State} = next_record(State2), next_state(hello, abbreviated, Record, State); #alert{} = Alert -> @@ -1351,11 +1352,11 @@ client_certify_and_key_exchange(#state{negotiated_version = Version} = State0) -> try do_client_certify_and_key_exchange(State0) of State1 = #state{} -> - {ConnectionStates, Hashes} = finalize_handshake(State1, certify), + {ConnectionStates, Handshake} = finalize_handshake(State1, certify), State2 = State1#state{connection_states = ConnectionStates, %% Reinitialize client_certificate_requested = false, - tls_handshake_hashes = Hashes}, + tls_handshake_history = Handshake}, {Record, State} = next_record(State2), next_state(certify, cipher, Record, State) catch @@ -1378,29 +1379,29 @@ server_hello(ServerHello, #state{transport_cb = Transport, socket = Socket, negotiated_version = Version, connection_states = ConnectionStates0, - tls_handshake_hashes = Hashes0} = State) -> + tls_handshake_history = Handshake0} = State) -> CipherSuite = ServerHello#server_hello.cipher_suite, {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), - {BinMsg, ConnectionStates1, Hashes1} = - encode_handshake(ServerHello, Version, ConnectionStates0, Hashes0), + {BinMsg, ConnectionStates1, Handshake1} = + encode_handshake(ServerHello, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates1, - tls_handshake_hashes = Hashes1, + tls_handshake_history = Handshake1, key_algorithm = KeyAlgorithm}. server_hello_done(#state{transport_cb = Transport, socket = Socket, negotiated_version = Version, connection_states = ConnectionStates0, - tls_handshake_hashes = Hashes0} = State) -> + tls_handshake_history = Handshake0} = State) -> HelloDone = ssl_handshake:server_hello_done(), - {BinHelloDone, ConnectionStates, Hashes} = - encode_handshake(HelloDone, Version, ConnectionStates0, Hashes0), + {BinHelloDone, ConnectionStates, Handshake} = + encode_handshake(HelloDone, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinHelloDone), State#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}. + tls_handshake_history = Handshake}. certify_server(#state{key_algorithm = dh_anon} = State) -> State; @@ -1409,17 +1410,17 @@ certify_server(#state{transport_cb = Transport, socket = Socket, negotiated_version = Version, connection_states = ConnectionStates0, - tls_handshake_hashes = Hashes0, + tls_handshake_history = Handshake0, cert_db = CertDbHandle, cert_db_ref = CertDbRef, session = #session{own_certificate = OwnCert}} = State) -> case ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of CertMsg = #certificate{} -> - {BinCertMsg, ConnectionStates, Hashes} = - encode_handshake(CertMsg, Version, ConnectionStates0, Hashes0), + {BinCertMsg, ConnectionStates, Handshake} = + encode_handshake(CertMsg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinCertMsg), State#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes + tls_handshake_history = Handshake }; Alert = #alert{} -> throw(Alert) @@ -1432,7 +1433,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, - tls_handshake_hashes = Hashes0, + tls_handshake_history = Handshake0, socket = Socket, transport_cb = Transport } = State) @@ -1449,12 +1450,12 @@ key_exchange(#state{role = server, key_algorithm = Algo, Algo, ClientRandom, ServerRandom, PrivateKey}), - {BinMsg, ConnectionStates, Hashes} = - encode_handshake(Msg, Version, ConnectionStates0, Hashes0), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, diffie_hellman_keys = Keys, - tls_handshake_hashes = Hashes}; + tls_handshake_history = Handshake}; key_exchange(#state{role = client, connection_states = ConnectionStates0, @@ -1463,36 +1464,36 @@ key_exchange(#state{role = client, negotiated_version = Version, premaster_secret = PremasterSecret, socket = Socket, transport_cb = Transport, - tls_handshake_hashes = Hashes0} = State) -> + tls_handshake_history = Handshake0} = State) -> Msg = rsa_key_exchange(PremasterSecret, PublicKeyInfo), - {BinMsg, ConnectionStates, Hashes} = - encode_handshake(Msg, Version, ConnectionStates0, Hashes0), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}; + tls_handshake_history = Handshake}; key_exchange(#state{role = client, connection_states = ConnectionStates0, key_algorithm = Algorithm, negotiated_version = Version, diffie_hellman_keys = {DhPubKey, _}, socket = Socket, transport_cb = Transport, - tls_handshake_hashes = Hashes0} = State) + tls_handshake_history = Handshake0} = State) when Algorithm == dhe_dss; Algorithm == dhe_rsa; Algorithm == dh_anon -> Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}), - {BinMsg, ConnectionStates, Hashes} = - encode_handshake(Msg, Version, ConnectionStates0, Hashes0), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}. + tls_handshake_history = Handshake}. rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) when Algorithm == ?rsaEncryption; Algorithm == ?md2WithRSAEncryption; Algorithm == ?md5WithRSAEncryption; Algorithm == ?sha1WithRSAEncryption -> - ssl_handshake:key_exchange(client, + ssl_handshake:key_exchange(client, {premaster_secret, PremasterSecret, PublicKeyInfo}); rsa_key_exchange(_, _) -> @@ -1502,17 +1503,17 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer}, connection_states = ConnectionStates0, cert_db = CertDbHandle, cert_db_ref = CertDbRef, - tls_handshake_hashes = Hashes0, + tls_handshake_history = Handshake0, negotiated_version = Version, socket = Socket, transport_cb = Transport} = State) -> Msg = ssl_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef), - {BinMsg, ConnectionStates, Hashes} = - encode_handshake(Msg, Version, ConnectionStates0, Hashes0), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{client_certificate_requested = true, connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}; + tls_handshake_history = Handshake}; request_client_cert(#state{ssl_options = #ssl_options{verify = verify_none}} = State) -> State. @@ -1538,14 +1539,14 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version, transport_cb = Transport, session = Session, connection_states = ConnectionStates0, - tls_handshake_hashes = Hashes0}, StateName) -> + tls_handshake_history = Handshake0}, StateName) -> MasterSecret = Session#session.master_secret, - Finished = ssl_handshake:finished(Version, Role, MasterSecret, Hashes0), + Finished = ssl_handshake:finished(Version, Role, MasterSecret, Handshake0), ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName), - {BinFinished, ConnectionStates, Hashes} = - encode_handshake(Finished, Version, ConnectionStates1, Hashes0), + {BinFinished, ConnectionStates, Handshake} = + encode_handshake(Finished, Version, ConnectionStates1, Handshake0), Transport:send(Socket, BinFinished), - {ConnectionStates, Hashes}. + {ConnectionStates, Handshake}. save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, certify) -> ssl_record:set_client_verify_data(current_write, Data, ConnectionStates); @@ -1641,26 +1642,26 @@ cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State) -> ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0), - {ConnectionStates, Hashes} = + {ConnectionStates, Handshake} = finalize_handshake(State#state{connection_states = ConnectionStates1, session = Session}, cipher), next_state_connection(cipher, ack_connection(State#state{connection_states = ConnectionStates, session = Session, - tls_handshake_hashes = - Hashes})). + tls_handshake_history = + Handshake})). encode_alert(#alert{} = Alert, Version, ConnectionStates) -> ssl_record:encode_alert_record(Alert, Version, ConnectionStates). encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) -> ssl_record:encode_change_cipher_spec(Version, ConnectionStates). -encode_handshake(HandshakeRec, Version, ConnectionStates0, Hashes0) -> +encode_handshake(HandshakeRec, Version, ConnectionStates0, Handshake0) -> Frag = ssl_handshake:encode_handshake(HandshakeRec, Version), - Hashes1 = ssl_handshake:update_hashes(Hashes0, Frag), + Handshake1 = ssl_handshake:update_handshake_history(Handshake0, Frag), {E, ConnectionStates1} = ssl_record:encode_handshake(Frag, Version, ConnectionStates0), - {E, ConnectionStates1, Hashes1}. + {E, ConnectionStates1, Handshake1}. encode_packet(Data, #socket_options{packet=Packet}) -> case Packet of @@ -1913,21 +1914,22 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) -> %% This message should not be included in handshake %% message hashes. Starts new handshake (renegotiation) - Hs0 = ssl_handshake:init_hashes(), - ?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs0, + Hs0 = ssl_handshake:init_handshake_history(), + ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs0, renegotiation = {true, peer}}); ({#hello_request{} = Packet, _}, {next_state, SName, State}) -> %% This message should not be included in handshake %% message hashes. Already in negotiation so it will be ignored! ?MODULE:SName(Packet, State); ({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) -> - Hs0 = ssl_handshake:init_hashes(), - Hs1 = ssl_handshake:update_hashes(Hs0, Raw), - ?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs1, + Version = Packet#client_hello.client_version, + Hs0 = ssl_handshake:init_handshake_history(), + Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw), + ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1, renegotiation = {true, peer}}); - ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_hashes=Hs0}}) -> - Hs1 = ssl_handshake:update_hashes(Hs0, Raw), - ?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs1}); + ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_history=Hs0}}) -> + Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw), + ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1}); (_, StopState) -> StopState end, try @@ -2011,7 +2013,7 @@ next_state_connection(StateName, #state{send_queue = Queue0, next_state_is_connection(StateName, State) end. -%% In next_state_is_connection/1: clear tls_handshake_hashes, +%% In next_state_is_connection/1: clear tls_handshake, %% premaster_secret and public_key_info (only needed during handshake) %% to reduce memory foot print of a connection. next_state_is_connection(_, State = @@ -2020,13 +2022,13 @@ next_state_is_connection(_, State = #socket_options{active = false}}) when RecvFrom =/= undefined -> passive_receive(State#state{premaster_secret = undefined, public_key_info = undefined, - tls_handshake_hashes = {<<>>, <<>>}}, connection); + tls_handshake_history = ssl_handshake:init_handshake_history()}, connection); next_state_is_connection(StateName, State0) -> {Record, State} = next_record_if_active(State0), next_state(StateName, connection, Record, State#state{premaster_secret = undefined, public_key_info = undefined, - tls_handshake_hashes = {<<>>, <<>>}}). + tls_handshake_history = ssl_handshake:init_handshake_history()}). register_session(client, Host, Port, #session{is_resumable = new} = Session0) -> Session = Session0#session{is_resumable = true}, @@ -2307,8 +2309,8 @@ ack_connection(State) -> renegotiate(#state{role = client} = State) -> %% Handle same way as if server requested %% the renegotiation - Hs0 = ssl_handshake:init_hashes(), - connection(#hello_request{}, State#state{tls_handshake_hashes = Hs0}); + Hs0 = ssl_handshake:init_handshake_history(), + connection(#hello_request{}, State#state{tls_handshake_history = Hs0}); renegotiate(#state{role = server, socket = Socket, transport_cb = Transport, @@ -2316,13 +2318,13 @@ renegotiate(#state{role = server, connection_states = ConnectionStates0} = State0) -> HelloRequest = ssl_handshake:hello_request(), Frag = ssl_handshake:encode_handshake(HelloRequest, Version), - Hs0 = ssl_handshake:init_hashes(), + Hs0 = ssl_handshake:init_handshake_history(), {BinMsg, ConnectionStates} = ssl_record:encode_handshake(Frag, Version, ConnectionStates0), Transport:send(Socket, BinMsg), {Record, State} = next_record(State0#state{connection_states = ConnectionStates, - tls_handshake_hashes = Hs0}), + tls_handshake_history = Hs0}), next_state(connection, hello, Record, State#state{allow_renegotiate = true}). notify_senders(SendQueue) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 06d45966c1..cf42129534 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -36,7 +36,7 @@ certificate_request/3, key_exchange/2, server_key_exchange_hash/2, finished/4, verify_connection/5, get_tls_handshake/2, decode_client_key/3, server_hello_done/0, - encode_handshake/2, init_hashes/0, update_hashes/2, + encode_handshake/2, init_handshake_history/0, update_handshake_history/2, decrypt_premaster_secret/2, prf/5]). -export([dec_hello_extensions/2]). @@ -258,7 +258,7 @@ certificate(OwnCert, CertDbHandle, CertDbRef, server) -> %%-------------------------------------------------------------------- -spec client_certificate_verify(undefined | der_cert(), binary(), tls_version(), private_key(), - {{binary(), binary()},{binary(), binary()}}) -> + tls_handshake_history()) -> #certificate_verify{} | ignore | #alert{}. %% %% Description: Creates a certificate_verify message, called by the client. @@ -268,28 +268,28 @@ client_certificate_verify(undefined, _, _, _, _) -> client_certificate_verify(_, _, _, undefined, _) -> ignore; client_certificate_verify(OwnCert, MasterSecret, Version, - PrivateKey, {Hashes0, _}) -> + PrivateKey, {Handshake, _}) -> case public_key:pkix_is_fixed_dh_cert(OwnCert) of true -> ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE); false -> Hashes = calc_certificate_verify(Version, MasterSecret, - alg_oid(PrivateKey), Hashes0), + alg_oid(PrivateKey), Handshake), Signed = digitally_signed(Hashes, PrivateKey), #certificate_verify{signature = Signed} end. %%-------------------------------------------------------------------- -spec certificate_verify(binary(), public_key_info(), tls_version(), - binary(), {_, {binary(), binary()}}) -> valid | #alert{}. + binary(), tls_handshake_history()) -> valid | #alert{}. %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- certificate_verify(Signature, {?'rsaEncryption'= Algorithm, PublicKey, _}, Version, - MasterSecret, {_, Hashes0}) -> + MasterSecret, {_, Handshake}) -> Hashes = calc_certificate_verify(Version, MasterSecret, - Algorithm, Hashes0), + Algorithm, Handshake), case public_key:decrypt_public(Signature, PublicKey, [{rsa_pad, rsa_pkcs1_padding}]) of Hashes -> @@ -298,9 +298,9 @@ certificate_verify(Signature, {?'rsaEncryption'= Algorithm, PublicKey, _}, Versi ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) end; certificate_verify(Signature, {?'id-dsa' = Algorithm, PublicKey, PublicKeyParams}, Version, - MasterSecret, {_, Hashes0}) -> + MasterSecret, {_, Handshake}) -> Hashes = calc_certificate_verify(Version, MasterSecret, - Algorithm, Hashes0), + Algorithm, Handshake), case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of true -> valid; @@ -416,26 +416,26 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> end. %%-------------------------------------------------------------------- --spec finished(tls_version(), client | server, binary(), {{binary(), binary()},_}) -> +-spec finished(tls_version(), client | server, binary(), tls_handshake_history()) -> #finished{}. %% %% Description: Creates a handshake finished message %%------------------------------------------------------------------- -finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes +finished(Version, Role, MasterSecret, {Handshake, _}) -> % use the current hashes #finished{verify_data = - calc_finished(Version, Role, MasterSecret, Hashes)}. + calc_finished(Version, Role, MasterSecret, Handshake)}. %%-------------------------------------------------------------------- -spec verify_connection(tls_version(), #finished{}, client | server, binary(), - {_, {binary(), binary()}}) -> verified | #alert{}. + tls_handshake_history()) -> verified | #alert{}. %% %% Description: Checks the ssl handshake finished message to verify %% the connection. %%------------------------------------------------------------------- verify_connection(Version, #finished{verify_data = Data}, - Role, MasterSecret, {_, {MD5, SHA}}) -> + Role, MasterSecret, {_, Handshake}) -> %% use the previous hashes - case calc_finished(Version, Role, MasterSecret, {MD5, SHA}) of + case calc_finished(Version, Role, MasterSecret, Handshake) of Data -> verified; _ -> @@ -482,39 +482,34 @@ decode_client_key(ClientKey, Type, Version) -> dec_client_key(ClientKey, key_exchange_alg(Type), Version). %%-------------------------------------------------------------------- --spec init_hashes() ->{{binary(), binary()}, {binary(), binary()}}. +-spec init_handshake_history() -> tls_handshake_history(). %% -%% Description: Calls crypto hash (md5 and sha) init functions to -%% initalize the hash context. +%% Description: Initialize the empty handshake history buffer. %%-------------------------------------------------------------------- -init_hashes() -> - T = {crypto:md5_init(), crypto:sha_init()}, - {T, T}. +init_handshake_history() -> + {[], []}. %%-------------------------------------------------------------------- --spec update_hashes({{binary(), binary()}, {binary(), binary()}}, Data ::term()) -> - {{binary(), binary()}, {binary(), binary()}}. +-spec update_handshake_history(tls_handshake_history(), Data ::term()) -> + tls_handshake_history(). %% -%% Description: Calls crypto hash (md5 and sha) update functions to -%% update the hash context with Data. +%% Description: Update the handshake history buffer with Data. %%-------------------------------------------------------------------- -update_hashes(Hashes, % special-case SSL2 client hello - <>) -> - update_hashes(Hashes, - <>); -update_hashes({{MD50, SHA0}, _Prev}, Data) -> - {MD51, SHA1} = {crypto:md5_update(MD50, Data), - crypto:sha_update(SHA0, Data)}, - {{MD51, SHA1}, {MD50, SHA0}}. +update_handshake_history(Handshake, % special-case SSL2 client hello + <>) -> + update_handshake_history(Handshake, + <>); +update_handshake_history({Handshake0, _Prev}, Data) -> + {[Data|Handshake0], Handshake0}. %%-------------------------------------------------------------------- -spec decrypt_premaster_secret(binary(), #'RSAPrivateKey'{}) -> binary(). @@ -1139,17 +1134,17 @@ setup_keys({3,1}, MasterSecret, ssl_tls1:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KML, IVS). -calc_finished({3, 0}, Role, MasterSecret, Hashes) -> - ssl_ssl3:finished(Role, MasterSecret, Hashes); -calc_finished({3, N}, Role, MasterSecret, Hashes) +calc_finished({3, 0}, Role, MasterSecret, Handshake) -> + ssl_ssl3:finished(Role, MasterSecret, lists:reverse(Handshake)); +calc_finished({3, N}, Role, MasterSecret, Handshake) when N == 1; N == 2 -> - ssl_tls1:finished(Role, MasterSecret, Hashes). + ssl_tls1:finished(Role, MasterSecret, lists:reverse(Handshake)). -calc_certificate_verify({3, 0}, MasterSecret, Algorithm, Hashes) -> - ssl_ssl3:certificate_verify(Algorithm, MasterSecret, Hashes); -calc_certificate_verify({3, N}, _, Algorithm, Hashes) +calc_certificate_verify({3, 0}, MasterSecret, Algorithm, Handshake) -> + ssl_ssl3:certificate_verify(Algorithm, MasterSecret, lists:reverse(Handshake)); +calc_certificate_verify({3, N}, _, Algorithm, Handshake) when N == 1; N == 2 -> - ssl_tls1:certificate_verify(Algorithm, Hashes). + ssl_tls1:certificate_verify(Algorithm, lists:reverse(Handshake)). key_exchange_alg(rsa) -> ?KEY_EXCHANGE_RSA; diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index fb0ebac7d1..8510def2fd 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,6 +31,7 @@ -type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'. -type public_key_params() :: #'Dss-Parms'{} | term(). -type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. +-type tls_handshake_history() :: {[binary()], [binary()]}. -record(session, { session_id, diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index f2926b2d2f..2b4ae1539f 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -54,9 +54,9 @@ master_secret(PremasterSecret, ClientRandom, ServerRandom) -> Block = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48), Block. --spec finished(client | server, binary(), {binary(), binary()}) -> binary(). +-spec finished(client | server, binary(), [binary()]) -> binary(). -finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> +finished(Role, MasterSecret, Handshake) -> %% draft-ietf-tls-ssl-version3-00 - 5.6.9 Finished %% struct { %% opaque md5_hash[16]; @@ -70,13 +70,13 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> %% SHA(handshake_messages + Sender + %% master_secret + pad1)); Sender = get_sender(Role), - MD5 = handshake_hash(?MD5, MasterSecret, Sender, MD5Hash), - SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash), + MD5 = handshake_hash(?MD5, MasterSecret, Sender, Handshake), + SHA = handshake_hash(?SHA, MasterSecret, Sender, Handshake), <>. --spec certificate_verify(OID::tuple(), binary(), {binary(), binary()}) -> binary(). +-spec certificate_verify(OID::tuple(), binary(), [binary()]) -> binary(). -certificate_verify(?'rsaEncryption', MasterSecret, {MD5Hash, SHAHash}) -> +certificate_verify(?'rsaEncryption', MasterSecret, Handshake) -> %% md5_hash %% MD5(master_secret + pad_2 + %% MD5(handshake_messages + master_secret + pad_1)); @@ -84,15 +84,16 @@ certificate_verify(?'rsaEncryption', MasterSecret, {MD5Hash, SHAHash}) -> %% SHA(master_secret + pad_2 + %% SHA(handshake_messages + master_secret + pad_1)); - MD5 = handshake_hash(?MD5, MasterSecret, undefined, MD5Hash), - SHA = handshake_hash(?SHA, MasterSecret, undefined, SHAHash), + MD5 = handshake_hash(?MD5, MasterSecret, undefined, Handshake), + SHA = handshake_hash(?SHA, MasterSecret, undefined, Handshake), <>; -certificate_verify(?'id-dsa', MasterSecret, {_, SHAHash}) -> +certificate_verify(?'id-dsa', MasterSecret, Handshake) -> %% sha_hash %% SHA(master_secret + pad_2 + %% SHA(handshake_messages + master_secret + pad_1)); - handshake_hash(?SHA, MasterSecret, undefined, SHAHash). + + handshake_hash(?SHA, MasterSecret, undefined, Handshake). -spec mac_hash(integer(), binary(), integer(), integer(), integer(), binary()) -> binary(). @@ -157,16 +158,6 @@ hash(?MD5, Data) -> hash(?SHA, Data) -> crypto:sha(Data). -hash_update(?MD5, Context, Data) -> - crypto:md5_update(Context, Data); -hash_update(?SHA, Context, Data) -> - crypto:sha_update(Context, Data). - -hash_final(?MD5, Context) -> - crypto:md5_final(Context); -hash_final(?SHA, Context) -> - crypto:sha_final(Context). - %%pad_1(?NULL) -> %% ""; pad_1(?MD5) -> @@ -189,19 +180,11 @@ mac_hash(Method, Secret, Data) -> InnerHash = hash(Method, [Secret, pad_1(Method), Data]), hash(Method, [Secret, pad_2(Method), InnerHash]). -handshake_hash(Method, HandshakeHash, Extra) -> - HSH = hash_update(Method, HandshakeHash, Extra), - hash_final(Method, HSH). - -handshake_hash(Method, MasterSecret, undefined, HandshakeHash) -> - InnerHash = - handshake_hash(Method, HandshakeHash, - [MasterSecret, pad_1(Method)]), +handshake_hash(Method, MasterSecret, undefined, Handshake) -> + InnerHash = hash(Method, [Handshake, MasterSecret, pad_1(Method)]), hash(Method, [MasterSecret, pad_2(Method), InnerHash]); -handshake_hash(Method, MasterSecret, Sender, HandshakeHash) -> - InnerHash = - handshake_hash(Method, HandshakeHash, - [Sender, MasterSecret, pad_1(Method)]), +handshake_hash(Method, MasterSecret, Sender, Handshake) -> + InnerHash = hash(Method, [Handshake, Sender, MasterSecret, pad_1(Method)]), hash(Method, [MasterSecret, pad_2(Method), InnerHash]). get_sender(client) -> "CLNT"; diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index c8aae34892..d64a8f815d 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -44,9 +44,9 @@ master_secret(PreMasterSecret, ClientRandom, ServerRandom) -> prf(PreMasterSecret, <<"master secret">>, [ClientRandom, ServerRandom], 48). --spec finished(client | server, binary(), {binary(), binary()}) -> binary(). +-spec finished(client | server, binary(), [binary()]) -> binary(). -finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> +finished(Role, MasterSecret, Handshake) -> %% RFC 2246 & 4346 - 7.4.9. Finished %% struct { %% opaque verify_data[12]; @@ -55,19 +55,19 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> %% verify_data %% PRF(master_secret, finished_label, MD5(handshake_messages) + %% SHA-1(handshake_messages)) [0..11]; - MD5 = hash_final(?MD5, MD5Hash), - SHA = hash_final(?SHA, SHAHash), + MD5 = crypto:md5(Handshake), + SHA = crypto:sha(Handshake), prf(MasterSecret, finished_label(Role), [MD5, SHA], 12). --spec certificate_verify(OID::tuple(), {binary(), binary()}) -> binary(). +-spec certificate_verify(OID::tuple(), [binary()]) -> binary(). -certificate_verify(?'rsaEncryption', {MD5Hash, SHAHash}) -> - MD5 = hash_final(?MD5, MD5Hash), - SHA = hash_final(?SHA, SHAHash), +certificate_verify(?'rsaEncryption', Handshake) -> + MD5 = crypto:md5(Handshake), + SHA = crypto:sha(Handshake), <>; -certificate_verify(?'id-dsa', {_, SHAHash}) -> - hash_final(?SHA, SHAHash). +certificate_verify(?'id-dsa', Handshake) -> + crypto:sha(Handshake). -spec setup_keys(binary(), binary(), binary(), integer(), integer(), integer()) -> {binary(), binary(), binary(), @@ -228,8 +228,3 @@ finished_label(client) -> <<"client finished">>; finished_label(server) -> <<"server finished">>. - -hash_final(?MD5, Conntext) -> - crypto:md5_final(Conntext); -hash_final(?SHA, Conntext) -> - crypto:sha_final(Conntext). -- cgit v1.2.3 From fb3b15a18e507859eb77e20ec1e9bed788e88908 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 6 Apr 2012 02:56:08 +0200 Subject: ssl: Consider TLS version when building cipher blocks With TLS 1.2 the handling of the IV in cipher blocks changed. This prepares ssl_cipher:cipher/5 for that change by passing the TLS version into it and allowing generic_block_cipher_from_bin/4 to overload the IV. --- lib/ssl/src/ssl_cipher.erl | 41 ++++++++++++++++++++++++----------------- lib/ssl/src/ssl_record.erl | 2 +- lib/ssl/src/ssl_record.hrl | 3 ++- 3 files changed, 27 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index d43d312be8..3837628347 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -32,7 +32,7 @@ -include_lib("public_key/include/public_key.hrl"). -export([security_parameters/2, suite_definition/1, - decipher/5, cipher/4, + decipher/5, cipher/5, suite/1, suites/1, anonymous_suites/0, openssl_suite/1, openssl_suite_name/1, filter/2]). @@ -59,16 +59,16 @@ security_parameters(CipherSuite, SecParams) -> hash_size = hash_size(Hash)}. %%-------------------------------------------------------------------- --spec cipher(cipher_enum(), #cipher_state{}, binary(), binary()) -> +-spec cipher(cipher_enum(), #cipher_state{}, binary(), binary(), tls_version()) -> {binary(), #cipher_state{}}. %% %% Description: Encrypts the data and the MAC using chipher described %% by cipher_enum() and updating the cipher state %%------------------------------------------------------------------- -cipher(?NULL, CipherState, <<>>, Fragment) -> +cipher(?NULL, CipherState, <<>>, Fragment, _Version) -> GenStreamCipherList = [Fragment, <<>>], {GenStreamCipherList, CipherState}; -cipher(?RC4, CipherState, Mac, Fragment) -> +cipher(?RC4, CipherState, Mac, Fragment, _Version) -> State0 = case CipherState#cipher_state.state of undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); S -> S @@ -76,30 +76,34 @@ cipher(?RC4, CipherState, Mac, Fragment) -> GenStreamCipherList = [Fragment, Mac], {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList), {T, CipherState#cipher_state{state = State1}}; -cipher(?DES, CipherState, Mac, Fragment) -> +cipher(?DES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) -> crypto:des_cbc_encrypt(Key, IV, T) - end, block_size(des_cbc), CipherState, Mac, Fragment); -cipher(?'3DES', CipherState, Mac, Fragment) -> + end, block_size(des_cbc), CipherState, Mac, Fragment, Version); +cipher(?'3DES', CipherState, Mac, Fragment, Version) -> block_cipher(fun(<>, IV, T) -> crypto:des3_cbc_encrypt(K1, K2, K3, IV, T) - end, block_size(des_cbc), CipherState, Mac, Fragment); -cipher(?AES, CipherState, Mac, Fragment) -> + end, block_size(des_cbc), CipherState, Mac, Fragment, Version); +cipher(?AES, CipherState, Mac, Fragment, Version) -> block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> crypto:aes_cbc_128_encrypt(Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> crypto:aes_cbc_256_encrypt(Key, IV, T) - end, block_size(aes_128_cbc), CipherState, Mac, Fragment). + end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version). %% cipher(?IDEA, CipherState, Mac, Fragment) -> %% block_cipher(fun(Key, IV, T) -> %% crypto:idea_cbc_encrypt(Key, IV, T) %% end, block_size(idea_cbc), CipherState, Mac, Fragment); -block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, - Mac, Fragment) -> +build_cipher_block(BlockSz, Mac, Fragment) -> TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1, {PaddingLength, Padding} = get_padding(TotSz, BlockSz), - L = [Fragment, Mac, PaddingLength, Padding], + [Fragment, Mac, PaddingLength, Padding]. + +block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, + Mac, Fragment, {3, N}) + when N == 0; N == 1 -> + L = build_cipher_block(BlockSz, Mac, Fragment), T = Fun(Key, IV, L), NextIV = next_iv(T, IV), {T, CS0#cipher_state{iv=NextIV}}. @@ -156,10 +160,11 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, HashSz, Fragment, Version) -> try Text = Fun(Key, IV, Fragment), - GBC = generic_block_cipher_from_bin(Text, HashSz), + NextIV = next_iv(Fragment, IV), + GBC = generic_block_cipher_from_bin(Version, Text, NextIV, HashSz), Content = GBC#generic_block_cipher.content, Mac = GBC#generic_block_cipher.mac, - CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, + CipherState1 = CipherState0#cipher_state{iv=GBC#generic_block_cipher.next_iv}, case is_correct_padding(GBC, Version) of true -> {Content, Mac, CipherState1}; @@ -525,7 +530,8 @@ hash_size(sha) -> %% We return the original (possibly invalid) PadLength in any case. %% An invalid PadLength will be caught by is_correct_padding/2 %% -generic_block_cipher_from_bin(T, HashSize) -> +generic_block_cipher_from_bin({3, N}, T, IV, HashSize) + when N == 0; N == 1 -> Sz1 = byte_size(T) - 1, <<_:Sz1/binary, ?BYTE(PadLength0)>> = T, PadLength = if @@ -536,7 +542,8 @@ generic_block_cipher_from_bin(T, HashSize) -> <> = T, #generic_block_cipher{content=Content, mac=Mac, - padding=Padding, padding_length=PadLength0}. + padding=Padding, padding_length=PadLength0, + next_iv = IV}. generic_stream_cipher_from_bin(T, HashSz) -> Sz = byte_size(T), diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 830026c825..f9ccaea0e3 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -633,7 +633,7 @@ cipher(Type, Version, Fragment, CS0) -> BCA} }} = hash_and_bump_seqno(CS0, Type, Version, Length, Fragment), - {Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, MacHash, Fragment), + {Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, MacHash, Fragment, Version), CS2 = CS1#connection_state{cipher_state=CipherS1}, {Ciphered, CS2}. diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index 282d642138..3d22fa6acb 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -176,7 +176,8 @@ content, % opaque content[TLSCompressed.length]; mac, % opaque MAC[CipherSpec.hash_size]; padding, % unit 8 padding[GenericBlockCipher.padding_length]; - padding_length % uint8 padding_length; + padding_length, % uint8 padding_length; + next_iv % opaque IV[SecurityParameters.record_iv_length]; }). -endif. % -ifdef(ssl_record). -- cgit v1.2.3 From be1d74144eef4ec4ffe1a0133aa533001458d50a Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 6 Apr 2012 03:04:23 +0200 Subject: ssl: Add TLS 1.2 block cipher IV handling --- lib/ssl/src/ssl_cipher.erl | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 3837628347..1b67260388 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -106,6 +106,15 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, L = build_cipher_block(BlockSz, Mac, Fragment), T = Fun(Key, IV, L), NextIV = next_iv(T, IV), + {T, CS0#cipher_state{iv=NextIV}}; + +block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, + Mac, Fragment, {3, N}) + when N == 2; N == 3 -> + NextIV = random_iv(IV), + L0 = build_cipher_block(BlockSz, Mac, Fragment), + L = [NextIV|L0], + T = Fun(Key, IV, L), {T, CS0#cipher_state{iv=NextIV}}. %%-------------------------------------------------------------------- @@ -543,7 +552,19 @@ generic_block_cipher_from_bin({3, N}, T, IV, HashSize) Padding:PadLength/binary, ?BYTE(PadLength0)>> = T, #generic_block_cipher{content=Content, mac=Mac, padding=Padding, padding_length=PadLength0, - next_iv = IV}. + next_iv = IV}; + +generic_block_cipher_from_bin({3, N}, T, IV, HashSize) + when N == 2; N == 3 -> + Sz1 = byte_size(T) - 1, + <<_:Sz1/binary, ?BYTE(PadLength)>> = T, + IVLength = byte_size(IV), + CompressedLength = byte_size(T) - IVLength - PadLength - 1 - HashSize, + <> = T, + #generic_block_cipher{content=Content, mac=Mac, + padding=Padding, padding_length=PadLength, + next_iv = NextIV}. generic_stream_cipher_from_bin(T, HashSz) -> Sz = byte_size(T), @@ -574,6 +595,10 @@ get_padding_aux(BlockSize, PadLength) -> N = BlockSize - PadLength, {N, list_to_binary(lists:duplicate(N, N))}. +random_iv(IV) -> + IVSz = byte_size(IV), + crypto:rand_bytes(IVSz). + next_iv(Bin, IV) -> BinSz = byte_size(Bin), IVSz = byte_size(IV), -- cgit v1.2.3 From 7dcf8182fb71d594d639c26aeedadef253be1733 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 1 Jun 2012 18:24:57 +0200 Subject: ssl: Update ssl_cipher_SUITE for TLS 1.1 and TLS 1.2 now that we handle TLS 1.1+ records correctly, the test suite have to take that into account. --- lib/ssl/test/ssl_cipher_SUITE.erl | 66 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl index 99bc21e820..83beeb0131 100644 --- a/lib/ssl/test/ssl_cipher_SUITE.erl +++ b/lib/ssl/test/ssl_cipher_SUITE.erl @@ -27,6 +27,7 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). +-include("ssl_alert.hrl"). -define(TIMEOUT, 600000). @@ -103,7 +104,7 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [aes_decipher_good, aes_decipher_fail]. + [aes_decipher_good, aes_decipher_good_tls11, aes_decipher_fail, aes_decipher_fail_tls11]. groups() -> []. @@ -131,10 +132,39 @@ aes_decipher_good(Config) when is_list(Config) -> 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160, 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, - Version = {3,3}, - Content = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56,72,69,76,76,79,10>>, + Content = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56, "HELLO\n">>, Mac = <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>, + Version = {3,0}, {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), + Version1 = {3,1}, + {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1), + ok. + +%%-------------------------------------------------------------------- + +aes_decipher_good_tls11(doc) -> + ["Decipher a known TLS 1.1 cryptotext."]; + +aes_decipher_good_tls11(suite) -> + []; + +%% the fragment is actuall a TLS 1.1 record, with +%% Version = TLS 1.1, we get the correct NextIV in #cipher_state +aes_decipher_good_tls11(Config) when is_list(Config) -> + HashSz = 32, + CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>, + key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,148>>}, + Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8, + 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160, + 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, + 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, + Content = <<"HELLO\n">>, + NextIV = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56>>, + Mac = <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>, + Version = {3,2}, + {Content, Mac, #cipher_state{iv = NextIV}} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), + Version1 = {3,2}, + {Content, Mac, #cipher_state{iv = NextIV}} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1), ok. %%-------------------------------------------------------------------- @@ -154,10 +184,38 @@ aes_decipher_fail(Config) when is_list(Config) -> 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160, 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, - Version = {3,3}, + Version = {3,0}, {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), 32 = byte_size(Content), 32 = byte_size(Mac), + Version1 = {3,1}, + {Content1, Mac1, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1), + 32 = byte_size(Content1), + 32 = byte_size(Mac1), + ok. + +%%-------------------------------------------------------------------- + +aes_decipher_fail_tls11(doc) -> + ["Decipher a known TLS 1.1 cryptotext."]; + +aes_decipher_fail_tls11(suite) -> + []; + +%% same as above, last byte of key replaced +%% stricter padding checks in TLS 1.1 mean we get an alert instead +aes_decipher_fail_tls11(Config) when is_list(Config) -> + HashSz = 32, + CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>, + key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,254>>}, + Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8, + 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160, + 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122, + 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>, + Version = {3,2}, + #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version), + Version1 = {3,3}, + #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1), ok. %%-------------------------------------------------------------------- -- cgit v1.2.3 From fc4c828438e99afe47f7531101a1561decc3cf37 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 15 Jun 2012 17:52:30 +0200 Subject: ssl: Add TLS version to ssl_handshake:key_exchange/3 TLS 1.2 changed the way digital signatures are done. key_exchange/3 needs to pass the version to it. --- lib/ssl/src/ssl_connection.erl | 12 ++++++------ lib/ssl/src/ssl_handshake.erl | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 965b396353..94d129de6f 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1446,7 +1446,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, - Msg = ssl_handshake:key_exchange(server, {dh, Keys, Params, + Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params, Algo, ClientRandom, ServerRandom, PrivateKey}), @@ -1465,7 +1465,7 @@ key_exchange(#state{role = client, premaster_secret = PremasterSecret, socket = Socket, transport_cb = Transport, tls_handshake_history = Handshake0} = State) -> - Msg = rsa_key_exchange(PremasterSecret, PublicKeyInfo), + Msg = rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo), {BinMsg, ConnectionStates, Handshake} = encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), @@ -1481,22 +1481,22 @@ key_exchange(#state{role = client, when Algorithm == dhe_dss; Algorithm == dhe_rsa; Algorithm == dh_anon -> - Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}), + Msg = ssl_handshake:key_exchange(client, Version, {dh, DhPubKey}), {BinMsg, ConnectionStates, Handshake} = encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, tls_handshake_history = Handshake}. -rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) +rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) when Algorithm == ?rsaEncryption; Algorithm == ?md2WithRSAEncryption; Algorithm == ?md5WithRSAEncryption; Algorithm == ?sha1WithRSAEncryption -> - ssl_handshake:key_exchange(client, + ssl_handshake:key_exchange(client, Version, {premaster_secret, PremasterSecret, PublicKeyInfo}); -rsa_key_exchange(_, _) -> +rsa_key_exchange(_, _, _) -> throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)). request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer}, diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index cf42129534..ef7900c470 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -33,7 +33,7 @@ -export([master_secret/4, client_hello/8, server_hello/4, hello/4, hello_request/0, certify/7, certificate/4, client_certificate_verify/5, certificate_verify/5, - certificate_request/3, key_exchange/2, server_key_exchange_hash/2, + certificate_request/3, key_exchange/3, server_key_exchange_hash/2, finished/4, verify_connection/5, get_tls_handshake/2, decode_client_key/3, server_hello_done/0, encode_handshake/2, init_handshake_history/0, update_handshake_history/2, @@ -327,7 +327,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> }. %%-------------------------------------------------------------------- --spec key_exchange(client | server, +-spec key_exchange(client | server, tls_version(), {premaster_secret, binary(), public_key_info()} | {dh, binary()} | {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(), @@ -336,18 +336,18 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> %% %% Description: Creates a keyexchange message. %%-------------------------------------------------------------------- -key_exchange(client, {premaster_secret, Secret, {_, PublicKey, _}}) -> +key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) -> EncPremasterSecret = encrypted_premaster_secret(Secret, PublicKey), #client_key_exchange{exchange_keys = EncPremasterSecret}; -key_exchange(client, {dh, <>}) -> +key_exchange(client, _Version, {dh, <>}) -> #client_key_exchange{ exchange_keys = #client_diffie_hellman_public{ dh_public = PublicKey} }; -key_exchange(server, {dh, {<>, _}, +key_exchange(server, _Version, {dh, {<>, _}, #'DHParameter'{prime = P, base = G}, KeyAlgo, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), -- cgit v1.2.3 From d7ced5ea0c0fa88a03adf0e5d05d6bac3c3fbaae Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 6 Apr 2012 04:01:35 +0200 Subject: ssl: Add TLS version to dec_hs/2 TLS 1.2 changes the layout of several handshake records. This adds the TLS version to dec_hs/2 so it can decode those. --- lib/ssl/src/ssl_connection.erl | 2 +- lib/ssl/src/ssl_handshake.erl | 48 ++++++++++++++++++------------------ lib/ssl/test/ssl_handshake_SUITE.erl | 3 ++- 3 files changed, 27 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 94d129de6f..0cf753303b 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1933,7 +1933,7 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, (_, StopState) -> StopState end, try - {Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0), + {Packets, Buf} = ssl_handshake:get_tls_handshake(Version,Data,Buf0), State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf}, handle_tls_handshake(Handle, Next, State) catch throw:#alert{} = Alert -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index ef7900c470..c7d5ca6903 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -34,7 +34,7 @@ hello_request/0, certify/7, certificate/4, client_certificate_verify/5, certificate_verify/5, certificate_request/3, key_exchange/3, server_key_exchange_hash/2, - finished/4, verify_connection/5, get_tls_handshake/2, + finished/4, verify_connection/5, get_tls_handshake/3, decode_client_key/3, server_hello_done/0, encode_handshake/2, init_handshake_history/0, update_handshake_history/2, decrypt_premaster_secret/2, prf/5]). @@ -460,17 +460,17 @@ encode_handshake(Package, Version) -> [MsgType, ?uint24(Len), Bin]. %%-------------------------------------------------------------------- --spec get_tls_handshake(binary(), binary() | iolist()) -> +-spec get_tls_handshake(tls_version(), binary(), binary() | iolist()) -> {[tls_handshake()], binary()}. %% %% Description: Given buffered and new data from ssl_record, collects %% and returns it as a list of handshake messages, also returns leftover %% data. %%-------------------------------------------------------------------- -get_tls_handshake(Data, <<>>) -> - get_tls_handshake_aux(Data, []); -get_tls_handshake(Data, Buffer) -> - get_tls_handshake_aux(list_to_binary([Buffer, Data]), []). +get_tls_handshake(Version, Data, <<>>) -> + get_tls_handshake_aux(Version, Data, []); +get_tls_handshake(Version, Data, Buffer) -> + get_tls_handshake_aux(Version, list_to_binary([Buffer, Data]), []). %%-------------------------------------------------------------------- -spec decode_client_key(binary(), key_algo(), tls_version()) -> @@ -555,12 +555,12 @@ prf({3,N}, Secret, Label, Seed, WantedLength) %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -get_tls_handshake_aux(<>, Acc) -> Raw = <>, - H = dec_hs(Type, Body), - get_tls_handshake_aux(Rest, [{H,Raw} | Acc]); -get_tls_handshake_aux(Data, Acc) -> + H = dec_hs(Version, Type, Body), + get_tls_handshake_aux(Version, Rest, [{H,Raw} | Acc]); +get_tls_handshake_aux(_Version, Data, Acc) -> {lists:reverse(Acc), Data}. path_validation_alert({bad_cert, cert_expired}) -> @@ -803,13 +803,13 @@ master_secret(Version, MasterSecret, #security_parameters{ ServerCipherState, Role)}. -dec_hs(?HELLO_REQUEST, <<>>) -> +dec_hs(_Version, ?HELLO_REQUEST, <<>>) -> #hello_request{}; %% Client hello v2. %% The server must be able to receive such messages, from clients that %% are willing to use ssl v3 or higher, but have ssl v2 compatibility. -dec_hs(?CLIENT_HELLO, <>) -> #server_hello{ @@ -849,7 +849,7 @@ dec_hs(?SERVER_HELLO, <>) -> @@ -863,37 +863,37 @@ dec_hs(?SERVER_HELLO, <>) -> +dec_hs(_Version, ?CERTIFICATE, <>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; -dec_hs(?SERVER_KEY_EXCHANGE, <>) -> %% May happen if key_algorithm is dh_anon #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, dh_y = Y}, signed_params = <<>>}; -dec_hs(?SERVER_KEY_EXCHANGE, <>) -> #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, dh_y = Y}, signed_params = Sig}; -dec_hs(?CERTIFICATE_REQUEST, +dec_hs(_Version, ?CERTIFICATE_REQUEST, <>) -> #certificate_request{certificate_types = CertTypes, certificate_authorities = CertAuths}; -dec_hs(?SERVER_HELLO_DONE, <<>>) -> +dec_hs(_Version, ?SERVER_HELLO_DONE, <<>>) -> #server_hello_done{}; -dec_hs(?CERTIFICATE_VERIFY,<>)-> +dec_hs(_Version, ?CERTIFICATE_VERIFY,<>)-> #certificate_verify{signature = Signature}; -dec_hs(?CLIENT_KEY_EXCHANGE, PKEPMS) -> +dec_hs(_Version, ?CLIENT_KEY_EXCHANGE, PKEPMS) -> #client_key_exchange{exchange_keys = PKEPMS}; -dec_hs(?FINISHED, VerifyData) -> +dec_hs(_Version, ?FINISHED, VerifyData) -> #finished{verify_data = VerifyData}; -dec_hs(_, _) -> +dec_hs(_, _, _) -> throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)). dec_client_key(PKEPMS, ?KEY_EXCHANGE_RSA, {3, 0}) -> diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index 08c23b2d47..946865a3d8 100644 --- a/lib/ssl/test/ssl_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -48,7 +48,8 @@ decode_hello_handshake(_Config) -> 16#00, 16#00, 16#33, 16#74, 16#00, 16#07, 16#06, 16#73, 16#70, 16#64, 16#79, 16#2f, 16#32>>, - {Records, _Buffer} = ssl_handshake:get_tls_handshake(HelloPacket, <<>>), + Version = {3, 0}, + {Records, _Buffer} = ssl_handshake:get_tls_handshake(Version, HelloPacket, <<>>), {Hello, _Data} = hd(Records), #renegotiation_info{renegotiated_connection = <<0>>} = Hello#server_hello.renegotiation_info. -- cgit v1.2.3 From 7c9639c785bb6b3047788b6b27ddbafb8f5b0b08 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 00:34:36 +0200 Subject: ssl: Add TLS version paramter to verify_dh_params dh parameter verification is done differently with TLS 1.2. Prepare for that by passing the verion to verify_dh_params. --- lib/ssl/src/ssl_connection.erl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 0cf753303b..4552941297 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1571,7 +1571,8 @@ handle_server_key( dh_g = G, dh_y = ServerPublicDhKey}, signed_params = Signed}, - #state{public_key_info = PubKeyInfo, + #state{negotiated_version = Version, + public_key_info = PubKeyInfo, key_algorithm = KeyAlgo, connection_states = ConnectionStates} = State) -> @@ -1592,14 +1593,17 @@ handle_server_key( ?UINT16(YLen), ServerPublicDhKey/binary>>), - case verify_dh_params(Signed, Hash, PubKeyInfo) of + case verify_dh_params(Version, Signed, Hash, PubKeyInfo) of true -> dh_master_secret(P, G, ServerPublicDhKey, undefined, State); false -> ?ALERT_REC(?FATAL, ?DECRYPT_ERROR) end. -verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> +verify_dh_params({3, Minor}, Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) + when Minor >= 3 -> + public_key:verify({digest, Hashes}, sha, Signed, PubKey); +verify_dh_params(_Version, Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> case public_key:decrypt_public(Signed, PubKey, [{rsa_pad, rsa_pkcs1_padding}]) of Hashes -> @@ -1607,8 +1611,8 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> _ -> false end; -verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) -> - public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}). +verify_dh_params(_Version, Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) -> + public_key:verify({digest, Hash}, sha, Signed, {PublicKey, PublicKeyParams}). dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> PMpint = mpint_binary(Prime), -- cgit v1.2.3 From d848984efd05314abf2de8da6ddd4ee651f0da35 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 02:39:18 +0200 Subject: ssl: make PRF function selectable TLS 1.2 allows to negotiate the used PRF, additional the default PRF uses a different hash. This change make the PRF selectable and hardwires the PRF for TLS < 1.2 --- lib/ssl/src/ssl.erl | 14 ++++++-- lib/ssl/src/ssl_cipher.erl | 78 +++++++++++++++++++++++++--------------- lib/ssl/src/ssl_cipher.hrl | 5 +-- lib/ssl/src/ssl_connection.erl | 28 +++++++++++---- lib/ssl/src/ssl_handshake.erl | 51 +++++++++++++------------- lib/ssl/src/ssl_record.hrl | 7 +++- lib/ssl/src/ssl_ssl3.erl | 21 +++++++++-- lib/ssl/src/ssl_tls1.erl | 38 +++++++++++--------- lib/ssl/test/ssl_basic_SUITE.erl | 2 +- 9 files changed, 160 insertions(+), 84 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 5e3ced144a..d645d89a68 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -25,7 +25,8 @@ -export([start/0, start/1, stop/0, transport_accept/1, transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3, - cipher_suites/0, cipher_suites/1, close/1, shutdown/2, + cipher_suites/0, cipher_suites/1, suite_definition/1, + close/1, shutdown/2, connect/3, connect/2, connect/4, connection_info/1, controlling_process/2, listen/2, pid/1, peername/1, peercert/1, recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1, @@ -303,6 +304,15 @@ peercert(#sslsocket{pid = Pid}) -> Result end. +%%-------------------------------------------------------------------- +-spec suite_definition(cipher_suite()) -> erl_cipher_suite(). +%% +%% Description: Return erlang cipher suite definition. +%%-------------------------------------------------------------------- +suite_definition(S) -> + {KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S), + {KeyExchange, Cipher, Hash}. + %%-------------------------------------------------------------------- -spec cipher_suites() -> [erl_cipher_suite()]. -spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()]. @@ -314,7 +324,7 @@ cipher_suites() -> cipher_suites(erlang) -> Version = ssl_record:highest_protocol_version([]), - [ssl_cipher:suite_definition(S) || S <- ssl_cipher:suites(Version)]; + [suite_definition(S) || S <- ssl_cipher:suites(Version)]; cipher_suites(openssl) -> Version = ssl_record:highest_protocol_version([]), diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 1b67260388..8fc3929b97 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,7 +46,7 @@ %% cipher values has been updated according to %%------------------------------------------------------------------- security_parameters(CipherSuite, SecParams) -> - { _, Cipher, Hash} = suite_definition(CipherSuite), + { _, Cipher, Hash, PrfHash} = suite_definition(CipherSuite), SecParams#security_parameters{ cipher_suite = CipherSuite, bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), @@ -56,6 +56,7 @@ security_parameters(CipherSuite, SecParams) -> key_material_length = key_material(Cipher), iv_size = iv_size(Cipher), mac_algorithm = mac_algorithm(Hash), + prf_algorithm = prf_algorithm(PrfHash), hash_size = hash_size(Hash)}. %%-------------------------------------------------------------------- @@ -218,7 +219,7 @@ anonymous_suites() -> ?TLS_DH_anon_WITH_AES_256_CBC_SHA]. %%-------------------------------------------------------------------- --spec suite_definition(cipher_suite()) -> erl_cipher_suite(). +-spec suite_definition(cipher_suite()) -> int_cipher_suite(). %% %% Description: Return erlang cipher suite definition. %% Note: Currently not supported suites are commented away. @@ -226,56 +227,56 @@ anonymous_suites() -> %%------------------------------------------------------------------- %% TLS v1.1 suites suite_definition(?TLS_NULL_WITH_NULL_NULL) -> - {null, null, null}; + {null, null, null, null}; %% suite_definition(?TLS_RSA_WITH_NULL_MD5) -> -%% {rsa, null, md5}; +%% {rsa, null, md5, default_prf}; %% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> -%% {rsa, null, sha}; +%% {rsa, null, sha, default_prf}; suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> - {rsa, rc4_128, md5}; + {rsa, rc4_128, md5, default_prf}; suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> - {rsa, rc4_128, sha}; + {rsa, rc4_128, sha, default_prf}; %% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> -%% {rsa, idea_cbc, sha}; +%% {rsa, idea_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> - {rsa, des_cbc, sha}; + {rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> - {rsa, '3des_ede_cbc', sha}; + {rsa, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) -> - {dhe_dss, des_cbc, sha}; + {dhe_dss, des_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> - {dhe_dss, '3des_ede_cbc', sha}; + {dhe_dss, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> - {dhe_rsa, des_cbc, sha}; + {dhe_rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> - {dhe_rsa, '3des_ede_cbc', sha}; + {dhe_rsa, '3des_ede_cbc', sha, default_prf}; %%% TSL V1.1 AES suites suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) -> - {rsa, aes_128_cbc, sha}; + {rsa, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> - {dhe_dss, aes_128_cbc, sha}; + {dhe_dss, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) -> - {dhe_rsa, aes_128_cbc, sha}; + {dhe_rsa, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> - {rsa, aes_256_cbc, sha}; + {rsa, aes_256_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> - {dhe_dss, aes_256_cbc, sha}; + {dhe_dss, aes_256_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> - {dhe_rsa, aes_256_cbc, sha}; + {dhe_rsa, aes_256_cbc, sha, default_prf}; %%% DH-ANON deprecated by TLS spec and not available %%% by default, but good for testing purposes. suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> - {dh_anon, rc4_128, md5}; + {dh_anon, rc4_128, md5, default_prf}; suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) -> - {dh_anon, des_cbc, sha}; + {dh_anon, des_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> - {dh_anon, '3des_ede_cbc', sha}; + {dh_anon, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> - {dh_anon, aes_128_cbc, sha}; + {dh_anon, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> - {dh_anon, aes_256_cbc, sha}. + {dh_anon, aes_256_cbc, sha, default_prf}. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -510,14 +511,35 @@ mac_algorithm(null) -> mac_algorithm(md5) -> ?MD5; mac_algorithm(sha) -> - ?SHA. + ?SHA; +mac_algorithm(sha256) -> + ?SHA256; +mac_algorithm(sha384) -> + ?SHA384. + +prf_algorithm(default_prf) -> + ?SHA256; +prf_algorithm(null) -> + ?NULL; +prf_algorithm(md5) -> + ?MD5; +prf_algorithm(sha) -> + ?SHA; +prf_algorithm(sha256) -> + ?SHA256; +prf_algorithm(sha384) -> + ?SHA384. hash_size(null) -> 0; hash_size(md5) -> 16; hash_size(sha) -> - 20. + 20; +hash_size(sha256) -> + 32; +hash_size(sha384) -> + 48. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 8bd68cc190..6509b977b6 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,8 +28,9 @@ -type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc. --type hash() :: null | sha | md5. +-type hash() :: null | sha | md5 | sha256 | sha384 | sha512. -type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. +-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}. -type cipher_suite() :: binary(). -type cipher_enum() :: integer(). -type openssl_cipher_suite() :: string(). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 4552941297..002565bc79 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -374,7 +374,7 @@ hello(#server_hello{cipher_suite = CipherSuite, ssl_options = SslOptions} = State0) -> case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of {Version, NewId, ConnectionStates} -> - {KeyAlgorithm, _, _} = + {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite), PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), @@ -435,8 +435,9 @@ abbreviated(#finished{verify_data = Data} = Finished, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State) -> -%%CHECKME +%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, client, + get_current_connection_state_prf(ConnectionStates0, read), MasterSecret, Handshake) of verified -> ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), @@ -452,7 +453,9 @@ abbreviated(#finished{verify_data = Data} = Finished, session = #session{master_secret = MasterSecret}, negotiated_version = Version, connection_states = ConnectionStates0} = State) -> +%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, server, + get_pending_connection_state_prf(ConnectionStates0, write), MasterSecret, Handshake0) of verified -> ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0), @@ -661,9 +664,12 @@ cipher(#finished{verify_data = Data} = Finished, role = Role, session = #session{master_secret = MasterSecret} = Session0, + connection_states = ConnectionStates0, tls_handshake_history = Handshake0} = State) -> +%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, opposite_role(Role), + get_current_connection_state_prf(ConnectionStates0, read), MasterSecret, Handshake0) of verified -> Session = register_session(Role, Host, Port, Session0), @@ -909,14 +915,14 @@ handle_sync_event(info, _, StateName, session = #session{cipher_suite = Suite}} = State) -> AtomVersion = ssl_record:protocol_version(Version), - {reply, {ok, {AtomVersion, ssl_cipher:suite_definition(Suite)}}, + {reply, {ok, {AtomVersion, ssl:suite_definition(Suite)}}, StateName, State, get_timeout(State)}; handle_sync_event(session_info, _, StateName, #state{session = #session{session_id = Id, cipher_suite = Suite}} = State) -> {reply, [{session_id, Id}, - {cipher_suite, ssl_cipher:suite_definition(Suite)}], + {cipher_suite, ssl:suite_definition(Suite)}], StateName, State, get_timeout(State)}; handle_sync_event(peer_certificate, _, StateName, @@ -1381,7 +1387,7 @@ server_hello(ServerHello, #state{transport_cb = Transport, connection_states = ConnectionStates0, tls_handshake_history = Handshake0} = State) -> CipherSuite = ServerHello#server_hello.cipher_suite, - {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), + {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite), {BinMsg, ConnectionStates1, Handshake1} = encode_handshake(ServerHello, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), @@ -1541,7 +1547,10 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version, connection_states = ConnectionStates0, tls_handshake_history = Handshake0}, StateName) -> MasterSecret = Session#session.master_secret, - Finished = ssl_handshake:finished(Version, Role, MasterSecret, Handshake0), +%%CHECKME: the connection state prf logic is pure guess work! + Finished = ssl_handshake:finished(Version, Role, + get_current_connection_state_prf(ConnectionStates0, write), + MasterSecret, Handshake0), ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName), {BinFinished, ConnectionStates, Handshake} = encode_handshake(Finished, Version, ConnectionStates1, Handshake0), @@ -2398,3 +2407,10 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref, _ -> ok end. + +get_current_connection_state_prf(CStates, Direction) -> + CS = ssl_record:current_connection_state(CStates, Direction), + CS#connection_state.security_parameters#security_parameters.prf_algorithm. +get_pending_connection_state_prf(CStates, Direction) -> + CS = ssl_record:pending_connection_state(CStates, Direction), + CS#connection_state.security_parameters#security_parameters.prf_algorithm. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index c7d5ca6903..1759c920cc 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -34,7 +34,7 @@ hello_request/0, certify/7, certificate/4, client_certificate_verify/5, certificate_verify/5, certificate_request/3, key_exchange/3, server_key_exchange_hash/2, - finished/4, verify_connection/5, get_tls_handshake/3, + finished/5, verify_connection/6, get_tls_handshake/3, decode_client_key/3, server_hello_done/0, encode_handshake/2, init_handshake_history/0, update_handshake_history/2, decrypt_premaster_secret/2, prf/5]). @@ -401,10 +401,11 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> ConnectionState = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = ConnectionState#connection_state.security_parameters, - #security_parameters{client_random = ClientRandom, + #security_parameters{prf_algorithm = PrfAlgo, + client_random = ClientRandom, server_random = ServerRandom} = SecParams, try master_secret(Version, - calc_master_secret(Version,PremasterSecret, + calc_master_secret(Version,PrfAlgo,PremasterSecret, ClientRandom, ServerRandom), SecParams, ConnectionStates, Role) catch @@ -416,26 +417,26 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> end. %%-------------------------------------------------------------------- --spec finished(tls_version(), client | server, binary(), tls_handshake_history()) -> +-spec finished(tls_version(), client | server, integer(), binary(), tls_handshake_history()) -> #finished{}. %% %% Description: Creates a handshake finished message %%------------------------------------------------------------------- -finished(Version, Role, MasterSecret, {Handshake, _}) -> % use the current hashes +finished(Version, Role, PrfAlgo, MasterSecret, {Handshake, _}) -> % use the current handshake #finished{verify_data = - calc_finished(Version, Role, MasterSecret, Handshake)}. + calc_finished(Version, Role, PrfAlgo, MasterSecret, Handshake)}. %%-------------------------------------------------------------------- --spec verify_connection(tls_version(), #finished{}, client | server, binary(), +-spec verify_connection(tls_version(), #finished{}, client | server, integer(), binary(), tls_handshake_history()) -> verified | #alert{}. %% %% Description: Checks the ssl handshake finished message to verify %% the connection. %%------------------------------------------------------------------- verify_connection(Version, #finished{verify_data = Data}, - Role, MasterSecret, {_, Handshake}) -> + Role, PrfAlgo, MasterSecret, {_, Handshake}) -> %% use the previous hashes - case calc_finished(Version, Role, MasterSecret, Handshake) of + case calc_finished(Version, Role, PrfAlgo, MasterSecret, Handshake) of Data -> verified; _ -> @@ -782,13 +783,14 @@ master_secret(Version, MasterSecret, #security_parameters{ client_random = ClientRandom, server_random = ServerRandom, hash_size = HashSize, + prf_algorithm = PrfAlgo, key_material_length = KML, expanded_key_material_length = EKML, iv_size = IVS}, ConnectionStates, Role) -> {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, ServerWriteKey, ClientIV, ServerIV} = - setup_keys(Version, MasterSecret, ServerRandom, + setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS), ConnStates1 = ssl_record:set_master_secret(MasterSecret, ConnectionStates), @@ -1117,34 +1119,35 @@ digitally_signed(Hash, #'RSAPrivateKey'{} = Key) -> digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> public_key:sign(Hash, none, Key). -calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) -> +calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); -calc_master_secret({3,N},PremasterSecret, ClientRandom, ServerRandom) +calc_master_secret({3,N}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) when N == 1; N == 2 -> - ssl_tls1:master_secret(PremasterSecret, ClientRandom, ServerRandom). + ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom). -setup_keys({3,0}, MasterSecret, +setup_keys({3,0}, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS) -> ssl_ssl3:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS); -setup_keys({3,1}, MasterSecret, - ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) -> - ssl_tls1:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, +setup_keys({3,N}, _PrfAlgo, MasterSecret, + ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) + when N == 1; N == 2 -> + ssl_tls1:setup_keys(N, ?MD5SHA, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, IVS). -calc_finished({3, 0}, Role, MasterSecret, Handshake) -> +calc_finished({3, 0}, Role, _PrfAlgo, MasterSecret, Handshake) -> ssl_ssl3:finished(Role, MasterSecret, lists:reverse(Handshake)); -calc_finished({3, N}, Role, MasterSecret, Handshake) +calc_finished({3, N}, Role, _PrfAlgo, MasterSecret, Handshake) when N == 1; N == 2 -> - ssl_tls1:finished(Role, MasterSecret, lists:reverse(Handshake)). + ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake)). -calc_certificate_verify({3, 0}, MasterSecret, Algorithm, Handshake) -> - ssl_ssl3:certificate_verify(Algorithm, MasterSecret, lists:reverse(Handshake)); -calc_certificate_verify({3, N}, _, Algorithm, Handshake) +calc_certificate_verify({3, 0}, HashAlgo, MasterSecret, Handshake) -> + ssl_ssl3:certificate_verify(HashAlgo, MasterSecret, lists:reverse(Handshake)); +calc_certificate_verify({3, N}, HashAlgo, _MasterSecret, Handshake) when N == 1; N == 2 -> - ssl_tls1:certificate_verify(Algorithm, lists:reverse(Handshake)). + ssl_tls1:certificate_verify(HashAlgo, N, lists:reverse(Handshake)). key_exchange_alg(rsa) -> ?KEY_EXCHANGE_RSA; diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index 3d22fa6acb..cb1008c2be 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -47,6 +47,7 @@ key_material_length, % unit 8 expanded_key_material_length, % unit 8 mac_algorithm, % unit 8 + prf_algorithm, % unit 8 hash_size, % unit 8 compression_algorithm, % unit 8 master_secret, % opaque 48 @@ -101,6 +102,10 @@ %-define(NULL, 0). %% Already defined by ssl_internal.hrl -define(MD5, 1). -define(SHA, 2). +-define(MD5SHA, 3). +-define(SHA256, 4). +-define(SHA384, 5). +-define(SHA512, 6). %% CompressionMethod % -define(NULL, 0). %% Already defined by ssl_internal.hrl diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 2b4ae1539f..11bc663e77 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -156,14 +156,22 @@ suites() -> hash(?MD5, Data) -> crypto:md5(Data); hash(?SHA, Data) -> - crypto:sha(Data). + crypto:sha(Data); +hash(?SHA256, Data) -> + crypto:sha256(Data); +hash(?SHA384, Data) -> + crypto:sha384(Data). %%pad_1(?NULL) -> %% ""; pad_1(?MD5) -> <<"666666666666666666666666666666666666666666666666">>; pad_1(?SHA) -> - <<"6666666666666666666666666666666666666666">>. + <<"6666666666666666666666666666666666666666">>; +pad_1(?SHA256) -> + <<"66666666666666666666666666666666">>; +pad_1(?SHA384) -> + <<"666666666666666666666666666666666666666666666666">>. %%pad_2(?NULL) -> %% ""; @@ -172,7 +180,14 @@ pad_2(?MD5) -> "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>; pad_2(?SHA) -> <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" - "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>. + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>; +pad_2(?SHA256) -> + <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + "\\\\\\\\\\\\\\\\\\\\\\\\">>; +pad_2(?SHA384) -> + <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + "\\\\\\\\\\\\\\\\">>. mac_hash(?NULL, _Secret, _Data) -> <<>>; diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index d64a8f815d..dc3d9774c2 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -28,25 +28,27 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). --export([master_secret/3, finished/3, certificate_verify/2, mac_hash/7, - setup_keys/6, suites/0, prf/4]). +-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, + setup_keys/8, suites/0, prf/5]). %%==================================================================== %% Internal application API %%==================================================================== --spec master_secret(binary(), binary(), binary()) -> binary(). +-spec master_secret(integer(), binary(), binary(), binary()) -> binary(). -master_secret(PreMasterSecret, ClientRandom, ServerRandom) -> - %% RFC 2246 & 4346 - 8.1 %% master_secret = PRF(pre_master_secret, - %% "master secret", ClientHello.random + - %% ServerHello.random)[0..47]; - prf(PreMasterSecret, <<"master secret">>, +master_secret(PrfAlgo, PreMasterSecret, ClientRandom, ServerRandom) -> + %% RFC 2246 & 4346 && RFC 5246 - 8.1 %% master_secret = PRF(pre_master_secret, + %% "master secret", ClientHello.random + + %% ServerHello.random)[0..47]; + + prf(PrfAlgo, PreMasterSecret, <<"master secret">>, [ClientRandom, ServerRandom], 48). --spec finished(client | server, binary(), [binary()]) -> binary(). +-spec finished(client | server, integer(), integer(), binary(), [binary()]) -> binary(). -finished(Role, MasterSecret, Handshake) -> +finished(Role, Version, PrfAlgo, MasterSecret, Handshake) + when Version == 1; Version == 2; PrfAlgo == ?MD5SHA -> %% RFC 2246 & 4346 - 7.4.9. Finished %% struct { %% opaque verify_data[12]; @@ -57,7 +59,7 @@ finished(Role, MasterSecret, Handshake) -> %% SHA-1(handshake_messages)) [0..11]; MD5 = crypto:md5(Handshake), SHA = crypto:sha(Handshake), - prf(MasterSecret, finished_label(Role), [MD5, SHA], 12). + prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12); -spec certificate_verify(OID::tuple(), [binary()]) -> binary(). @@ -69,12 +71,13 @@ certificate_verify(?'rsaEncryption', Handshake) -> certificate_verify(?'id-dsa', Handshake) -> crypto:sha(Handshake). --spec setup_keys(binary(), binary(), binary(), integer(), +-spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(), integer(), integer()) -> {binary(), binary(), binary(), binary(), binary(), binary()}. -setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, - KeyMatLen, IVSize) -> +setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, + KeyMatLen, IVSize) + when Version == 1 -> %% RFC 2246 - 6.3. Key calculation %% key_block = PRF(SecurityParameters.master_secret, %% "key expansion", @@ -88,7 +91,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, %% client_write_IV[SecurityParameters.IV_size] %% server_write_IV[SecurityParameters.IV_size] WantedLength = 2 * (HashSize + KeyMatLen + IVSize), - KeyBlock = prf(MasterSecret, "key expansion", + KeyBlock = prf(?MD5SHA, MasterSecret, "key expansion", [ServerRandom, ClientRandom], WantedLength), < Keep = byte_size(Last) + WantedLength, <> = Last, - lists:reverse(Acc, [B]); + list_to_binary(lists:reverse(Acc, [B])); p_hash(Secret, Seed, WantedLength, Method, N, Acc) -> N1 = N+1, Bin = hmac_hash(Method, Secret, [a(N1, Secret, Seed, Method), Seed]), @@ -214,7 +217,8 @@ split_secret(BinSecret) -> <<_:Div/binary, Secret2:EvenLength/binary>> = BinSecret, {Secret1, Secret2}. -prf(Secret, Label, Seed, WantedLength) -> +prf(MAC, Secret, Label, Seed, WantedLength) + when MAC == ?MD5SHA -> %% PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR %% P_SHA-1(S2, label + seed); {S1, S2} = split_secret(Secret), diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 5a52917d6c..24b41124c6 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -1860,7 +1860,7 @@ run_suites(Ciphers, Version, Config, Type) -> end. erlang_cipher_suite(Suite) when is_list(Suite)-> - ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite)); + ssl:suite_definition(ssl_cipher:openssl_suite(Suite)); erlang_cipher_suite(Suite) -> Suite. -- cgit v1.2.3 From 5f81b3f94f82107bf830b46ee643787b774d8634 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 03:19:43 +0200 Subject: ssl: Implement and activate PRFs for TLS 1.1 and 1.2 --- lib/ssl/src/ssl_handshake.erl | 25 ++++++++-- lib/ssl/src/ssl_tls1.erl | 111 +++++++++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 1759c920cc..1b83293730 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -549,9 +549,10 @@ server_key_exchange_hash(dhe_dss, Value) -> %%-------------------------------------------------------------------- prf({3,0}, _, _, _, _) -> {error, undefined}; -prf({3,N}, Secret, Label, Seed, WantedLength) - when N == 1; N == 2 -> - {ok, ssl_tls1:prf(Secret, Label, Seed, WantedLength)}. +prf({3,1}, Secret, Label, Seed, WantedLength) -> + {ok, ssl_tls1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)}; +prf({3,N}, Secret, Label, Seed, WantedLength) -> + {ok, ssl_tls1:prf(?SHA256, Secret, Label, Seed, WantedLength)}. %%-------------------------------------------------------------------- %%% Internal functions @@ -1124,7 +1125,12 @@ calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) calc_master_secret({3,N}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) when N == 1; N == 2 -> - ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom). + ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom); + +calc_master_secret({3,N}, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) + when N == 3 -> + %% only from TLS 1.2 onwards the selection of a PrfAlgo is supported + ssl_tls1:master_secret(PrfAlgo, PremasterSecret, ClientRandom, ServerRandom). setup_keys({3,0}, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS) -> @@ -1135,13 +1141,22 @@ setup_keys({3,N}, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) when N == 1; N == 2 -> ssl_tls1:setup_keys(N, ?MD5SHA, MasterSecret, ServerRandom, ClientRandom, HashSize, + KML, IVS); + +setup_keys({3,N}, PrfAlgo, MasterSecret, + ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) + when N == 3 -> + ssl_tls1:setup_keys(N, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, IVS). calc_finished({3, 0}, Role, _PrfAlgo, MasterSecret, Handshake) -> ssl_ssl3:finished(Role, MasterSecret, lists:reverse(Handshake)); calc_finished({3, N}, Role, _PrfAlgo, MasterSecret, Handshake) when N == 1; N == 2 -> - ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake)). + ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake)); +calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake) + when N == 3 -> + ssl_tls1:finished(Role, N, PrfAlgo, MasterSecret, lists:reverse(Handshake)). calc_certificate_verify({3, 0}, HashAlgo, MasterSecret, Handshake) -> ssl_ssl3:certificate_verify(HashAlgo, MasterSecret, lists:reverse(Handshake)); diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index dc3d9774c2..9569cef8d1 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -61,6 +61,18 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake) SHA = crypto:sha(Handshake), prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12); +finished(Role, Version, PrfAlgo, MasterSecret, Handshake) + when Version == 3 -> + %% RFC 5246 - 7.4.9. Finished + %% struct { + %% opaque verify_data[12]; + %% } Finished; + %% + %% verify_data + %% PRF(master_secret, finished_label, Hash(handshake_messages)) [0..11]; + Hash = crypto:hash(mac_algo(PrfAlgo), Handshake), + prf(PrfAlgo, MasterSecret, finished_label(Role), Hash, 12). + -spec certificate_verify(OID::tuple(), [binary()]) -> binary(). certificate_verify(?'rsaEncryption', Handshake) -> @@ -98,29 +110,60 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary, ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock, {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, - ServerWriteKey, ClientIV, ServerIV}. + ServerWriteKey, ClientIV, ServerIV}; + +%% TLS v1.1 +setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, + KeyMatLen, IVSize) + when Version == 2 -> + %% RFC 4346 - 6.3. Key calculation + %% key_block = PRF(SecurityParameters.master_secret, + %% "key expansion", + %% SecurityParameters.server_random + + %% SecurityParameters.client_random); + %% Then the key_block is partitioned as follows: + %% client_write_MAC_secret[SecurityParameters.hash_size] + %% server_write_MAC_secret[SecurityParameters.hash_size] + %% client_write_key[SecurityParameters.key_material_length] + %% server_write_key[SecurityParameters.key_material_length] + %% + %% RFC 4346 is incomplete, the client and server IVs have to + %% be generated just like for TLS 1.0 + WantedLength = 2 * (HashSize + KeyMatLen + IVSize), + KeyBlock = prf(?MD5SHA, MasterSecret, "key expansion", + [ServerRandom, ClientRandom], WantedLength), + <> = KeyBlock, + {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, + ServerWriteKey, ClientIV, ServerIV}; -%% TLS v1.1 uncomment when supported. -%% setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KeyMatLen) -> -%% %% RFC 4346 - 6.3. Key calculation -%% %% key_block = PRF(SecurityParameters.master_secret, -%% %% "key expansion", -%% %% SecurityParameters.server_random + -%% %% SecurityParameters.client_random); -%% %% Then the key_block is partitioned as follows: -%% %% client_write_MAC_secret[SecurityParameters.hash_size] -%% %% server_write_MAC_secret[SecurityParameters.hash_size] -%% %% client_write_key[SecurityParameters.key_material_length] -%% %% server_write_key[SecurityParameters.key_material_length] -%% WantedLength = 2 * (HashSize + KeyMatLen), -%% KeyBlock = prf(MasterSecret, "key expansion", -%% [ServerRandom, ClientRandom], WantedLength), -%% <> -%% = KeyBlock, -%% {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, -%% ServerWriteKey, undefined, undefined}. +%% TLS v1.2 +setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, + KeyMatLen, IVSize) + when Version == 3 -> + %% RFC 5246 - 6.3. Key calculation + %% key_block = PRF(SecurityParameters.master_secret, + %% "key expansion", + %% SecurityParameters.server_random + + %% SecurityParameters.client_random); + %% Then the key_block is partitioned as follows: + %% client_write_MAC_secret[SecurityParameters.hash_size] + %% server_write_MAC_secret[SecurityParameters.hash_size] + %% client_write_key[SecurityParameters.key_material_length] + %% server_write_key[SecurityParameters.key_material_length] + %% client_write_IV[SecurityParameters.fixed_iv_length] + %% server_write_IV[SecurityParameters.fixed_iv_length] + WantedLength = 2 * (HashSize + KeyMatLen + IVSize), + KeyBlock = prf(PrfAlgo, MasterSecret, "key expansion", + [ServerRandom, ClientRandom], WantedLength), + <> = KeyBlock, + {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, + ServerWriteKey, ClientIV, ServerIV}. -spec mac_hash(integer(), binary(), integer(), integer(), tls_version(), integer(), binary()) -> binary(). @@ -166,7 +209,22 @@ hmac_hash(?NULL, _, _) -> hmac_hash(?MD5, Key, Value) -> crypto:md5_mac(Key, Value); hmac_hash(?SHA, Key, Value) -> - crypto:sha_mac(Key, Value). + crypto:sha_mac(Key, Value); +hmac_hash(?MD5SHA, Key, Value) -> + crypto:sha256_mac(Key, Value); +hmac_hash(?SHA256, Key, Value) -> + crypto:sha256_mac(Key, Value); +hmac_hash(?SHA384, Key, Value) -> + crypto:sha384_mac(Key, Value); +hmac_hash(?SHA512, Key, Value) -> + crypto:sha512_mac(Key, Value). + +mac_algo(?MD5) -> md5; +mac_algo(?SHA) -> sha; +mac_algo(?MD5SHA) -> sha256; %% RFC 5246 defines minimum hash for TLS 1.2 +mac_algo(?SHA256) -> sha256; +mac_algo(?SHA384) -> sha384; +mac_algo(?SHA512) -> sha512. % First, we define a data expansion function, P_hash(secret, data) that % uses a single hash function to expand a secret and seed into an @@ -224,7 +282,12 @@ prf(MAC, Secret, Label, Seed, WantedLength) {S1, S2} = split_secret(Secret), LS = list_to_binary([Label, Seed]), crypto:exor(p_hash(S1, LS, WantedLength, ?MD5), - p_hash(S2, LS, WantedLength, ?SHA)). + p_hash(S2, LS, WantedLength, ?SHA)); + +prf(MAC, Secret, Label, Seed, WantedLength) -> + %% PRF(secret, label, seed) = P_SHA256(secret, label + seed); + LS = list_to_binary([Label, Seed]), + p_hash(Secret, LS, WantedLength, MAC). %%%% Misc help functions %%%% -- cgit v1.2.3 From aa9a388f9498028f7288fc2f61264cf13bec7278 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 03:52:42 +0200 Subject: ssl: Add TLS 1.2 cipher suites --- lib/ssl/src/ssl_cipher.erl | 106 +++++++++++++++++++++++++++++++++++++++++---- lib/ssl/src/ssl_cipher.hrl | 41 ++++++++++++++++++ lib/ssl/src/ssl_tls1.erl | 22 +++++++--- 3 files changed, 156 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 8fc3929b97..b58c496bfa 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -202,8 +202,8 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, %%-------------------------------------------------------------------- suites({3, 0}) -> ssl_ssl3:suites(); -suites({3, N}) when N == 1; N == 2 -> - ssl_tls1:suites(). +suites({3, N}) -> + ssl_tls1:suites(N). %%-------------------------------------------------------------------- -spec anonymous_suites() -> [cipher_suite()]. @@ -216,7 +216,9 @@ anonymous_suites() -> ?TLS_DH_anon_WITH_DES_CBC_SHA, ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, ?TLS_DH_anon_WITH_AES_128_CBC_SHA, - ?TLS_DH_anon_WITH_AES_256_CBC_SHA]. + ?TLS_DH_anon_WITH_AES_256_CBC_SHA, + ?TLS_DH_anon_WITH_AES_128_CBC_SHA256, + ?TLS_DH_anon_WITH_AES_256_CBC_SHA256]. %%-------------------------------------------------------------------- -spec suite_definition(cipher_suite()) -> int_cipher_suite(). @@ -265,6 +267,29 @@ suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> {dhe_rsa, aes_256_cbc, sha, default_prf}; +%% TLS v1.2 suites + +%% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> +%% {rsa, null, sha, default_prf}; +suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA256) -> + {rsa, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA256) -> + {rsa, aes_256_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) -> + {dhe_dss, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) -> + {dhe_rsa, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) -> + {dhe_dss, aes_256_cbc, sha256, default_prf}; +suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) -> + {dhe_rsa, aes_256_cbc, sha256, default_prf}; + +%% not defined YET: +%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256 +%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256 +%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256 +%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256 + %%% DH-ANON deprecated by TLS spec and not available %%% by default, but good for testing purposes. suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> @@ -276,7 +301,11 @@ suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> {dh_anon, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> - {dh_anon, aes_256_cbc, sha, default_prf}. + {dh_anon, aes_256_cbc, sha, default_prf}; +suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) -> + {dh_anon, aes_128_cbc, sha256, default_prf}; +suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) -> + {dh_anon, aes_256_cbc, sha256, default_prf}. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -330,7 +359,28 @@ suite({dhe_dss, aes_256_cbc, sha}) -> suite({dhe_rsa, aes_256_cbc, sha}) -> ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; suite({dh_anon, aes_256_cbc, sha}) -> - ?TLS_DH_anon_WITH_AES_256_CBC_SHA. + ?TLS_DH_anon_WITH_AES_256_CBC_SHA; + +%% TLS v1.2 suites + +%% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> +%% {rsa, null, sha, sha256}; +suite({rsa, aes_128_cbc, sha256}) -> + ?TLS_RSA_WITH_AES_128_CBC_SHA256; +suite({rsa, aes_256_cbc, sha256}) -> + ?TLS_RSA_WITH_AES_256_CBC_SHA256; +suite({dhe_dss, aes_128_cbc, sha256}) -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256; +suite({dhe_rsa, aes_128_cbc, sha256}) -> + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; +suite({dhe_dss, aes_256_cbc, sha256}) -> + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256; +suite({dhe_rsa, aes_256_cbc, sha256}) -> + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; +suite({dh_anon, aes_128_cbc, sha256}) -> + ?TLS_DH_anon_WITH_AES_128_CBC_SHA256; +suite({dh_anon, aes_256_cbc, sha256}) -> + ?TLS_DH_anon_WITH_AES_256_CBC_SHA256. %%-------------------------------------------------------------------- -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -338,6 +388,18 @@ suite({dh_anon, aes_256_cbc, sha}) -> %% Description: Return TLS cipher suite definition. %%-------------------------------------------------------------------- %% translate constants <-> openssl-strings +openssl_suite("DHE-RSA-AES256-SHA256") -> + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; +openssl_suite("DHE-DSS-AES256-SHA256") -> + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256; +openssl_suite("AES256-SHA256") -> + ?TLS_RSA_WITH_AES_256_CBC_SHA256; +openssl_suite("DHE-RSA-AES128-SHA256") -> + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256; +openssl_suite("DHE-DSS-AES128-SHA256") -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256; +openssl_suite("AES128-SHA256") -> + ?TLS_RSA_WITH_AES_128_CBC_SHA256; openssl_suite("DHE-RSA-AES256-SHA") -> ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; openssl_suite("DHE-DSS-AES256-SHA") -> @@ -399,6 +461,28 @@ openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> "EDH-RSA-DES-CBC-SHA"; openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) -> "DES-CBC-SHA"; +openssl_suite_name(?TLS_RSA_WITH_NULL_SHA256) -> + "NULL-SHA256"; +openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA256) -> + "AES128-SHA256"; +openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA256) -> + "AES256-SHA256"; +openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_CBC_SHA256) -> + "DH-DSS-AES128-SHA256"; +openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_CBC_SHA256) -> + "DH-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) -> + "DHE-DSS-AES128-SHA256"; +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) -> + "DHE-RSA-AES128-SHA256"; +openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_CBC_SHA256) -> + "DH-DSS-AES256-SHA256"; +openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_CBC_SHA256) -> + "DH-RSA-AES256-SHA256"; +openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) -> + "DHE-DSS-AES256-SHA256"; +openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) -> + "DHE-RSA-AES256-SHA256"; %% No oppenssl name openssl_suite_name(Cipher) -> suite_definition(Cipher). @@ -632,14 +716,18 @@ rsa_signed_suites() -> dhe_rsa_suites() ++ rsa_suites(). dhe_rsa_suites() -> - [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_RSA_WITH_DES_CBC_SHA]. rsa_suites() -> - [?TLS_RSA_WITH_AES_256_CBC_SHA, + [?TLS_RSA_WITH_AES_256_CBC_SHA256, + ?TLS_RSA_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_WITH_AES_128_CBC_SHA256, ?TLS_RSA_WITH_AES_128_CBC_SHA, %%?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, @@ -650,8 +738,10 @@ dsa_signed_suites() -> dhe_dss_suites(). dhe_dss_suites() -> - [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA]. diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 6509b977b6..0f439f8ed5 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -178,6 +178,47 @@ %% TLS_DH_anon_WITH_AES_256_CBC_SHA = { 0x00, 0x3A }; -define(TLS_DH_anon_WITH_AES_256_CBC_SHA, <>). +%%% TLS 1.2 Cipher Suites RFC 5246 + +%% TLS_RSA_WITH_NULL_SHA256 = { 0x00,0x3B }; +-define(TLS_RSA_WITH_NULL_SHA256, <>). + +%% TLS_RSA_WITH_AES_128_CBC_SHA256 = { 0x00,0x3C }; +-define(TLS_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_RSA_WITH_AES_256_CBC_SHA256 = { 0x00,0x3D }; +-define(TLS_RSA_WITH_AES_256_CBC_SHA256, <>). + +%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = { 0x00,0x3E }; +-define(TLS_DH_DSS_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = { 0x00,0x3F }; +-define(TLS_DH_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = { 0x00,0x40 }; +-define(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = { 0x00,0x67 }; +-define(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = { 0x00,0x68 }; +-define(TLS_DH_DSS_WITH_AES_256_CBC_SHA256, <>). + +%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = { 0x00,0x69 }; +-define(TLS_DH_RSA_WITH_AES_256_CBC_SHA256, <>). + +%% TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = { 0x00,0x6A }; +-define(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, <>). + +%% TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = { 0x00,0x6B }; +-define(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, <>). + +%% TLS_DH_anon_WITH_AES_128_CBC_SHA256 = { 0x00,0x6C }; +-define(TLS_DH_anon_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D }; +-define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <>). + %%% Kerberos Cipher Suites %% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E }; diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 9569cef8d1..d56b8ee07f 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -26,10 +26,10 @@ -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). --include("ssl_record.hrl"). +-include("ssl_record.hrl"). -export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, - setup_keys/8, suites/0, prf/5]). + setup_keys/8, suites/1, prf/5]). %%==================================================================== %% Internal application API @@ -180,9 +180,9 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, Fragment]), Mac. --spec suites() -> [cipher_suite()]. +-spec suites(1|2|3) -> [cipher_suite()]. -suites() -> +suites(Minor) when Minor == 1; Minor == 2-> [ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, @@ -198,7 +198,19 @@ suites() -> ?TLS_RSA_WITH_RC4_128_MD5, ?TLS_DHE_RSA_WITH_DES_CBC_SHA, ?TLS_RSA_WITH_DES_CBC_SHA - ]. + ]; + +suites(Minor) when Minor == 3 -> + [ + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + ?TLS_RSA_WITH_AES_256_CBC_SHA256, + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + ?TLS_RSA_WITH_AES_128_CBC_SHA256 + %% ?TLS_DH_anon_WITH_AES_128_CBC_SHA256, + %% ?TLS_DH_anon_WITH_AES_256_CBC_SHA256 + ] ++ suites(2). %%-------------------------------------------------------------------- %%% Internal functions -- cgit v1.2.3 From 7682bd59933f20cba5c32df96a58f252924478a9 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 28 Jun 2012 16:02:27 +0200 Subject: ssl: Fix PRF logic --- lib/ssl/src/ssl_cipher.erl | 68 +++++++++++++++++++----------------- lib/ssl/src/ssl_connection.erl | 42 ++++++++++++++++++++-- lib/ssl/src/ssl_handshake.erl | 79 +++++++++++++++++++++--------------------- lib/ssl/src/ssl_handshake.hrl | 6 ++++ lib/ssl/src/ssl_record.erl | 6 ++-- lib/ssl/src/ssl_record.hrl | 5 +-- lib/ssl/src/ssl_ssl3.erl | 30 ++++------------ lib/ssl/src/ssl_tls1.erl | 10 +++--- 8 files changed, 139 insertions(+), 107 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index b58c496bfa..9e1fbe20f4 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -28,10 +28,11 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). +-include("ssl_handshake.hrl"). -include("ssl_alert.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([security_parameters/2, suite_definition/1, +-export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, suite/1, suites/1, anonymous_suites/0, openssl_suite/1, openssl_suite_name/1, filter/2]). @@ -39,14 +40,14 @@ -compile(inline). %%-------------------------------------------------------------------- --spec security_parameters(cipher_suite(), #security_parameters{}) -> +-spec security_parameters(tls_version(), cipher_suite(), #security_parameters{}) -> #security_parameters{}. %% %% Description: Returns a security parameters record where the %% cipher values has been updated according to %%------------------------------------------------------------------- -security_parameters(CipherSuite, SecParams) -> - { _, Cipher, Hash, PrfHash} = suite_definition(CipherSuite), +security_parameters(Version, CipherSuite, SecParams) -> + { _, Cipher, Hash, PrfHashAlg} = suite_definition(CipherSuite), SecParams#security_parameters{ cipher_suite = CipherSuite, bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), @@ -55,8 +56,8 @@ security_parameters(CipherSuite, SecParams) -> expanded_key_material_length = expanded_key_material(Cipher), key_material_length = key_material(Cipher), iv_size = iv_size(Cipher), - mac_algorithm = mac_algorithm(Hash), - prf_algorithm = prf_algorithm(PrfHash), + mac_algorithm = hash_algorithm(Hash), + prf_algorithm = prf_algorithm(PrfHashAlg, Version), hash_size = hash_size(Hash)}. %%-------------------------------------------------------------------- @@ -590,29 +591,36 @@ block_size(Cipher) when Cipher == aes_128_cbc; Cipher == aes_256_cbc -> 16. -mac_algorithm(null) -> - ?NULL; -mac_algorithm(md5) -> - ?MD5; -mac_algorithm(sha) -> - ?SHA; -mac_algorithm(sha256) -> - ?SHA256; -mac_algorithm(sha384) -> - ?SHA384. - -prf_algorithm(default_prf) -> +prf_algorithm(default_prf, {3, N}) when N >= 3 -> ?SHA256; -prf_algorithm(null) -> - ?NULL; -prf_algorithm(md5) -> - ?MD5; -prf_algorithm(sha) -> - ?SHA; -prf_algorithm(sha256) -> - ?SHA256; -prf_algorithm(sha384) -> - ?SHA384. +prf_algorithm(default_prf, {3, _}) -> + ?MD5SHA; +prf_algorithm(Algo, _) -> + hash_algorithm(Algo). + +hash_algorithm(null) -> ?NULL; +hash_algorithm(md5) -> ?MD5; +hash_algorithm(sha) -> ?SHA; %% Only sha always refers to "SHA-1" +hash_algorithm(sha224) -> ?SHA224; +hash_algorithm(sha256) -> ?SHA256; +hash_algorithm(sha384) -> ?SHA384; +hash_algorithm(sha512) -> ?SHA512; +hash_algorithm(?NULL) -> null; +hash_algorithm(?MD5) -> md5; +hash_algorithm(?SHA) -> sha; +%%hash_algorithm(?SHA224) -> sha224; +hash_algorithm(?SHA256) -> sha256; +hash_algorithm(?SHA384) -> sha384; +hash_algorithm(?SHA512) -> sha512. + +sign_algorithm(anon) -> ?ANON; +sign_algorithm(rsa) -> ?RSA; +sign_algorithm(dsa) -> ?DSA; +sign_algorithm(ecdsa) -> ?ECDSA; +sign_algorithm(?ANON) -> anon; +sign_algorithm(?RSA) -> rsa; +sign_algorithm(?DSA) -> dsa; +sign_algorithm(?ECDSA) -> ecdsa. hash_size(null) -> 0; @@ -621,9 +629,7 @@ hash_size(md5) -> hash_size(sha) -> 20; hash_size(sha256) -> - 32; -hash_size(sha384) -> - 48. + 32. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 002565bc79..0d3efae5f4 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -435,9 +435,8 @@ abbreviated(#finished{verify_data = Data} = Finished, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State) -> -%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, client, - get_current_connection_state_prf(ConnectionStates0, read), + get_current_connection_state_prf(ConnectionStates0, write), MasterSecret, Handshake) of verified -> ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), @@ -453,7 +452,6 @@ abbreviated(#finished{verify_data = Data} = Finished, session = #session{master_secret = MasterSecret}, negotiated_version = Version, connection_states = ConnectionStates0} = State) -> -%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, server, get_pending_connection_state_prf(ConnectionStates0, write), MasterSecret, Handshake0) of @@ -2414,3 +2412,41 @@ get_current_connection_state_prf(CStates, Direction) -> get_pending_connection_state_prf(CStates, Direction) -> CS = ssl_record:pending_connection_state(CStates, Direction), CS#connection_state.security_parameters#security_parameters.prf_algorithm. + +connection_hash_algo({HashAlgo, _}, _State) -> + HashAlgo; +connection_hash_algo(_, #state{hashsign_algorithm = {HashAlgo, _}}) -> + HashAlgo. + +%% RFC 5246, Sect. 7.4.1.4.1. Signature Algorithms +%% If the client does not send the signature_algorithms extension, the +%% server MUST do the following: +%% +%% - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, +%% DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had +%% sent the value {sha1,rsa}. +%% +%% - If the negotiated key exchange algorithm is one of (DHE_DSS, +%% DH_DSS), behave as if the client had sent the value {sha1,dsa}. +%% +%% - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, +%% ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}. + +default_hashsign(_Version = {Major, Minor}, KeyExchange) + when Major == 3 andalso Minor >= 3 andalso + (KeyExchange == rsa orelse + KeyExchange == dhe_rsa orelse + KeyExchange == dh_rsa) -> + {sha, rsa}; +default_hashsign(_Version, KeyExchange) + when KeyExchange == rsa; + KeyExchange == dhe_rsa; + KeyExchange == dh_rsa -> + {md5sha, rsa}; +default_hashsign(_Version, KeyExchange) + when KeyExchange == dhe_dss; + KeyExchange == dh_dss -> + {sha, dsa}; +default_hashsign(_Version, KeyExchange) + when KeyExchange == dh_anon -> + {null, anon}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 1b83293730..7dba77560c 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -131,7 +131,7 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, Renegotiation, SecureRenegotation, []) of {ok, ConnectionStates1} -> ConnectionStates = - hello_pending_connection_states(client, CipherSuite, Random, + hello_pending_connection_states(client, Version, CipherSuite, Random, Compression, ConnectionStates1), {Version, SessionId, ConnectionStates}; #alert{} = Alert -> @@ -164,6 +164,7 @@ hello(#client_hello{client_version = ClientVersion, random = Random, {ok, ConnectionStates1} -> ConnectionStates = hello_pending_connection_states(server, + Version, CipherSuite, Random, Compression, @@ -286,10 +287,13 @@ client_certificate_verify(OwnCert, MasterSecret, Version, %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- -certificate_verify(Signature, {?'rsaEncryption'= Algorithm, PublicKey, _}, Version, - MasterSecret, {_, Handshake}) -> - Hashes = calc_certificate_verify(Version, MasterSecret, - Algorithm, Handshake), +certificate_verify_rsa(Hashes, sha, Signature, PublicKey, {Major, Minor}) + when Major == 3, Minor >= 3 -> + public_key:verify({digest, Hashes}, sha, Signature, PublicKey); +certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor}) + when Major == 3, Minor >= 3 -> + public_key:verify({digest, Hashes}, HashAlgo, Signature, PublicKey); +certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) -> case public_key:decrypt_public(Signature, PublicKey, [{rsa_pad, rsa_pkcs1_padding}]) of Hashes -> @@ -527,8 +531,7 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> end. %%-------------------------------------------------------------------- --spec server_key_exchange_hash(rsa | dhe_rsa| dhe_dss | dh_anon, binary()) -> binary(). - +-spec server_key_exchange_hash(md5sha1 | md5 | sha | sha256 | sha384 | sha512, binary()) -> binary(). %% %% Description: Calculate server key exchange hash %%-------------------------------------------------------------------- @@ -551,7 +554,7 @@ prf({3,0}, _, _, _, _) -> {error, undefined}; prf({3,1}, Secret, Label, Seed, WantedLength) -> {ok, ssl_tls1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)}; -prf({3,N}, Secret, Label, Seed, WantedLength) -> +prf({3,_N}, Secret, Label, Seed, WantedLength) -> {ok, ssl_tls1:prf(?SHA256, Secret, Label, Seed, WantedLength)}. %%-------------------------------------------------------------------- @@ -719,7 +722,7 @@ handle_renegotiation_info(ConnectionStates, SecureRenegotation) -> %% hello messages %% NOTE : Role is the role of the receiver of the hello message %% currently being processed. -hello_pending_connection_states(Role, CipherSuite, Random, Compression, +hello_pending_connection_states(Role, Version, CipherSuite, Random, Compression, ConnectionStates) -> ReadState = ssl_record:pending_connection_state(ConnectionStates, read), @@ -727,30 +730,30 @@ hello_pending_connection_states(Role, CipherSuite, Random, Compression, ssl_record:pending_connection_state(ConnectionStates, write), NewReadSecParams = - hello_security_parameters(Role, ReadState, CipherSuite, + hello_security_parameters(Role, Version, ReadState, CipherSuite, Random, Compression), NewWriteSecParams = - hello_security_parameters(Role, WriteState, CipherSuite, + hello_security_parameters(Role, Version, WriteState, CipherSuite, Random, Compression), ssl_record:update_security_params(NewReadSecParams, NewWriteSecParams, ConnectionStates). -hello_security_parameters(client, ConnectionState, CipherSuite, Random, +hello_security_parameters(client, Version, ConnectionState, CipherSuite, Random, Compression) -> SecParams = ConnectionState#connection_state.security_parameters, - NewSecParams = ssl_cipher:security_parameters(CipherSuite, SecParams), + NewSecParams = ssl_cipher:security_parameters(Version, CipherSuite, SecParams), NewSecParams#security_parameters{ server_random = Random, compression_algorithm = Compression }; -hello_security_parameters(server, ConnectionState, CipherSuite, Random, +hello_security_parameters(server, Version, ConnectionState, CipherSuite, Random, Compression) -> SecParams = ConnectionState#connection_state.security_parameters, - NewSecParams = ssl_cipher:security_parameters(CipherSuite, SecParams), + NewSecParams = ssl_cipher:security_parameters(Version, CipherSuite, SecParams), NewSecParams#security_parameters{ client_random = Random, compression_algorithm = Compression @@ -1093,6 +1096,17 @@ certificate_types({KeyExchange, _, _, _}) certificate_types(_) -> <>. +hashsign_dec(<>) -> + {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}. + +hashsign_enc(HashAlgo, SignAlgo) -> + Hash = ssl_cipher:hash_algorithm(HashAlgo), + Sign = ssl_cipher:sign_algorithm(SignAlgo), + <>. + +hashsign_algorithms(_) -> + hashsign_enc(sha, rsa). + certificate_authorities(CertDbHandle, CertDbRef) -> Authorities = certificate_authorities_from_db(CertDbHandle, CertDbRef), Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) -> @@ -1114,7 +1128,12 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) -> end, ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle). -digitally_signed(Hash, #'RSAPrivateKey'{} = Key) -> + +digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 -> + public_key:sign({digest, Hash}, HashAlgo, Key); +digitally_signed(_Version, Hash, _HashAlgo, #'DSAPrivateKey'{} = Key) -> + public_key:sign({digest, Hash}, sha, Key); +digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]); digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> @@ -1123,45 +1142,27 @@ digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); -calc_master_secret({3,N}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) - when N == 1; N == 2 -> - ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom); - -calc_master_secret({3,N}, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) - when N == 3 -> - %% only from TLS 1.2 onwards the selection of a PrfAlgo is supported +calc_master_secret({3,_}, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_tls1:master_secret(PrfAlgo, PremasterSecret, ClientRandom, ServerRandom). setup_keys({3,0}, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS) -> - ssl_ssl3:setup_keys(MasterSecret, ServerRandom, + ssl_ssl3:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS); -setup_keys({3,N}, _PrfAlgo, MasterSecret, - ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) - when N == 1; N == 2 -> - ssl_tls1:setup_keys(N, ?MD5SHA, MasterSecret, ServerRandom, ClientRandom, HashSize, - KML, IVS); - setup_keys({3,N}, PrfAlgo, MasterSecret, - ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) - when N == 3 -> + ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) -> ssl_tls1:setup_keys(N, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, IVS). calc_finished({3, 0}, Role, _PrfAlgo, MasterSecret, Handshake) -> ssl_ssl3:finished(Role, MasterSecret, lists:reverse(Handshake)); -calc_finished({3, N}, Role, _PrfAlgo, MasterSecret, Handshake) - when N == 1; N == 2 -> - ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake)); -calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake) - when N == 3 -> +calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake) -> ssl_tls1:finished(Role, N, PrfAlgo, MasterSecret, lists:reverse(Handshake)). calc_certificate_verify({3, 0}, HashAlgo, MasterSecret, Handshake) -> ssl_ssl3:certificate_verify(HashAlgo, MasterSecret, lists:reverse(Handshake)); -calc_certificate_verify({3, N}, HashAlgo, _MasterSecret, Handshake) - when N == 1; N == 2 -> +calc_certificate_verify({3, N}, HashAlgo, _MasterSecret, Handshake) -> ssl_tls1:certificate_verify(HashAlgo, N, lists:reverse(Handshake)). key_exchange_alg(rsa) -> diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 8510def2fd..20e498ea2e 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -33,6 +33,12 @@ -type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. -type tls_handshake_history() :: {[binary()], [binary()]}. +%% Signature algorithms +-define(ANON, 0). +-define(RSA, 1). +-define(DSA, 2). +-define(ECDSA, 3). + -record(session, { session_id, peer_certificate, diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index f9ccaea0e3..676c191c17 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -561,14 +561,14 @@ highest_protocol_version() -> initial_connection_state(ConnectionEnd) -> #connection_state{security_parameters = - initial_security_params(ConnectionEnd), + initial_security_params(ConnectionEnd), sequence_number = 0 }. initial_security_params(ConnectionEnd) -> SecParams = #security_parameters{connection_end = ConnectionEnd, compression_algorithm = ?NULL}, - ssl_cipher:security_parameters(?TLS_NULL_WITH_NULL_NULL, + ssl_cipher:security_parameters(highest_protocol_version(), ?TLS_NULL_WITH_NULL_NULL, SecParams). empty_connection_state(ConnectionEnd) -> diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index cb1008c2be..f73da92a52 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -98,11 +98,12 @@ %-define(TRUE, 0). %% Already defined by ssl_internal.hrl %-define(FALSE, 1). %% Already defined by ssl_internal.hrl -%% MACAlgorithm +%% MAC and PRF Algorithms %-define(NULL, 0). %% Already defined by ssl_internal.hrl -define(MD5, 1). -define(SHA, 2). --define(MD5SHA, 3). +-define(MD5SHA, 4711). %% Not defined in protocol used to represent old prf +-define(SHA224, 3). -define(SHA256, 4). -define(SHA384, 5). -define(SHA512, 6). diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 11bc663e77..bb368fe5d0 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -74,7 +74,7 @@ finished(Role, MasterSecret, Handshake) -> SHA = handshake_hash(?SHA, MasterSecret, Sender, Handshake), <>. --spec certificate_verify(OID::tuple(), binary(), [binary()]) -> binary(). +-spec certificate_verify(md5sha | sha, binary(), [binary()]) -> binary(). certificate_verify(?'rsaEncryption', MasterSecret, Handshake) -> %% md5_hash @@ -88,7 +88,7 @@ certificate_verify(?'rsaEncryption', MasterSecret, Handshake) -> SHA = handshake_hash(?SHA, MasterSecret, undefined, Handshake), <>; -certificate_verify(?'id-dsa', MasterSecret, Handshake) -> +certificate_verify(sha, MasterSecret, Handshake) -> %% sha_hash %% SHA(master_secret + pad_2 + %% SHA(handshake_messages + master_secret + pad_1)); @@ -153,26 +153,17 @@ suites() -> %%% Internal functions %%-------------------------------------------------------------------- -hash(?MD5, Data) -> +hash(?MD5, Data) -> crypto:md5(Data); -hash(?SHA, Data) -> - crypto:sha(Data); -hash(?SHA256, Data) -> - crypto:sha256(Data); -hash(?SHA384, Data) -> - crypto:sha384(Data). +hash(?SHA, Data) -> + crypto:sha(Data). %%pad_1(?NULL) -> %% ""; pad_1(?MD5) -> <<"666666666666666666666666666666666666666666666666">>; pad_1(?SHA) -> - <<"6666666666666666666666666666666666666666">>; -pad_1(?SHA256) -> - <<"66666666666666666666666666666666">>; -pad_1(?SHA384) -> - <<"666666666666666666666666666666666666666666666666">>. - + <<"6666666666666666666666666666666666666666">>. %%pad_2(?NULL) -> %% ""; pad_2(?MD5) -> @@ -180,14 +171,7 @@ pad_2(?MD5) -> "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>; pad_2(?SHA) -> <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" - "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>; -pad_2(?SHA256) -> - <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" - "\\\\\\\\\\\\\\\\\\\\\\\\">>; -pad_2(?SHA384) -> - <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" - "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" - "\\\\\\\\\\\\\\\\">>. + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>. mac_hash(?NULL, _Secret, _Data) -> <<>>; diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index d56b8ee07f..e6e55048a4 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -28,7 +28,7 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). --export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, +-export([master_secret/4, finished/5, certificate_verify/2, mac_hash/7, setup_keys/8, suites/1, prf/5]). %%==================================================================== @@ -73,14 +73,14 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake) Hash = crypto:hash(mac_algo(PrfAlgo), Handshake), prf(PrfAlgo, MasterSecret, finished_label(Role), Hash, 12). --spec certificate_verify(OID::tuple(), [binary()]) -> binary(). +-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary(). certificate_verify(?'rsaEncryption', Handshake) -> MD5 = crypto:md5(Handshake), SHA = crypto:sha(Handshake), <>; -certificate_verify(?'id-dsa', Handshake) -> +certificate_verify(sha, _Version, Handshake) -> crypto:sha(Handshake). -spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(), @@ -233,7 +233,6 @@ hmac_hash(?SHA512, Key, Value) -> mac_algo(?MD5) -> md5; mac_algo(?SHA) -> sha; -mac_algo(?MD5SHA) -> sha256; %% RFC 5246 defines minimum hash for TLS 1.2 mac_algo(?SHA256) -> sha256; mac_algo(?SHA384) -> sha384; mac_algo(?SHA512) -> sha512. @@ -287,8 +286,7 @@ split_secret(BinSecret) -> <<_:Div/binary, Secret2:EvenLength/binary>> = BinSecret, {Secret1, Secret2}. -prf(MAC, Secret, Label, Seed, WantedLength) - when MAC == ?MD5SHA -> +prf(?MD5SHA, Secret, Label, Seed, WantedLength) -> %% PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR %% P_SHA-1(S2, label + seed); {S1, S2} = split_secret(Secret), -- cgit v1.2.3 From 0bcbe96a1a68fef87efc43719853edcee2f58720 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 03:39:52 +0200 Subject: ssl: Make signature handling version dependant TLS 1.2 introduces changes on how signatures are calculate and encoded. This makes the signature handling version aware --- lib/ssl/src/ssl_cipher.erl | 5 +- lib/ssl/src/ssl_connection.erl | 21 +++++--- lib/ssl/src/ssl_handshake.erl | 113 ++++++++++++++++++++++------------------- lib/ssl/src/ssl_handshake.hrl | 6 ++- lib/ssl/src/ssl_ssl3.erl | 2 +- lib/ssl/src/ssl_tls1.erl | 4 +- 6 files changed, 85 insertions(+), 66 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 9e1fbe20f4..8b6d5ea4ea 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -35,7 +35,8 @@ -export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, suite/1, suites/1, anonymous_suites/0, - openssl_suite/1, openssl_suite_name/1, filter/2]). + openssl_suite/1, openssl_suite_name/1, filter/2, + hash_algorithm/1, sign_algorithm/1]). -compile(inline). @@ -608,7 +609,7 @@ hash_algorithm(sha512) -> ?SHA512; hash_algorithm(?NULL) -> null; hash_algorithm(?MD5) -> md5; hash_algorithm(?SHA) -> sha; -%%hash_algorithm(?SHA224) -> sha224; +hash_algorithm(?SHA224) -> sha224; hash_algorithm(?SHA256) -> sha256; hash_algorithm(?SHA384) -> sha384; hash_algorithm(?SHA512) -> sha512. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 0d3efae5f4..19847575e5 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -77,6 +77,7 @@ supported_protocol_versions, % [atom()] client_certificate_requested = false, key_algorithm, % atom as defined by cipher_suite + hashsign_algorithm, % atom as defined by cipher_suite public_key_info, % PKIX: {Algorithm, PublicKey, PublicKeyParams} private_key, % PKIX: #'RSAPrivateKey'{} diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side @@ -380,6 +381,7 @@ hello(#server_hello{cipher_suite = CipherSuite, PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), State = State0#state{key_algorithm = KeyAlgorithm, + hashsign_algorithm = default_hashsign(Version, KeyAlgorithm), negotiated_version = Version, connection_states = ConnectionStates, premaster_secret = PremasterSecret}, @@ -643,10 +645,11 @@ cipher(#certificate_verify{signature = Signature}, public_key_info = PublicKeyInfo, negotiated_version = Version, session = #session{master_secret = MasterSecret}, + hashsign_algorithm = HashSign, tls_handshake_history = Handshake } = State0) -> case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, - Version, MasterSecret, Handshake) of + Version, HashSign, MasterSecret, Handshake) of valid -> {Record, State} = next_record(State0), next_state(cipher, cipher, Record, State); @@ -1247,10 +1250,11 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, private_key = PrivateKey, session = #session{master_secret = MasterSecret, own_certificate = OwnCert}, + hashsign_algorithm = HashSign, tls_handshake_history = Handshake0} = State) -> case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, - Version, PrivateKey, Handshake0) of + Version, HashSign, PrivateKey, Handshake0) of #certificate_verify{} = Verified -> {BinVerified, ConnectionStates, Handshake} = encode_handshake(Verified, Version, @@ -1391,7 +1395,8 @@ server_hello(ServerHello, #state{transport_cb = Transport, Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates1, tls_handshake_history = Handshake1, - key_algorithm = KeyAlgorithm}. + key_algorithm = KeyAlgorithm, + hashsign_algorithm = default_hashsign(Version, KeyAlgorithm)}. server_hello_done(#state{transport_cb = Transport, socket = Socket, @@ -1433,6 +1438,7 @@ certify_server(#state{transport_cb = Transport, key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; key_exchange(#state{role = server, key_algorithm = Algo, + hashsign_algorithm = {HashAlgo, _}, diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, @@ -1451,7 +1457,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params, - Algo, ClientRandom, + HashAlgo, ClientRandom, ServerRandom, PrivateKey}), {BinMsg, ConnectionStates, Handshake} = @@ -1577,22 +1583,23 @@ handle_server_key( #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}, - signed_params = Signed}, + signed_params = Signed, + hashsign = HashSign}, #state{negotiated_version = Version, public_key_info = PubKeyInfo, - key_algorithm = KeyAlgo, connection_states = ConnectionStates} = State) -> PLen = size(P), GLen = size(G), YLen = size(ServerPublicDhKey), + HashAlgo = connection_hash_algo(HashSign, State), ConnectionState = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, - Hash = ssl_handshake:server_key_exchange_hash(KeyAlgo, + Hash = ssl_handshake:server_key_exchange_hash(HashAlgo, < %%-------------------------------------------------------------------- -spec client_certificate_verify(undefined | der_cert(), binary(), - tls_version(), private_key(), + tls_version(), term(), private_key(), tls_handshake_history()) -> #certificate_verify{} | ignore | #alert{}. %% %% Description: Creates a certificate_verify message, called by the client. %%-------------------------------------------------------------------- -client_certificate_verify(undefined, _, _, _, _) -> +client_certificate_verify(undefined, _, _, _, _, _) -> ignore; -client_certificate_verify(_, _, _, undefined, _) -> +client_certificate_verify(_, _, _, _, undefined, _) -> ignore; client_certificate_verify(OwnCert, MasterSecret, Version, + {HashAlgo, SignAlgo}, PrivateKey, {Handshake, _}) -> case public_key:pkix_is_fixed_dh_cert(OwnCert) of true -> ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE); - false -> - Hashes = - calc_certificate_verify(Version, MasterSecret, - alg_oid(PrivateKey), Handshake), - Signed = digitally_signed(Hashes, PrivateKey), - #certificate_verify{signature = Signed} + false -> + Hashes = + calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), + Signed = digitally_signed(Version, Hashes, HashAlgo, PrivateKey), + #certificate_verify{signature = Signed, hashsign_algorithm = {HashAlgo, SignAlgo}} end. %%-------------------------------------------------------------------- --spec certificate_verify(binary(), public_key_info(), tls_version(), +-spec certificate_verify(binary(), public_key_info(), tls_version(), term(), binary(), tls_handshake_history()) -> valid | #alert{}. %% %% Description: Checks that the certificate_verify message is valid. @@ -296,18 +296,25 @@ certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor}) certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) -> case public_key:decrypt_public(Signature, PublicKey, [{rsa_pad, rsa_pkcs1_padding}]) of - Hashes -> + Hashes -> true; + _ -> false + end. + +certificate_verify(Signature, {?'rsaEncryption', PublicKey, _}, Version, + {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) -> + Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), + case certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, Version) of + true -> valid; _ -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) end; -certificate_verify(Signature, {?'id-dsa' = Algorithm, PublicKey, PublicKeyParams}, Version, - MasterSecret, {_, Handshake}) -> - Hashes = calc_certificate_verify(Version, MasterSecret, - Algorithm, Handshake), +certificate_verify(Signature, {?'id-dsa', PublicKey, PublicKeyParams}, Version, + {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) -> + Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of - true -> - valid; + true -> + valid; false -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) end. @@ -324,9 +331,11 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> #security_parameters{cipher_suite = CipherSuite}} = ssl_record:pending_connection_state(ConnectionStates, read), Types = certificate_types(CipherSuite), + HashSigns = hashsign_algorithms(CipherSuite), Authorities = certificate_authorities(CertDbHandle, CertDbRef), #certificate_request{ certificate_types = Types, + hashsign_algorithms = HashSigns, certificate_authorities = Authorities }. @@ -334,7 +343,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> -spec key_exchange(client | server, tls_version(), {premaster_secret, binary(), public_key_info()} | {dh, binary()} | - {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(), + {dh, {binary(), binary()}, #'DHParameter'{}, hash_algo(), binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% @@ -351,9 +360,9 @@ key_exchange(client, _Version, {dh, <>}) -> dh_public = PublicKey} }; -key_exchange(server, _Version, {dh, {<>, _}, +key_exchange(server, Version, {dh, {<>, _}, #'DHParameter'{prime = P, base = G}, - KeyAlgo, ClientRandom, ServerRandom, PrivateKey}) -> + HashAlgo, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), <> = crypto:mpint(G), PLen = byte_size(PBin), @@ -362,20 +371,22 @@ key_exchange(server, _Version, {dh, {<>, _}, ServerDHParams = #server_dh_params{dh_p = PBin, dh_g = GBin, dh_y = PublicKey}, - case KeyAlgo of - dh_anon -> + case HashAlgo of + null -> #server_key_exchange{params = ServerDHParams, - signed_params = <<>>}; + signed_params = <<>>, + hashsign = {null, anon}}; _ -> Hash = - server_key_exchange_hash(KeyAlgo, <>), - Signed = digitally_signed(Hash, PrivateKey), + Signed = digitally_signed(Version, Hash, HashAlgo, PrivateKey), #server_key_exchange{params = ServerDHParams, - signed_params = Signed} + signed_params = Signed, + hashsign = {HashAlgo, digitally_signed_alg(PrivateKey)}} end. %%-------------------------------------------------------------------- @@ -527,6 +538,7 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> [{rsa_pad, rsa_pkcs1_padding}]) catch _:_ -> + io:format("decrypt_premaster_secret error"), throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR)) end. @@ -535,14 +547,13 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> %% %% Description: Calculate server key exchange hash %%-------------------------------------------------------------------- -server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa; - Algorithm == dhe_rsa -> +server_key_exchange_hash(md5sha, Value) -> MD5 = crypto:md5(Value), - SHA = crypto:sha(Value), + SHA = crypto:sha(Value), <>; -server_key_exchange_hash(dhe_dss, Value) -> - crypto:sha(Value). +server_key_exchange_hash(Hash, Value) -> + crypto:hash(Hash, Value). %%-------------------------------------------------------------------- -spec prf(tls_version(), binary(), binary(), [binary()], non_neg_integer()) -> @@ -878,14 +889,14 @@ dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <>) -> %% May happen if key_algorithm is dh_anon #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, dh_y = Y}, - signed_params = <<>>}; + signed_params = <<>>, hashsign = {null, anon}}; dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <>) -> #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, dh_y = Y}, - signed_params = Sig}; + signed_params = Sig, hashsign = undefined}; dec_hs(_Version, ?CERTIFICATE_REQUEST, <>) -> @@ -894,7 +905,7 @@ dec_hs(_Version, ?CERTIFICATE_REQUEST, dec_hs(_Version, ?SERVER_HELLO_DONE, <<>>) -> #server_hello_done{}; dec_hs(_Version, ?CERTIFICATE_VERIFY,<>)-> - #certificate_verify{signature = Signature}; + #certificate_verify{hashsign_algorithm = {unknown, unknown}, signature = Signature}; dec_hs(_Version, ?CLIENT_KEY_EXCHANGE, PKEPMS) -> #client_key_exchange{exchange_keys = PKEPMS}; dec_hs(_Version, ?FINISHED, VerifyData) -> @@ -1005,15 +1016,15 @@ enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) -> {?CERTIFICATE, <>}; enc_hs(#server_key_exchange{params = #server_dh_params{ dh_p = P, dh_g = G, dh_y = Y}, - signed_params = SignedParams}, _Version) -> + signed_params = SignedParams, hashsign = HashSign}, Version) -> PLen = byte_size(P), GLen = byte_size(G), YLen = byte_size(Y), - SignedLen = byte_size(SignedParams), + Signature = enc_sign(HashSign, SignedParams, Version), {?SERVER_KEY_EXCHANGE, <> + Signature/binary>> }; enc_hs(#certificate_request{certificate_types = CertTypes, certificate_authorities = CertAuths}, @@ -1028,8 +1039,8 @@ enc_hs(#server_hello_done{}, _Version) -> {?SERVER_HELLO_DONE, <<>>}; enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version) -> {?CLIENT_KEY_EXCHANGE, enc_cke(ExchangeKeys, Version)}; -enc_hs(#certificate_verify{signature = BinSig}, _) -> - EncSig = enc_bin_sig(BinSig), +enc_hs(#certificate_verify{signature = BinSig, hashsign_algorithm = HashSign}, Version) -> + EncSig = enc_sign(HashSign, BinSig, Version), {?CERTIFICATE_VERIFY, EncSig}; enc_hs(#finished{verify_data = VerifyData}, _Version) -> {?FINISHED, VerifyData}. @@ -1043,9 +1054,9 @@ enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), <>. -enc_bin_sig(BinSig) -> - Size = byte_size(BinSig), - <>. +enc_sign(_HashSign, Sign, _Version) -> + SignLen = byte_size(Sign), + <>. %% Renegotiation info, only current extension hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) -> @@ -1125,7 +1136,7 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) -> [Cert | Acc]; (_, Acc) -> Acc - end, + end, ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle). @@ -1135,10 +1146,11 @@ digitally_signed(_Version, Hash, _HashAlgo, #'DSAPrivateKey'{} = Key) -> public_key:sign({digest, Hash}, sha, Key); digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, - [{rsa_pad, rsa_pkcs1_padding}]); -digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> - public_key:sign(Hash, none, Key). - + [{rsa_pad, rsa_pkcs1_padding}]). + +digitally_signed_alg(#'RSAPrivateKey'{} = _Key) -> rsa; +digitally_signed_alg(#'DSAPrivateKey'{} = _Key) -> dsa. + calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); @@ -1182,8 +1194,3 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) -> {unknown, UserState} -> {unknown, {SslState, UserState}} end. - -alg_oid(#'RSAPrivateKey'{}) -> - ?'rsaEncryption'; -alg_oid(#'DSAPrivateKey'{}) -> - ?'id-dsa'. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 20e498ea2e..abe2fa5261 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -32,6 +32,7 @@ -type public_key_params() :: #'Dss-Parms'{} | term(). -type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. -type tls_handshake_history() :: {[binary()], [binary()]}. +-type hash_algo() :: atom(). %% Signature algorithms -define(ANON, 0). @@ -136,7 +137,8 @@ -record(server_key_exchange, { params, %% #server_rsa_params{} | #server_dh_params{} - signed_params %% #signature{} + signed_params, %% #signature{} + hashsign %% term(atom(), atom()) }). %% enum { anonymous, rsa, dsa } SignatureAlgorithm; @@ -166,6 +168,7 @@ -record(certificate_request, { certificate_types, %ClientCertificateType <1..2^8-1> + hashsign_algorithms, %%SignatureAndHashAlgorithm <2^16-1>; certificate_authorities %DistinguishedName <0..2^16-1> }). @@ -200,6 +203,7 @@ %%% Certificate verify - RFC 4346 section 7.4.8 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -record(certificate_verify, { + hashsign_algorithm, signature % binary() }). diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index bb368fe5d0..a11c5b8c0c 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -76,7 +76,7 @@ finished(Role, MasterSecret, Handshake) -> -spec certificate_verify(md5sha | sha, binary(), [binary()]) -> binary(). -certificate_verify(?'rsaEncryption', MasterSecret, Handshake) -> +certificate_verify(md5sha, MasterSecret, Handshake) -> %% md5_hash %% MD5(master_secret + pad_2 + %% MD5(handshake_messages + master_secret + pad_1)); diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index e6e55048a4..d62ea6e5a4 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -28,7 +28,7 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). --export([master_secret/4, finished/5, certificate_verify/2, mac_hash/7, +-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, setup_keys/8, suites/1, prf/5]). %%==================================================================== @@ -75,7 +75,7 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake) -spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary(). -certificate_verify(?'rsaEncryption', Handshake) -> +certificate_verify(md5sha, _Version, Handshake) -> MD5 = crypto:md5(Handshake), SHA = crypto:sha(Handshake), <>; -- cgit v1.2.3 From 3f10f10404ee85fcf9d8f7915f768b4826eed12a Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Mon, 18 Jun 2012 12:07:37 +0200 Subject: ssl: Implement TLS 1.2 signature support --- lib/ssl/src/ssl_handshake.erl | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 0d681e9fcb..2957059b74 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -312,10 +312,10 @@ certificate_verify(Signature, {?'rsaEncryption', PublicKey, _}, Version, certificate_verify(Signature, {?'id-dsa', PublicKey, PublicKeyParams}, Version, {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) -> Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), - case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of + case public_key:verify({digest, Hashes}, sha, Signature, {PublicKey, PublicKeyParams}) of true -> valid; - false -> + false -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) end. @@ -890,6 +890,16 @@ dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <>, hashsign = {null, anon}}; +dec_hs({Major, Minor}, ?SERVER_KEY_EXCHANGE, <>) + when Major == 3, Minor >= 3 -> + #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, + dh_y = Y}, + signed_params = Sig, + hashsign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}}; dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <>) + when Major == 3, Minor >= 3 -> + #certificate_request{certificate_types = CertTypes, + hashsign_algorithms = HashSigns, + certificate_authorities = CertAuths}; dec_hs(_Version, ?CERTIFICATE_REQUEST, <>) -> @@ -904,6 +922,9 @@ dec_hs(_Version, ?CERTIFICATE_REQUEST, certificate_authorities = CertAuths}; dec_hs(_Version, ?SERVER_HELLO_DONE, <<>>) -> #server_hello_done{}; +dec_hs({Major, Minor}, ?CERTIFICATE_VERIFY,<>) + when Major == 3, Minor >= 3 -> + #certificate_verify{hashsign_algorithm = hashsign_dec(HashSign), signature = Signature}; dec_hs(_Version, ?CERTIFICATE_VERIFY,<>)-> #certificate_verify{hashsign_algorithm = {unknown, unknown}, signature = Signature}; dec_hs(_Version, ?CLIENT_KEY_EXCHANGE, PKEPMS) -> @@ -1026,6 +1047,19 @@ enc_hs(#server_key_exchange{params = #server_dh_params{ ?UINT16(YLen), Y/binary, Signature/binary>> }; +enc_hs(#certificate_request{certificate_types = CertTypes, + hashsign_algorithms = HashSigns, + certificate_authorities = CertAuths}, + {Major, Minor}) + when Major == 3, Minor >= 3 -> + CertTypesLen = byte_size(CertTypes), + HashSignsLen = byte_size(HashSigns), + CertAuthsLen = byte_size(CertAuths), + {?CERTIFICATE_REQUEST, + <> + }; enc_hs(#certificate_request{certificate_types = CertTypes, certificate_authorities = CertAuths}, _Version) -> @@ -1054,6 +1088,11 @@ enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), <>. +enc_sign({HashAlg, SignAlg}, Signature, _Version = {Major, Minor}) + when Major == 3, Minor >= 3-> + SignLen = byte_size(Signature), + HashSign = hashsign_enc(HashAlg, SignAlg), + <>; enc_sign(_HashSign, Sign, _Version) -> SignLen = byte_size(Sign), <>. -- cgit v1.2.3 From c2761da0b7d764ca2862a4ea138cfe8a95f96c59 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 03:49:36 +0200 Subject: ssl: Enable mac_hash for TLS 1.2 --- lib/ssl/src/ssl_record.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 676c191c17..4cf962c9ea 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -687,6 +687,6 @@ mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) -> ssl_ssl3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment); mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) - when N =:= 1; N =:= 2 -> + when N =:= 1; N =:= 2; N =:= 3 -> ssl_tls1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, Length, Fragment). -- cgit v1.2.3 From 263e1ab8a7e1a36481b4526bdb933e0fa2998953 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sun, 8 Apr 2012 03:55:39 +0200 Subject: ssl: Enable TLS 1.2 --- lib/ssl/src/ssl.erl | 3 ++- lib/ssl/src/ssl_internal.hrl | 8 ++++---- lib/ssl/src/ssl_record.erl | 4 ++++ 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index d645d89a68..5bd382b8c4 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -719,7 +719,8 @@ validate_option(Opt, Value) -> validate_versions([], Versions) -> Versions; -validate_versions([Version | Rest], Versions) when Version == 'tlsv1.1'; +validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2'; + Version == 'tlsv1.1'; Version == tlsv1; Version == sslv3 -> validate_versions(Rest, Versions); diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 18cfcdcd68..87f85c5775 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -34,7 +34,7 @@ -type host() :: inet:ip_address() | inet:hostname(). -type session_id() :: 0 | binary(). -type tls_version() :: {integer(), integer()}. --type tls_atom_version() :: sslv3 | tlsv1. +-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'. -type certdb_ref() :: reference(). -type db_handle() :: term(). -type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon. @@ -69,11 +69,11 @@ -define(TRUE, 0). -define(FALSE, 1). --define(DEFAULT_SUPPORTED_VERSIONS, [tlsv1, sslv3]). % TODO: This is temporary -%-define(DEFAULT_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1, sslv3]). +-define(DEFAULT_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). % TODO: This is temporary +%-define(DEFAULT_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). -record(ssl_options, { - versions, % 'tlsv1.1' | tlsv1 | sslv3 + versions, % 'tlsv1.2' | 'tlsv1.1' | tlsv1 | sslv3 verify, % verify_none | verify_peer verify_fun, % fun(CertVerifyErrors) -> boolean() fail_if_no_peer_cert, % boolean() diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 4cf962c9ea..3bfcff5517 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -383,6 +383,8 @@ get_tls_records_aux(Data, Acc) -> %% Description: Creates a protocol version record from a version atom %% or vice versa. %%-------------------------------------------------------------------- +protocol_version('tlsv1.2') -> + {3, 3}; protocol_version('tlsv1.1') -> {3, 2}; protocol_version(tlsv1) -> @@ -391,6 +393,8 @@ protocol_version(sslv3) -> {3, 0}; protocol_version(sslv2) -> %% Backwards compatibility {2, 0}; +protocol_version({3, 3}) -> + 'tlsv1.2'; protocol_version({3, 2}) -> 'tlsv1.1'; protocol_version({3, 1}) -> -- cgit v1.2.3 From cc8d74769cc49a754598bf914e585d193177a00d Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Sat, 2 Jun 2012 15:15:38 +0200 Subject: ssl: Add TLS version switches to openssl tests --- lib/ssl/test/ssl_to_openssl_SUITE.erl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index f593c1c552..72090c1db0 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -1193,6 +1193,10 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> version_flag(tlsv1) -> " -tls1 "; +version_flag('tlsv1.1') -> + " -tls1_1 "; +version_flag('tlsv1.2') -> + " -tls1_2 "; version_flag(sslv3) -> " -ssl3 ". -- cgit v1.2.3 From a3f30e77131de6dc2f9e5746a9274f35d6b0c440 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 20 Jun 2012 10:58:04 +0200 Subject: ssl: Run relevant tests for all SSL/TLS versions --- lib/ssl/test/ssl_basic_SUITE.erl | 337 ++++++++++--------- lib/ssl/test/ssl_packet_SUITE.erl | 1 + lib/ssl/test/ssl_payload_SUITE.erl | 49 ++- lib/ssl/test/ssl_test_lib.erl | 19 +- lib/ssl/test/ssl_to_openssl_SUITE.erl | 606 ++++++++++------------------------ 5 files changed, 411 insertions(+), 601 deletions(-) (limited to 'lib') diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 24b41124c6..1cfe8d0367 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -27,9 +27,11 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). +-include("ssl_internal.hrl"). -include("ssl_alert.hrl"). -include("ssl_internal.hrl"). -include("ssl_record.hrl"). +-include("ssl_handshake.hrl"). -define('24H_in_sec', 86400). -define(TIMEOUT, 60000). @@ -54,7 +56,6 @@ init_per_suite(Config0) -> try crypto:start() of ok -> application:start(public_key), - ssl:start(), %% make rsa certs using oppenssl Result = @@ -91,46 +92,28 @@ end_per_suite(_Config) -> %% variable, but should NOT alter/remove any existing entries. %% Description: Initialization before each test case %%-------------------------------------------------------------------- -init_per_testcase(session_cache_process_list, Config) -> - init_customized_session_cache(list, Config); - -init_per_testcase(session_cache_process_mnesia, Config) -> - mnesia:start(), - init_customized_session_cache(mnesia, Config); - -init_per_testcase(reuse_session_expired, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), - ssl:stop(), - application:load(ssl), - application:set_env(ssl, session_lifetime, ?EXPIRE), - ssl:start(), - [{watchdog, Dog} | Config]; - init_per_testcase(no_authority_key_identifier, Config) -> %% Clear cach so that root cert will not %% be found. - ssl:stop(), - ssl:start(), + ssl:clear_pem_cache(), Config; -init_per_testcase(TestCase, Config) when TestCase == ciphers_rsa_signed_certs_ssl3; - TestCase == ciphers_rsa_signed_certs_openssl_names_ssl3; - TestCase == ciphers_dsa_signed_certs_ssl3; - TestCase == ciphers_dsa_signed_certs_openssl_names_ssl3 -> +init_per_testcase(protocol_versions, Config) -> ssl:stop(), application:load(ssl), - application:set_env(ssl, protocol_version, sslv3), + %% For backwards compatibility sslv2 should be filtered out. + application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]), ssl:start(), Config; -init_per_testcase(protocol_versions, Config) -> +init_per_testcase(reuse_session_expired, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), ssl:stop(), application:load(ssl), - %% For backwards compatibility sslv2 should be filtered out. - application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]), + application:set_env(ssl, session_lifetime, ?EXPIRE), ssl:start(), - Config; + [{watchdog, Dog} | Config]; init_per_testcase(empty_protocol_versions, Config) -> ssl:stop(), @@ -139,24 +122,15 @@ init_per_testcase(empty_protocol_versions, Config) -> ssl:start(), Config; -init_per_testcase(different_ca_peer_sign, Config0) -> - ssl_test_lib:make_mix_cert(Config0); +%% init_per_testcase(different_ca_peer_sign, Config0) -> +%% ssl_test_lib:make_mix_cert(Config0); init_per_testcase(_TestCase, Config0) -> + test_server:format("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]), Config = lists:keydelete(watchdog, 1, Config0), Dog = test_server:timetrap(?TIMEOUT), [{watchdog, Dog} | Config]. -init_customized_session_cache(Type, Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = test_server:timetrap(?TIMEOUT), - ssl:stop(), - application:load(ssl), - application:set_env(ssl, session_cb, ?MODULE), - application:set_env(ssl, session_cb_init_args, [Type]), - ssl:start(), - [{watchdog, Dog} | Config]. - %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ %% Case - atom() @@ -165,27 +139,10 @@ init_customized_session_cache(Type, Config0) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(session_cache_process_list, Config) -> - application:unset_env(ssl, session_cb), - end_per_testcase(default_action, Config); -end_per_testcase(session_cache_process_mnesia, Config) -> - application:unset_env(ssl, session_cb), - application:unset_env(ssl, session_cb_init_args), - mnesia:stop(), - ssl:stop(), - ssl:start(), - end_per_testcase(default_action, Config); end_per_testcase(reuse_session_expired, Config) -> application:unset_env(ssl, session_lifetime), end_per_testcase(default_action, Config); -end_per_testcase(TestCase, Config) when TestCase == ciphers_rsa_signed_certs_ssl3; - TestCase == ciphers_rsa_signed_certs_openssl_names_ssl3; - TestCase == ciphers_dsa_signed_certs_ssl3; - TestCase == ciphers_dsa_signed_certs_openssl_names_ssl3; - TestCase == protocol_versions; - TestCase == empty_protocol_versions-> - application:unset_env(ssl, protocol_version), - end_per_testcase(default_action, Config); + end_per_testcase(_TestCase, Config) -> Dog = ?config(watchdog, Config), case Dog of @@ -206,74 +163,163 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [app, alerts, connection_info, protocol_versions, - empty_protocol_versions, controlling_process, - controller_dies, client_closes_socket, - connect_dist, peername, peercert, sockname, socket_options, - invalid_inet_get_option, invalid_inet_get_option_not_list, + [ + {group, basic}, + {group, options}, + {group, session}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'} + ]. + +groups() -> + [{basic, [], basic_tests()}, + {options, [], options_tests()}, + {'tlsv1.2', [], all_versions_groups()}, + {'tlsv1.1', [], all_versions_groups()}, + {'tlsv1', [], all_versions_groups() ++ rizzo_tests()}, + {'sslv3', [], all_versions_groups() ++ rizzo_tests()}, + {api,[], api_tests()}, + {certificate_verify, [], certificate_verify_tests()}, + {session, [], session_tests()}, + {renegotiate, [], renegotiate_tests()}, + {ciphers, [], cipher_tests()}, + {error_handling_tests, [], error_handling_tests()} + ]. + +all_versions_groups ()-> + [{group, api}, + {group, certificate_verify}, + {group, renegotiate}, + {group, ciphers}, + {group, error_handling_tests}]. + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName); + _ -> + ssl:start() + end, + Config. + +end_per_group(_GroupName, Config) -> + Config. + +basic_tests() -> + [app, + alerts, + send_close, + connect_twice, + connect_dist + ]. + +options_tests() -> + [der_input, + misc_ssl_options, + socket_options, + invalid_inet_get_option, + invalid_inet_get_option_not_list, invalid_inet_get_option_improper_list, - invalid_inet_set_option, invalid_inet_set_option_not_list, + invalid_inet_set_option, + invalid_inet_set_option_not_list, invalid_inet_set_option_improper_list, - misc_ssl_options, versions, cipher_suites, upgrade, - upgrade_with_timeout, tcp_connect, tcp_connect_big, ipv6, ekeyfile, - ecertfile, ecacertfile, eoptions, shutdown, - shutdown_write, shutdown_both, shutdown_error, - ciphers_rsa_signed_certs, ciphers_rsa_signed_certs_ssl3, - ciphers_rsa_signed_certs_openssl_names, - ciphers_rsa_signed_certs_openssl_names_ssl3, - ciphers_dsa_signed_certs, ciphers_dsa_signed_certs_ssl3, - ciphers_dsa_signed_certs_openssl_names, - ciphers_dsa_signed_certs_openssl_names_ssl3, - anonymous_cipher_suites, - default_reject_anonymous, - send_close, - close_transport_accept, dh_params, - server_verify_peer_passive, server_verify_peer_active, + dh_params, + ecertfile, + ecacertfile, + ekeyfile, + eoptions, + protocol_versions, + empty_protocol_versions, + ipv6, + reuseaddr]. + +api_tests() -> + [connection_info, + peername, + peercert, + sockname, + versions, + controlling_process, + upgrade, + upgrade_with_timeout, + shutdown, + shutdown_write, + shutdown_both, + shutdown_error, + hibernate + ]. + +certificate_verify_tests() -> + [server_verify_peer_passive, + server_verify_peer_active, server_verify_peer_active_once, - server_verify_none_passive, server_verify_none_active, + server_verify_none_passive, + server_verify_none_active, server_verify_none_active_once, - server_verify_no_cacerts, server_require_peer_cert_ok, + server_verify_no_cacerts, + server_require_peer_cert_ok, server_require_peer_cert_fail, server_verify_client_once_passive, server_verify_client_once_active, server_verify_client_once_active_once, - client_verify_none_passive, client_verify_none_active, + client_verify_none_passive, + client_verify_none_active, client_verify_none_active_once, - reuse_session, - reuse_session_expired, - server_does_not_want_to_reuse_session, - client_renegotiate, server_renegotiate, - client_renegotiate_reused_session, - server_renegotiate_reused_session, - client_no_wrap_sequence_number, - server_no_wrap_sequence_number, extended_key_usage_verify_peer, + extended_key_usage_verify_peer, extended_key_usage_verify_none, - no_authority_key_identifier, invalid_signature_client, - invalid_signature_server, cert_expired, + invalid_signature_client, + invalid_signature_server, + cert_expired, client_with_cert_cipher_suites_handshake, verify_fun_always_run_client, verify_fun_always_run_server, - unknown_server_ca_fail, der_input, + unknown_server_ca_fail, unknown_server_ca_accept_verify_none, unknown_server_ca_accept_verify_peer, unknown_server_ca_accept_backwardscompatibility, - %%different_ca_peer_sign, - no_reuses_session_server_restart_new_cert, - no_reuses_session_server_restart_new_cert_file, reuseaddr, - hibernate, connect_twice, renegotiate_dos_mitigate_active, - renegotiate_dos_mitigate_passive, - tcp_error_propagation_in_active_mode, rizzo, no_rizzo_rc4, - recv_error_handling + no_authority_key_identifier ]. -groups() -> - []. +session_tests() -> + [reuse_session, + reuse_session_expired, + server_does_not_want_to_reuse_session, + no_reuses_session_server_restart_new_cert, + no_reuses_session_server_restart_new_cert_file]. -init_per_group(_GroupName, Config) -> - Config. +renegotiate_tests() -> + [client_renegotiate, + server_renegotiate, + client_renegotiate_reused_session, + server_renegotiate_reused_session, + client_no_wrap_sequence_number, + server_no_wrap_sequence_number, + renegotiate_dos_mitigate_active, + renegotiate_dos_mitigate_passive]. -end_per_group(_GroupName, Config) -> - Config. +cipher_tests() -> + [cipher_suites, + ciphers_rsa_signed_certs, + ciphers_rsa_signed_certs_openssl_names, + ciphers_dsa_signed_certs, + ciphers_dsa_signed_certs_openssl_names, + anonymous_cipher_suites, + default_reject_anonymous]. + +error_handling_tests()-> + [controller_dies, + client_closes_socket, + tcp_error_propagation_in_active_mode, + tcp_connect, + tcp_connect_big, + close_transport_accept + ]. + +rizzo_tests() -> + [rizzo, + no_rizzo_rc4]. %% Test cases starts here. %%-------------------------------------------------------------------- @@ -1726,21 +1772,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) -> ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:rsa_suites(), - test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), - run_suites(Ciphers, Version, Config, rsa). - -ciphers_rsa_signed_certs_ssl3(doc) -> - ["Test all rsa ssl cipher suites in ssl3"]; - -ciphers_rsa_signed_certs_ssl3(suite) -> - []; - -ciphers_rsa_signed_certs_ssl3(Config) when is_list(Config) -> - Version = - ssl_record:protocol_version({3,0}), - - Ciphers = ssl_test_lib:rsa_suites(), - test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), + test_server:format("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, rsa). ciphers_rsa_signed_certs_openssl_names(doc) -> @@ -1757,18 +1789,6 @@ ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) -> run_suites(Ciphers, Version, Config, rsa). -ciphers_rsa_signed_certs_openssl_names_ssl3(doc) -> - ["Test all dsa ssl cipher suites in ssl3"]; - -ciphers_rsa_signed_certs_openssl_names_ssl3(suite) -> - []; - -ciphers_rsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) -> - Version = ssl_record:protocol_version({3,0}), - Ciphers = ssl_test_lib:openssl_rsa_suites(), - run_suites(Ciphers, Version, Config, rsa). - - ciphers_dsa_signed_certs(doc) -> ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; @@ -1780,24 +1800,9 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) -> ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl_test_lib:dsa_suites(), - test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), + test_server:format("~p erlang cipher suites ~p~n", [Version, Ciphers]), run_suites(Ciphers, Version, Config, dsa). -ciphers_dsa_signed_certs_ssl3(doc) -> - ["Test all dsa ssl cipher suites in ssl3"]; - -ciphers_dsa_signed_certs_ssl3(suite) -> - []; - -ciphers_dsa_signed_certs_ssl3(Config) when is_list(Config) -> - Version = - ssl_record:protocol_version({3,0}), - - Ciphers = ssl_test_lib:dsa_suites(), - test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), - run_suites(Ciphers, Version, Config, dsa). - - ciphers_dsa_signed_certs_openssl_names(doc) -> ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; @@ -1812,18 +1817,6 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) -> test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), run_suites(Ciphers, Version, Config, dsa). - -ciphers_dsa_signed_certs_openssl_names_ssl3(doc) -> - ["Test all dsa ssl cipher suites in ssl3"]; - -ciphers_dsa_signed_certs_openssl_names_ssl3(suite) -> - []; - -ciphers_dsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) -> - Version = ssl_record:protocol_version({3,0}), - Ciphers = ssl_test_lib:openssl_dsa_suites(), - run_suites(Ciphers, Version, Config, dsa). - anonymous_cipher_suites(doc)-> ["Test the anonymous ciphersuites"]; anonymous_cipher_suites(suite) -> @@ -2087,7 +2080,9 @@ reuse_session_expired(Config) when is_list(Config) -> Server ! listen, %% Make sure session is unregistered due to expiration - test_server:sleep((?EXPIRE+1) * 1000), + test_server:sleep((?EXPIRE+1)), + [{session_id, Id} |_] = SessionInfo, + make_sure_expired(Hostname, Port, Id), Client2 = ssl_test_lib:start_client([{node, ClientNode}, @@ -2106,6 +2101,22 @@ reuse_session_expired(Config) when is_list(Config) -> ssl_test_lib:close(Client1), ssl_test_lib:close(Client2). +make_sure_expired(Host, Port, Id) -> + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + Cache = element(2, State), + case ssl_session_cache:lookup(Cache, {{Host, Port}, Id}) of + undefined -> + ok; + #session{is_resumable = false} -> + ok; + _ -> + test_server:sleep(100), + make_sure_expired(Host, Port, Id) + end. + + %%-------------------------------------------------------------------- server_does_not_want_to_reuse_session(doc) -> ["Test reuse of sessions (short handshake)"]; @@ -3912,7 +3923,7 @@ recv_error_handling(Config) when is_list(Config) -> {mfa, {?MODULE, recv_close, []}}, {options, [{active, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket, + {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket, {node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 593b1fda5e..9238dcadf9 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -169,6 +169,7 @@ groups() -> header_decode_two_bytes_two_sent]}]. init_per_group(header, Config) -> + %% Does not work when N < 2 due to rizzo/duong countermeasure case ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()) of {3, N} when N < 2 -> {skip, ""}; diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index 02b5516e35..9633942ac3 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -103,22 +103,49 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> + [ + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'} + ]. + +groups() -> + [ + {'tlsv1.2', [], payload_tests()}, + {'tlsv1.1', [], payload_tests()}, + {'tlsv1', [], payload_tests()}, + {'sslv3', [], payload_tests()} + ]. + +payload_tests() -> [server_echos_passive_small, server_echos_active_once_small, - server_echos_active_small, client_echos_passive_small, + server_echos_active_small, + client_echos_passive_small, client_echos_active_once_small, - client_echos_active_small, server_echos_passive_big, - server_echos_active_once_big, server_echos_active_big, - client_echos_passive_big, client_echos_active_once_big, - client_echos_active_big, server_echos_passive_huge, - server_echos_active_once_huge, server_echos_active_huge, + client_echos_active_small, + server_echos_passive_big, + server_echos_active_once_big, + server_echos_active_big, + client_echos_passive_big, + client_echos_active_once_big, + client_echos_active_big, + server_echos_passive_huge, + server_echos_active_once_huge, + server_echos_active_huge, client_echos_passive_huge, - client_echos_active_once_huge, client_echos_active_huge]. + client_echos_active_once_huge, + client_echos_active_huge]. -groups() -> - []. -init_per_group(_GroupName, Config) -> +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName); + _ -> + ssl:start() + end, Config. end_per_group(_GroupName, Config) -> diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index fa8a1826f2..905801fe3d 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -708,3 +708,20 @@ state([{data,[{"StateData", State}]} | _]) -> State; state([_ | Rest]) -> state(Rest). + +is_tls_version('tlsv1.2') -> + true; +is_tls_version('tlsv1.1') -> + true; +is_tls_version('tlsv1') -> + true; +is_tls_version('sslv3') -> + true; +is_tls_version(_) -> + false. + +init_tls_version(Version) -> + ssl:stop(), + application:load(ssl), + application:set_env(ssl, protocol_version, Version), + ssl:start(). diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 72090c1db0..e5f8d4ae4e 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -106,8 +106,7 @@ init_per_testcase(TestCase, Config0) -> special_init(TestCase, Config) when TestCase == erlang_client_openssl_server_renegotiate; - TestCase == erlang_client_openssl_server_no_wrap_sequence_number; - TestCase == erlang_server_openssl_client_no_wrap_sequence_number -> + TestCase == erlang_client_openssl_server_no_wrap_sequence_number -> check_sane_openssl_renegotaite(Config); special_init(ssl2_erlang_server_openssl_client, Config) -> @@ -153,37 +152,59 @@ end_per_testcase(_, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [erlang_client_openssl_server, + [ + {group, basic}, + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'} + ]. + +groups() -> + [{basic, [], basic_tests()}, + {'tlsv1.2', [], all_versions_tests()}, + {'tlsv1.1', [], all_versions_tests()}, + {'tlsv1', [], all_versions_tests()}, + {'sslv3', [], all_versions_tests()}]. + +basic_tests() -> + [basic_erlang_client_openssl_server, + basic_erlang_server_openssl_client, + expired_session]. + +all_versions_tests() -> + [ + erlang_client_openssl_server, erlang_server_openssl_client, - tls1_erlang_client_openssl_server_dsa_cert, - tls1_erlang_server_openssl_client_dsa_cert, - ssl3_erlang_client_openssl_server_dsa_cert, - ssl3_erlang_server_openssl_client_dsa_cert, + erlang_client_openssl_server_dsa_cert, + erlang_server_openssl_client_dsa_cert, erlang_server_openssl_client_reuse_session, erlang_client_openssl_server_renegotiate, erlang_client_openssl_server_no_wrap_sequence_number, erlang_server_openssl_client_no_wrap_sequence_number, erlang_client_openssl_server_no_server_ca_cert, - ssl3_erlang_client_openssl_server, - ssl3_erlang_server_openssl_client, - ssl3_erlang_client_openssl_server_client_cert, - ssl3_erlang_server_openssl_client_client_cert, - ssl3_erlang_server_erlang_client_client_cert, - tls1_erlang_client_openssl_server, - tls1_erlang_server_openssl_client, - tls1_erlang_client_openssl_server_client_cert, - tls1_erlang_server_openssl_client_client_cert, - tls1_erlang_server_erlang_client_client_cert, - ciphers_rsa_signed_certs, ciphers_dsa_signed_certs, + erlang_client_openssl_server_client_cert, + erlang_server_openssl_client_client_cert, + ciphers_rsa_signed_certs, + ciphers_dsa_signed_certs, erlang_client_bad_openssl_server, - expired_session, - ssl2_erlang_server_openssl_client]. + ssl2_erlang_server_openssl_client + ]. -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case check_sane_openssl_version(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, openssl_does_not_support_version} + end; + _ -> + ssl:start(), + Config + end. end_per_group(_GroupName, Config) -> Config. @@ -191,12 +212,11 @@ end_per_group(_GroupName, Config) -> %% Test cases starts here. %%-------------------------------------------------------------------- - -erlang_client_openssl_server(doc) -> +basic_erlang_client_openssl_server(doc) -> ["Test erlang client with openssl server"]; -erlang_client_openssl_server(suite) -> +basic_erlang_client_openssl_server(suite) -> []; -erlang_client_openssl_server(Config) when is_list(Config) -> +basic_erlang_client_openssl_server(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), ClientOpts = ?config(client_opts, Config), @@ -208,8 +228,8 @@ erlang_client_openssl_server(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile, test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -234,13 +254,12 @@ erlang_client_openssl_server(Config) when is_list(Config) -> process_flag(trap_exit, false), ok. - %%-------------------------------------------------------------------- -erlang_server_openssl_client(doc) -> +basic_erlang_server_openssl_client(doc) -> ["Test erlang server with openssl client"]; -erlang_server_openssl_client(suite) -> +basic_erlang_server_openssl_client(suite) -> []; -erlang_server_openssl_client(Config) when is_list(Config) -> +basic_erlang_server_openssl_client(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_opts, Config), @@ -253,8 +272,8 @@ erlang_server_openssl_client(Config) when is_list(Config) -> {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ " -host localhost", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -269,30 +288,26 @@ erlang_server_openssl_client(Config) when is_list(Config) -> close_port(OpenSslPort), process_flag(trap_exit, false), ok. - -%%-------------------------------------------------------------------- - -tls1_erlang_client_openssl_server_dsa_cert(doc) -> - ["Test erlang server with openssl client"]; -tls1_erlang_client_openssl_server_dsa_cert(suite) -> +%%-------------------------------------------------------------------- +erlang_client_openssl_server(doc) -> + ["Test erlang client with openssl server"]; +erlang_client_openssl_server(suite) -> []; -tls1_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> +erlang_client_openssl_server(Config) when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = ?config(client_dsa_opts, Config), - ServerOpts = ?config(server_dsa_opts, Config), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - + Data = "From openssl to erlang", Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -Verify 2 -tls1 -msg", + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile, test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -306,44 +321,39 @@ tls1_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ClientOpts}]), - port_command(OpensslPort, Data), - ssl_test_lib:check_result(Client, ok), - + ssl_test_lib:check_result(Client, ok), + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. -%%-------------------------------------------------------------------- -tls1_erlang_server_openssl_client_dsa_cert(doc) -> +%%-------------------------------------------------------------------- +erlang_server_openssl_client(doc) -> ["Test erlang server with openssl client"]; -tls1_erlang_server_openssl_client_dsa_cert(suite) -> +erlang_server_openssl_client(suite) -> []; -tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> +erlang_server_openssl_client(Config) when is_list(Config) -> process_flag(trap_exit, true), - ClientOpts = ?config(client_dsa_opts, Config), - ServerOpts = ?config(server_dsa_verify_opts, Config), + ServerOpts = ?config(server_opts, Config), {_, ServerNode, _} = ssl_test_lib:run_where(Config), Data = "From openssl to erlang", - CaCertFile = proplists:get_value(cacertfile, ClientOpts), - CertFile = proplists:get_value(certfile, ClientOpts), - KeyFile = proplists:get_value(keyfile, ClientOpts), - + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ - " -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -tls1 -msg", + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -host localhost", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -351,7 +361,7 @@ tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), - + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), close_port(OpenSslPort), @@ -360,11 +370,11 @@ tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -ssl3_erlang_client_openssl_server_dsa_cert(doc) -> +erlang_client_openssl_server_dsa_cert(doc) -> ["Test erlang server with openssl client"]; -ssl3_erlang_client_openssl_server_dsa_cert(suite) -> +erlang_client_openssl_server_dsa_cert(suite) -> []; -ssl3_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> +erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_dsa_opts, Config), ServerOpts = ?config(server_dsa_opts, Config), @@ -377,10 +387,11 @@ ssl3_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> CaCertFile = proplists:get_value(cacertfile, ServerOpts), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -Verify 2 -ssl3 -msg", + ++ " -key " ++ KeyFile ++ " -Verify 2 -msg", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -404,49 +415,46 @@ ssl3_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. - -%%-------------------------------------------------------------------- - -ssl3_erlang_server_openssl_client_dsa_cert(doc) -> +%%-------------------------------------------------------------------- +erlang_server_openssl_client_dsa_cert(doc) -> ["Test erlang server with openssl client"]; -ssl3_erlang_server_openssl_client_dsa_cert(suite) -> +erlang_server_openssl_client_dsa_cert(suite) -> []; -ssl3_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> +erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_dsa_opts, Config), - ServerOpts = ?config(server_dsa_verify_opts, Config), + ServerOpts = ?config(server_dsa_verify_opts, Config), {_, ServerNode, _} = ssl_test_lib:run_where(Config), - + Data = "From openssl to erlang", CaCertFile = proplists:get_value(cacertfile, ClientOpts), CertFile = proplists:get_value(certfile, ClientOpts), KeyFile = proplists:get_value(keyfile, ClientOpts), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, - {options, ServerOpts}]), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ - " -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -ssl3 -msg", + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile + ++ " -key " ++ KeyFile ++ " -msg", test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), port_command(OpenSslPort, Data), - + ssl_test_lib:check_result(Server, ok), - + %% Clean close down! Server needs to be closed first !! ssl_test_lib:close(Server), close_port(OpenSslPort), process_flag(trap_exit, false), ok. - %%-------------------------------------------------------------------- erlang_server_openssl_client_reuse_session(doc) -> @@ -468,8 +476,8 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> {reconnect_times, 5}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost -reconnect", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -505,8 +513,9 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -556,8 +565,8 @@ erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -606,8 +615,8 @@ erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config trigger_renegotiate, [[Data, N+2]]}}, {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -host localhost -msg", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -643,8 +652,8 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -671,85 +680,11 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> ok. %%-------------------------------------------------------------------- -ssl3_erlang_client_openssl_server(doc) -> - ["Test erlang client with openssl server"]; -ssl3_erlang_client_openssl_server(suite) -> - []; -ssl3_erlang_client_openssl_server(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -ssl3", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - - wait_for_openssl_server(), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - connection_info, [sslv3]}}, - {options, - [{versions, [sslv3]} | ClientOpts]}]), - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- - -ssl3_erlang_server_openssl_client(doc) -> - ["Test erlang server with openssl client"]; -ssl3_erlang_server_openssl_client(suite) -> - []; -ssl3_erlang_server_openssl_client(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_opts, Config), - - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, - {?MODULE, connection_info, [sslv3]}}, - {options, - [{versions, [sslv3]} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ - " -host localhost -ssl3", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - - ssl_test_lib:check_result(Server, ok), - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- -ssl3_erlang_client_openssl_server_client_cert(doc) -> +erlang_client_openssl_server_client_cert(doc) -> ["Test erlang client with openssl server when client sends cert"]; -ssl3_erlang_client_openssl_server_client_cert(suite) -> +erlang_client_openssl_server_client_cert(suite) -> []; -ssl3_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> +erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), ClientOpts = ?config(client_verification_opts, Config), @@ -762,10 +697,10 @@ ssl3_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), CaCertFile = proplists:get_value(cacertfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -Verify 2 -ssl3", + ++ " -key " ++ KeyFile ++ " -Verify 2", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -791,11 +726,11 @@ ssl3_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -ssl3_erlang_server_openssl_client_client_cert(doc) -> +erlang_server_openssl_client_client_cert(doc) -> ["Test erlang server with openssl client when client sends cert"]; -ssl3_erlang_server_openssl_client_client_cert(suite) -> +erlang_server_openssl_client_client_cert(suite) -> []; -ssl3_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> +erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), ClientOpts = ?config(client_verification_opts, Config), @@ -816,10 +751,10 @@ ssl3_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> CaCertFile = proplists:get_value(cacertfile, ClientOpts), CertFile = proplists:get_value(certfile, ClientOpts), KeyFile = proplists:get_value(keyfile, ClientOpts), - + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ - " -host localhost -ssl3", + ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++ + " -host localhost", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -837,15 +772,15 @@ ssl3_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -ssl3_erlang_server_erlang_client_client_cert(doc) -> +erlang_server_erlang_client_client_cert(doc) -> ["Test erlang server with erlang client when client sends cert"]; -ssl3_erlang_server_erlang_client_client_cert(suite) -> +erlang_server_erlang_client_client_cert(suite) -> []; -ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> +erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, true), ServerOpts = ?config(server_verification_opts, Config), ClientOpts = ?config(client_verification_opts, Config), - + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Data = "From erlang to erlang", @@ -867,7 +802,7 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast {mfa, {ssl, send, [Data]}}, {options, - [{versions, [sslv3]} | ClientOpts]}]), + [{versions, [Version]} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -875,215 +810,8 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> ssl_test_lib:close(Client), process_flag(trap_exit, false), ok. - - -%%-------------------------------------------------------------------- - -tls1_erlang_client_openssl_server(doc) -> - ["Test erlang client with openssl server"]; -tls1_erlang_client_openssl_server(suite) -> - []; -tls1_erlang_client_openssl_server(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_opts, Config), - ClientOpts = ?config(client_opts, Config), - - - test_server:format("Server Opts", [ServerOpts]), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Port = ssl_test_lib:inet_port(node()), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -tls1", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - - wait_for_openssl_server(), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - connection_info, [tlsv1]}}, - {options, - [{versions, [tlsv1]} | ClientOpts]}]), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- - -tls1_erlang_server_openssl_client(doc) -> - ["Test erlang server with openssl client"]; -tls1_erlang_server_openssl_client(suite) -> - []; -tls1_erlang_server_openssl_client(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_opts, Config), - - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, - {?MODULE, connection_info, [tlsv1]}}, - {options, - [{versions, [tlsv1]} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ - " -host localhost -tls1", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- - -tls1_erlang_client_openssl_server_client_cert(doc) -> - ["Test erlang client with openssl server when client sends cert"]; -tls1_erlang_client_openssl_server_client_cert(suite) -> - []; -tls1_erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_verification_opts, Config), - ClientOpts = ?config(client_verification_opts, Config), - - {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Port = ssl_test_lib:inet_port(node()), - CaCertFile = proplists:get_value(cacertfile, ServerOpts), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -Verify 2 -tls1", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - - wait_for_openssl_server(), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, ClientOpts}]), - port_command(OpensslPort, Data), - - ssl_test_lib:check_result(Client, ok), - - %% Clean close down! Server needs to be closed first !! - close_port(OpensslPort), - ssl_test_lib:close(Client), - process_flag(trap_exit, false), - ok. - %%-------------------------------------------------------------------- -tls1_erlang_server_openssl_client_client_cert(doc) -> - ["Test erlang server with openssl client when client sends cert"]; -tls1_erlang_server_openssl_client_client_cert(suite) -> - []; -tls1_erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_verification_opts, Config), - ClientOpts = ?config(client_verification_opts, Config), - - {_, ServerNode, _} = ssl_test_lib:run_where(Config), - - Data = "From openssl to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, - [{verify , verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - CaCertFile = proplists:get_value(cacertfile, ClientOpts), - CertFile = proplists:get_value(certfile, ClientOpts), - KeyFile = proplists:get_value(keyfile, ClientOpts), - - Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ - " -host localhost -tls1", - - test_server:format("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - port_command(OpenSslPort, Data), - - ssl_test_lib:check_result(Server, ok), - - %% Clean close down! Server needs to be closed first !! - ssl_test_lib:close(Server), - close_port(OpenSslPort), - process_flag(trap_exit, false), - ok. - -%%-------------------------------------------------------------------- -tls1_erlang_server_erlang_client_client_cert(doc) -> - ["Test erlang server with erlang client when client sends cert"]; -tls1_erlang_server_erlang_client_client_cert(suite) -> - []; -tls1_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ServerOpts = ?config(server_verification_opts, Config), - ClientOpts = ?config(client_verification_opts, Config), - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Data = "From erlang to erlang", - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, - {options, - [{verify , verify_peer} - | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {ssl, send, [Data]}}, - {options, - [{versions, [tlsv1]} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - ssl_test_lib:close(Server), - process_flag(trap_exit, false), - ok. -%%-------------------------------------------------------------------- - ciphers_rsa_signed_certs(doc) -> ["Test cipher suites that uses rsa certs"]; @@ -1190,16 +918,6 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> process_flag(trap_exit, false), Return. - -version_flag(tlsv1) -> - " -tls1 "; -version_flag('tlsv1.1') -> - " -tls1_1 "; -version_flag('tlsv1.2') -> - " -tls1_2 "; -version_flag(sslv3) -> - " -ssl3 ". - %%-------------------------------------------------------------------- erlang_client_bad_openssl_server(doc) -> [""]; @@ -1215,8 +933,8 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -1230,7 +948,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> {from, self()}, {mfa, {?MODULE, server_sent_garbage, []}}, {options, - [{versions, [tlsv1]} | ClientOpts]}]), + [{versions, [Version]} | ClientOpts]}]), %% Send garbage port_command(OpensslPort, ?OPENSSL_GARBAGE), @@ -1249,7 +967,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> {from, self()}, {mfa, {ssl_test_lib, no_result_msg, []}}, {options, - [{versions, [tlsv1]} | ClientOpts]}]), + [{versions, [Version]} | ClientOpts]}]), %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), @@ -1275,8 +993,8 @@ expired_session(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(node()), CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", test_server:format("openssl cmd: ~p~n", [Cmd]), @@ -1441,15 +1159,35 @@ wait_for_openssl_server() -> %% more so than sleep!) test_server:sleep(?SLEEP) end. + +version_flag(tlsv1) -> + " -tls1 "; +version_flag('tlsv1.1') -> + " -tls1_1 "; +version_flag('tlsv1.2') -> + " -tls1_2 "; +version_flag(sslv3) -> + " -ssl3 ". +check_sane_openssl_tls_client_renegotaite(Config) -> + case proplists:get_value(name, ?config(tc_group_properties, Config)) of + Version when Version == 'tlsv1.2'; Version == 'tlsv1.1' -> + case os:cmd("openssl version") of + "OpenSSL 1.0.1 " ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; + _ -> + Config + end + end. + check_sane_openssl_renegotaite(Config) -> case os:cmd("openssl version") of "OpenSSL 0.9.8" ++ _ -> - {skip, "Known renegotiation bug in OppenSSL"}; + {skip, "Known renegotiation bug in OpenSSL"}; "OpenSSL 0.9.7" ++ _ -> - {skip, "Known renegotiation bug in OppenSSL"}; + {skip, "Known renegotiation bug in OpenSSL"}; "OpenSSL 1.0.1c" ++ _ -> - {skip, "Known renegotiation bug in OppenSSL"}; + {skip, "Known renegotiation bug in OpenSSL"}; _ -> Config end. @@ -1465,7 +1203,23 @@ check_sane_openssl_sslv2(Config) -> check_sane_openssl_dsa(Config) -> case os:cmd("openssl version") of "OpenSSL 1.0.1" ++ _ -> - {skip, "known dsa bug in openssl"}; + {skip, "known dsa bug in OpenSSL"}; _ -> Config end. + +check_sane_openssl_version(Version) -> + case {Version, os:cmd("openssl version")} of + {_, "OpenSSL 1.0.1" ++ _} -> + true; + {'tlsv1.2', "OpenSSL 1.0" ++ _} -> + false; + {'tlsv1.1', "OpenSSL 1.0" ++ _} -> + false; + {'tlsv1.2', "OpenSSL 0" ++ _} -> + false; + {'tlsv1.1', "OpenSSL 0" ++ _} -> + false; + {_, _} -> + true + end. -- cgit v1.2.3 From efcf7a86cd03799671bd518a20dfb84d34ed11d7 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 27 Jun 2012 13:28:37 +0200 Subject: ssl: IDEA cipher is deprecated by TLS 1.2 As we did not yet support IDEA ciphers and they have now become deprecated we skip supporting them altogether. --- lib/ssl/src/ssl_cipher.erl | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 8b6d5ea4ea..86b09b3f32 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -93,10 +93,6 @@ cipher(?AES, CipherState, Mac, Fragment, Version) -> (Key, IV, T) when byte_size(Key) =:= 32 -> crypto:aes_cbc_256_encrypt(Key, IV, T) end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version). -%% cipher(?IDEA, CipherState, Mac, Fragment) -> -%% block_cipher(fun(Key, IV, T) -> -%% crypto:idea_cbc_encrypt(Key, IV, T) -%% end, block_size(idea_cbc), CipherState, Mac, Fragment); build_cipher_block(BlockSz, Mac, Fragment) -> TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1, @@ -163,10 +159,6 @@ decipher(?AES, HashSz, CipherState, Fragment, Version) -> (Key, IV, T) when byte_size(Key) =:= 32 -> crypto:aes_cbc_256_decrypt(Key, IV, T) end, CipherState, HashSz, Fragment, Version). -%% decipher(?IDEA, HashSz, CipherState, Fragment, Version) -> -%% block_decipher(fun(Key, IV, T) -> -%% crypto:idea_cbc_decrypt(Key, IV, T) -%% end, CipherState, HashSz, Fragment, Version); block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, HashSz, Fragment, Version) -> @@ -238,11 +230,9 @@ suite_definition(?TLS_NULL_WITH_NULL_NULL) -> %% {rsa, null, sha, default_prf}; suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> {rsa, rc4_128, md5, default_prf}; -suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> +suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> {rsa, rc4_128, sha, default_prf}; -%% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> -%% {rsa, idea_cbc, sha, default_prf}; -suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> +suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> {rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> {rsa, '3des_ede_cbc', sha, default_prf}; @@ -324,8 +314,6 @@ suite({rsa, rc4_128, md5}) -> ?TLS_RSA_WITH_RC4_128_MD5; suite({rsa, rc4_128, sha}) -> ?TLS_RSA_WITH_RC4_128_SHA; -%% suite({rsa, idea_cbc, sha}) -> -%% ?TLS_RSA_WITH_IDEA_CBC_SHA; suite({rsa, des_cbc, sha}) -> ?TLS_RSA_WITH_DES_CBC_SHA; suite({rsa, '3des_ede_cbc', sha}) -> @@ -420,8 +408,6 @@ openssl_suite("DHE-DSS-AES128-SHA") -> ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; openssl_suite("AES128-SHA") -> ?TLS_RSA_WITH_AES_128_CBC_SHA; -%%openssl_suite("IDEA-CBC-SHA") -> -%% ?TLS_RSA_WITH_IDEA_CBC_SHA; openssl_suite("RC4-SHA") -> ?TLS_RSA_WITH_RC4_128_SHA; openssl_suite("RC4-MD5") -> @@ -453,8 +439,6 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> "DHE-DSS-AES128-SHA"; openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA) -> "AES128-SHA"; -%% openssl_suite_name(?TLS_RSA_WITH_IDEA_CBC_SHA) -> -%% "IDEA-CBC-SHA"; openssl_suite_name(?TLS_RSA_WITH_RC4_128_SHA) -> "RC4-SHA"; openssl_suite_name(?TLS_RSA_WITH_RC4_128_MD5) -> @@ -512,9 +496,6 @@ filter(DerCert, Ciphers) -> bulk_cipher_algorithm(null) -> ?NULL; -%% Not supported yet -%% bulk_cipher_algorithm(idea_cbc) -> -%% ?IDEA; bulk_cipher_algorithm(rc4_128) -> ?RC4; bulk_cipher_algorithm(des_cbc) -> @@ -529,8 +510,7 @@ type(Cipher) when Cipher == null; Cipher == rc4_128 -> ?STREAM; -type(Cipher) when Cipher == idea_cbc; - Cipher == des_cbc; +type(Cipher) when Cipher == des_cbc; Cipher == '3des_ede_cbc'; Cipher == aes_128_cbc; Cipher == aes_256_cbc -> @@ -538,8 +518,7 @@ type(Cipher) when Cipher == idea_cbc; key_material(null) -> 0; -key_material(Cipher) when Cipher == idea_cbc; - Cipher == rc4_128 -> +key_material(rc4_128) -> 16; key_material(des_cbc) -> 8; @@ -552,8 +531,7 @@ key_material(aes_256_cbc) -> expanded_key_material(null) -> 0; -expanded_key_material(Cipher) when Cipher == idea_cbc; - Cipher == rc4_128 -> +expanded_key_material(rc4_128) -> 16; expanded_key_material(Cipher) when Cipher == des_cbc -> 8; @@ -568,8 +546,7 @@ effective_key_bits(null) -> 0; effective_key_bits(des_cbc) -> 56; -effective_key_bits(Cipher) when Cipher == idea_cbc; - Cipher == rc4_128; +effective_key_bits(Cipher) when Cipher == rc4_128; Cipher == aes_128_cbc -> 128; effective_key_bits('3des_ede_cbc') -> @@ -583,8 +560,7 @@ iv_size(Cipher) when Cipher == null; iv_size(Cipher) -> block_size(Cipher). -block_size(Cipher) when Cipher == idea_cbc; - Cipher == des_cbc; +block_size(Cipher) when Cipher == des_cbc; Cipher == '3des_ede_cbc' -> 8; @@ -736,7 +712,6 @@ rsa_suites() -> ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA256, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, ?TLS_RSA_WITH_DES_CBC_SHA]. -- cgit v1.2.3 From a0bd4951be74a5db1c382a7e19432903db10e576 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 29 Jun 2012 14:48:44 +0200 Subject: ssl: Dialyzer fixes --- lib/ssl/src/ssl_certificate.erl | 2 +- lib/ssl/src/ssl_certificate_db.erl | 14 ++++++-------- lib/ssl/src/ssl_handshake.erl | 33 +++++++++++++++------------------ lib/ssl/src/ssl_manager.erl | 4 ++-- 4 files changed, 24 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 0931b86782..605c267144 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -103,7 +103,7 @@ certificate_chain(OwnCert, CertDbHandle, CertsDbRef) -> ErlCert = public_key:pkix_decode_cert(OwnCert, otp), certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert]). %%-------------------------------------------------------------------- --spec file_to_certificats(string(), term()) -> [der_cert()]. +-spec file_to_certificats(binary(), term()) -> [der_cert()]. %% %% Description: Return list of DER encoded certificates. %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index 01ddf056c9..67d00f0da7 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -106,7 +106,7 @@ add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) -> {ok, Ref}; [Content] -> Ref = make_ref(), - insert(Ref, [], 1, RefDb), + update_counter(Ref, 1, RefDb), insert(MD5, {Content, Ref}, PemChache), add_certs_from_pem(Content, Ref, CertsDb), {ok, Ref}; @@ -114,8 +114,8 @@ add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) -> new_trusted_cert_entry({MD5, File}, Db) end. %%-------------------------------------------------------------------- --spec cache_pem_file(string(), [db_handle()]) -> term(). --spec cache_pem_file(reference(), string(), [db_handle()]) -> term(). +-spec cache_pem_file({binary(), binary()}, [db_handle()]) -> term(). +-spec cache_pem_file(reference(), {binary(), binary()}, [db_handle()]) -> term(). %% %% Description: Cache file as binary in DB %%-------------------------------------------------------------------- @@ -204,10 +204,8 @@ insert(Key, Data, Db) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -insert(Key, [], Count, Db) -> - true = ets:insert(Db, {Key, Count}); -insert(Key, Data, Count, Db) -> - true = ets:insert(Db, {Key, Count, Data}). +update_counter(Key, Count, Db) -> + true = ets:insert(Db, {Key, Count}). remove_certs(Ref, CertsDb) -> ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}). @@ -236,7 +234,7 @@ add_certs(Cert, Ref, CertsDb) -> new_trusted_cert_entry(FileRef, [CertsDb, RefDb, _] = Db) -> Ref = make_ref(), - insert(Ref, [], 1, RefDb), + update_counter(Ref, 1, RefDb), {ok, Content} = cache_pem_file(Ref, FileRef, Db), add_certs_from_pem(Content, Ref, CertsDb), {ok, Ref}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 2957059b74..7edbf3d7c7 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -287,19 +287,6 @@ client_certificate_verify(OwnCert, MasterSecret, Version, %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- -certificate_verify_rsa(Hashes, sha, Signature, PublicKey, {Major, Minor}) - when Major == 3, Minor >= 3 -> - public_key:verify({digest, Hashes}, sha, Signature, PublicKey); -certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor}) - when Major == 3, Minor >= 3 -> - public_key:verify({digest, Hashes}, HashAlgo, Signature, PublicKey); -certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) -> - case public_key:decrypt_public(Signature, PublicKey, - [{rsa_pad, rsa_pkcs1_padding}]) of - Hashes -> true; - _ -> false - end. - certificate_verify(Signature, {?'rsaEncryption', PublicKey, _}, Version, {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) -> Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), @@ -386,7 +373,7 @@ key_exchange(server, Version, {dh, {<>, _}, Signed = digitally_signed(Version, Hash, HashAlgo, PrivateKey), #server_key_exchange{params = ServerDHParams, signed_params = Signed, - hashsign = {HashAlgo, digitally_signed_alg(PrivateKey)}} + hashsign = {HashAlgo, dsa}} end. %%-------------------------------------------------------------------- @@ -543,7 +530,7 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> end. %%-------------------------------------------------------------------- --spec server_key_exchange_hash(md5sha1 | md5 | sha | sha256 | sha384 | sha512, binary()) -> binary(). +-spec server_key_exchange_hash(md5sha | md5 | sha | sha256 | sha384 | sha512, binary()) -> binary(). %% %% Description: Calculate server key exchange hash %%-------------------------------------------------------------------- @@ -1187,9 +1174,6 @@ digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]). -digitally_signed_alg(#'RSAPrivateKey'{} = _Key) -> rsa; -digitally_signed_alg(#'DSAPrivateKey'{} = _Key) -> dsa. - calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); @@ -1233,3 +1217,16 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) -> {unknown, UserState} -> {unknown, {SslState, UserState}} end. + +certificate_verify_rsa(Hashes, sha, Signature, PublicKey, {Major, Minor}) + when Major == 3, Minor >= 3 -> + public_key:verify({digest, Hashes}, sha, Signature, PublicKey); +certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor}) + when Major == 3, Minor >= 3 -> + public_key:verify({digest, Hashes}, HashAlgo, Signature, PublicKey); +certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) -> + case public_key:decrypt_public(Signature, PublicKey, + [{rsa_pad, rsa_pkcs1_padding}]) of + Hashes -> true; + _ -> false + end. diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 3e947af2c9..af2bfa394d 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -86,7 +86,7 @@ start_link_dist(Opts) -> %%-------------------------------------------------------------------- -spec connection_init(binary()| {der, list()}, client | server) -> - {ok, certdb_ref(), db_handle(), db_handle()}. + {ok, certdb_ref(), db_handle(), db_handle(), db_handle(), db_handle()}. %% %% Description: Do necessary initializations for a new connection. %%-------------------------------------------------------------------- @@ -325,7 +325,7 @@ handle_info({clean_cert_db, Ref, File}, case ssl_certificate_db:ref_count(Ref, RefDb, 0) of 0 -> MD5 = crypto:md5(File), - case ssl_certificate_db:lookup_cached_pem(MD5, PemCache) of + case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of [{Content, Ref}] -> ssl_certificate_db:insert(MD5, Content, PemCache); undefined -> -- cgit v1.2.3 From 4f68e36b57bf7b2cc608bf1fb5d50486529bff10 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 9 Aug 2012 15:15:51 +0200 Subject: ssl: Add crypto support check (TLS 1.2 require sha256 support) --- lib/ssl/src/ssl_tls1.erl | 2 -- lib/ssl/test/ssl_basic_SUITE.erl | 15 +++++++++++---- lib/ssl/test/ssl_payload_SUITE.erl | 16 +++++++++++----- lib/ssl/test/ssl_test_lib.erl | 13 +++++++++++++ lib/ssl/test/ssl_to_openssl_SUITE.erl | 6 ++++-- 5 files changed, 39 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index d62ea6e5a4..91b321bcd9 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -222,8 +222,6 @@ hmac_hash(?MD5, Key, Value) -> crypto:md5_mac(Key, Value); hmac_hash(?SHA, Key, Value) -> crypto:sha_mac(Key, Value); -hmac_hash(?MD5SHA, Key, Value) -> - crypto:sha256_mac(Key, Value); hmac_hash(?SHA256, Key, Value) -> crypto:sha256_mac(Key, Value); hmac_hash(?SHA384, Key, Value) -> diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 1cfe8d0367..de883d5425 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -198,11 +198,18 @@ all_versions_groups ()-> init_per_group(GroupName, Config) -> case ssl_test_lib:is_tls_version(GroupName) of true -> - ssl_test_lib:init_tls_version(GroupName); + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, "Missing crypto support"} + end; _ -> - ssl:start() - end, - Config. + ssl:start(), + Config + end. + end_per_group(_GroupName, Config) -> Config. diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index 9633942ac3..c97f97e70b 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -140,13 +140,19 @@ payload_tests() -> init_per_group(GroupName, Config) -> - case ssl_test_lib:is_tls_version(GroupName) of + case ssl_test_lib:is_tls_version(GroupName) of true -> - ssl_test_lib:init_tls_version(GroupName); + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, "Missing crypto support"} + end; _ -> - ssl:start() - end, - Config. + ssl:start(), + Config + end. end_per_group(_GroupName, Config) -> Config. diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 905801fe3d..b39c995552 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -725,3 +725,16 @@ init_tls_version(Version) -> application:load(ssl), application:set_env(ssl, protocol_version, Version), ssl:start(). + +sufficient_crypto_support('tlsv1.2') -> + Data = "Sampl", + Data2 = "e #1", + Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39, + 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>, + try + crypto:sha256_mac(Key, lists:flatten([Data, Data2])), + true + catch _:_ -> false + end; +sufficient_crypto_support(_) -> + true. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index e5f8d4ae4e..ec35c42773 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -112,7 +112,9 @@ special_init(TestCase, Config) special_init(ssl2_erlang_server_openssl_client, Config) -> check_sane_openssl_sslv2(Config); -special_init(ciphers_dsa_signed_certs, Config) -> +special_init(TestCase, Config) when TestCase == erlang_client_openssl_server_dsa_cert; + TestCase == erlang_server_openssl_client_dsa_cert; + TestCase == ciphers_dsa_signed_certs -> check_sane_openssl_dsa(Config); special_init(_, Config) -> @@ -1186,7 +1188,7 @@ check_sane_openssl_renegotaite(Config) -> {skip, "Known renegotiation bug in OpenSSL"}; "OpenSSL 0.9.7" ++ _ -> {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 1.0.1c" ++ _ -> + "OpenSSL 1.0.1" ++ _ -> {skip, "Known renegotiation bug in OpenSSL"}; _ -> Config -- cgit v1.2.3 From ced8f02c4b2ee4de06abba48db459c677611fb36 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 13 Aug 2012 16:00:47 +0200 Subject: ssl: Signture type bug --- lib/ssl/src/ssl_connection.erl | 4 ++-- lib/ssl/src/ssl_handshake.erl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 19847575e5..ad02c6c0cf 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1438,7 +1438,7 @@ certify_server(#state{transport_cb = Transport, key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; key_exchange(#state{role = server, key_algorithm = Algo, - hashsign_algorithm = {HashAlgo, _}, + hashsign_algorithm = HashSignAlgo, diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, @@ -1457,7 +1457,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params, - HashAlgo, ClientRandom, + HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), {BinMsg, ConnectionStates, Handshake} = diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 7edbf3d7c7..5a14841949 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -349,7 +349,7 @@ key_exchange(client, _Version, {dh, <>}) -> key_exchange(server, Version, {dh, {<>, _}, #'DHParameter'{prime = P, base = G}, - HashAlgo, ClientRandom, ServerRandom, PrivateKey}) -> + {HashAlgo, SignAlgo}, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), <> = crypto:mpint(G), PLen = byte_size(PBin), @@ -373,7 +373,7 @@ key_exchange(server, Version, {dh, {<>, _}, Signed = digitally_signed(Version, Hash, HashAlgo, PrivateKey), #server_key_exchange{params = ServerDHParams, signed_params = Signed, - hashsign = {HashAlgo, dsa}} + hashsign = {HashAlgo, SignAlgo}} end. %%-------------------------------------------------------------------- -- cgit v1.2.3 From 859493b164e9e018c0e5f668d1167ad25bda8eac Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 14 Aug 2012 11:34:01 +0200 Subject: ssl: TLS-1.1 and TLS-1.2 support should not be default until R16 --- lib/ssl/src/ssl.erl | 2 +- lib/ssl/src/ssl_internal.hrl | 6 +++--- lib/ssl/src/ssl_record.erl | 26 +++++++++++++++++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 5bd382b8c4..4372a147fa 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -418,7 +418,7 @@ session_info(#sslsocket{pid = Pid, fd = new_ssl}) -> versions() -> Vsns = ssl_record:supported_protocol_versions(), SupportedVsns = [ssl_record:protocol_version(Vsn) || Vsn <- Vsns], - AvailableVsns = ?DEFAULT_SUPPORTED_VERSIONS, + AvailableVsns = ?ALL_SUPPORTED_VERSIONS, [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}]. diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 87f85c5775..b8f2ae3b51 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -69,8 +69,8 @@ -define(TRUE, 0). -define(FALSE, 1). --define(DEFAULT_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). % TODO: This is temporary -%-define(DEFAULT_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). +-define(DEFAULT_SUPPORTED_VERSIONS, [tlsv1, sslv3]). %% Add 'tlsv1.1' in R16 +-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). -record(ssl_options, { versions, % 'tlsv1.2' | 'tlsv1.1' | tlsv1 | sslv3 diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 3bfcff5517..8e93ce4634 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -449,9 +449,9 @@ supported_protocol_versions() -> end, case application:get_env(ssl, protocol_version) of undefined -> - lists:map(Fun, ?DEFAULT_SUPPORTED_VERSIONS); + lists:map(Fun, supported_protocol_versions([])); {ok, []} -> - lists:map(Fun, ?DEFAULT_SUPPORTED_VERSIONS); + lists:map(Fun, supported_protocol_versions([])); {ok, Vsns} when is_list(Vsns) -> Versions = lists:filter(fun is_acceptable_version/1, lists:map(Fun, Vsns)), supported_protocol_versions(Versions); @@ -461,7 +461,16 @@ supported_protocol_versions() -> end. supported_protocol_versions([]) -> - ?DEFAULT_SUPPORTED_VERSIONS; + Vsns = case sufficient_tlsv1_2_crypto_support() of + true -> + %%?ALL_SUPPORTED_VERSIONS; %% Add TlS-1.2 as default in R16 + ?DEFAULT_SUPPORTED_VERSIONS; + false -> + ?DEFAULT_SUPPORTED_VERSIONS + end, + application:set_env(ssl, protocol_version, Vsns), + Vsns; + supported_protocol_versions([_|_] = Vsns) -> Vsns. @@ -694,3 +703,14 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) when N =:= 1; N =:= 2; N =:= 3 -> ssl_tls1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, Length, Fragment). + +sufficient_tlsv1_2_crypto_support() -> + Data = "Sampl", + Data2 = "e #1", + Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39, + 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>, + try + crypto:sha256_mac(Key, lists:flatten([Data, Data2])), + true + catch _:_ -> false + end. -- cgit v1.2.3 From 6c53c50ca047dc006af75dd6045e096a4bd97153 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 16 Aug 2012 11:09:36 +0200 Subject: ssl: Fix rizzo tests to run as intended The Rizzo tests ran both SSL 3.0 and TLS 1.0 tests in the same test case but the new group structure that run all relevant test for all relevant SSL/TLS versions we need to change that to run the protocol version of the group the we are currently running. --- lib/ssl/test/ssl_basic_SUITE.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index de883d5425..ea29fa8f35 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -3947,9 +3947,9 @@ rizzo(doc) -> ["Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as i rizzo(Config) when is_list(Config) -> Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(), Y =/= rc4_128], - run_send_recv_rizzo(Ciphers, Config, sslv3, - {?MODULE, send_recv_result_active_rizzo, []}), - run_send_recv_rizzo(Ciphers, Config, tlsv1, + Prop = ?config(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_rizzo, []}). %%-------------------------------------------------------------------- no_rizzo_rc4(doc) -> @@ -3957,9 +3957,9 @@ no_rizzo_rc4(doc) -> no_rizzo_rc4(Config) when is_list(Config) -> Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(),Y == rc4_128], - run_send_recv_rizzo(Ciphers, Config, sslv3, - {?MODULE, send_recv_result_active_no_rizzo, []}), - run_send_recv_rizzo(Ciphers, Config, tlsv1, + Prop = ?config(tc_group_properties, Config), + Version = proplists:get_value(name, Prop), + run_send_recv_rizzo(Ciphers, Config, Version, {?MODULE, send_recv_result_active_no_rizzo, []}). %%-------------------------------------------------------------------- -- cgit v1.2.3 From 332716f059f291eba836fb46071a9b3e718f43c0 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Wed, 15 Aug 2012 10:52:39 +0200 Subject: ssl: Add Signature Algorithms hello extension from TLS 1.2 This is also avoids triggering some bugs in OpenSSL. --- lib/ssl/src/ssl_cipher.erl | 6 ++- lib/ssl/src/ssl_connection.erl | 16 ++++--- lib/ssl/src/ssl_handshake.erl | 85 ++++++++++++++++++++++++++++------- lib/ssl/src/ssl_handshake.hrl | 15 ++++++- lib/ssl/test/ssl_to_openssl_SUITE.erl | 13 ------ 5 files changed, 95 insertions(+), 40 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 86b09b3f32..358972f522 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -606,7 +606,11 @@ hash_size(md5) -> hash_size(sha) -> 20; hash_size(sha256) -> - 32. + 32; +hash_size(sha384) -> + 48; +hash_size(sha512) -> + 64. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index ad02c6c0cf..c09e07018d 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1606,18 +1606,18 @@ handle_server_key( ?UINT16(GLen), G/binary, ?UINT16(YLen), ServerPublicDhKey/binary>>), - - case verify_dh_params(Version, Signed, Hash, PubKeyInfo) of + + case verify_dh_params(Version, Signed, Hash, HashAlgo, PubKeyInfo) of true -> dh_master_secret(P, G, ServerPublicDhKey, undefined, State); false -> ?ALERT_REC(?FATAL, ?DECRYPT_ERROR) end. -verify_dh_params({3, Minor}, Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) +verify_dh_params({3, Minor}, Signed, Hashes, HashAlgo, {?rsaEncryption, PubKey, _PubKeyParams}) when Minor >= 3 -> - public_key:verify({digest, Hashes}, sha, Signed, PubKey); -verify_dh_params(_Version, Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> + public_key:verify({digest, Hashes}, HashAlgo, Signed, PubKey); +verify_dh_params(_Version, Signed, Hashes, _HashAlgo, {?rsaEncryption, PubKey, _PubKeyParams}) -> case public_key:decrypt_public(Signed, PubKey, [{rsa_pad, rsa_pkcs1_padding}]) of Hashes -> @@ -1625,8 +1625,10 @@ verify_dh_params(_Version, Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParam _ -> false end; -verify_dh_params(_Version, Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) -> - public_key:verify({digest, Hash}, sha, Signed, {PublicKey, PublicKeyParams}). +verify_dh_params(_Version, Signed, Hash, undefined, {?'id-dsa', PublicKey, PublicKeyParams}) -> + public_key:verify({digest, Hash}, sha, Signed, {PublicKey, PublicKeyParams}); +verify_dh_params(_Version, Signed, Hash, HashAlgo, {?'id-dsa', PublicKey, PublicKeyParams}) -> + public_key:verify({digest, Hash}, HashAlgo, Signed, {PublicKey, PublicKeyParams}). dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> PMpint = mpint_binary(Prime), diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 5a14841949..d096bc347d 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -78,7 +78,8 @@ client_hello(Host, Port, ConnectionStates, compression_methods = ssl_record:compressions(), random = SecParams#security_parameters.client_random, renegotiation_info = - renegotiation_info(client, ConnectionStates, Renegotiation) + renegotiation_info(client, ConnectionStates, Renegotiation), + hash_signs = default_hash_signs() }. %%-------------------------------------------------------------------- @@ -121,10 +122,11 @@ hello_request() -> %%-------------------------------------------------------------------- hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, compression_method = Compression, random = Random, - session_id = SessionId, renegotiation_info = Info}, + session_id = SessionId, renegotiation_info = Info, + hash_signs = _HashSigns}, #ssl_options{secure_renegotiate = SecureRenegotation}, ConnectionStates0, Renegotiation) -> - +%%TODO: select hash and signature algorigthm case ssl_record:is_acceptable_version(Version) of true -> case handle_renegotiation_info(client, Info, ConnectionStates0, @@ -143,10 +145,12 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, hello(#client_hello{client_version = ClientVersion, random = Random, cipher_suites = CipherSuites, - renegotiation_info = Info} = Hello, + renegotiation_info = Info, + hash_signs = _HashSigns} = Hello, #ssl_options{versions = Versions, secure_renegotiate = SecureRenegotation} = SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> +%% TODO: select hash and signature algorithm Version = select_version(ClientVersion, Versions), case ssl_record:is_acceptable_version(Version) of true -> @@ -830,16 +834,19 @@ dec_hs(_Version, ?CLIENT_HELLO, <>) -> - - RenegotiationInfo = proplists:get_value(renegotiation_info, dec_hello_extensions(Extensions), - undefined), + HelloExtensions = dec_hello_extensions(Extensions), + RenegotiationInfo = proplists:get_value(renegotiation_info, HelloExtensions, + undefined), + HashSigns = proplists:get_value(hash_signs, HelloExtensions, + undefined), #client_hello{ client_version = {Major,Minor}, random = Random, session_id = Session_ID, cipher_suites = from_2bytes(CipherSuites), compression_methods = Comp_methods, - renegotiation_info = RenegotiationInfo + renegotiation_info = RenegotiationInfo, + hash_signs = HashSigns }; dec_hs(_Version, ?SERVER_HELLO, <>) -> - RenegotiationInfo = proplists:get_value(renegotiation_info, dec_hello_extensions(Extensions, []), - undefined), + HelloExtensions = dec_hello_extensions(Extensions, []), + RenegotiationInfo = proplists:get_value(renegotiation_info, HelloExtensions, + undefined), + HashSigns = proplists:get_value(hash_signs, HelloExtensions, + undefined), #server_hello{ server_version = {Major,Minor}, random = Random, session_id = Session_ID, cipher_suite = Cipher_suite, compression_method = Comp_method, - renegotiation_info = RenegotiationInfo}; + renegotiation_info = RenegotiationInfo, + hash_signs = HashSigns}; dec_hs(_Version, ?CERTIFICATE, <>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; @@ -952,6 +964,15 @@ dec_hello_extensions(<>, Acc) -> + SignAlgoListLen = Len - 2, + <> = ExtData, + HashSignAlgos = [{ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)} || + <> <= SignAlgoList], + dec_hello_extensions(Rest, [{hash_signs, + #hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]); + %% Ignore data following the ClientHello (i.e., %% extensions) if not understood. dec_hello_extensions(<>, Acc) -> @@ -993,14 +1014,19 @@ enc_hs(#client_hello{client_version = {Major, Minor}, session_id = SessionID, cipher_suites = CipherSuites, compression_methods = CompMethods, - renegotiation_info = RenegotiationInfo}, _Version) -> + renegotiation_info = RenegotiationInfo, + hash_signs = HashSigns}, _Version) -> SIDLength = byte_size(SessionID), BinCompMethods = list_to_binary(CompMethods), CmLength = byte_size(BinCompMethods), BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), - Extensions = hello_extensions(RenegotiationInfo), - ExtensionsBin = enc_hello_extensions(Extensions), + Extensions0 = hello_extensions(RenegotiationInfo), + Extensions1 = if + Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); + true -> Extensions0 + end, + ExtensionsBin = enc_hello_extensions(Extensions1), {?CLIENT_HELLO, < SignLen = byte_size(Sign), <>. -%% Renegotiation info, only current extension +hello_extensions(undefined) -> + []; +%% Renegotiation info hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) -> []; hello_extensions(#renegotiation_info{} = Info) -> + [Info]; +hello_extensions(#hash_sign_algos{} = Info) -> [Info]. enc_hello_extensions(Extensions) -> @@ -1105,7 +1135,14 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = I enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest], Acc) -> InfoLen = byte_size(Info), Len = InfoLen +1, - enc_hello_extensions(Rest, <>). + enc_hello_extensions(Rest, <>); + +enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) -> + SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> || + {Hash, Sign} <- HashSignAlgos >>, + ListLen = byte_size(SignAlgoList), + Len = ListLen + 2, + enc_hello_extensions(Rest, <>). from_3bytes(Bin3) -> @@ -1230,3 +1267,17 @@ certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) -> Hashes -> true; _ -> false end. + +-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}). +-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}). + +-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)). + +default_hash_signs() -> + #hash_sign_algos{hash_sign_algos = + [?TLSEXT_SIGALG(sha512), + ?TLSEXT_SIGALG(sha384), + ?TLSEXT_SIGALG(sha256), + ?TLSEXT_SIGALG(sha), + ?TLSEXT_SIGALG_DSA(sha), + ?TLSEXT_SIGALG_RSA(md5)]}. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index abe2fa5261..9967a265c1 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -97,7 +97,8 @@ session_id, % opaque SessionID<0..32> cipher_suites, % cipher_suites<2..2^16-1> compression_methods, % compression_methods<1..2^8-1>, - renegotiation_info + renegotiation_info, + hash_signs % supported combinations of hashes/signature algos }). -record(server_hello, { @@ -106,7 +107,8 @@ session_id, % opaque SessionID<0..32> cipher_suite, % cipher_suites compression_method, % compression_method - renegotiation_info + renegotiation_info, + hash_signs % supported combinations of hashes/signature algos }). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -224,6 +226,15 @@ renegotiated_connection }). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Signature Algorithms RFC 5746 section 7.4.1.4.1. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(SIGNATURE_ALGORITHMS_EXT, 13). + +-record(hash_sign_algos, { + hash_sign_algos + }). + -endif. % -ifdef(ssl_handshake). diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index ec35c42773..ce481919f2 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -1170,17 +1170,6 @@ version_flag('tlsv1.2') -> " -tls1_2 "; version_flag(sslv3) -> " -ssl3 ". - -check_sane_openssl_tls_client_renegotaite(Config) -> - case proplists:get_value(name, ?config(tc_group_properties, Config)) of - Version when Version == 'tlsv1.2'; Version == 'tlsv1.1' -> - case os:cmd("openssl version") of - "OpenSSL 1.0.1 " ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; - _ -> - Config - end - end. check_sane_openssl_renegotaite(Config) -> case os:cmd("openssl version") of @@ -1188,8 +1177,6 @@ check_sane_openssl_renegotaite(Config) -> {skip, "Known renegotiation bug in OpenSSL"}; "OpenSSL 0.9.7" ++ _ -> {skip, "Known renegotiation bug in OpenSSL"}; - "OpenSSL 1.0.1" ++ _ -> - {skip, "Known renegotiation bug in OpenSSL"}; _ -> Config end. -- cgit v1.2.3 From 191931c58ebc9f18efb2422d296b4a246119ab83 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Wed, 15 Aug 2012 18:44:31 +0200 Subject: ssl: TLS 1.2: fix Certificate Request list of Accepted Signatur/Hash combinations --- lib/ssl/src/ssl_handshake.erl | 13 +++++++------ lib/ssl/test/ssl_to_openssl_SUITE.erl | 13 ------------- 2 files changed, 7 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index d096bc347d..9d251054c9 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -322,7 +322,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> #security_parameters{cipher_suite = CipherSuite}} = ssl_record:pending_connection_state(ConnectionStates, read), Types = certificate_types(CipherSuite), - HashSigns = hashsign_algorithms(CipherSuite), + HashSigns = default_hash_signs(), Authorities = certificate_authorities(CertDbHandle, CertDbRef), #certificate_request{ certificate_types = Types, @@ -911,8 +911,10 @@ dec_hs({Major, Minor}, ?CERTIFICATE_REQUEST, ?UINT16(HashSignsLen), HashSigns:HashSignsLen/binary, ?UINT16(CertAuthsLen), CertAuths:CertAuthsLen/binary>>) when Major == 3, Minor >= 3 -> + HashSignAlgos = [{ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)} || + <> <= HashSigns], #certificate_request{certificate_types = CertTypes, - hashsign_algorithms = HashSigns, + hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSignAlgos}, certificate_authorities = CertAuths}; dec_hs(_Version, ?CERTIFICATE_REQUEST, <> }; enc_hs(#certificate_request{certificate_types = CertTypes, - hashsign_algorithms = HashSigns, + hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSignAlgos}, certificate_authorities = CertAuths}, {Major, Minor}) when Major == 3, Minor >= 3 -> + HashSigns= << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> || + {Hash, Sign} <- HashSignAlgos >>, CertTypesLen = byte_size(CertTypes), HashSignsLen = byte_size(HashSigns), CertAuthsLen = byte_size(CertAuths), @@ -1178,9 +1182,6 @@ hashsign_enc(HashAlgo, SignAlgo) -> Sign = ssl_cipher:sign_algorithm(SignAlgo), <>. -hashsign_algorithms(_) -> - hashsign_enc(sha, rsa). - certificate_authorities(CertDbHandle, CertDbRef) -> Authorities = certificate_authorities_from_db(CertDbHandle, CertDbRef), Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) -> diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index ce481919f2..05ed325ae2 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -112,11 +112,6 @@ special_init(TestCase, Config) special_init(ssl2_erlang_server_openssl_client, Config) -> check_sane_openssl_sslv2(Config); -special_init(TestCase, Config) when TestCase == erlang_client_openssl_server_dsa_cert; - TestCase == erlang_server_openssl_client_dsa_cert; - TestCase == ciphers_dsa_signed_certs -> - check_sane_openssl_dsa(Config); - special_init(_, Config) -> Config. @@ -1189,14 +1184,6 @@ check_sane_openssl_sslv2(Config) -> Config end. -check_sane_openssl_dsa(Config) -> - case os:cmd("openssl version") of - "OpenSSL 1.0.1" ++ _ -> - {skip, "known dsa bug in OpenSSL"}; - _ -> - Config - end. - check_sane_openssl_version(Version) -> case {Version, os:cmd("openssl version")} of {_, "OpenSSL 1.0.1" ++ _} -> -- cgit v1.2.3 From be66663142da66e013ad65c4ebe429d9391312b0 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 16 Aug 2012 11:23:33 +0200 Subject: ssl: TLS 1.2: fix hash and signature handling with TLS 1.2 the hash and signature on a certify message can differ from the defaults. So we have to make sure to always use the hash and signature algorithm indicated in the handshake message --- lib/ssl/src/ssl_connection.erl | 9 +++++++-- lib/ssl/src/ssl_handshake.erl | 2 +- lib/ssl/src/ssl_tls1.erl | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index c09e07018d..fc2488952d 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -640,14 +640,18 @@ cipher(#hello_request{}, State0) -> {Record, State} = next_record(State0), next_state(cipher, hello, Record, State); -cipher(#certificate_verify{signature = Signature}, +cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign}, #state{role = server, public_key_info = PublicKeyInfo, negotiated_version = Version, session = #session{master_secret = MasterSecret}, - hashsign_algorithm = HashSign, + hashsign_algorithm = ConnectionHashSign, tls_handshake_history = Handshake } = State0) -> + HashSign = case CertHashSign of + {_, _} -> CertHashSign; + _ -> ConnectionHashSign + end, case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, Version, HashSign, MasterSecret, Handshake) of valid -> @@ -1253,6 +1257,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, hashsign_algorithm = HashSign, tls_handshake_history = Handshake0} = State) -> + %%TODO: for TLS 1.2 we can choose a different/stronger HashSign combination for this. case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, Version, HashSign, PrivateKey, Handshake0) of #certificate_verify{} = Verified -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 9d251054c9..497f778bc2 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -927,7 +927,7 @@ dec_hs({Major, Minor}, ?CERTIFICATE_VERIFY,<= 3 -> #certificate_verify{hashsign_algorithm = hashsign_dec(HashSign), signature = Signature}; dec_hs(_Version, ?CERTIFICATE_VERIFY,<>)-> - #certificate_verify{hashsign_algorithm = {unknown, unknown}, signature = Signature}; + #certificate_verify{signature = Signature}; dec_hs(_Version, ?CLIENT_KEY_EXCHANGE, PKEPMS) -> #client_key_exchange{exchange_keys = PKEPMS}; dec_hs(_Version, ?FINISHED, VerifyData) -> diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 91b321bcd9..1daf9640ab 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -80,11 +80,11 @@ certificate_verify(md5sha, _Version, Handshake) -> SHA = crypto:sha(Handshake), <>; -certificate_verify(sha, _Version, Handshake) -> - crypto:sha(Handshake). +certificate_verify(HashAlgo, _Version, Handshake) -> + Hash = crypto:hash(HashAlgo, Handshake). -spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(), - integer(), integer()) -> {binary(), binary(), binary(), + integer(), integer()) -> {binary(), binary(), binary(), binary(), binary(), binary()}. setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, -- cgit v1.2.3 From 8f97b428eb8f2fb89c3f9ec348f577304b1b9131 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 21 Aug 2012 14:58:15 +0200 Subject: ssl: Fix inet header option to behave as in inet This options is useless and should be deprecated. But we behave as inet does for now! --- lib/ssl/src/ssl_connection.erl | 2 +- lib/ssl/test/ssl_packet_SUITE.erl | 355 ++++++++++++++++++++++++++++++-------- 2 files changed, 281 insertions(+), 76 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index fc2488952d..86555dd0d9 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1883,7 +1883,7 @@ format_reply(list, _,_, Data) -> binary_to_list(Data). header(0, <<>>) -> - <<>>; + []; header(_, <<>>) -> []; header(0, Binary) -> diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 9238dcadf9..8ce80cb725 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -122,15 +122,56 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> + [ + {group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'} + ]. + +groups() -> + [{'tlsv1.2', [], packet_tests()}, + {'tlsv1.1', [], packet_tests()}, + {'tlsv1', [], packet_tests()}, + {'sslv3', [], packet_tests()}]. + +packet_tests() -> + active_packet_tests() ++ active_once_packet_tests() ++ passive_packet_tests() ++ + [packet_send_to_large, + packet_cdr_decode, packet_cdr_decode_list, + packet_http_decode, packet_http_decode_list, + packet_http_bin_decode_multi, + packet_line_decode, packet_line_decode_list, + packet_asn1_decode, packet_asn1_decode_list, + packet_tpkt_decode, packet_tpkt_decode_list, + packet_sunrm_decode, packet_sunrm_decode_list]. + +passive_packet_tests() -> [packet_raw_passive_many_small, packet_0_passive_many_small, packet_1_passive_many_small, packet_2_passive_many_small, packet_4_passive_many_small, - packet_raw_passive_some_big, packet_0_passive_some_big, - packet_1_passive_some_big, packet_2_passive_some_big, + packet_raw_passive_some_big, + packet_0_passive_some_big, + packet_1_passive_some_big, + packet_2_passive_some_big, packet_4_passive_some_big, - packet_raw_active_once_many_small, + packet_httph_passive, + packet_httph_bin_passive, + packet_http_error_passive, + packet_wait_passive, + packet_size_passive, + packet_baddata_passive, + %% inet header option should be deprecated! + header_decode_one_byte_passive, + header_decode_two_bytes_passive, + header_decode_two_bytes_two_sent_passive, + header_decode_two_bytes_one_sent_passive + ]. + +active_once_packet_tests() -> + [packet_raw_active_once_many_small, packet_0_active_once_many_small, packet_1_active_once_many_small, packet_2_active_once_many_small, @@ -140,45 +181,49 @@ all() -> packet_1_active_once_some_big, packet_2_active_once_some_big, packet_4_active_once_some_big, - packet_raw_active_many_small, - packet_0_active_many_small, packet_1_active_many_small, - packet_2_active_many_small, packet_4_active_many_small, - packet_raw_active_some_big, packet_0_active_some_big, - packet_1_active_some_big, packet_2_active_some_big, - packet_4_active_some_big, packet_send_to_large, - packet_wait_passive, packet_wait_active, - packet_baddata_passive, packet_baddata_active, - packet_size_passive, packet_size_active, - packet_cdr_decode, packet_cdr_decode_list, - packet_http_decode, packet_http_decode_list, - packet_http_bin_decode_multi, packet_http_error_passive, - packet_httph_active, packet_httph_bin_active, - packet_httph_active_once, packet_httph_bin_active_once, - packet_httph_passive, packet_httph_bin_passive, - packet_line_decode, packet_line_decode_list, - packet_asn1_decode, packet_asn1_decode_list, - packet_tpkt_decode, packet_tpkt_decode_list, - packet_sunrm_decode, packet_sunrm_decode_list, - {group, header} + packet_httph_active_once, + packet_httph_bin_active_once ]. -groups() -> - [{header, [], [ header_decode_one_byte, - header_decode_two_bytes, - header_decode_two_bytes_one_sent, - header_decode_two_bytes_two_sent]}]. - -init_per_group(header, Config) -> - %% Does not work when N < 2 due to rizzo/duong countermeasure - case ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()) of - {3, N} when N < 2 -> - {skip, ""}; +active_packet_tests() -> + [packet_raw_active_many_small, + packet_0_active_many_small, + packet_1_active_many_small, + packet_2_active_many_small, + packet_4_active_many_small, + packet_raw_active_some_big, + packet_0_active_some_big, + packet_1_active_some_big, + packet_2_active_some_big, + packet_4_active_some_big, + packet_httph_active, + packet_httph_bin_active, + packet_wait_active, + packet_baddata_active, + packet_size_active, + %% inet header option should be deprecated! + header_decode_one_byte_active, + header_decode_two_bytes_active, + header_decode_two_bytes_two_sent_active, + header_decode_two_bytes_one_sent_active + ]. + + +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, "Missing crypto support"} + end; _ -> + ssl:start(), Config - end; + end. -init_per_group(_, Config) -> - Config. end_per_group(_GroupName, Config) -> Config. @@ -2437,11 +2482,11 @@ packet_sunrm_decode_list(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -header_decode_one_byte(doc) -> +header_decode_one_byte_active(doc) -> ["Test setting the packet option {header, 1}"]; -header_decode_one_byte(suite) -> +header_decode_one_byte_active(suite) -> []; -header_decode_one_byte(Config) when is_list(Config) -> +header_decode_one_byte_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2450,7 +2495,7 @@ header_decode_one_byte(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, server_header_decode, + {mfa, {?MODULE, server_header_decode_active, [Data, [11 | <<"Hello world">>]]}}, {options, [{active, true}, binary, {header,1}|ServerOpts]}]), @@ -2459,7 +2504,7 @@ header_decode_one_byte(Config) when is_list(Config) -> Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, client_header_decode, + {mfa, {?MODULE, client_header_decode_active, [Data, [11 | <<"Hello world">> ]]}}, {options, [{active, true}, {header, 1}, binary | ClientOpts]}]), @@ -2471,11 +2516,11 @@ header_decode_one_byte(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes(doc) -> +header_decode_two_bytes_active(doc) -> ["Test setting the packet option {header, 2}"]; -header_decode_two_bytes(suite) -> +header_decode_two_bytes_active(suite) -> []; -header_decode_two_bytes(Config) when is_list(Config) -> +header_decode_two_bytes_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2484,7 +2529,7 @@ header_decode_two_bytes(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, server_header_decode, + {mfa, {?MODULE, server_header_decode_active, [Data, [11, $H | <<"ello world">> ]]}}, {options, [{active, true}, binary, {header,2}|ServerOpts]}]), @@ -2493,7 +2538,7 @@ header_decode_two_bytes(Config) when is_list(Config) -> Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, client_header_decode, + {mfa, {?MODULE, client_header_decode_active, [Data, [11, $H | <<"ello world">> ]]}}, {options, [{active, true}, {header, 2}, binary | ClientOpts]}]), @@ -2506,11 +2551,11 @@ header_decode_two_bytes(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_two_sent(doc) -> - ["Test setting the packet option {header, 2} and sending on byte"]; -header_decode_two_bytes_two_sent(suite) -> +header_decode_two_bytes_two_sent_active(doc) -> + ["Test setting the packet option {header, 2} and sending two byte"]; +header_decode_two_bytes_two_sent_active(suite) -> []; -header_decode_two_bytes_two_sent(Config) when is_list(Config) -> +header_decode_two_bytes_two_sent_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2519,8 +2564,8 @@ header_decode_two_bytes_two_sent(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, server_header_decode, - [Data, [$H, $e | <<>> ]]}}, + {mfa, {?MODULE, server_header_decode_active, + [Data, [$H, $e]]}}, {options, [{active, true}, binary, {header,2}|ServerOpts]}]), @@ -2528,8 +2573,8 @@ header_decode_two_bytes_two_sent(Config) when is_list(Config) -> Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, client_header_decode, - [Data, [$H, $e | <<>> ]]}}, + {mfa, {?MODULE, client_header_decode_active, + [Data, [$H, $e]]}}, {options, [{active, true}, {header, 2}, binary | ClientOpts]}]), @@ -2541,11 +2586,11 @@ header_decode_two_bytes_two_sent(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -header_decode_two_bytes_one_sent(doc) -> - ["Test setting the packet option {header, 2} and sending on byte"]; -header_decode_two_bytes_one_sent(suite) -> +header_decode_two_bytes_one_sent_active(doc) -> + ["Test setting the packet option {header, 2} and sending one byte"]; +header_decode_two_bytes_one_sent_active(suite) -> []; -header_decode_two_bytes_one_sent(Config) when is_list(Config) -> +header_decode_two_bytes_one_sent_active(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2554,7 +2599,7 @@ header_decode_two_bytes_one_sent(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, server_header_decode, + {mfa, {?MODULE, server_header_decode_active, [Data, "H"]}}, {options, [{active, true}, binary, {header,2}|ServerOpts]}]), @@ -2563,7 +2608,7 @@ header_decode_two_bytes_one_sent(Config) when is_list(Config) -> Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, client_header_decode, + {mfa, {?MODULE, client_header_decode_active, [Data, "H"]}}, {options, [{active, true}, {header, 2}, binary | ClientOpts]}]), @@ -2573,6 +2618,143 @@ header_decode_two_bytes_one_sent(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- + +header_decode_one_byte_passive(doc) -> + ["Test setting the packet option {header, 1}"]; +header_decode_one_byte_passive(suite) -> + []; +header_decode_one_byte_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = <<11:8, "Hello world">>, + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_header_decode_passive, + [Data, [11 | <<"Hello world">>]]}}, + {options, [{active, false}, binary, + {header,1}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_header_decode_passive, + [Data, [11 | <<"Hello world">> ]]}}, + {options, [{active, false}, {header, 1}, + binary | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +header_decode_two_bytes_passive(doc) -> + ["Test setting the packet option {header, 2}"]; +header_decode_two_bytes_passive(suite) -> + []; +header_decode_two_bytes_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = <<11:8, "Hello world">>, + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_header_decode_passive, + [Data, [11, $H | <<"ello world">> ]]}}, + {options, [{active, false}, binary, + {header,2}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_header_decode_passive, + [Data, [11, $H | <<"ello world">> ]]}}, + {options, [{active, false}, {header, 2}, + binary | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- + +header_decode_two_bytes_two_sent_passive(doc) -> + ["Test setting the packet option {header, 2} and sending two byte"]; +header_decode_two_bytes_two_sent_passive(suite) -> + []; +header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = <<"He">>, + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_header_decode_passive, + [Data, [$H, $e]]}}, + {options, [{active, false}, binary, + {header,2}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_header_decode_passive, + [Data, [$H, $e]]}}, + {options, [{active, false}, {header, 2}, + binary | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- + +header_decode_two_bytes_one_sent_passive(doc) -> + ["Test setting the packet option {header, 2} and sending one byte"]; +header_decode_two_bytes_one_sent_passive(suite) -> + []; +header_decode_two_bytes_one_sent_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = <<"H">>, + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_header_decode_passive, + [Data, "H"]}}, + {options, [{active, false}, binary, + {header,2}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_header_decode_passive, + [Data, "H"]}}, + {options, [{active, false}, {header, 2}, + binary | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). %%-------------------------------------------------------------------- %% Internal functions @@ -2759,29 +2941,52 @@ client_packet_decode(Socket, P1, P2, Packet) -> Other2 -> exit({?LINE, Other2}) end. -server_header_decode(Socket, Packet, Result) -> +server_header_decode_active(Socket, Packet, Result) -> receive - {ssl, Socket, Result} -> ok; - Other1 -> exit({?LINE, Other1}) - end, - ok = ssl:send(Socket, Packet), - receive - {ssl, Socket, Result} -> ok; - Other2 -> exit({?LINE, Other2}) + {ssl, Socket, Result} -> + ok; + {ssl, Socket, Other1} -> + check_header_result(Result, Other1) end, ok = ssl:send(Socket, Packet). -client_header_decode(Socket, Packet, Result) -> +client_header_decode_active(Socket, Packet, Result) -> ok = ssl:send(Socket, Packet), receive - {ssl, Socket, Result} -> ok; - Other1 -> exit({?LINE, Other1}) + {ssl, Socket, Result} -> + ok; + {ssl, Socket, Other1} -> + check_header_result(Result, Other1) + end. + +server_header_decode_passive(Socket, Packet, Result) -> + case ssl:recv(Socket, 0) of + {ok, Result} -> + ok; + {ok, Other} -> + check_header_result(Result, Other) end, + ok = ssl:send(Socket, Packet). + +client_header_decode_passive(Socket, Packet, Result) -> ok = ssl:send(Socket, Packet), - receive - {ssl, Socket, Result} -> ok; - Other2 -> exit({?LINE, Other2}) + + case ssl:recv(Socket, 0) of + {ok, Result} -> + ok; + {ok, Other} -> + check_header_result(Result, Other) end. + +%% The inet header option is a broken option as it does not buffer until it gets enough data. +%% This check only checks that it has the same behavior as inet, but it is a quite useless +%% option and the bitsynax makes it obsolete! +check_header_result([Byte1 | _], [Byte1]) -> + ok; +check_header_result([Byte1, Byte2 | _], [Byte1, Byte2]) -> + ok; +check_header_result(_,Got) -> + exit({?LINE, Got}). server_line_packet_decode(Socket, Packet) when is_binary(Packet) -> [L1, L2] = string:tokens(binary_to_list(Packet), "\n"), -- cgit v1.2.3 From c9db6bc867ecf1bf581849dd3290b0c9a40e1961 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 21 Aug 2012 16:51:29 +0200 Subject: ssl & public_key: Add use of more "sha-rsa oids" --- lib/public_key/asn1/PKCS-1.asn1 | 3 +++ lib/ssl/src/ssl_certificate.erl | 7 ++++++- lib/ssl/src/ssl_connection.erl | 9 ++++++--- lib/ssl/src/ssl_handshake.erl | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1 index b06f5efa9d..c83289e779 100644 --- a/lib/public_key/asn1/PKCS-1.asn1 +++ b/lib/public_key/asn1/PKCS-1.asn1 @@ -33,6 +33,9 @@ sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } +sha224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 14 } + + id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 605c267144..86f5617b54 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -172,7 +172,12 @@ extensions_list(Extensions) -> %% Description: %%-------------------------------------------------------------------- signature_type(RSA) when RSA == ?sha1WithRSAEncryption; - RSA == ?md5WithRSAEncryption -> + RSA == ?md5WithRSAEncryption; + RSA == ?sha224WithRSAEncryption; + RSA == ?sha256WithRSAEncryption; + RSA == ?sha384WithRSAEncryption; + RSA == ?sha512WithRSAEncryption + -> rsa; signature_type(?'id-dsa-with-sha1') -> dsa. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 86555dd0d9..f83341dee7 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -671,7 +671,6 @@ cipher(#finished{verify_data = Data} = Finished, = Session0, connection_states = ConnectionStates0, tls_handshake_history = Handshake0} = State) -> -%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, opposite_role(Role), get_current_connection_state_prf(ConnectionStates0, read), @@ -1507,7 +1506,12 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) when Algorithm == ?rsaEncryption; Algorithm == ?md2WithRSAEncryption; Algorithm == ?md5WithRSAEncryption; - Algorithm == ?sha1WithRSAEncryption -> + Algorithm == ?sha1WithRSAEncryption; + Algorithm == ?sha224WithRSAEncryption; + Algorithm == ?sha256WithRSAEncryption; + Algorithm == ?sha384WithRSAEncryption; + Algorithm == ?sha512WithRSAEncryption + -> ssl_handshake:key_exchange(client, Version, {premaster_secret, PremasterSecret, PublicKeyInfo}); @@ -1556,7 +1560,6 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version, connection_states = ConnectionStates0, tls_handshake_history = Handshake0}, StateName) -> MasterSecret = Session#session.master_secret, -%%CHECKME: the connection state prf logic is pure guess work! Finished = ssl_handshake:finished(Version, Role, get_current_connection_state_prf(ConnectionStates0, write), MasterSecret, Handshake0), diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 497f778bc2..f198591c93 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -534,7 +534,7 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> end. %%-------------------------------------------------------------------- --spec server_key_exchange_hash(md5sha | md5 | sha | sha256 | sha384 | sha512, binary()) -> binary(). +-spec server_key_exchange_hash(md5sha | md5 | sha | sha224 |sha256 | sha384 | sha512, binary()) -> binary(). %% %% Description: Calculate server key exchange hash %%-------------------------------------------------------------------- -- cgit v1.2.3 From 8aa39bf90a213f086b8e4990e77570ddb6748496 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 22 Aug 2012 09:58:22 +0200 Subject: ssl: Use crypto:strong_rand_bytes if possible --- lib/ssl/src/ssl.erl | 19 ++++++++++++++++++- lib/ssl/src/ssl_cipher.erl | 2 +- lib/ssl/src/ssl_connection.erl | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 4372a147fa..40d933a256 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -31,7 +31,7 @@ controlling_process/2, listen/2, pid/1, peername/1, peercert/1, recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1, versions/0, session_info/1, format_error/1, - renegotiate/1, prf/5, clear_pem_cache/0]). + renegotiate/1, prf/5, clear_pem_cache/0, random_bytes/1]). -deprecated({pid, 1, next_major_release}). @@ -484,6 +484,23 @@ format_error(Error) -> Other end. +%%-------------------------------------------------------------------- +-spec random_bytes(integer()) -> binary(). + +%% +%% Description: Generates cryptographically secure random sequence if possible +%% fallbacks on pseudo random function +%%-------------------------------------------------------------------- +random_bytes(N) -> + try crypto:strong_rand_bytes(N) of + RandBytes -> + RandBytes + catch + error:low_entropy -> + crypto:rand_bytes(N) + end. + + %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 358972f522..80df8fd5cb 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -690,7 +690,7 @@ get_padding_aux(BlockSize, PadLength) -> random_iv(IV) -> IVSz = byte_size(IV), - crypto:rand_bytes(IVSz). + ssl:random_bytes(IVSz). next_iv(Bin, IV) -> BinSz = byte_size(Bin), diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index f83341dee7..4954f5d668 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -2310,7 +2310,7 @@ handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = Stat {stop, normal, State}. make_premaster_secret({MajVer, MinVer}, rsa) -> - Rand = crypto:rand_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), + Rand = ssl:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), <>; make_premaster_secret(_, _) -> undefined. -- cgit v1.2.3 From d799aa95dcff2fc2602db2b98798e1bca21a3a35 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 22 Aug 2012 13:50:37 +0200 Subject: ssl & public_key: Prepare for release Tickets solved by this branch: OTP-8871, OTP-8872 and OTP-9908 --- lib/public_key/vsn.mk | 2 +- lib/ssl/doc/src/ssl.xml | 10 +++++++--- lib/ssl/src/ssl.appup.src | 2 ++ lib/ssl/vsn.mk | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index ab4ee8b0ff..c8165fa247 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.15 +PUBLIC_KEY_VSN = 0.16 diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 28bf82b406..5098d26a3a 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -36,12 +36,16 @@ ssl requires the crypto and public_key applications. - Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0 + Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0, experimental + support for TLS-1.1 and TLS-1.2 is also available (no support for elliptic curve cipher suites yet). For security reasons sslv2 is not supported. Ephemeral Diffie-Hellman cipher suites are supported but not Diffie Hellman Certificates cipher suites. Export cipher suites are not supported as the U.S. lifted its export restrictions in early 2000. + IDEA cipher suites are not supported as they have + become deprecated by the latest TLS spec so there is not any + real motivation to implement them. CRL and policy certificate extensions are not supported yet. @@ -75,7 +79,7 @@ {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} | {cacertfile, path()} | |{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} | - {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} + {ssl_imp, ssl_imp()}| {reuse_sessions, boolean()} | {reuse_session, fun()}

transportoption() = {CallbackModule, DataTag, ClosedTag} @@ -106,7 +110,7 @@

sslsocket() - opaque to the user.

-

protocol() = sslv3 | tlsv1

+

protocol() = sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'

ciphers() = [ciphersuite()] | string() (according to old API)

diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index e346b1e9e6..76550fa04b 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,11 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ + {"5.0.1", [{restart_application, ssl}]}, {"5.0", [{restart_application, ssl}]}, {<<"4\\.*">>, [{restart_application, ssl}]}, {<<"3\\.*">>, [{restart_application, ssl}]} ], [ + {"5.0.1", [{restart_application, ssl}]}, {"5.0", [{restart_application, ssl}]}, {<<"4\\.*">>, [{restart_application, ssl}]}, {<<"3\\.*">>, [{restart_application, ssl}]} diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 0fccbfe908..e381b73c27 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 5.0.1 +SSL_VSN = 5.1 -- cgit v1.2.3 From f87936b28199e4ed6e67ff188996108776fbfb1f Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 22 Aug 2012 14:21:24 +0200 Subject: ssl: Test suite adjustments --- lib/ssl/test/ssl_basic_SUITE.erl | 2 +- lib/ssl/test/ssl_to_openssl_SUITE.erl | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index ea29fa8f35..93f7209aea 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -2119,7 +2119,7 @@ make_sure_expired(Host, Port, Id) -> #session{is_resumable = false} -> ok; _ -> - test_server:sleep(100), + test_server:sleep(?SLEEP), make_sure_expired(Host, Port, Id) end. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 05ed325ae2..d446014f7b 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -106,7 +106,9 @@ init_per_testcase(TestCase, Config0) -> special_init(TestCase, Config) when TestCase == erlang_client_openssl_server_renegotiate; - TestCase == erlang_client_openssl_server_no_wrap_sequence_number -> + TestCase == erlang_client_openssl_server_no_wrap_sequence_number; + TestCase == erlang_server_openssl_client_no_wrap_sequence_number + -> check_sane_openssl_renegotaite(Config); special_init(ssl2_erlang_server_openssl_client, Config) -> -- cgit v1.2.3 From c30ab31df2b00c6c74de23a27ca7244fb897ef36 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 22 Aug 2012 15:54:55 +0200 Subject: ssl: Add missing sslv3 alert --- lib/ssl/src/ssl_alert.erl | 4 +++- lib/ssl/src/ssl_alert.hrl | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index eb1228afa4..222b3f1ad7 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -84,6 +84,8 @@ description_txt(?DECOMPRESSION_FAILURE) -> "decompression failure"; description_txt(?HANDSHAKE_FAILURE) -> "handshake failure"; +description_txt(?NO_CERTIFICATE_RESERVED) -> + "No certificate reserved"; description_txt(?BAD_CERTIFICATE) -> "bad certificate"; description_txt(?UNSUPPORTED_CERTIFICATE) -> diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl index 6470b82d50..92548edab7 100644 --- a/lib/ssl/src/ssl_alert.hrl +++ b/lib/ssl/src/ssl_alert.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -43,6 +43,7 @@ %% record_overflow(22), %% decompression_failure(30), %% handshake_failure(40), +%% no_certificate_RESERVED(41), %% Only sslv3 %% bad_certificate(42), %% unsupported_certificate(43), %% certificate_revoked(44), @@ -69,6 +70,7 @@ -define(RECORD_OVERFLOW, 22). -define(DECOMPRESSION_FAILURE, 30). -define(HANDSHAKE_FAILURE, 40). +-define(NO_CERTIFICATE_RESERVED, 41). -define(BAD_CERTIFICATE, 42). -define(UNSUPPORTED_CERTIFICATE, 43). -define(CERTIFICATE_REVOKED, 44). -- cgit v1.2.3 From f5c54053e4d99c7c6eb1163047632d16c1fd5f19 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Thu, 23 Aug 2012 15:01:40 +0200 Subject: ssl: Clean up of code thanks to dialyzer --- lib/ssl/src/ssl_cipher.erl | 12 +++++++----- lib/ssl/src/ssl_connection.erl | 2 -- lib/ssl/src/ssl_handshake.erl | 2 +- lib/ssl/src/ssl_handshake.hrl | 1 - 4 files changed, 8 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 80df8fd5cb..567690a413 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -606,11 +606,13 @@ hash_size(md5) -> hash_size(sha) -> 20; hash_size(sha256) -> - 32; -hash_size(sha384) -> - 48; -hash_size(sha512) -> - 64. + 32. +%% Currently no supported cipher suites defaults to sha384 or sha512 +%% so these clauses are not needed at the moment. +%% hash_size(sha384) -> +%% 48; +%% hash_size(sha512) -> +%% 64. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 4954f5d668..ff2556c488 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1633,8 +1633,6 @@ verify_dh_params(_Version, Signed, Hashes, _HashAlgo, {?rsaEncryption, PubKey, _ _ -> false end; -verify_dh_params(_Version, Signed, Hash, undefined, {?'id-dsa', PublicKey, PublicKeyParams}) -> - public_key:verify({digest, Hash}, sha, Signed, {PublicKey, PublicKeyParams}); verify_dh_params(_Version, Signed, Hash, HashAlgo, {?'id-dsa', PublicKey, PublicKeyParams}) -> public_key:verify({digest, Hash}, HashAlgo, Signed, {PublicKey, PublicKeyParams}). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f198591c93..28469dfa5f 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -334,7 +334,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> -spec key_exchange(client | server, tls_version(), {premaster_secret, binary(), public_key_info()} | {dh, binary()} | - {dh, {binary(), binary()}, #'DHParameter'{}, hash_algo(), + {dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()}, binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 9967a265c1..cc17dc2975 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -32,7 +32,6 @@ -type public_key_params() :: #'Dss-Parms'{} | term(). -type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. -type tls_handshake_history() :: {[binary()], [binary()]}. --type hash_algo() :: atom(). %% Signature algorithms -define(ANON, 0). -- cgit v1.2.3