-- 0.20.0: a proof runs as its author. Up to 0.19.0 it ran with the rights of whoever called verify(): a -- low-privilege asserter could make a privileged verifier read for it (a confused deputy), here through the error. \set VERBOSITY terse CREATE EXTENSION pg_phasevec; SELECT phasevec.reader_register($n$r1$n$, repeat($h$a$h$, 64), 4) > 0 AS r1; r1 ---- t (1 row) CREATE TABLE notes (id int PRIMARY KEY, body text); INSERT INTO notes VALUES (1, $t$a claim$t$), (2, $t$another claim$t$), (3, $t$a third one$t$); SELECT phasevec.watch($w$notes$w$, $w$notes$w$::regclass, $k$id$k$, $r$r.body$r$, $n$r1$n$) > 0 AS watch; watch ------- t (1 row) CREATE SCHEMA pv_private; CREATE TABLE pv_private.secret (v text); INSERT INTO pv_private.secret VALUES ($s$hunter2$s$); CREATE TABLE pv_shared (n int); INSERT INTO pv_shared VALUES (7); CREATE ROLE pv_author; GRANT USAGE ON SCHEMA phasevec TO pv_author; GRANT EXECUTE ON FUNCTION phasevec.assert(text, text, text, text, jsonb, timestamptz) TO pv_author; GRANT SELECT ON pv_shared TO pv_author; -- an author vouches for the row's text as it reads it: it must be able to read the row GRANT SELECT ON notes TO pv_author; GRANT UPDATE ON notes TO pv_author; -- the author says two things: one it can check, one that reads what only the verifier can SET ROLE pv_author; SELECT phasevec.assert($w$notes$w$, $k$1$k$, $p$(SELECT n FROM public.pv_shared) = 7$p$); assert -------- (1 row) SELECT phasevec.assert($w$notes$w$, $k$2$k$, $p$(SELECT v FROM pv_private.secret LIMIT 1)::int = 0$p$); assert -------- (1 row) RESET ROLE; SELECT key, asserted_by FROM phasevec.truth ORDER BY key; key | asserted_by -----+------------- 1 | pv_author 2 | pv_author (2 rows) -- the superuser verifies: each proof runs as pv_author, so the secret stays out of the error and the verdict SELECT key, verdict, error FROM phasevec.verify($w$notes$w$) ORDER BY key; key | verdict | error -----+----------+----------------------------------------- 1 | verified | 2 | refuted | permission denied for schema pv_private (2 rows) SELECT key, verdict, last_error FROM phasevec.truth ORDER BY key; key | verdict | last_error -----+----------+----------------------------------------- 1 | verified | 2 | refuted | permission denied for schema pv_private (2 rows) -- the author is the caller's current user, also inside a SECURITY DEFINER function of someone else CREATE FUNCTION pv_author_says(p text) RETURNS void LANGUAGE sql SECURITY DEFINER AS $f$ SELECT phasevec.assert('notes', '3', p) $f$; ALTER FUNCTION pv_author_says(text) OWNER TO pv_author; SELECT pv_author_says($p$true$p$); pv_author_says ---------------- (1 row) SELECT key, asserted_by FROM phasevec.truth WHERE key = $k$3$k$; key | asserted_by -----+------------- 3 | pv_author (1 row) -- a verifier that does not hold the author's privileges runs none of its proofs: it cannot lend itself rights it -- does not have, nor borrow the author's -- (a verifier is granted verify() or verify_one() and nothing else) CREATE ROLE pv_verifier; GRANT USAGE ON SCHEMA phasevec TO pv_verifier; GRANT EXECUTE ON FUNCTION phasevec.verify(text, int, interval, interval, int, float8), phasevec.verify_one(text, text, int, float8) TO pv_verifier; SET ROLE pv_verifier; SELECT count(*) AS run FROM phasevec.verify($w$notes$w$, p_every => interval $i$0$i$); run ----- 0 (1 row) SELECT phasevec.verify_one($w$notes$w$, $k$3$k$); ERROR: phasevec: role "pv_verifier" cannot run a proof as its author "pv_author" RESET ROLE; -- once it is a member of the author, it may GRANT pv_author TO pv_verifier; SET ROLE pv_verifier; SELECT key, verdict FROM phasevec.verify($w$notes$w$, p_every => interval $i$0$i$) ORDER BY key; key | verdict -----+---------- 1 | verified 2 | refuted 3 | verified (3 rows) RESET ROLE; -- the proof runs in a security-restricted operation: it cannot change role, even to one its author may use CREATE ROLE pv_other; GRANT pv_other TO pv_author; SET ROLE pv_author; SELECT phasevec.assert($w$notes$w$, $k$3$k$, $p$set_config('role', 'pv_other', true) IS NOT NULL$p$); assert -------- (1 row) RESET ROLE; SELECT phasevec.verify_one($w$notes$w$, $k$3$k$); verify_one ------------ refuted (1 row) SELECT last_error FROM phasevec.truth WHERE key = $k$3$k$; last_error -------------------------------------------------------------- cannot set parameter "role" within security-definer function (1 row) DROP FUNCTION pv_author_says(text); DROP TABLE notes, pv_shared; DROP SCHEMA pv_private CASCADE; NOTICE: drop cascades to table pv_private.secret DROP EXTENSION pg_phasevec; DROP OWNED BY pv_verifier, pv_author, pv_other; DROP ROLE pv_verifier; DROP ROLE pv_author; DROP ROLE pv_other;