diff options
-rw-r--r-- | lib/diameter/src/base/diameter_traffic.erl | 2 | ||||
-rw-r--r-- | lib/diameter/src/diameter.appup.src | 6 | ||||
-rw-r--r-- | lib/diameter/src/transport/diameter_sctp.erl | 47 | ||||
-rw-r--r-- | lib/diameter/test/diameter_traffic_SUITE.erl | 19 | ||||
-rw-r--r-- | lib/diameter/vsn.mk | 2 | ||||
-rw-r--r-- | lib/public_key/doc/src/public_key_records.xml | 6 | ||||
-rw-r--r-- | lib/public_key/src/public_key.erl | 26 | ||||
-rw-r--r-- | lib/public_key/test/public_key_SUITE.erl | 44 | ||||
-rw-r--r-- | lib/public_key/test/public_key_SUITE_data/ec_key2.pem | 29 |
9 files changed, 149 insertions, 32 deletions
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index f510f40a17..d2856ae530 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -684,7 +684,7 @@ resend(false, Route = #diameter_avp{data = {Dict0, 'Route-Record', OH}}, Seq = diameter_session:sequence(Mask), Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq}, - Msg = [Hdr, Route | Avps], %% reordered at encode + Msg = [Hdr | Avps ++ [Route]], case send_request(SvcName, App, Msg, Opts) of #diameter_packet{} = Ans -> Ans; diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src index 07d0389bfd..7566cf25c3 100644 --- a/lib/diameter/src/diameter.appup.src +++ b/lib/diameter/src/diameter.appup.src @@ -52,7 +52,8 @@ {"1.11.2", [{restart_application, diameter}]}, %% 18.3 {"1.12", [{restart_application, diameter}]}, %% 19.0 {"1.12.1", [{restart_application, diameter}]}, %% 19.1 - {"1.12.2", [{restart_application, diameter}]} %% 19.3 + {"1.12.2", [{restart_application, diameter}]}, %% 19.3 + {"2.0", [{restart_application, diameter}]} %% 20.0 ], [ {"0.9", [{restart_application, diameter}]}, @@ -86,6 +87,7 @@ {"1.11.2", [{restart_application, diameter}]}, {"1.12", [{restart_application, diameter}]}, {"1.12.1", [{restart_application, diameter}]}, - {"1.12.2", [{restart_application, diameter}]} + {"1.12.2", [{restart_application, diameter}]}, + {"2.0", [{restart_application, diameter}]} ] }. diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index 4eb3379d59..64b34da690 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -103,6 +103,8 @@ | undefined, os = 0 :: uint(), %% next output stream rotate = 1 :: boolean() | 0 | 1, %% rotate os? + unordered = false :: boolean() %% always send unordered? + | pos_integer(),% or if =< N outbound streams? packet = true :: boolean() %% legacy transport_data? | raw, message_cb = false :: false | diameter:eval(), @@ -242,8 +244,11 @@ i(#monitor{transport = TPid} = S) -> i({listen, Ref, {Opts, SvcPid, Addrs}}) -> monitor(process, SvcPid), [_] = diameter_config:subscribe(Ref, transport), %% assert existence - {Split, Rest} - = proplists:split(Opts, [accept, packet, sender, message_cb]), + {Split, Rest} = proplists:split(Opts, [accept, + packet, + sender, + message_cb, + unordered]), OwnOpts = lists:append(Split), {LAs, Sock} = AS = open(Addrs, Rest, ?DEFAULT_PORT), ok = gen_sctp:listen(Sock, true), @@ -255,12 +260,16 @@ i({listen, Ref, {Opts, SvcPid, Addrs}}) -> opts = [[[M] || {accept, M} <- OwnOpts], proplists:get_value(packet, OwnOpts, true) | [proplists:get_value(K, OwnOpts, false) - || K <- [sender, message_cb]]]}; + || K <- [sender, message_cb, unordered]]]}; %% A connecting transport. i({connect, Pid, Opts, Addrs, Ref}) -> - {[Ps | Split], Rest} - = proplists:split(Opts, [rport, raddr, packet, sender, message_cb]), + {[Ps | Split], Rest} = proplists:split(Opts, [rport, + raddr, + packet, + sender, + message_cb, + unordered]), OwnOpts = lists:append(Split), CB = proplists:get_value(message_cb, OwnOpts, false), false == CB orelse (Pid ! {diameter, ack}), @@ -274,6 +283,7 @@ i({connect, Pid, Opts, Addrs, Ref}) -> mode = {connect, connect(Sock, RAs, RP, [])}, socket = Sock, message_cb = CB, + unordered = proplists:get_value(ordered, OwnOpts, false), packet = proplists:get_value(packet, OwnOpts, true), send = proplists:get_value(sender, OwnOpts, false)}; @@ -311,12 +321,13 @@ i({K, Ref}, #transport{mode = {accept, _}} = S) -> S#transport{parent = Pid}; {K, T, Opts} when K == peeloff -> %% association {sctp, Sock, _RA, _RP, _Data} = T, - [Matches, Packet, Sender, CB] = Opts, + [Matches, Packet, Sender, CB, Unordered] = Opts, ok = accept_peer(Sock, Matches), demonitor(Ref, [flush]), false == CB orelse (S#transport.parent ! {diameter, ack}), t(T, S#transport{socket = Sock, message_cb = CB, + unordered = Unordered, packet = Packet, send = Sender}); accept_timeout = T -> @@ -799,14 +810,30 @@ recv(#transport{rotate = B} = S) when is_boolean(B) -> S; -recv(#transport{rotate = 0, streams = {_,N}, socket = Sock} = S) -> - ok = inet:setopts(Sock, [{sctp_default_send_param, - #sctp_sndrcvinfo{flags = [unordered]}}]), - S#transport{rotate = 1 < N}; +recv(#transport{rotate = 0, + streams = {_,OS}, + socket = Sock, + unordered = B} + = S) -> + ok = unordered(Sock, OS, B), + S#transport{rotate = 1 < OS}; recv(#transport{rotate = N} = S) -> S#transport{rotate = N-1}. +%% unordered/3 + +unordered(Sock, OS, B) + when B; + is_integer(B), OS =< B -> + inet:setopts(Sock, [{sctp_default_send_param, + #sctp_sndrcvinfo{flags = [unordered]}}]); + +unordered(_, OS, B) + when not B; + is_integer(B), B < OS -> + ok. + %% publish/4 publish(T, Ref, Id, Sock) -> diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index ffb4a508cd..c224f9a27e 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -533,9 +533,10 @@ add_transports(Config) -> LRef = ?util:listen(SN, [T, {sender, SS}, - {message_cb, ST andalso {?MODULE, message, [0]}} - | [{packet, hd(?util:scramble([false, raw]))} - || T == sctp andalso CS]], + {message_cb, ST andalso {?MODULE, message, [0]}}] + ++ [{packet, hd(?util:scramble([false, raw]))} + || T == sctp andalso CS] + ++ [{unordered, unordered()} || T == sctp], [{capabilities_cb, fun capx/2}, {pool_size, 8} | server_apps()] @@ -551,13 +552,17 @@ add_transports(Config) -> Id <- [{D,E}]], ?util:write_priv(Config, "transport", [LRef | Cs]). +unordered() -> + element(rand:uniform(4), {true, false, 1, 2}). + client_opts(tcp) -> []; client_opts(sctp) -> - [{sctp_initmsg, #sctp_initmsg{num_ostreams = N, - max_instreams = 5}} - || N <- [rand:uniform(8)], - N =< 6]. + [{unordered, unordered()} + | [{sctp_initmsg, #sctp_initmsg{num_ostreams = N, + max_instreams = 5}} + || N <- [rand:uniform(8)], + N =< 6]]. server_apps() -> B = have_nas(), diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk index 4801f542fb..e6dfddb5b2 100644 --- a/lib/diameter/vsn.mk +++ b/lib/diameter/vsn.mk @@ -17,5 +17,5 @@ # %CopyrightEnd% APPLICATION = diameter -DIAMETER_VSN = 2.0 +DIAMETER_VSN = 2.1 APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN) diff --git a/lib/public_key/doc/src/public_key_records.xml b/lib/public_key/doc/src/public_key_records.xml index d34f3ed9a3..739310c88b 100644 --- a/lib/public_key/doc/src/public_key_records.xml +++ b/lib/public_key/doc/src/public_key_records.xml @@ -171,9 +171,9 @@ #'ECPrivateKey'{ version, % integer() privateKey, % binary() - parameters, % der_encoded() - {'EcpkParameters', #'ECParameters'{}} | - {'EcpkParameters', {namedCurve, oid()}} | - {'EcpkParameters', 'NULL'} % Inherited by CA + parameters, % {ecParameters, #'ECParameters'{}} | + % {namedCurve, Oid::tuple()} | + % {implicitlyCA, 'NULL'} publicKey % bitstring() }. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index c2060c144c..9a61184f8a 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -71,7 +71,9 @@ -type rsa_private_key() :: #'RSAPrivateKey'{}. -type dsa_private_key() :: #'DSAPrivateKey'{}. -type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. --type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}}. +-type ecpk_parameters() :: {ecParameters, #'ECParameters'{}} | {namedCurve, Oid::tuple()}. +-type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::atom()}. +-type ec_public_key() :: {#'ECPoint'{}, ecpk_parameters_api()}. -type ec_private_key() :: #'ECPrivateKey'{}. -type der_encoded() :: binary(). -type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey' @@ -399,9 +401,7 @@ dh_gex_group(Min, N, Max, Groups) -> %%-------------------------------------------------------------------- -spec generate_key(#'DHParameter'{}) -> {Public::binary(), Private::binary()}; - ({namedCurve, Name ::oid()}) -> - #'ECPrivateKey'{}; - (#'ECParameters'{}) -> + (ecpk_parameters_api()) -> #'ECPrivateKey'{}; ({rsa, Size::pos_integer(), PubExp::pos_integer()}) -> #'RSAPrivateKey'{}. @@ -412,6 +412,8 @@ generate_key(#'DHParameter'{prime = P, base = G}) -> crypto:generate_key(dh, [P, G]); generate_key({namedCurve, _} = Params) -> ec_generate_key(Params); +generate_key({ecParameters, _} = Params) -> + ec_generate_key(Params); generate_key(#'ECParameters'{} = Params) -> ec_generate_key(Params); generate_key({rsa, ModulusSize, PublicExponent}) -> @@ -1286,22 +1288,34 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, is_integer(D) -> [E, N, D]. +-spec ec_generate_key(ecpk_parameters_api()) -> #'ECPrivateKey'{}. ec_generate_key(Params) -> Curve = ec_curve_spec(Params), Term = crypto:generate_key(ecdh, Curve), - ec_key(Term, Params). + NormParams = ec_normalize_params(Params), + ec_key(Term, NormParams). +-spec ec_normalize_params(ecpk_parameters_api()) -> ecpk_parameters(). +ec_normalize_params({namedCurve, Name}) when is_atom(Name) -> + {namedCurve, pubkey_cert_records:namedCurves(Name)}; +ec_normalize_params(#'ECParameters'{} = ECParams) -> + {ecParameters, ECParams}; +ec_normalize_params(Other) -> Other. + +-spec ec_curve_spec(ecpk_parameters_api()) -> term(). ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) -> Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'FieldID'.fieldType), FieldId#'FieldID'.parameters}, Curve = {PCurve#'Curve'.a, PCurve#'Curve'.b, none}, {Field, Curve, Base, Order, CoFactor}; +ec_curve_spec({ecParameters, ECParams}) -> + ec_curve_spec(ECParams); ec_curve_spec({namedCurve, OID}) when is_tuple(OID), is_integer(element(1,OID)) -> ec_curve_spec({namedCurve, pubkey_cert_records:namedCurves(OID)}); ec_curve_spec({namedCurve, Name}) when is_atom(Name) -> crypto:ec_curve(Name). - +-spec ec_key({PubKey::term(), PrivateKey::term()}, Params::ecpk_parameters()) -> #'ECPrivateKey'{}. ec_key({PubKey, PrivateKey}, Params) -> #'ECPrivateKey'{version = 1, privateKey = PrivateKey, diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 80895ce97c..4b1b771613 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -60,7 +60,8 @@ all() -> groups() -> [{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem, - dh_pem, cert_pem, pkcs7_pem, pkcs10_pem]}, + dh_pem, cert_pem, pkcs7_pem, pkcs10_pem, ec_pem2, + ec_pem_encode_generated]}, {ssh_public_key_decode_encode, [], [ssh_rsa_public_key, ssh_dsa_public_key, ssh_ecdsa_public_key, ssh_rfc4716_rsa_comment, ssh_rfc4716_dsa_comment, @@ -101,6 +102,7 @@ init_per_testcase(TestCase, Config) -> ssh_hostkey_fingerprint_sha384 -> init_fingerprint_testcase([sha384], Config); ssh_hostkey_fingerprint_sha512 -> init_fingerprint_testcase([sha512], Config); ssh_hostkey_fingerprint_list -> init_fingerprint_testcase([sha,md5], Config); + ec_pem_encode_generated -> init_ec_pem_encode_generated(Config); _ -> init_common_per_testcase(Config) end. @@ -217,9 +219,47 @@ ec_pem(Config) when is_list(Config) -> true = check_entry_type(ECParams, 'EcpkParameters'), ECPrivKey = public_key:pem_entry_decode(Entry2), true = check_entry_type(ECPrivKey, 'ECPrivateKey'), + true = check_entry_type(ECPrivKey#'ECPrivateKey'.parameters, 'EcpkParameters'), ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem), ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])). +ec_pem2() -> + [{doc, "EC key w/explicit params PEM-file decode/encode"}]. +ec_pem2(Config) when is_list(Config) -> + Datadir = proplists:get_value(data_dir, Config), + + %% Load key with explicit curve parameters. Generated with... + %% openssl ecparam -name secp521r1 -genkey -param_enc explicit -out ec_key2.pem + {ok, ECPrivPem} = file:read_file(filename:join(Datadir, "ec_key2.pem")), + [{'EcpkParameters', _, not_encrypted} = Entry1, + {'ECPrivateKey', _, not_encrypted} = Entry2] = public_key:pem_decode(ECPrivPem), + + ECParams = public_key:pem_entry_decode(Entry1), + true = check_entry_type(ECParams, 'EcpkParameters'), + ECPrivKey = public_key:pem_entry_decode(Entry2), + true = check_entry_type(ECPrivKey, 'ECPrivateKey'), + true = check_entry_type(ECPrivKey#'ECPrivateKey'.parameters, 'EcpkParameters'), + ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem), + ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])). + + +init_ec_pem_encode_generated(Config) -> + case catch true = lists:member('secp384r1', crypto:ec_curves()) of + {'EXIT', _} -> {skip, {'secp384r1', not_supported}}; + _ -> init_common_per_testcase(Config) + end. + +ec_pem_encode_generated() -> + [{doc, "PEM-encode generated EC key"}]. +ec_pem_encode_generated(Config) -> + + Key1 = public_key:generate_key({namedCurve, 'secp384r1'}), + public_key:pem_entry_encode('ECPrivateKey', Key1), + + Key2 = public_key:generate_key({namedCurve, ?'secp384r1'}), + public_key:pem_entry_encode('ECPrivateKey', Key2). + + %%-------------------------------------------------------------------- encrypted_pem() -> @@ -1095,7 +1135,7 @@ check_entry_type(#'ECPrivateKey'{}, 'ECPrivateKey') -> true; check_entry_type({namedCurve, _}, 'EcpkParameters') -> true; -check_entry_type(#'ECParameters'{}, 'EcpkParameters') -> +check_entry_type({ecParameters, #'ECParameters'{}}, 'EcpkParameters') -> true; check_entry_type(_,_) -> false. diff --git a/lib/public_key/test/public_key_SUITE_data/ec_key2.pem b/lib/public_key/test/public_key_SUITE_data/ec_key2.pem new file mode 100644 index 0000000000..56b8169e86 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ec_key2.pem @@ -0,0 +1,29 @@ +-----BEGIN EC PARAMETERS----- +MIIBwgIBATBNBgcqhkjOPQEBAkIB//////////////////////////////////// +//////////////////////////////////////////////////8wgZ4EQgH///// +//////////////////////////////////////////////////////////////// +/////////////////ARBUZU+uWGOHJofkpohoLaFQO6i2nJbmbMV87i0iZGO8Qnh +Vhk5Uex+k3sWUsC9O7G/BzVz34g9LDTx70Uf1GtQPwADFQDQnogAKRy4U5bMZxc5 +MoSqoNpkugSBhQQAxoWOBrcEBOnNnj7LZiOVtEKcZIE5BT+1Ifgor2BrTT26oUte +d+/nWSj+HcEnov+o3jNIs8GFakKb+X5+McLlvWYBGDkpaniaO8AEXIpftCx9G9mY +9URJV5tEaBevvRcnPmYsl+5ymV70JkDFULkBP60HYTU8cIaicsJAiL6Udp/RZlAC +QgH///////////////////////////////////////////pRhoeDvy+Wa3/MAUj3 +CaXQO7XJuImcR667b7cekThkCQIBAQ== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MIICnQIBAQRCAVE6lUKRj5AE8Cw21A+iPWhXSg+XNuerrTyeFERY6AtOrRJ9mTQ3 +Av3xjiM3zhZy2KWnm62hvkvlGbZ7iDKcqg2GoIIBxjCCAcICAQEwTQYHKoZIzj0B +AQJCAf////////////////////////////////////////////////////////// +////////////////////////////MIGeBEIB//////////////////////////// +//////////////////////////////////////////////////////////wEQVGV +PrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ4VYZOVHsfpN7FlLAvTuxvwc1 +c9+IPSw08e9FH9RrUD8AAxUA0J6IACkcuFOWzGcXOTKEqqDaZLoEgYUEAMaFjga3 +BATpzZ4+y2YjlbRCnGSBOQU/tSH4KK9ga009uqFLXnfv51ko/h3BJ6L/qN4zSLPB +hWpCm/l+fjHC5b1mARg5KWp4mjvABFyKX7QsfRvZmPVESVebRGgXr70XJz5mLJfu +cple9CZAxVC5AT+tB2E1PHCGonLCQIi+lHaf0WZQAkIB//////////////////// +///////////////////////6UYaHg78vlmt/zAFI9wml0Du1ybiJnEeuu2+3HpE4 +ZAkCAQGhgYkDgYYABAFLBJzBphlIJmSPuXzTDTnZpL7A0fnyqit9V3TBvaOcL6Iw +6m2TpXvNakxi8Flj0Ok4hdRt+YhawFs0bmzZCT8kfAFs7p55BPHk7FaMZaba77R8 +4V6MhUJSKLc0I/XQBtvoOgVlPJ0MPOndnIxPspCPll886yxG5kOMUAx3HjFg16RT +eA== +-----END EC PRIVATE KEY----- |