From b22fe98ab0fa43e25d2b8fcb4b881cee860ff731 Mon Sep 17 00:00:00 2001 From: Steffen Beyer Date: Fri, 20 Mar 2026 02:32:30 +0100 Subject: [PATCH] auth: use constant-time NIP-42 challenge comparison --- lib/parrhesia/auth/challenges.ex | 11 ++++++++++- test/parrhesia/auth/challenges_test.exs | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/parrhesia/auth/challenges.ex b/lib/parrhesia/auth/challenges.ex index 6b6c839..c7bf162 100644 --- a/lib/parrhesia/auth/challenges.ex +++ b/lib/parrhesia/auth/challenges.ex @@ -67,7 +67,16 @@ defmodule Parrhesia.Auth.Challenges do end def handle_call({:valid?, owner_pid, challenge}, _from, state) do - {:reply, Map.get(state.entries, owner_pid) == challenge, state} + valid? = + case Map.get(state.entries, owner_pid) do + stored_challenge when is_binary(stored_challenge) -> + Plug.Crypto.secure_compare(stored_challenge, challenge) + + _other -> + false + end + + {:reply, valid?, state} end def handle_call({:clear, owner_pid}, _from, state) do diff --git a/test/parrhesia/auth/challenges_test.exs b/test/parrhesia/auth/challenges_test.exs index e0ec254..877fa2e 100644 --- a/test/parrhesia/auth/challenges_test.exs +++ b/test/parrhesia/auth/challenges_test.exs @@ -13,6 +13,7 @@ defmodule Parrhesia.Auth.ChallengesTest do assert Challenges.valid?(server, self(), challenge) refute Challenges.valid?(server, self(), "wrong") + refute Challenges.valid?(server, self(), challenge <> "x") assert :ok = Challenges.clear(server, self()) assert Challenges.current(server, self()) == nil