diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12d2fd8..6be2c24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,8 @@ jobs: name: lint OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} strategy: matrix: - otp: ['25'] - elixir: ['1.13.2'] + otp: ['26'] + elixir: ['1.16'] steps: - uses: actions/checkout@v2 - uses: erlef/setup-beam@v1 @@ -16,6 +16,7 @@ jobs: elixir-version: ${{matrix.elixir}} - run: mix deps.get - run: mix credo + - run: mix dialyzer - run: mix format --check-formatted - run: mix docs 2>&1 | (! grep -q "warning:") @@ -24,11 +25,10 @@ jobs: name: test OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} strategy: matrix: - otp: ['25'] - elixir: ['1.13.2'] + otp: ['26'] + elixir: ['1.16'] env: MIX_ENV: test - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v2 - uses: erlef/setup-beam@v1 diff --git a/README.md b/README.md index 09c2a27..783da79 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # ExSTUN +[![Hex.pm](https://img.shields.io/hexpm/v/ex_stun.svg)](https://hex.pm/packages/ex_stun) +[![API Docs](https://img.shields.io/badge/api-docs-yellow.svg?style=flat)](https://hexdocs.pm/ex_stun) +[![CI](https://img.shields.io/github/actions/workflow/status/elixir-webrtc/ex_stun/ci.yml?logo=github&label=CI)](https://github.com/elixir-webrtc/ex_stun/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/elixir-webrtc/ex_stun/branch/master/graph/badge.svg?token=7FJ64MDD0J)](https://codecov.io/gh/elixir-webrtc/ex_stun) -Implementation of STUN protocol - [RFC 8489](https://datatracker.ietf.org/doc/html/rfc8489) +Implementation of the STUN protocol in Elixir - [RFC 8489](https://datatracker.ietf.org/doc/html/rfc8489) ## Installation ```elixir @@ -41,8 +44,9 @@ Operating System: Linux CPU Information: Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz Number of Available Cores: 6 Available memory: 15.55 GB -Elixir 1.14.2 -Erlang 25.1 +Elixir 1.16.0 +Erlang 26.2.1 +JIT enabled: true Benchmark suite executing with the following configuration: warmup: 2 s @@ -51,7 +55,7 @@ memory time: 2 s reduction time: 2 s parallel: 1 inputs: none specified -Estimated total run time: 3.30 min +Estimated total run time: 3 min 29 s Benchmarking binding_request.decode ... Benchmarking binding_request.encode ... @@ -59,11 +63,12 @@ Benchmarking binding_response.decode ... Benchmarking binding_response.encode ... Benchmarking error_code.from_raw ... Benchmarking error_code.to_raw ... -Benchmarking message_full.authenticate_lt ... -Benchmarking message_full.authenticate_st ... +Benchmarking message_full.authenticate (long-term) ... +Benchmarking message_full.authenticate (short-term) ... Benchmarking message_full.check_fingerprint ... Benchmarking message_full.decode ... Benchmarking message_full.encode ... +Benchmarking new_transaction_id ... Benchmarking raw_attr.encode ... Benchmarking software.from_raw ... Benchmarking software.to_raw ... @@ -71,94 +76,100 @@ Benchmarking type.from_value ... Benchmarking type.to_value ... Benchmarking xor_mapped_address.from_raw ... Benchmarking xor_mapped_address.to_raw ... - -Name ips average deviation median 99th % -type.to_value 10.36 M 96.49 ns ±21841.52% 82 ns 85 ns -software.to_raw 9.27 M 107.92 ns ±18500.54% 88 ns 127 ns -software.from_raw 9.09 M 109.98 ns ±10619.86% 93 ns 146 ns -raw_attr.encode 5.52 M 181.24 ns ±20597.53% 134 ns 151 ns -error_code.to_raw 5.33 M 187.68 ns ±18721.74% 131 ns 173 ns -error_code.from_raw 5.24 M 190.85 ns ±21761.54% 133 ns 188 ns -xor_mapped_address.from_raw 4.26 M 234.63 ns ±20120.48% 139 ns 404 ns -type.from_value 3.52 M 284.43 ns ±16103.68% 203 ns 345 ns -xor_mapped_address.to_raw 3.32 M 301.39 ns ±15498.33% 224 ns 280 ns -binding_request.decode 2.55 M 391.79 ns ±8498.86% 312 ns 562 ns -message_full.check_fingerprint 2.44 M 410.01 ns ±8473.68% 321 ns 568 ns -binding_response.decode 1.91 M 522.90 ns ±7523.76% 419 ns 743 ns -binding_response.encode 1.51 M 661.60 ns ±4805.20% 536 ns 830 ns -message_full.decode 0.93 M 1069.54 ns ±2911.76% 943 ns 1285 ns -binding_request.encode 0.74 M 1353.22 ns ±1471.32% 1268 ns 1510 ns -message_full.authenticate_st 0.38 M 2624.01 ns ±938.16% 2325 ns 3347 ns -message_full.encode 0.22 M 4590.41 ns ±382.62% 3880 ns 6658 ns -message_full.authenticate_lt 0.182 M 5505.80 ns ±331.43% 4992 ns 7209.08 ns +Calculating statistics... +Formatting results... + +Name ips average deviation median 99th % +error_code.to_raw 36.93 M 27.08 ns ±7981.76% 26 ns 39 ns +software.to_raw 17.55 M 56.99 ns ±58293.86% 32 ns 47 ns +type.to_value 13.21 M 75.68 ns ±53851.08% 47 ns 60 ns +software.from_raw 12.70 M 78.76 ns ±48756.65% 39 ns 53 ns +raw_attr.encode 6.76 M 147.84 ns ±35284.68% 84 ns 99 ns +error_code.from_raw 6.68 M 149.72 ns ±31869.06% 68 ns 308 ns +xor_mapped_address.from_raw 6.53 M 153.04 ns ±24195.15% 90 ns 317 ns +type.from_value 5.93 M 168.77 ns ±29536.32% 89 ns 169 ns +xor_mapped_address.to_raw 4.83 M 206.94 ns ±18672.29% 154 ns 204 ns +binding_request.decode 3.88 M 257.52 ns ±18794.26% 164 ns 405 ns +binding_response.decode 2.58 M 387.01 ns ±12289.08% 258 ns 598 ns +message_full.check_fingerprint 1.96 M 509.65 ns ±8520.92% 410 ns 631 ns +binding_response.encode 1.75 M 572.69 ns ±7262.63% 463 ns 800 ns +message_full.decode 1.18 M 848.38 ns ±3970.03% 719 ns 1054 ns +new_transaction_id 0.98 M 1024.22 ns ±1116.74% 1010 ns 1049 ns +binding_request.encode 0.76 M 1321.81 ns ±1477.79% 1272 ns 1540 ns +message_full.authenticate (short-term) 0.35 M 2845.65 ns ±876.74% 2516 ns 3779 ns +message_full.authenticate (long-term) 0.26 M 3873.42 ns ±532.72% 3423 ns 5354 ns +message_full.encode 0.21 M 4870.66 ns ±604.07% 4115 ns 8119 ns Extended statistics: -Name minimum maximum sample size mode -type.to_value 77 ns 53061243 ns 10.88 M 82 ns -software.to_raw 82 ns 53144998 ns 10.48 M 86 ns -software.from_raw 88 ns 25514683 ns 10.09 M 92 ns -raw_attr.encode 128 ns 74961546 ns 9.52 M 134 ns -error_code.to_raw 121 ns 74838686 ns 9.54 M 130 ns -error_code.from_raw 123 ns 71867196 ns 9.47 M 133 ns -xor_mapped_address.from_raw 131 ns 74689484 ns 9.00 M 138 ns -type.from_value 191 ns 70955773 ns 8.15 M 201 ns -xor_mapped_address.to_raw 211 ns 71053082 ns 7.87 M 224 ns -binding_request.decode 296 ns 51298433 ns 6.98 M 310 ns -message_full.check_fingerprint 308 ns 59012006 ns 6.64 M 318 ns -binding_response.decode 394 ns 48415319 ns 5.96 M 414 ns -binding_response.encode 519 ns 36950899 ns 5.04 M 535 ns -message_full.decode 860 ns 29238503 ns 3.61 M 927 ns -binding_request.encode 1227 ns 19876704 ns 2.95 M 1267 ns -message_full.authenticate_st 2236 ns 14685021 ns 1.68 M 2309 ns -message_full.encode 3688 ns 7095523 ns 1.00 M 3848 ns -message_full.authenticate_lt 4837 ns 6284531 ns 844.69 K 4973 ns, 4968 ns +Name minimum maximum sample size mode +error_code.to_raw 23 ns 7959548 ns 13.57 M 26 ns +software.to_raw 28 ns 113335333 ns 12.84 M 32 ns +type.to_value 42 ns 103387309 ns 12.87 M 46 ns +software.from_raw 35 ns 115844653 ns 12.51 M 39 ns +raw_attr.encode 79 ns 112984566 ns 11.40 M 84 ns +error_code.from_raw 63 ns 112746828 ns 11.17 M 68 ns +xor_mapped_address.from_raw 84 ns 83446950 ns 10.82 M 90 ns +type.from_value 81 ns 99367969 ns 10.89 M 89 ns +xor_mapped_address.to_raw 146 ns 80528411 ns 9.65 M 153 ns +binding_request.decode 153 ns 94202921 ns 9.29 M 162 ns +binding_response.decode 240 ns 68201852 ns 7.57 M 250 ns +message_full.check_fingerprint 390 ns 59291887 ns 6.27 M 409 ns +binding_response.encode 448 ns 59683037 ns 5.73 M 463 ns +message_full.decode 681 ns 44644869 ns 4.46 M 704 ns +new_transaction_id 975 ns 20779566 ns 3.65 M 1013 ns +binding_request.encode 1225 ns 23295785 ns 2.94 M 1271 ns +message_full.authenticate (short-term) 2401 ns 14778234 ns 1.58 M 2500 ns +message_full.authenticate (long-term) 3243 ns 9581577 ns 1.18 M 3368 ns +message_full.encode 3880 ns 19112426 ns 948.71 K 4085 ns Memory usage statistics: -Name Memory usage -type.to_value 0 B -software.to_raw 80 B - ∞ x memory usage +80 B -software.from_raw 88 B - ∞ x memory usage +88 B -raw_attr.encode 32 B - ∞ x memory usage +32 B -error_code.to_raw 112 B - ∞ x memory usage +112 B -error_code.from_raw 176 B - ∞ x memory usage +176 B -xor_mapped_address.from_raw 312 B - ∞ x memory usage +312 B -type.from_value 416 B - ∞ x memory usage +416 B -xor_mapped_address.to_raw 264 B - ∞ x memory usage +264 B -binding_request.decode 752 B - ∞ x memory usage +752 B -message_full.check_fingerprint 256 B - ∞ x memory usage +256 B -binding_response.decode 1160 B - ∞ x memory usage +1160 B -binding_response.encode 832 B - ∞ x memory usage +832 B -message_full.decode 3192 B - ∞ x memory usage +3192 B -binding_request.encode 432 B - ∞ x memory usage +432 B -message_full.authenticate_st 736 B - ∞ x memory usage +736 B -message_full.encode 2664 B - ∞ x memory usage +2664 B -message_full.authenticate_lt 1448 B - ∞ x memory usage +1448 B +Name Memory usage +error_code.to_raw 0 B +software.to_raw 48 B - ∞ x memory usage +48 B +type.to_value 0 B - 1.00x memory usage +0 B +software.from_raw 64 B - ∞ x memory usage +64 B +raw_attr.encode 32 B - ∞ x memory usage +32 B +error_code.from_raw 144 B - ∞ x memory usage +144 B +xor_mapped_address.from_raw 264 B - ∞ x memory usage +264 B +type.from_value 384 B - ∞ x memory usage +384 B +xor_mapped_address.to_raw 232 B - ∞ x memory usage +232 B +binding_request.decode 648 B - ∞ x memory usage +648 B +binding_response.decode 1024 B - ∞ x memory usage +1024 B +message_full.check_fingerprint 232 B - ∞ x memory usage +232 B +binding_response.encode 688 B - ∞ x memory usage +688 B +message_full.decode 2928 B - ∞ x memory usage +2928 B +new_transaction_id 72 B - ∞ x memory usage +72 B +binding_request.encode 360 B - ∞ x memory usage +360 B +message_full.authenticate (short-term) 664 B - ∞ x memory usage +664 B +message_full.authenticate (long-term) 808 B - ∞ x memory usage +808 B +message_full.encode 2344 B - ∞ x memory usage +2344 B **All measurements for memory usage were the same** Reduction count statistics: -Name Reduction count -type.to_value 5 -software.to_raw 1 - 0.20x reduction count -4 -software.from_raw 3 - 0.60x reduction count -2 -raw_attr.encode 1 - 0.20x reduction count -4 -error_code.to_raw 3 - 0.60x reduction count -2 -error_code.from_raw 3 - 0.60x reduction count -2 -xor_mapped_address.from_raw 11 - 2.20x reduction count +6 -type.from_value 6 - 1.20x reduction count +1 -xor_mapped_address.to_raw 7 - 1.40x reduction count +2 -binding_request.decode 11 - 2.20x reduction count +6 -message_full.check_fingerprint 43 - 8.60x reduction count +38 -binding_response.decode 17 - 3.40x reduction count +12 -binding_response.encode 37 - 7.40x reduction count +32 -message_full.decode 56 - 11.20x reduction count +51 -binding_request.encode 21 - 4.20x reduction count +16 -message_full.authenticate_st 60 - 12.00x reduction count +55 -message_full.encode 108 - 21.60x reduction count +103 -message_full.authenticate_lt 113 - 22.60x reduction count +108 +Name Reduction count +error_code.to_raw 0 +software.to_raw 2 - ∞ x reduction count +2 +type.to_value 5 - ∞ x reduction count +5 +software.from_raw 3 - ∞ x reduction count +3 +raw_attr.encode 1 - ∞ x reduction count +1 +error_code.from_raw 3 - ∞ x reduction count +3 +xor_mapped_address.from_raw 13 - ∞ x reduction count +13 +type.from_value 6 - ∞ x reduction count +6 +xor_mapped_address.to_raw 10 - ∞ x reduction count +10 +binding_request.decode 11 - ∞ x reduction count +11 +binding_response.decode 17 - ∞ x reduction count +17 +message_full.check_fingerprint 43 - ∞ x reduction count +43 +binding_response.encode 40 - ∞ x reduction count +40 +message_full.decode 53 - ∞ x reduction count +53 +new_transaction_id 3 - ∞ x reduction count +3 +binding_request.encode 22 - ∞ x reduction count +22 +message_full.authenticate (short-term) 49 - ∞ x reduction count +49 +message_full.authenticate (long-term) 84 - ∞ x reduction count +84 +message_full.encode 99 - ∞ x reduction count +99 **All measurements for reduction count were the same** ``` \ No newline at end of file diff --git a/bench/message.exs b/bench/message.exs index 3fe1128..733c123 100644 --- a/bench/message.exs +++ b/bench/message.exs @@ -14,8 +14,7 @@ alias ExSTUN.Message.Type # therefore they are not fully symmetric with "encode" benchmarks fix_lt_password = :crypto.mac(:hmac, :sha, "123456789", "someusername") |> :base64.encode() -fix_lt_key = "someusername" <> ":" <> "somerealm" <> ":" <> fix_lt_password -fix_lt_key = :crypto.hash(:md5, fix_lt_key) +fix_lt_key = Message.lt_key("someusername", fix_lt_password, "somerealm") fix_st_key = "somekey" <> = :crypto.strong_rand_bytes(12) @@ -77,15 +76,20 @@ Benchee.run( "binding_response.decode" => fn -> {:ok, _} = Message.decode(fix_enc_binding_response) end, "message_full.encode" => fn -> full_msg_enc.(fix_st_key) end, "message_full.decode" => fn -> {:ok, _} = Message.decode(fix_enc_full_message) end, - "message_full.authenticate_st" => fn -> - {:ok, _} = Message.authenticate_st(fix_full_message, "someusername", fix_st_key) + "message_full.authenticate (short-term)" => fn -> + # check if username is correct and authenticate + {:ok, username} = Message.get_attribute(fix_full_message, Username) + username.value == "someusername" + :ok = Message.authenticate(fix_full_message, fix_st_key) end, - "message_full.authenticate_lt" => fn -> - password = :crypto.mac(:hmac, :sha, "123456789", "someusername") |> :base64.encode() - {:ok, _} = Message.authenticate_lt(fix_full_lt_message, password) + "message_full.authenticate (long-term)" => fn -> + {:ok, username} = Message.get_attribute(fix_full_lt_message, Username) + {:ok, realm} = Message.get_attribute(fix_full_lt_message, Realm) + key = Message.lt_key(username.value, fix_lt_password, realm.value) + :ok = Message.authenticate(fix_full_lt_message, key) end, "message_full.check_fingerprint" => fn -> - true = Message.check_fingerprint(fix_full_message) + :ok = Message.check_fingerprint(fix_full_message) end, "type.to_value" => fn -> Type.to_value(%Type{class: :success_response, method: :binding}) diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..3e1ce5d --- /dev/null +++ b/codecov.yml @@ -0,0 +1,18 @@ +codecov: + require_ci_to_pass: false + +comment: + layout: "header, diff, files, footer" + behavior: default + +coverage: + status: + project: + default: + informational: true + patch: + default: + informational: true + +github_checks: + annotations: false \ No newline at end of file diff --git a/lib/ex_stun.ex b/lib/ex_stun.ex index f1f2cda..bdf69b2 100644 --- a/lib/ex_stun.ex +++ b/lib/ex_stun.ex @@ -6,11 +6,11 @@ defmodule ExSTUN do @doc """ Checks if binary is a STUN message. """ - @spec is_stun(binary()) :: boolean() - def is_stun(<>) + @spec stun?(binary()) :: boolean() + def stun?(<>) when first_byte in 0..3 do true end - def is_stun(_other), do: false + def stun?(_other), do: false end diff --git a/lib/ex_stun/message.ex b/lib/ex_stun/message.ex index 7ff1911..ab57cf6 100644 --- a/lib/ex_stun/message.ex +++ b/lib/ex_stun/message.ex @@ -19,8 +19,8 @@ defmodule ExSTUN.Message do ``` """ import Bitwise - alias ExSTUN.Message.Attribute.Fingerprint - alias ExSTUN.Message.Attribute.{MessageIntegrity, Realm, Username} + + alias ExSTUN.Message.Attribute.{Fingerprint, MessageIntegrity} alias ExSTUN.Message.{RawAttribute, Type} @magic_cookie 0x2112A442 @@ -221,74 +221,40 @@ defmodule ExSTUN.Message do end @doc """ - Authenticates a message long-term mechanism. - - `password` depends on the STUN authentication method and has to - be provided from the outside. - - `key` is a key used for calculating MAC and can be used - for adding message integrity in a response. See `with_integrity/2`. + Create longe-term authentication key. """ - @spec authenticate_lt(t(), binary()) :: - {:ok, key :: binary()} - | {:error, - :no_message_integrity - | :no_username - | :no_realm - | :no_matching_message_integrity - | atom()} - def authenticate_lt(msg, password) do - with {:ok, %MessageIntegrity{} = msg_int} <- get_message_integrity(msg), - {:ok, %Username{value: username}} <- get_username(msg), - {:ok, %Realm{value: realm}} <- get_realm(msg) do - key = username <> ":" <> realm <> ":" <> password - key = :crypto.hash(:md5, key) - - # + 20 for STUN message header - # - 24 for message integrity - len = msg.len_to_int + 20 - 24 - <> = msg.raw - <> = msg_without_integrity - msg_without_integrity = <> - - mac = :crypto.mac(:hmac, :sha, key, msg_without_integrity) - - if mac == msg_int.value do - {:ok, key} - else - {:error, :no_matching_message_integrity} - end - else - {:error, _reason} = err -> err - end + @spec lt_key(binary(), binary(), binary()) :: binary() + def lt_key(username, password, realm) do + :crypto.hash(:md5, username <> ":" <> realm <> ":" <> password) end @doc """ - Authenticates a message using short-term mechanism. + Authenticates a message. - It is assumed that username attribute of this message is valid. + `key` depends on the authentication method. + When authenticating using short-term mechanism, it is simply a password. + When authenticating using long-term mechanism, use `lt_key/3` to obtain the key. - `key` is a key used for calculating MAC and can be used - for adding message integrity in a response. See `with_integrity/2`. + Presence of username, realm and nonce attributes is not checked. + Depending on the authentication method and its context (client/server side), + user has to perform those checks on their own. """ - @spec authenticate_st(t(), binary()) :: - {:ok, key :: binary()} - | {:error, :no_message_integrity | :no_matching_message_integrity | atom()} - def authenticate_st(msg, password) do + @spec authenticate(t(), binary()) :: + :ok | {:error, :no_message_integrity, :no_matching_message_integrity | atom()} + def authenticate(msg, key) do case get_message_integrity(msg) do {:ok, %MessageIntegrity{} = msg_int} -> # + 20 for STUN message header # - 24 for message integrity - len = msg.len_to_int + 20 - (20 + 4) + len = msg.len_to_int + 20 - 24 <> = msg.raw <> = msg_without_integrity msg_without_integrity = <> - # in short-term authentication key == password - mac = :crypto.mac(:hmac, :sha, password, msg_without_integrity) + mac = :crypto.mac(:hmac, :sha, key, msg_without_integrity) if mac == msg_int.value do - {:ok, password} + :ok else {:error, :no_matching_message_integrity} end @@ -404,18 +370,4 @@ defmodule ExSTUN.Message do other -> other end end - - defp get_username(msg) do - case get_attribute(msg, Username) do - nil -> {:error, :no_username} - other -> other - end - end - - defp get_realm(msg) do - case get_attribute(msg, Realm) do - nil -> {:error, :no_realm} - other -> other - end - end end diff --git a/mix.exs b/mix.exs index e100b93..6a428c0 100644 --- a/mix.exs +++ b/mix.exs @@ -10,7 +10,7 @@ defmodule ExSTUN.MixProject do version: @version, elixir: "~> 1.13", start_permanent: Mix.env() == :prod, - description: "Implementation of STUN protocol", + description: "Implementation of the STUN protocol", package: package(), deps: deps(), diff --git a/mix.lock b/mix.lock index bd3d10e..701749c 100644 --- a/mix.lock +++ b/mix.lock @@ -1,26 +1,26 @@ %{ - "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, - "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, - "credo": {:hex, :credo, "1.6.4", "ddd474afb6e8c240313f3a7b0d025cc3213f0d171879429bf8535d7021d9ad78", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "c28f910b61e1ff829bffa056ef7293a8db50e87f2c57a9b5c3f57eee124536b7"}, + "benchee": {:hex, :benchee, "1.3.0", "f64e3b64ad3563fa9838146ddefb2d2f94cf5b473bdfd63f5ca4d0657bf96694", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "34f4294068c11b2bd2ebf2c59aac9c7da26ffa0068afdf3419f1b176e16c5f81"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, + "credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"}, + "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, + "ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"}, "excoveralls": {:hex, :excoveralls, "0.14.6", "610e921e25b180a8538229ef547957f7e04bd3d3e9a55c7c5b7d24354abbba70", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "0eceddaa9785cfcefbf3cd37812705f9d8ad34a758e513bb975b081dce4eb11e"}, - "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, - "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, - "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, - "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } diff --git a/test/ex_stun/message_test.exs b/test/ex_stun/message_test.exs index 0350f0d..3ecab01 100644 --- a/test/ex_stun/message_test.exs +++ b/test/ex_stun/message_test.exs @@ -329,7 +329,7 @@ defmodule ExSTUN.MessageTest do end end - describe "authenticate_st/2" do + describe "authenticate/2" do test "valid key" do key = "somekey" username = "someuser" @@ -344,7 +344,7 @@ defmodule ExSTUN.MessageTest do {:ok, username_attr} = Message.get_attribute(decoded, Username) assert username == username_attr.value - assert {:ok, ^key} = Message.authenticate_st(decoded, key) + assert :ok == Message.authenticate(decoded, key) end test "invalid key" do @@ -357,7 +357,7 @@ defmodule ExSTUN.MessageTest do {:ok, %Message{} = decoded} = Message.decode(encoded) assert {:error, :no_matching_message_integrity} == - Message.authenticate_st(decoded, "invalidkey") + Message.authenticate(decoded, "invalidkey") end test "no message integrity" do @@ -368,100 +368,7 @@ defmodule ExSTUN.MessageTest do {:ok, %Message{} = decoded} = Message.decode(encoded) - assert {:error, :no_message_integrity} == Message.authenticate_st(decoded, "somekey") - end - end - - describe "authenticate_lt/2" do - test "valid credentials" do - username = "someuser" - password = "somepassword" - realm = "somerealm" - - key = username <> ":" <> realm <> ":" <> password - key = :crypto.hash(:md5, key) - - encoded = - %Message.Type{class: :request, method: :binding} - |> Message.new([ - %Username{value: username}, - %Realm{value: realm} - ]) - |> Message.with_integrity(key) - |> Message.encode() - - {:ok, %Message{} = decoded} = Message.decode(encoded) - {:ok, username_attr} = Message.get_attribute(decoded, Username) - - assert username == username_attr.value - assert {:ok, ^key} = Message.authenticate_lt(decoded, password) - end - - test "invalid credentials" do - username = "someuser" - realm = "somerealm" - - key = username <> ":" <> realm <> ":" <> "somepassowrd" - key = :crypto.hash(:md5, key) - - encoded = - %Message.Type{class: :request, method: :binding} - |> Message.new([ - %Username{value: username}, - %Realm{value: realm} - ]) - |> Message.with_integrity(key) - |> Message.encode() - - {:ok, %Message{} = decoded} = Message.decode(encoded) - - assert {:error, :no_matching_message_integrity} == - Message.authenticate_lt(decoded, "invalidpassword") - end - - test "no username, realm or message integrity" do - username = "someuser" - password = "somepassword" - realm = "somerealm" - - key = username <> ":" <> realm <> ":" <> password - key = :crypto.hash(:md5, key) - - encoded = - %Message.Type{class: :request, method: :binding} - |> Message.new([ - %Realm{value: realm} - ]) - |> Message.with_integrity(key) - |> Message.encode() - - {:ok, %Message{} = decoded} = Message.decode(encoded) - - assert {:error, :no_username} = Message.authenticate_lt(decoded, password) - - encoded = - %Message.Type{class: :request, method: :binding} - |> Message.new([ - %Username{value: username} - ]) - |> Message.with_integrity(key) - |> Message.encode() - - {:ok, %Message{} = decoded} = Message.decode(encoded) - - assert {:error, :no_realm} = Message.authenticate_lt(decoded, password) - - encoded = - %Message.Type{class: :request, method: :binding} - |> Message.new([ - %Username{value: username}, - %Realm{value: realm} - ]) - |> Message.encode() - - {:ok, %Message{} = decoded} = Message.decode(encoded) - - assert {:error, :no_message_integrity} = Message.authenticate_lt(decoded, password) + assert {:error, :no_message_integrity} == Message.authenticate(decoded, "somekey") end end diff --git a/test/rfc5769_test.exs b/test/rfc5769_test.exs index 877e03b..81ca4e6 100644 --- a/test/rfc5769_test.exs +++ b/test/rfc5769_test.exs @@ -24,7 +24,7 @@ defmodule ExSTUN.RFC5769Test do assert {:ok, %Username{value: "evtj:h6vY"}} = Message.get_attribute(message, Username) password = "VOkJxbRl1RmTxUk/WvJxBt" - assert {:ok, ^password} = Message.authenticate_st(message, password) + assert :ok == Message.authenticate(message, password) assert Message.check_fingerprint(message) end @@ -47,7 +47,7 @@ defmodule ExSTUN.RFC5769Test do Message.get_attribute(message, XORMappedAddress) password = "VOkJxbRl1RmTxUk/WvJxBt" - assert {:ok, ^password} = Message.authenticate_st(message, password) + assert :ok == Message.authenticate(message, password) assert Message.check_fingerprint(message) end @@ -74,7 +74,7 @@ defmodule ExSTUN.RFC5769Test do }} = Message.get_attribute(message, XORMappedAddress) password = "VOkJxbRl1RmTxUk/WvJxBt" - assert {:ok, ^password} = Message.authenticate_st(message, password) + assert :ok == Message.authenticate(message, password) assert Message.check_fingerprint(message) end @@ -104,9 +104,7 @@ defmodule ExSTUN.RFC5769Test do assert {:ok, %Realm{value: ^realm}} = Message.get_attribute(message, Realm) password = "TheMatrIX" - key = username <> ":" <> realm <> ":" <> password - key = :crypto.hash(:md5, key) - - assert {:ok, ^key} = Message.authenticate_lt(message, password) + key = Message.lt_key(username, password, realm) + assert :ok == Message.authenticate(message, key) end end