Verify signatures of signing keys
This commit is contained in:
parent
fb59fee754
commit
ff3dd38369
2 changed files with 48 additions and 8 deletions
|
@ -91,6 +91,13 @@ defmodule MatrixServer do
|
||||||
|> Map.drop(waste_fields)
|
|> Map.drop(waste_fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def serialize_and_encode(struct) do
|
||||||
|
# TODO: handle nil values in struct?
|
||||||
|
struct
|
||||||
|
|> to_serializable_map()
|
||||||
|
|> encode_canonical_json()
|
||||||
|
end
|
||||||
|
|
||||||
def add_signature(object, key_id, sig) when not is_map_key(object, :signatures) do
|
def add_signature(object, key_id, sig) when not is_map_key(object, :signatures) do
|
||||||
Map.put(object, :signatures, %{MatrixServer.server_name() => %{key_id => sig}})
|
Map.put(object, :signatures, %{MatrixServer.server_name() => %{key_id => sig}})
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,15 +17,39 @@ defmodule MatrixServerWeb.FederationClient do
|
||||||
Tesla.client([{Tesla.Middleware.BaseUrl, "http://" <> server_name} | @middleware], @adapter)
|
Tesla.client([{Tesla.Middleware.BaseUrl, "http://" <> server_name} | @middleware], @adapter)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@path RouteHelpers.key_path(Endpoint, :get_signing_keys)
|
||||||
def get_signing_keys(client) do
|
def get_signing_keys(client) do
|
||||||
# TODO: Extract into seperate function.
|
# TODO: Which server_name should we take?
|
||||||
# TODO: Check signatures for each verify key.
|
# TODO: Should probably catch enacl exceptions and just return error atom,
|
||||||
with {:ok, %Tesla.Env{body: body}} <-
|
# create seperate function for this.
|
||||||
Tesla.get(client, RouteHelpers.key_path(Endpoint, :get_signing_keys)),
|
with {:ok,
|
||||||
%Ecto.Changeset{valid?: true} = cs <- GetSigningKeys.changeset(body) do
|
%GetSigningKeys{server_name: server_name, verify_keys: verify_keys, signatures: sigs} =
|
||||||
{:ok, Ecto.Changeset.apply_changes(cs)}
|
response} <- tesla_request(:get, client, @path, GetSigningKeys),
|
||||||
else
|
{:ok, encoded_body} <- MatrixServer.serialize_and_encode(response) do
|
||||||
_ -> :error
|
# For each verify key, check if there is a matching signature.
|
||||||
|
# If not, invalidate the whole response.
|
||||||
|
if Map.has_key?(sigs, server_name) do
|
||||||
|
server_sigs = sigs[server_name]
|
||||||
|
|
||||||
|
all_keys_signed? =
|
||||||
|
Enum.all?(verify_keys, fn {key_id, %{"key" => key}} ->
|
||||||
|
with true <- Map.has_key?(server_sigs, key_id),
|
||||||
|
{:ok, decoded_key} <- MatrixServer.decode_base64(key),
|
||||||
|
{:ok, decoded_sig} <- MatrixServer.decode_base64(server_sigs[key_id]) do
|
||||||
|
:enacl.sign_verify_detached(decoded_sig, encoded_body, decoded_key)
|
||||||
|
else
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if all_keys_signed? do
|
||||||
|
{:ok, response}
|
||||||
|
else
|
||||||
|
:error
|
||||||
|
end
|
||||||
|
else
|
||||||
|
:error
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,4 +78,13 @@ defmodule MatrixServerWeb.FederationClient do
|
||||||
{"Authorization", "X-Matrix origin=#{origin},key=\"#{key}\",sig=\"#{sig}\""}
|
{"Authorization", "X-Matrix origin=#{origin},key=\"#{key}\",sig=\"#{sig}\""}
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp tesla_request(method, client, path, request_schema) do
|
||||||
|
with {:ok, %Tesla.Env{body: body}} <- Tesla.request(client, url: path, method: method),
|
||||||
|
%Ecto.Changeset{valid?: true} = cs <- apply(request_schema, :changeset, [body]) do
|
||||||
|
{:ok, Ecto.Changeset.apply_changes(cs)}
|
||||||
|
else
|
||||||
|
_ -> :error
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue