From: Roger Braun Date: Sun, 23 Apr 2017 13:21:58 +0000 (+0200) Subject: Decode and verify salmons. X-Git-Url: https://git.squeep.com/?a=commitdiff_plain;h=4c216cba9cd5fc20e03e1f68a4d347cfbc2a2a0b;p=akkoma Decode and verify salmons. --- diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex new file mode 100644 index 000000000..7f1c63a5f --- /dev/null +++ b/lib/pleroma/web/salmon/salmon.ex @@ -0,0 +1,48 @@ +defmodule Pleroma.Web.Salmon do + use Bitwise + + def decode_and_validate(magickey, salmon) do + {doc, _rest} = :xmerl_scan.string(to_charlist(salmon)) + + {:xmlObj, :string, data} = :xmerl_xpath.string('string(//me:data[1])', doc) + {:xmlObj, :string, sig} = :xmerl_xpath.string('string(//me:sig[1])', doc) + {:xmlObj, :string, alg} = :xmerl_xpath.string('string(//me:alg[1])', doc) + {:xmlObj, :string, encoding} = :xmerl_xpath.string('string(//me:encoding[1])', doc) + {:xmlObj, :string, type} = :xmerl_xpath.string('string(//me:data[1]/@type)', doc) + + + {:ok, data} = Base.url_decode64(to_string(data), ignore: :whitespace) + {:ok, sig} = Base.url_decode64(to_string(sig), ignore: :whitespace) + alg = to_string(alg) + encoding = to_string(encoding) + type = to_string(type) + + signed_text = [data, type, encoding, alg] + |> Enum.map(&Base.url_encode64/1) + |> Enum.join(".") + + key = decode_key(magickey) + + verify = :public_key.verify(signed_text, :sha256, sig, key) + + if verify do + {:ok, data} + else + :error + end + end + + defp decode_key("RSA." <> magickey) do + make_integer = fn(bin) -> + list = :erlang.binary_to_list(bin) + Enum.reduce(list, 0, fn (el, acc) -> (acc <<< 8) ||| el end) + end + + [modulus, exponent] = magickey + |> String.split(".") + |> Enum.map(&Base.url_decode64!/1) + |> Enum.map(make_integer) + + {:RSAPublicKey, modulus, exponent} + end +end diff --git a/test/fixtures/salmon.xml b/test/fixtures/salmon.xml new file mode 100644 index 000000000..fadcd3219 --- /dev/null +++ b/test/fixtures/salmon.xml @@ -0,0 +1,2 @@ + +PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiID8-PGVudHJ5IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDA1L0F0b20iIHhtbG5zOnRocj0iaHR0cDovL3B1cmwub3JnL3N5bmRpY2F0aW9uL3RocmVhZC8xLjAiIHhtbG5zOmFjdGl2aXR5PSJodHRwOi8vYWN0aXZpdHlzdHJlYS5tcy9zcGVjLzEuMC8iIHhtbG5zOmdlb3Jzcz0iaHR0cDovL3d3dy5nZW9yc3Mub3JnL2dlb3JzcyIgeG1sbnM6b3N0YXR1cz0iaHR0cDovL29zdGF0dXMub3JnL3NjaGVtYS8xLjAiIHhtbG5zOnBvY289Imh0dHA6Ly9wb3J0YWJsZWNvbnRhY3RzLm5ldC9zcGVjLzEuMCIgeG1sbnM6bWVkaWE9Imh0dHA6Ly9wdXJsLm9yZy9zeW5kaWNhdGlvbi9hdG9tbWVkaWEiIHhtbG5zOnN0YXR1c25ldD0iaHR0cDovL3N0YXR1cy5uZXQvc2NoZW1hL2FwaS8xLyI-CiA8aWQ-dGFnOmdzLmV4YW1wbGUub3JnOjQwNDAsMjAxNy0wNC0yMzpkaXNmYXZvcjoxOjg6MTk3MC0wMS0wMVQwMDowMDowMCswMDowMDwvaWQ-CiA8dGl0bGU-VW5saWtlPC90aXRsZT4KIDxjb250ZW50IHR5cGU9Imh0bWwiPmxhbWJkYSBubyBsb25nZXIgbGlrZXMgaHR0cDovL3BsZXJvbWEuZXhhbXBsZS5vcmc6NDAwMC9vYmplY3RzL2UyODk2ZmMxLTY1OGItNDJhNy1hMzYyLWUyNThkMzkwNmRlOS48L2NvbnRlbnQ-CiA8YWN0aXZpdHk6dmVyYj5odHRwOi8vYWN0aXZpdHlzdHJlYS5tcy9zY2hlbWEvMS4wL3VuZmF2b3JpdGU8L2FjdGl2aXR5OnZlcmI-CiA8cHVibGlzaGVkPjIwMTctMDQtMjNUMTE6NDc6NTUrMDA6MDA8L3B1Ymxpc2hlZD4KIDx1cGRhdGVkPjIwMTctMDQtMjNUMTE6NDc6NTUrMDA6MDA8L3VwZGF0ZWQ-CiA8YXV0aG9yPgogIDxhY3Rpdml0eTpvYmplY3QtdHlwZT5odHRwOi8vYWN0aXZpdHlzdHJlYS5tcy9zY2hlbWEvMS4wL3BlcnNvbjwvYWN0aXZpdHk6b2JqZWN0LXR5cGU-CiAgPHVyaT5odHRwOi8vZ3MuZXhhbXBsZS5vcmc6NDA0MC9pbmRleC5waHAvdXNlci8xPC91cmk-CiAgPG5hbWU-bGFtYmRhPC9uYW1lPgogIDxsaW5rIHJlbD0iYWx0ZXJuYXRlIiB0eXBlPSJ0ZXh0L2h0bWwiIGhyZWY9Imh0dHA6Ly9ncy5leGFtcGxlLm9yZzo0MDQwL2luZGV4LnBocC9sYW1iZGEiLz4KICA8bGluayByZWw9ImF2YXRhciIgdHlwZT0iaW1hZ2UvcG5nIiBtZWRpYTp3aWR0aD0iOTYiIG1lZGlhOmhlaWdodD0iOTYiIGhyZWY9Imh0dHA6Ly9ncy5leGFtcGxlLm9yZzo0MDQwL3RoZW1lL25lby1nbnUvZGVmYXVsdC1hdmF0YXItcHJvZmlsZS5wbmciLz4KICA8bGluayByZWw9ImF2YXRhciIgdHlwZT0iaW1hZ2UvcG5nIiBtZWRpYTp3aWR0aD0iNDgiIG1lZGlhOmhlaWdodD0iNDgiIGhyZWY9Imh0dHA6Ly9ncy5leGFtcGxlLm9yZzo0MDQwL3RoZW1lL25lby1nbnUvZGVmYXVsdC1hdmF0YXItc3RyZWFtLnBuZyIvPgogIDxsaW5rIHJlbD0iYXZhdGFyIiB0eXBlPSJpbWFnZS9wbmciIG1lZGlhOndpZHRoPSIyNCIgbWVkaWE6aGVpZ2h0PSIyNCIgaHJlZj0iaHR0cDovL2dzLmV4YW1wbGUub3JnOjQwNDAvdGhlbWUvbmVvLWdudS9kZWZhdWx0LWF2YXRhci1taW5pLnBuZyIvPgogIDxwb2NvOnByZWZlcnJlZFVzZXJuYW1lPmxhbWJkYTwvcG9jbzpwcmVmZXJyZWRVc2VybmFtZT4KICA8cG9jbzpkaXNwbGF5TmFtZT5sYW1iZGE8L3BvY286ZGlzcGxheU5hbWU-CiAgPGZvbGxvd2VycyB1cmw9Imh0dHA6Ly9ncy5leGFtcGxlLm9yZzo0MDQwL2luZGV4LnBocC9sYW1iZGEvc3Vic2NyaWJlcnMiPjwvZm9sbG93ZXJzPgogPC9hdXRob3I-CiA8YWN0aXZpdHk6b2JqZWN0PgogIDxhY3Rpdml0eTpvYmplY3QtdHlwZT5odHRwOi8vYWN0aXZpdHlzdHJlYS5tcy9zY2hlbWEvMS4wL25vdGU8L2FjdGl2aXR5Om9iamVjdC10eXBlPgogIDxpZD5odHRwOi8vcGxlcm9tYS5leGFtcGxlLm9yZzo0MDAwL29iamVjdHMvZTI4OTZmYzEtNjU4Yi00MmE3LWEzNjItZTI1OGQzOTA2ZGU5PC9pZD4KICA8dGl0bGU-TmV3IG5vdGUgYnkgbGFpbjI8L3RpdGxlPgogIDxjb250ZW50IHR5cGU9Imh0bWwiPkhlbGxvLjwvY29udGVudD4KICA8bGluayByZWw9ImFsdGVybmF0ZSIgdHlwZT0idGV4dC9odG1sIiBocmVmPSJodHRwOi8vcGxlcm9tYS5leGFtcGxlLm9yZzo0MDAwL29iamVjdHMvZTI4OTZmYzEtNjU4Yi00MmE3LWEzNjItZTI1OGQzOTA2ZGU5Ii8-CiAgPHN0YXR1c19uZXQgbm90aWNlX2lkPSI4Ij48L3N0YXR1c19uZXQ-CiA8L2FjdGl2aXR5Om9iamVjdD4KPC9lbnRyeT4Kbase64urlRSA-SHA256ZXXHgp_ihTZIJnnFiQuJD0TSvo4OIqrpblHHQQwfpCy-85mtTf0QO1LclX3P3Ra8BqAmhs7j9nDxuEGLuVLTt53DvMP-pOjCtWYDKBbEZQtFIVnCcvBzGPW1HmimdN49M3VtAohbhfVilTrApQpGnI6kHvx7G1fQdQxHRtMsdNI= \ No newline at end of file diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs new file mode 100644 index 000000000..4ebb32081 --- /dev/null +++ b/test/web/salmon/salmon_test.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Web.Salmon.SalmonTest do + use Pleroma.DataCase + alias Pleroma.Web.Salmon + + @magickey "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwQhh-1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" + + @wrong_magickey "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwQhh-1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAA" + + test "decodes a salmon" do + {:ok, salmon} = File.read("test/fixtures/salmon.xml") + {:ok, doc} = Salmon.decode_and_validate(@magickey, salmon) + assert Regex.match?(~r/xml/, doc) + end + + test "errors on wrong magic key" do + {:ok, salmon} = File.read("test/fixtures/salmon.xml") + assert Salmon.decode_and_validate(@wrong_magickey, salmon) == :error + end +end