From 420c071e90f1f306db7a914dc0d0d3acd111dbe3 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 11:48:54 +0200 Subject: [PATCH 01/12] Set version 3.2.0 --- META.json | 4 ++-- pgsodium.control | 2 +- pgsodium_tapgen.pl | 2 +- sql/pgsodium--3.1.7--3.2.0.sql | 1 + test/pgsodium_schema.sql | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 sql/pgsodium--3.1.7--3.2.0.sql diff --git a/META.json b/META.json index cacea64..3ad9892 100644 --- a/META.json +++ b/META.json @@ -2,7 +2,7 @@ "name": "pgsodium", "abstract": "Postgres extension for libsodium functions", "description": "pgsodium is a PostgreSQL extension that exposes modern libsodium based cryptographic functions to SQL.", - "version": "3.1.7", + "version": "3.2.0", "maintainer": [ "Michel Pelletier " ], @@ -13,7 +13,7 @@ "abstract": "Postgres extension for libsodium functions", "file": "src/pgsodium.h", "docfile": "README.md", - "version": "3.1.7" + "version": "3.2.0" } }, "prereqs": { diff --git a/pgsodium.control b/pgsodium.control index c4db242..3f89d95 100644 --- a/pgsodium.control +++ b/pgsodium.control @@ -1,5 +1,5 @@ # pgsodium extension comment = 'Postgres extension for libsodium functions' -default_version = '3.1.7' +default_version = '3.2.0' relocatable = false schema = pgsodium diff --git a/pgsodium_tapgen.pl b/pgsodium_tapgen.pl index 4429215..57ec545 100755 --- a/pgsodium_tapgen.pl +++ b/pgsodium_tapgen.pl @@ -7,7 +7,7 @@ use Getopt::Long; use File::Spec; -my $PGSODIUM_VERSION = '3.1.7'; +my $PGSODIUM_VERSION = '3.2.0'; my $curr; my $rs; diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -0,0 +1 @@ + diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index d500c85..3e8953b 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -8,7 +8,7 @@ SELECT cmp_ok(current_setting('server_version_num')::int, '>=', 130000, format(' ---- EXTENSION VERSION -SELECT results_eq('SELECT pgsodium.version()', $$VALUES ('3.1.7'::text)$$, 'Version of pgsodium is 3.1.7'); +SELECT results_eq('SELECT pgsodium.version()', $$VALUES ('3.2.0'::text)$$, 'Version of pgsodium is 3.2.0'); ---- EXTENSION OBJECTS From fec4f1cc660b0f5575a0e29e65118b43d357ea7f Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 11:51:06 +0200 Subject: [PATCH 02/12] Remove useless pgsodium.create_mask_view(oid,boolean) --- sql/pgsodium--3.1.7--3.2.0.sql | 5 ++++- test/pgsodium_schema.sql | 36 ---------------------------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index 8b13789..a778ca8 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -1 +1,4 @@ - +/* + * change: replaced in 3.0.5 with "create_mask_view(oid, integer, boolean)". + */ +DROP FUNCTION IF EXISTS pgsodium.create_mask_view(oid, boolean); diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index 3e8953b..e0b0f60 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -24,7 +24,6 @@ SELECT bag_eq($$ $$ VALUES ('event trigger pgsodium_trg_mask_update' ::text), ('function pgsodium.create_key(pgsodium.key_type,text,bytea,bytea,uuid,bytea,timestamp with time zone,text)' ::text), - ('function pgsodium.create_mask_view(oid,boolean)' ::text), ('function pgsodium.create_mask_view(oid,integer,boolean)' ::text), ('function pgsodium.crypto_aead_det_decrypt(bytea,bytea,bigint,bytea,bytea)' ::text), ('function pgsodium.crypto_aead_det_decrypt(bytea,bytea,bytea,bytea)' ::text), @@ -971,41 +970,6 @@ SELECT function_privs_are('pgsodium'::name, proname, proargtypes::regtype[]::tex AND proname = 'create_key' AND oidvectortypes(proargtypes) = 'pgsodium.key_type, text, bytea, bytea, uuid, bytea, timestamp with time zone, text'; -SELECT unnest(ARRAY[ - is(md5(prosrc), 'a34e96732392101c6e438288325151c0', - format('Function pgsodium.%s(%s) body should match checksum', - proname, pg_get_function_identity_arguments(oid)) - ), - function_owner_is( - 'pgsodium'::name, proname, - proargtypes::regtype[]::name[], 'postgres'::name, - format('Function pgsodium.%s(%s) owner is %s', - proname, pg_get_function_identity_arguments(oid), 'postgres') - ), - function_lang_is('pgsodium'::name, proname, proargtypes::regtype[]::name[], 'plpgsql'::name ), - function_returns('pgsodium'::name, proname, proargtypes::regtype[]::name[], 'void' ), - volatility_is('pgsodium'::name, proname, proargtypes::regtype[]::name[], 'volatile'), - isnt_definer('pgsodium'::name, proname, proargtypes::regtype[]::name[]), - isnt_strict('pgsodium'::name, proname, proargtypes::regtype[]::name[]), - is_normal_function('pgsodium'::name, proname, proargtypes::regtype[]::name[]) -]) - FROM pg_catalog.pg_proc - WHERE pronamespace = 'pgsodium'::regnamespace - AND proname = 'create_mask_view' - AND oidvectortypes(proargtypes) = 'oid, boolean'; - -SELECT function_privs_are('pgsodium'::name, proname, proargtypes::regtype[]::text[], 'postgres', '{EXECUTE}'::text[]) - FROM pg_catalog.pg_proc - WHERE pronamespace = 'pgsodium'::regnamespace - AND proname = 'create_mask_view' - AND oidvectortypes(proargtypes) = 'oid, boolean'; - -SELECT function_privs_are('pgsodium'::name, proname, proargtypes::regtype[]::text[], 'public', '{EXECUTE}'::text[]) - FROM pg_catalog.pg_proc - WHERE pronamespace = 'pgsodium'::regnamespace - AND proname = 'create_mask_view' - AND oidvectortypes(proargtypes) = 'oid, boolean'; - SELECT unnest(ARRAY[ is(md5(prosrc), 'fb42e03b118baa4eec1ff6fd3773ef3e', format('Function pgsodium.%s(%s) body should match checksum', From d072843f8eda14374e6b17963d7b456c9f0d545b Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 12:17:58 +0200 Subject: [PATCH 03/12] Remove useless pgsodium.mask_columns(oid) --- sql/pgsodium--3.1.7--3.2.0.sql | 5 +++++ test/pgsodium_schema.sql | 37 ---------------------------------- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index a778ca8..c9ea5c8 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -2,3 +2,8 @@ * change: replaced in 3.0.5 with "create_mask_view(oid, integer, boolean)". */ DROP FUNCTION IF EXISTS pgsodium.create_mask_view(oid, boolean); + +/* + * change: replaced in 3.0.5 by the "pgsodium.mask_columns" view. + */ +DROP FUNCTION IF EXISTS pgsodium.mask_columns(oid); diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index e0b0f60..9f7ef70 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -144,7 +144,6 @@ SELECT bag_eq($$ ('function pgsodium.get_named_keys(text)' ::text), ('function pgsodium.has_mask(regrole,text)' ::text), ('function pgsodium.key_encrypt_secret_raw_key()' ::text), - ('function pgsodium.mask_columns(oid)' ::text), ('function pgsodium.mask_role(regrole,text,text)' ::text), ('function pgsodium.pgsodium_derive(bigint,integer,bytea)' ::text), ('function pgsodium.quote_assoc(text,boolean)' ::text), @@ -912,7 +911,6 @@ SELECT functions_are('pgsodium', ARRAY[ 'get_named_keys', 'has_mask', 'key_encrypt_secret_raw_key', - 'mask_columns', 'mask_role', 'pgsodium_derive', 'quote_assoc', @@ -5176,41 +5174,6 @@ SELECT function_privs_are('pgsodium'::name, proname, proargtypes::regtype[]::tex AND proname = 'key_encrypt_secret_raw_key' AND oidvectortypes(proargtypes) = ''; -SELECT unnest(ARRAY[ - is(md5(prosrc), 'dad5c5f648d4aec8e8142213de721039', - format('Function pgsodium.%s(%s) body should match checksum', - proname, pg_get_function_identity_arguments(oid)) - ), - function_owner_is( - 'pgsodium'::name, proname, - proargtypes::regtype[]::name[], 'postgres'::name, - format('Function pgsodium.%s(%s) owner is %s', - proname, pg_get_function_identity_arguments(oid), 'postgres') - ), - function_lang_is('pgsodium'::name, proname, proargtypes::regtype[]::name[], 'sql'::name ), - function_returns('pgsodium'::name, proname, proargtypes::regtype[]::name[], 'setof record' ), - volatility_is('pgsodium'::name, proname, proargtypes::regtype[]::name[], 'volatile'), - isnt_definer('pgsodium'::name, proname, proargtypes::regtype[]::name[]), - isnt_strict('pgsodium'::name, proname, proargtypes::regtype[]::name[]), - is_normal_function('pgsodium'::name, proname, proargtypes::regtype[]::name[]) -]) - FROM pg_catalog.pg_proc - WHERE pronamespace = 'pgsodium'::regnamespace - AND proname = 'mask_columns' - AND oidvectortypes(proargtypes) = 'oid'; - -SELECT function_privs_are('pgsodium'::name, proname, proargtypes::regtype[]::text[], 'postgres', '{EXECUTE}'::text[]) - FROM pg_catalog.pg_proc - WHERE pronamespace = 'pgsodium'::regnamespace - AND proname = 'mask_columns' - AND oidvectortypes(proargtypes) = 'oid'; - -SELECT function_privs_are('pgsodium'::name, proname, proargtypes::regtype[]::text[], 'public', '{EXECUTE}'::text[]) - FROM pg_catalog.pg_proc - WHERE pronamespace = 'pgsodium'::regnamespace - AND proname = 'mask_columns' - AND oidvectortypes(proargtypes) = 'oid'; - SELECT unnest(ARRAY[ is(md5(prosrc), '1b1d814a258347381f8989c6874dc01c', format('Function pgsodium.%s(%s) body should match checksum', From e3821050232e68d36b077105535b4767ca67942b Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 12:23:51 +0200 Subject: [PATCH 04/12] Remove useless schema pgsodium_masks --- sql/pgsodium--3.1.7--3.2.0.sql | 9 +++++++++ test/pgsodium_schema.sql | 4 ---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index c9ea5c8..e33dd84 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -7,3 +7,12 @@ DROP FUNCTION IF EXISTS pgsodium.create_mask_view(oid, boolean); * change: replaced in 3.0.5 by the "pgsodium.mask_columns" view. */ DROP FUNCTION IF EXISTS pgsodium.mask_columns(oid); + +/* + * change: schema "pgsodium_masks" removed in 3.0.4 + * FIXME: how the extension handle bw compatibility when a table having a view + * in pgsodium_masks is update or has a seclabel added/changed? A new + * view is created outside of pgsodium_masks? What about the client app + * and the old view? + */ +DROP SCHEMA IF EXISTS pgsodium_masks; diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index 9f7ef70..02f98b5 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -158,7 +158,6 @@ SELECT bag_eq($$ ('function pgsodium.update_mask(oid,boolean)' ::text), ('function pgsodium.update_masks(boolean)' ::text), ('function pgsodium.version()' ::text), - ('schema pgsodium_masks' ::text), ('sequence pgsodium.key_key_id_seq' ::text), ('table pgsodium.key' ::text), ('type pgsodium._key_id_context' ::text), @@ -195,9 +194,6 @@ SELECT is_member_of( 'pgsodium_keyiduser', 'pgsodium_keymaker' ); SELECT has_schema('pgsodium'); SELECT schema_owner_is('pgsodium', 'postgres'); -SELECT has_schema('pgsodium_masks'); -SELECT schema_owner_is('pgsodium_masks', 'postgres'); - From b56d91470ad12f455c11b27a6598cb74d5c68c93 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 13:42:53 +0200 Subject: [PATCH 05/12] Add 3.2.0 full script --- sql/pgsodium--3.2.0.sql | 2672 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 2672 insertions(+) create mode 100644 sql/pgsodium--3.2.0.sql diff --git a/sql/pgsodium--3.2.0.sql b/sql/pgsodium--3.2.0.sql new file mode 100644 index 0000000..bf62272 --- /dev/null +++ b/sql/pgsodium--3.2.0.sql @@ -0,0 +1,2672 @@ +-- TODO: check namespaces in funcs body +-- TODO: check strictiness of the functions + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgsodium" to load this file. \quit + +COMMENT ON EXTENSION pgsodium IS +'Pgsodium is a modern cryptography library for Postgres.'; + +--============================================================================== +-- ROLES +--============================================================================== + +/* */ +DO $$ +DECLARE + new_role text; +BEGIN + FOREACH new_role IN ARRAY + ARRAY['pgsodium_keyiduser', + 'pgsodium_keyholder', + 'pgsodium_keymaker'] + LOOP + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = new_role) THEN + EXECUTE format($i$ + CREATE ROLE %I WITH + NOLOGIN + NOSUPERUSER + NOCREATEDB + NOCREATEROLE + INHERIT + NOREPLICATION + CONNECTION LIMIT -1; + $i$, new_role); + END IF; + END LOOP; +END +$$; + + +GRANT pgsodium_keyholder TO pgsodium_keymaker; -- deprecating keyholder +GRANT pgsodium_keyiduser TO pgsodium_keymaker; +GRANT pgsodium_keyiduser TO pgsodium_keyholder; + + +--============================================================================== +-- PRIVILEGES +--============================================================================== + +-- All roles cannot execute functions in pgsodium +REVOKE ALL ON SCHEMA pgsodium FROM PUBLIC; + +-- But they can see the objects in pgsodium +GRANT USAGE ON SCHEMA pgsodium TO PUBLIC; + +-- By default, public can't use any table, functions, or sequences +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON TABLES FROM PUBLIC; +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON FUNCTIONS FROM PUBLIC; +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON SEQUENCES FROM PUBLIC; + +-- pgsodium_keyiduser can use all tables and sequences (functions are granted individually) +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON TABLES FROM pgsodium_keyiduser; +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON FUNCTIONS FROM pgsodium_keyiduser; +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON SEQUENCES FROM pgsodium_keyiduser; + + +--============================================================================== +-- TRIGGERS +--============================================================================== + + +/* + * trg_mask_update() + */ +CREATE FUNCTION pgsodium.trg_mask_update() + RETURNS EVENT_TRIGGER + AS $$ +DECLARE + r record; +BEGIN + IF (select bool_or(in_extension) FROM pg_event_trigger_ddl_commands()) THEN + RAISE NOTICE 'skipping pgsodium mask regeneration in extension'; + RETURN; + END IF; + PERFORM pgsodium.update_masks(); +END +$$ + LANGUAGE plpgsql + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* */ +CREATE EVENT TRIGGER pgsodium_trg_mask_update + ON ddl_command_end + WHEN TAG IN ( + 'SECURITY LABEL', + 'ALTER TABLE' + ) + EXECUTE PROCEDURE pgsodium.trg_mask_update(); + +--============================================================================== +-- TYPES +--============================================================================== + +/* */ +CREATE TYPE pgsodium.crypto_box_keypair AS (public bytea, secret bytea); + +/* */ +CREATE TYPE pgsodium.crypto_sign_keypair AS (public bytea, secret bytea); + +/* */ +CREATE TYPE pgsodium.crypto_kx_keypair AS (public bytea, secret bytea); + +/* */ +CREATE TYPE pgsodium.crypto_kx_session AS (rx bytea, tx bytea); + +/* */ +CREATE TYPE pgsodium.crypto_signcrypt_state_key AS (state bytea, shared_key bytea); + +/* */ +CREATE TYPE pgsodium.crypto_signcrypt_keypair AS (public bytea, secret bytea); + +/* Internal Key Management */ +CREATE TYPE pgsodium.key_status AS ENUM ( + 'default', + 'valid', + 'invalid', + 'expired' +); + +/* */ +CREATE TYPE pgsodium.key_type AS ENUM ( + 'aead-ietf', + 'aead-det', + 'hmacsha512', + 'hmacsha256', + 'auth', + 'shorthash', + 'generichash', + 'kdf', + 'secretbox', + 'secretstream', + 'stream_xchacha20' +); + +/* Deterministic AEAD functions by key uuid */ +CREATE TYPE pgsodium._key_id_context AS ( + key_id bigint, + key_context bytea +); + + +--============================================================================== +-- TABLE +--============================================================================== + +/* */ +CREATE TABLE pgsodium.key ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + status pgsodium.key_status DEFAULT 'valid', + created timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, + expires timestamptz, + key_type pgsodium.key_type, + key_id bigserial, + key_context bytea DEFAULT 'pgsodium' CHECK (length(key_context) = 8), + "name" text UNIQUE, + associated_data text DEFAULT 'associated', + raw_key bytea, + raw_key_nonce bytea, + parent_key uuid REFERENCES pgsodium.key(id), + -- This is for bw compat with old dumps that don't go through the UPDATE TO process + "comment" text, + -- deprecated for b/w compat with <= 3.0.4 + user_data text, + CHECK ( + CASE WHEN raw_key IS NOT NULL + THEN key_id IS NULL AND key_context IS NULL AND parent_key IS NOT NULL + ELSE key_id IS NOT NULL AND key_context IS NOT NULL AND parent_key IS NULL + END + ) +); + +-- serial pseudo-type force NOT NULL but we allow them. +ALTER TABLE pgsodium.key ALTER COLUMN key_id DROP NOT NULL; + +-- FIXME: owner? +-- FIXME: revoke? +GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.key TO pgsodium_keymaker; + +GRANT ALL ON SEQUENCE pgsodium.key_key_id_seq TO pgsodium_keymaker; + +CREATE INDEX ON pgsodium.key (status) WHERE status IN ('valid', 'default'); +CREATE UNIQUE INDEX ON pgsodium.key (status) WHERE status = 'default'; +CREATE UNIQUE INDEX ON pgsodium.key (key_id, key_context, key_type); + +COMMENT ON TABLE pgsodium.key IS + 'This table holds metadata for derived keys given a key_id ' + 'and key_context. The raw key is never stored.'; + +SELECT pg_catalog.pg_extension_config_dump('pgsodium.key', ''); +SELECT pg_catalog.pg_extension_config_dump('pgsodium.key_key_id_seq', ''); + +--============================================================================== +-- VIEWS +--============================================================================== + +/* */ +CREATE VIEW pgsodium.valid_key AS + SELECT id, name, status, key_type, key_id, key_context, created, expires, associated_data + FROM pgsodium.key + WHERE status IN ('valid', 'default') + AND CASE WHEN expires IS NULL THEN true ELSE expires > now() END; + +-- FIXME: owner? +-- FIXME: revoke? +GRANT SELECT ON pgsodium.valid_key TO pgsodium_keyiduser; +GRANT ALL ON pgsodium.valid_key TO pgsodium_keyholder; + +/* */ +CREATE VIEW pgsodium.masking_rule AS + WITH const AS ( + SELECT + 'encrypt +with +key +id +([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})' + AS pattern_key_id, + 'encrypt +with +key +column +([\w\"\-$]+)' + AS pattern_key_id_column, + '(?<=associated) +\(([\w\"\-$, ]+)\)' + AS pattern_associated_columns, + '(?<=nonce) +([\w\"\-$]+)' + AS pattern_nonce_column, + '(?<=decrypt with view) +([\w\"\-$]+\.[\w\"\-$]+)' + AS pattern_view_name, + '(?<=security invoker)' + AS pattern_security_invoker + ), + rules_from_seclabels AS ( + SELECT + sl.objoid AS attrelid, + sl.objsubid AS attnum, + c.relnamespace::regnamespace, + c.relname, + a.attname, + pg_catalog.format_type(a.atttypid, a.atttypmod), + sl.label AS col_description, + (regexp_match(sl.label, k.pattern_key_id_column, 'i'))[1] AS key_id_column, + (regexp_match(sl.label, k.pattern_key_id, 'i'))[1] AS key_id, + (regexp_match(sl.label, k.pattern_associated_columns, 'i'))[1] AS associated_columns, + (regexp_match(sl.label, k.pattern_nonce_column, 'i'))[1] AS nonce_column, + coalesce((regexp_match(sl2.label, k.pattern_view_name, 'i'))[1], + c.relnamespace::regnamespace || '.' || quote_ident('decrypted_' || c.relname)) AS view_name, + 100 AS priority, + (regexp_match(sl.label, k.pattern_security_invoker, 'i'))[1] IS NOT NULL AS security_invoker + FROM const k, + pg_catalog.pg_seclabel sl + JOIN pg_catalog.pg_class c ON sl.classoid = c.tableoid AND sl.objoid = c.oid + JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid AND sl.objsubid = a.attnum + LEFT JOIN pg_catalog.pg_seclabel sl2 ON sl2.objoid = c.oid AND sl2.objsubid = 0 + WHERE a.attnum > 0 + AND c.relnamespace::regnamespace != 'pg_catalog'::regnamespace + AND NOT a.attisdropped + AND sl.label ilike 'ENCRYPT%' + AND sl.provider = 'pgsodium' + ) + SELECT + DISTINCT ON (attrelid, attnum) * + FROM rules_from_seclabels + ORDER BY attrelid, attnum, priority DESC; + +-- FIXME: owner? +-- FIXME: revoke? +GRANT ALL ON pgsodium.masking_rule TO pgsodium_keyholder; + +/* */ +CREATE VIEW pgsodium.mask_columns AS SELECT + a.attname, + a.attrelid, + m.key_id, + m.key_id_column, + m.associated_columns, + m.nonce_column, + m.format_type +FROM pg_attribute a +LEFT JOIN pgsodium.masking_rule m ON m.attrelid = a.attrelid + AND m.attname = a.attname +WHERE a.attnum > 0 -- exclude ctid, cmin, cmax + AND NOT a.attisdropped +ORDER BY a.attnum; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? +GRANT ALL ON pgsodium.mask_columns TO pgsodium_keyholder; + +--============================================================================== +-- FUNCTIONS +--============================================================================== + +/* + * create_key(pgsodium.key_type, text, bytea, bytea, uuid, bytea, timestamptz, text) + * + * Insert new key in "pgsodium.valid_key" table. + */ +CREATE FUNCTION pgsodium.create_key( + key_type pgsodium.key_type = 'aead-det', + name text = NULL, + raw_key bytea = NULL, + raw_key_nonce bytea = NULL, + parent_key uuid = NULL, + key_context bytea = 'pgsodium', + expires timestamptz = NULL, + associated_data text = '' + ) + RETURNS pgsodium.valid_key + AS $$ +DECLARE + new_key pgsodium.key; + valid_key pgsodium.valid_key; +BEGIN + INSERT INTO pgsodium.key (key_id, key_context, key_type, raw_key, + raw_key_nonce, parent_key, expires, name, associated_data) + VALUES ( + CASE WHEN raw_key IS NULL THEN + NEXTVAL('pgsodium.key_key_id_seq'::REGCLASS) + ELSE NULL END, + CASE WHEN raw_key IS NULL THEN + key_context + ELSE NULL END, + key_type, + raw_key, + CASE WHEN raw_key IS NOT NULL THEN + COALESCE(raw_key_nonce, pgsodium.crypto_aead_det_noncegen()) + ELSE NULL END, + CASE WHEN parent_key IS NULL and raw_key IS NOT NULL THEN + (pgsodium.create_key('aead-det')).id + ELSE parent_key END, + expires, + name, + associated_data) + RETURNING * INTO new_key; + SELECT * INTO valid_key FROM pgsodium.valid_key WHERE id = new_key.id; + RETURN valid_key; +END; +$$ + LANGUAGE plpgsql + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.create_key(pgsodium.key_type, text, bytea, bytea, uuid, bytea, timestamptz, text) OWNER TO pgsodium_keymaker; +-- FIXME: REVOKE? +GRANT EXECUTE ON FUNCTION pgsodium.create_key(pgsodium.key_type, text, bytea, bytea, uuid, bytea, timestamptz, text) TO pgsodium_keyiduser; + + +/* + * create_mask_view(oid, integer, boolean) + * + * - drop and create view "decrypted_" for given relation + * - drop and create associated triggers to encrypt data on INSERT OR UPDATE for given relation + */ +CREATE FUNCTION pgsodium.create_mask_view(relid oid, subid integer, debug boolean = false) + RETURNS void AS $$ +DECLARE + m record; + body text; + source_name text; + view_owner regrole = session_user; + rule pgsodium.masking_rule; + privs aclitem[]; + priv record; +BEGIN + SELECT DISTINCT * INTO STRICT rule FROM pgsodium.masking_rule WHERE attrelid = relid AND attnum = subid; + + source_name := relid::regclass::text; + + BEGIN + SELECT relacl INTO STRICT privs FROM pg_catalog.pg_class WHERE oid = rule.view_name::regclass::oid; + EXCEPTION + WHEN undefined_table THEN + SELECT relacl INTO STRICT privs FROM pg_catalog.pg_class WHERE oid = relid; + END; + + body = format( + $c$ + DROP VIEW IF EXISTS %1$s; + CREATE VIEW %1$s %5$s AS SELECT %2$s + FROM %3$s; + ALTER VIEW %1$s OWNER TO %4$s; + $c$, + rule.view_name, + pgsodium.decrypted_columns(relid), + source_name, + view_owner, + CASE WHEN rule.security_invoker THEN 'WITH (security_invoker=true)' ELSE '' END + ); + IF debug THEN + RAISE NOTICE '%', body; + END IF; + EXECUTE body; + + FOR priv IN SELECT * FROM pg_catalog.aclexplode(privs) LOOP + body = format( + $c$ + GRANT %s ON %s TO %s; + $c$, + priv.privilege_type, + rule.view_name, + priv.grantee::regrole::text + ); + IF debug THEN + RAISE NOTICE '%', body; + END IF; + EXECUTE body; + END LOOP; + + FOR m IN SELECT * FROM pgsodium.mask_columns where attrelid = relid LOOP + IF m.key_id IS NULL AND m.key_id_column is NULL THEN + CONTINUE; + ELSE + body = format( + $c$ + DROP FUNCTION IF EXISTS %1$s."%2$s_encrypt_secret_%3$s"() CASCADE; + + CREATE OR REPLACE FUNCTION %1$s."%2$s_encrypt_secret_%3$s"() + RETURNS TRIGGER + LANGUAGE plpgsql + AS $t$ + BEGIN + %4$s; + RETURN new; + END; + $t$; + + ALTER FUNCTION %1$s."%2$s_encrypt_secret_%3$s"() OWNER TO %5$s; + + DROP TRIGGER IF EXISTS "%2$s_encrypt_secret_trigger_%3$s" ON %6$s; + + CREATE TRIGGER "%2$s_encrypt_secret_trigger_%3$s" + BEFORE INSERT OR UPDATE OF "%3$s" ON %6$s + FOR EACH ROW + EXECUTE FUNCTION %1$s."%2$s_encrypt_secret_%3$s" (); + $c$, + rule.relnamespace, + rule.relname, + m.attname, + pgsodium.encrypted_column(relid, m), + view_owner, + source_name + ); + if debug THEN + RAISE NOTICE '%', body; + END IF; + EXECUTE body; + END IF; + END LOOP; + + raise notice 'about to masking role % %', source_name, rule.view_name; + PERFORM pgsodium.mask_role(oid::regrole, source_name, rule.view_name) + FROM pg_roles WHERE pgsodium.has_mask(oid::regrole, source_name); + + RETURN; +END + $$ + LANGUAGE plpgsql + VOLATILE + SET search_path='pg_catalog'; + +-- FIXME no OWNER +-- FIXME no REVOKE ? +-- FIXME no GRANT + +/* + * (bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key bytea, nonce bytea = NULL) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_det_decrypt' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_aead_det_decrypt(bytea, bytea, bigint, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key_id bigint, context bytea = 'pgsodium', nonce bytea = NULL) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_det_decrypt_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION crypto_aead_det_decrypt(bytea, bytea, bigint, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION crypto_aead_det_decrypt(bytea, bytea, bigint, bytea, bytea) TO pgsodium_keyiduser; + +/* + * crypto_aead_det_decrypt(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'aead-det'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_aead_det_decrypt(message, additional, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_aead_det_decrypt(message, additional, key.key_id, key.key_context); +END; + $$ + LANGUAGE plpgsql + SECURITY DEFINER + STABLE + SET search_path=''; + +ALTER FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_aead_det_decrypt(bytea, bytea, uuid, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key_uuid uuid, nonce bytea) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'aead-det'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_aead_det_decrypt(message, additional, key.decrypted_raw_key, nonce); + END IF; + RETURN pgsodium.crypto_aead_det_decrypt(message, additional, key.key_id, key.key_context, nonce); +END; + $$ + LANGUAGE plpgsql + SECURITY DEFINER + STABLE + SET search_path=''; + +ALTER FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid, bytea) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid, bytea) TO pgsodium_keyiduser; + +/* + * crypto_aead_det_encrypt(bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key bytea, nonce bytea = NULL) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_det_encrypt' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION crypto_aead_det_encrypt(bytea, bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION crypto_aead_det_encrypt(bytea, bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_aead_det_encrypt(bytea, bytea, bigint, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key_id bigint, context bytea = 'pgsodium', nonce bytea = NULL) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_det_encrypt_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION crypto_aead_det_encrypt(bytea, bytea, bigint, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION crypto_aead_det_encrypt(bytea, bytea, bigint, bytea, bytea) TO pgsodium_keyiduser; + +/* + * crypto_aead_det_encrypt(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'aead-det'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_aead_det_encrypt(message, additional, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_aead_det_encrypt(message, additional, key.key_id, key.key_context); +END; + $$ + LANGUAGE plpgsql + SECURITY DEFINER + STABLE + SET search_path=''; + +ALTER FUNCTION pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_aead_det_encrypt(bytea, bytea, uuid, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key_uuid uuid, nonce bytea) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'aead-det'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_aead_det_encrypt(message, additional, key.decrypted_raw_key, nonce); + END IF; + RETURN pgsodium.crypto_aead_det_encrypt(message, additional, key.key_id, key.key_context, nonce); +END; + $$ + LANGUAGE plpgsql + SECURITY DEFINER + STABLE + SET search_path=''; + +ALTER FUNCTION pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid, bytea) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid, bytea) TO pgsodium_keyiduser; + +/* + * crypto_aead_det_keygen() + */ +CREATE FUNCTION pgsodium.crypto_aead_det_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_det_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION crypto_aead_det_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION crypto_aead_det_keygen TO pgsodium_keymaker; + +/* + * crypto_aead_det_noncegen() + */ +CREATE FUNCTION pgsodium.crypto_aead_det_noncegen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_det_noncegen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_noncegen() TO pgsodium_keyiduser; + +/* + * crypto_aead_ietf_decrypt(bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_ietf_decrypt' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION crypto_aead_ietf_decrypt(bytea, bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION crypto_aead_ietf_decrypt(bytea, bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_aead_ietf_decrypt(bytea, bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_ietf_decrypt_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION crypto_aead_ietf_decrypt(bytea, bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION crypto_aead_ietf_decrypt(bytea, bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_aead_ietf_decrypt(bytea, bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'aead-ietf'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_aead_ietf_decrypt(message, additional, nonce, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_aead_ietf_decrypt(message, additional, nonce, key.key_id, key.key_context); +END; + $$ + LANGUAGE plpgsql + SECURITY DEFINER + STABLE + SET search_path=''; + +ALTER FUNCTION pgsodium.crypto_aead_ietf_decrypt(bytea, bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_decrypt(bytea, bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_ietf_decrypt(bytea, bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_aead_ietf_encrypt(bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_ietf_encrypt' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_aead_ietf_encrypt(bytea, bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_ietf_encrypt_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_aead_ietf_encrypt(bytea, bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'aead-ietf'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_aead_ietf_encrypt(message, additional, nonce, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_aead_ietf_encrypt(message, additional, nonce, key.key_id, key.key_context); +END; + $$ + LANGUAGE plpgsql + SECURITY DEFINER + STABLE + SET search_path=''; + +ALTER FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(bytea, bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_aead_ietf_keygen() + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_ietf_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_ietf_keygen TO pgsodium_keymaker; + +/* + * crypto_aead_ietf_noncegen() + */ +CREATE FUNCTION pgsodium.crypto_aead_ietf_noncegen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_aead_ietf_noncegen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_noncegen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_ietf_noncegen TO pgsodium_keyiduser; + +/* + * crypto_auth(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth(message bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth(bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth(bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_auth(bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth(message bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth(bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth(bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_auth(bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_auth(message bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'auth'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_auth(message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_auth(message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_auth(bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_auth(bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth(bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha256(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, secret bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha256' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_auth_hmacsha256(bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha256_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha256(bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'hmacsha256'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_auth_hmacsha256(message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_auth_hmacsha256(message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256(bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha256_keygen() + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha256_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256_keygen TO pgsodium_keymaker; + +/* + * crypto_auth_hmacsha256_verify(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256_verify(hash bytea, message bytea, secret bytea) + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha256_verify' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_auth_hmacsha256_verify(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256_verify(hash bytea, message bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha256_verify_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha256_verify(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha256_verify(signature bytea, message bytea, key_uuid uuid) + RETURNS boolean AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'hmacsha256'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_auth_hmacsha256_verify(signature, message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_auth_hmacsha256_verify(signature, message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha512(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, secret bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha512' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_auth_hmacsha512(bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha512_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha512(bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'hmacsha512'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_auth_hmacsha512(message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_auth_hmacsha512(message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha512(bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha512_keygen() + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha512_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_auth_hmacsha512_verify(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512_verify(hash bytea, message bytea, secret bytea) + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha512_verify' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_auth_hmacsha512_verify(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512_verify(hash bytea, message bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_hmacsha512_verify_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_auth_hmacsha512_verify(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_auth_hmacsha512_verify(signature bytea, message bytea, key_uuid uuid) + RETURNS boolean AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'hmacsha512'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_auth_hmacsha512_verify(signature, message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_auth_hmacsha512_verify(signature, message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_auth_keygen() + */ +CREATE FUNCTION pgsodium.crypto_auth_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_keygen TO pgsodium_keymaker; + +/* + * crypto_auth_verify(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key bytea) + RETURNS boolean + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_verify' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_auth_verify(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS boolean + AS '$libdir/pgsodium', 'pgsodium_crypto_auth_verify_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_auth_verify(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key_uuid uuid) + RETURNS boolean AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'auth'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_auth_verify(mac, message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_auth_verify(mac, message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_auth_verify(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_box(bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_box(message bytea, nonce bytea, public bytea, secret bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_box' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_box FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_box TO pgsodium_keyholder; + +/* + * crypto_box_new_keypair() + */ +CREATE FUNCTION pgsodium.crypto_box_new_keypair() + RETURNS crypto_box_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_box_keypair' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_box_new_keypair FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_box_new_keypair TO pgsodium_keymaker; + +/* + * crypto_box_new_seed() + */ +CREATE FUNCTION pgsodium.crypto_box_new_seed() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_box_new_seed' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_box_noncegen() + */ +CREATE FUNCTION pgsodium.crypto_box_noncegen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_box_noncegen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_box_noncegen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_box_noncegen TO pgsodium_keymaker; + +/* + * crypto_box_open(bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_box_open(ciphertext bytea, nonce bytea, public bytea, secret bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_box_open' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_box_open FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_box_open TO pgsodium_keyholder; + +/* + * crypto_box_seal(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_box_seal(message bytea, public_key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_box_seal' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_box_seal_open(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_box_seal_open(ciphertext bytea, public_key bytea, secret_key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_box_seal_open' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_box_seed_new_keypair(bytea) + */ +CREATE FUNCTION pgsodium.crypto_box_seed_new_keypair(seed bytea) + RETURNS pgsodium.crypto_box_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_box_seed_keypair' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_box_seed_new_keypair FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_box_seed_new_keypair TO pgsodium_keymaker; + +/* + * crypto_cmp(text, text) + */ +CREATE FUNCTION pgsodium.crypto_cmp(text, text) + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_cmp' + LANGUAGE C + IMMUTABLE + STRICT; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_generichash(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_generichash(message bytea, key bytea DEFAULT NULL) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_generichash' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +REVOKE ALL ON FUNCTION pgsodium.crypto_generichash(bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_generichash(bytea, bytea) TO pgsodium_keyiduser; + +/* + * crypto_generichash(bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_generichash(message bytea, key bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_generichash_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_generichash(bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_generichash(message bytea, key_uuid uuid) + RETURNS bytea AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'generichash'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_generichash(message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_generichash(message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_generichash(bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_generichash(bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_generichash(bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_generichash_keygen() + */ +CREATE FUNCTION pgsodium.crypto_generichash_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_generichash_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_generichash_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_generichash_keygen TO pgsodium_keymaker; + +/* + * crypto_hash_sha256(bytea) + */ +CREATE FUNCTION pgsodium.crypto_hash_sha256(message bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_hash_sha256' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_hash_sha512(bytea) + */ +CREATE FUNCTION pgsodium.crypto_hash_sha512(message bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_hash_sha512' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_kdf_derive_from_key(bigint, bigint, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_kdf_derive_from_key(subkey_size bigint, subkey_id bigint, context bytea, primary_key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_kdf_derive_from_key' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_kdf_derive_from_key(bigint, bigint, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_kdf_derive_from_key(bigint, bigint, bytea, bytea) TO pgsodium_keymaker; + +/* + * crypto_kdf_derive_from_key(integer, bigint, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_kdf_derive_from_key(subkey_size integer, subkey_id bigint, context bytea, primary_key uuid) + RETURNS bytea + AS $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = primary_key AND key_type = 'kdf'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_kdf_derive_from_key(subkey_size, subkey_id, context, key.decrypted_raw_key); + END IF; + RETURN pgsodium.derive_key(key.key_id, subkey_size, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STRICT STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_kdf_derive_from_key(integer, bigint, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_kdf_derive_from_key(integer, bigint, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_kdf_derive_from_key(integer, bigint, bytea, uuid) TO pgsodium_keyiduser; + + +/* + * crypto_kdf_keygen() + */ +CREATE FUNCTION pgsodium.crypto_kdf_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_kdf_keygen' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_kdf_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_kdf_keygen TO pgsodium_keymaker; + +/* + * crypto_kx_client_session_keys(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_kx_client_session_keys(client_pk bytea, client_sk bytea, server_pk bytea) + RETURNS crypto_kx_session + AS '$libdir/pgsodium', 'pgsodium_crypto_kx_client_session_keys' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_kx_new_keypair() + */ +CREATE FUNCTION pgsodium.crypto_kx_new_keypair() + RETURNS crypto_kx_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_kx_keypair' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_kx_new_keypair FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_kx_new_keypair TO pgsodium_keymaker; + +/* + * crypto_kx_new_seed() + */ +CREATE FUNCTION pgsodium.crypto_kx_new_seed() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_kx_new_seed' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_kx_new_seed FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_kx_new_seed TO pgsodium_keymaker; + +/* + * crypto_kx_seed_new_keypair(bytea) + */ +CREATE FUNCTION pgsodium.crypto_kx_seed_new_keypair(seed bytea) + RETURNS crypto_kx_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_kx_seed_keypair' + LANGUAGE C IMMUTABLE + STRICT; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_kx_seed_new_keypair FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_kx_seed_new_keypair TO pgsodium_keymaker; + +/* + * crypto_kx_server_session_keys(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_kx_server_session_keys(server_pk bytea, server_sk bytea, client_pk bytea) + RETURNS crypto_kx_session + AS '$libdir/pgsodium', 'pgsodium_crypto_kx_server_session_keys' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_pwhash(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_pwhash(password bytea, salt bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_pwhash' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_pwhash_saltgen() + */ +CREATE FUNCTION pgsodium.crypto_pwhash_saltgen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_pwhash_saltgen' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_pwhash_str(bytea) + */ +CREATE FUNCTION pgsodium.crypto_pwhash_str(password bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_pwhash_str' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_pwhash_str_verify(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_pwhash_str_verify(hashed_password bytea, password bytea) + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_pwhash_str_verify' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_secretbox(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretbox' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox(bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox(bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_secretbox(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretbox_by_id' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox(bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox(bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_secretbox(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key_uuid uuid) + RETURNS bytea AS + $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'secretbox'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_secretbox(message, nonce, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_secretbox(message, nonce, key.key_id, key.key_context); +END; +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_secretbox(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_secretbox_keygen() + */ +CREATE FUNCTION pgsodium.crypto_secretbox_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretbox_keygen' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox_keygen TO pgsodium_keymaker; + +/* + * crypto_secretbox_noncegen() + */ +CREATE FUNCTION pgsodium.crypto_secretbox_noncegen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretbox_noncegen' + LANGUAGE C VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_noncegen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox_noncegen TO pgsodium_keyiduser; + +/* + * crypto_secretbox_open(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_secretbox_open(ciphertext bytea, nonce bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretbox_open' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, bytea) TO pgsodium_keyholder; + +/* + * crypto_secretbox_open(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_secretbox_open(message bytea, nonce bytea, key_id bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretbox_open_by_id' + LANGUAGE C IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, bigint, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, bigint, bytea) TO pgsodium_keyiduser; + +/* + * crypto_secretbox_open(bytea, bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_secretbox_open(message bytea, nonce bytea, key_uuid uuid) + RETURNS bytea AS + $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'secretbox'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_secretbox_open(message, nonce, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_secretbox_open(message, nonce, key.key_id, key.key_context); +END; +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_secretbox_open(bytea, bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_secretstream_keygen() + */ +CREATE FUNCTION pgsodium.crypto_secretstream_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_secretstream_xchacha20poly1305_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_shorthash(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_shorthash(message bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_shorthash' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_shorthash(bytea, bytea) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_shorthash(bytea, bytea) TO pgsodium_keyiduser; + +/* + * crypto_shorthash(bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_shorthash(message bytea, key bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_shorthash_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_shorthash(bytea, uuid) + */ +CREATE FUNCTION pgsodium.crypto_shorthash(message bytea, key_uuid uuid) + RETURNS bytea AS + $$ +DECLARE + key pgsodium.decrypted_key; +BEGIN + SELECT * INTO STRICT key + FROM pgsodium.decrypted_key v + WHERE id = key_uuid AND key_type = 'shorthash'; + + IF key.decrypted_raw_key IS NOT NULL THEN + RETURN pgsodium.crypto_shorthash(message, key.decrypted_raw_key); + END IF; + RETURN pgsodium.crypto_shorthash(message, key.key_id, key.key_context); +END; + +$$ + LANGUAGE plpgsql + STABLE + SECURITY DEFINER + SET search_path = ''; + +ALTER FUNCTION pgsodium.crypto_shorthash(bytea, uuid) OWNER TO pgsodium_keymaker; +REVOKE ALL ON FUNCTION pgsodium.crypto_shorthash(bytea, uuid) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_shorthash(bytea, uuid) TO pgsodium_keyiduser; + +/* + * crypto_shorthash_keygen() + */ +CREATE FUNCTION pgsodium.crypto_shorthash_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_shorthash_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_shorthash_keygen FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_shorthash_keygen TO pgsodium_keymaker; + +/* + * crypto_sign(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign(message bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_sign_detached(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_detached(message bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_detached' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_sign_final_create(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_final_create(state bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_final_create' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_final_create FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_final_create TO pgsodium_keyholder; + +/* + * crypto_sign_final_verify(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_final_verify(state bytea, signature bytea, key bytea) + RETURNS boolean + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_final_verify' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_final_verify FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_final_verify TO pgsodium_keyholder; + +/* + * crypto_sign_init() + */ +CREATE FUNCTION pgsodium.crypto_sign_init() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_init' + LANGUAGE C + IMMUTABLE + STRICT; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_init FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_init TO pgsodium_keyholder; + +/* + * crypto_sign_new_keypair() + */ +CREATE FUNCTION pgsodium.crypto_sign_new_keypair() + RETURNS crypto_sign_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_keypair' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_new_keypair FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_new_keypair TO pgsodium_keymaker; + +/* + * crypto_sign_new_seed() + */ +CREATE FUNCTION pgsodium.crypto_sign_new_seed() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_new_seed' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_sign_open(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_open(signed_message bytea, key bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_open' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_sign_seed_new_keypair(bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_seed_new_keypair(seed bytea) + RETURNS crypto_sign_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_seed_keypair' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_sign_update(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_update(state bytea, message bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_update' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_update FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_update TO pgsodium_keyholder; + +/* + * crypto_sign_update_agg1(bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_update_agg1(state bytea, message bytea) + RETURNS bytea + AS $$ + SELECT pgsodium.crypto_sign_update(COALESCE(state, pgsodium.crypto_sign_init()), message); +$$ + LANGUAGE SQL + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_update_agg1 FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_update_agg1 TO pgsodium_keyholder; + +COMMENT ON FUNCTION pgsodium.crypto_sign_update_agg1(bytea, bytea) IS +'Internal helper function for crypto_sign_update_agg(bytea). This +initializes state if it has not already been initialized.'; + +/* + * pgsodium.crypto_sign_update_agg2(cur_state bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_update_agg2(cur_state bytea, + initial_state bytea, + message bytea) + RETURNS bytea + AS $$ + SELECT pgsodium.crypto_sign_update( + COALESCE(cur_state, initial_state), + message) +$$ + LANGUAGE SQL + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_sign_update_agg2 FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_sign_update_agg2 TO pgsodium_keyholder; + +COMMENT ON FUNCTION pgsodium.crypto_sign_update_agg2(bytea, bytea, bytea) IS +'Internal helper function for crypto_sign_update_agg(bytea, bytea). This +initializes state to the state passed to the aggregate as a parameter, +if it has not already been initialized.'; + +CREATE AGGREGATE pgsodium.crypto_sign_update_agg(message bytea) + ( + SFUNC = pgsodium.crypto_sign_update_agg1, + STYPE = bytea, + PARALLEL = unsafe); + +COMMENT ON AGGREGATE pgsodium.crypto_sign_update_agg(bytea) IS +'Multi-part message signing aggregate that returns a state which can +then be finalised using crypto_sign_final() or to which other parts +can be added crypto_sign_update() or another message signing aggregate +function. + +Note that when signing mutli-part messages using aggregates, the order +in which message parts is processed is critical. You *must* ensure +that the order of messages passed to the aggregate is invariant.'; + +CREATE AGGREGATE pgsodium.crypto_sign_update_agg(state bytea, message bytea) + ( + SFUNC = pgsodium.crypto_sign_update_agg2, + STYPE = bytea, + PARALLEL = unsafe); + +COMMENT ON AGGREGATE pgsodium.crypto_sign_update_agg(bytea, bytea) IS +'Multi-part message signing aggregate that returns a state which can +then be finalised using crypto_sign_final() or to which other parts +can be added crypto_sign_update() or another message signing aggregate +function. + +The first argument to this aggregate is the input state. This may be +the result of a previous crypto_sign_update_agg(), a previous +crypto_sign_update(). + +Note that when signing mutli-part messages using aggregates, the order +in which message parts is processed is critical. You *must* ensure +that the order of messages passed to the aggregate is invariant.'; + +/* + * crypto_sign_verify_detached(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_sign_verify_detached(sig bytea, message bytea, key bytea) + RETURNS boolean + AS '$libdir/pgsodium', 'pgsodium_crypto_sign_verify_detached' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_signcrypt_new_keypair() + */ +CREATE FUNCTION pgsodium.crypto_signcrypt_new_keypair() + RETURNS pgsodium.crypto_signcrypt_keypair + AS '$libdir/pgsodium', 'pgsodium_crypto_signcrypt_keypair' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_new_keypair FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_signcrypt_new_keypair TO pgsodium_keymaker; + +/* + * crypto_signcrypt_sign_after(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_signcrypt_sign_after(state bytea, sender_sk bytea, ciphertext bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_signcrypt_sign_after' + LANGUAGE C; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_sign_after FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_signcrypt_sign_after TO pgsodium_keyholder; + +/* + * crypto_signcrypt_sign_before(bytea, bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_signcrypt_sign_before(sender bytea, recipient bytea, sender_sk bytea, recipient_pk bytea, additional bytea) + RETURNS crypto_signcrypt_state_key + AS '$libdir/pgsodium', 'pgsodium_crypto_signcrypt_sign_before' + LANGUAGE C; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_sign_before FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_signcrypt_sign_before TO pgsodium_keyholder; + +/* + * crypto_signcrypt_verify_after(bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_signcrypt_verify_after(state bytea, signature bytea, sender_pk bytea, ciphertext bytea) + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_signcrypt_verify_after' + LANGUAGE C; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_after FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_signcrypt_verify_after TO pgsodium_keyholder; + +/* + * crypto_signcrypt_verify_before(bytea, bytea, bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_signcrypt_verify_before(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, recipient_sk bytea) + RETURNS pgsodium.crypto_signcrypt_state_key + AS '$libdir/pgsodium', 'pgsodium_crypto_signcrypt_verify_before' + LANGUAGE C; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_before FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_signcrypt_verify_before TO pgsodium_keyholder; + +/* + * crypto_signcrypt_verify_public(bytea, bytea, bytea, bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_signcrypt_verify_public(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, ciphertext bytea) + RETURNS bool + AS '$libdir/pgsodium', 'pgsodium_crypto_signcrypt_verify_public' + LANGUAGE C; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_public FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.crypto_signcrypt_verify_public TO pgsodium_keyholder; + +/* + * crypto_stream_xchacha20(bigint, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20(bigint, bytea, bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20(bigint, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20(bigint, bytea, bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20_keygen() + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20_keygen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_keygen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20_noncegen() + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20_noncegen() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_noncegen' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20_xor(bytea, bytea, bytea) + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20_xor(bytea, bytea, bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_xor' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20_xor(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20_xor(bytea, bytea, bigint, context bytea = 'pgosdium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_xor_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20_xor_ic(bytea, bytea, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20_xor_ic(bytea, bytea, bigint, bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_xor_ic' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * crypto_stream_xchacha20_xor_ic(bytea, bytea, bigint, bigint, bytea) + */ +CREATE FUNCTION pgsodium.crypto_stream_xchacha20_xor_ic(bytea, bytea, bigint, bigint, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_crypto_stream_xchacha20_xor_ic_by_id' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * decrypted_columns(oid) + */ +CREATE FUNCTION pgsodium.decrypted_columns(relid OID) + RETURNS TEXT AS $$ +DECLARE + m RECORD; + expression TEXT; + comma TEXT; + padding text = ' '; +BEGIN + expression := E'\n'; + comma := padding; + FOR m IN SELECT * FROM pgsodium.mask_columns where attrelid = relid LOOP + expression := expression || comma; + IF m.key_id IS NULL AND m.key_id_column IS NULL THEN + expression := expression || padding || quote_ident(m.attname); + ELSE + expression := expression || padding || quote_ident(m.attname) || E',\n'; + IF m.format_type = 'text' THEN + expression := expression || format( + $f$ + CASE WHEN %s IS NULL THEN NULL ELSE + CASE WHEN %s IS NULL THEN NULL ELSE pg_catalog.convert_from( + pgsodium.crypto_aead_det_decrypt( + pg_catalog.decode(%s, 'base64'), + pg_catalog.convert_to((%s)::text, 'utf8'), + %s::uuid, + %s + ), + 'utf8') END + END AS %s$f$, + quote_ident(m.attname), + coalesce(quote_ident(m.key_id_column), quote_literal(m.key_id)), + quote_ident(m.attname), + coalesce(pgsodium.quote_assoc(m.associated_columns), quote_literal('')), + coalesce(quote_ident(m.key_id_column), quote_literal(m.key_id)), + coalesce(quote_ident(m.nonce_column), 'NULL'), + quote_ident('decrypted_' || m.attname) + ); + ELSIF m.format_type = 'bytea' THEN + expression := expression || format( + $f$ + CASE WHEN %s IS NULL THEN NULL ELSE + CASE WHEN %s IS NULL THEN NULL ELSE pgsodium.crypto_aead_det_decrypt( + %s::bytea, + pg_catalog.convert_to((%s)::text, 'utf8'), + %s::uuid, + %s + ) END + END AS %s$f$, + quote_ident(m.attname), + coalesce(quote_ident(m.key_id_column), quote_literal(m.key_id)), + quote_ident(m.attname), + coalesce(pgsodium.quote_assoc(m.associated_columns), quote_literal('')), + coalesce(quote_ident(m.key_id_column), quote_literal(m.key_id)), + coalesce(quote_ident(m.nonce_column), 'NULL'), + 'decrypted_' || quote_ident(m.attname) + ); + END IF; + END IF; + comma := E', \n'; + END LOOP; + RETURN expression; +END +$$ + LANGUAGE plpgsql + VOLATILE + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * derive_key(bigint, integer, bytea) + */ +CREATE FUNCTION pgsodium.derive_key(key_id bigint, key_len integer = 32, context bytea = 'pgsodium') + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_derive' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.derive_key FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.derive_key TO pgsodium_keymaker; + +/* + * disable_security_label_trigger() + */ +CREATE FUNCTION pgsodium.disable_security_label_trigger() RETURNS void AS + $$ + ALTER EVENT TRIGGER pgsodium_trg_mask_update DISABLE; + $$ + LANGUAGE sql + SECURITY DEFINER + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * enable_security_label_trigger() + */ +CREATE FUNCTION pgsodium.enable_security_label_trigger() RETURNS void AS + $$ + ALTER EVENT TRIGGER pgsodium_trg_mask_update ENABLE; + $$ + LANGUAGE sql + SECURITY DEFINER + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * encrypted_column(oid, record) + */ +CREATE FUNCTION pgsodium.encrypted_column(relid OID, m record) + RETURNS TEXT AS $$ +DECLARE + expression TEXT; + comma TEXT; +BEGIN + expression := ''; + comma := E' '; + expression := expression || comma; + IF m.format_type = 'text' THEN + expression := expression || format( + $f$%s = CASE WHEN %s IS NULL THEN NULL ELSE + CASE WHEN %s IS NULL THEN NULL ELSE pg_catalog.encode( + pgsodium.crypto_aead_det_encrypt( + pg_catalog.convert_to(%s, 'utf8'), + pg_catalog.convert_to((%s)::text, 'utf8'), + %s::uuid, + %s + ), + 'base64') END END$f$, + 'new.' || quote_ident(m.attname), + 'new.' || quote_ident(m.attname), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + 'new.' || quote_ident(m.attname), + COALESCE(pgsodium.quote_assoc(m.associated_columns, true), quote_literal('')), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + COALESCE('new.' || quote_ident(m.nonce_column), 'NULL') + ); + ELSIF m.format_type = 'bytea' THEN + expression := expression || format( + $f$%s = CASE WHEN %s IS NULL THEN NULL ELSE + CASE WHEN %s IS NULL THEN NULL ELSE + pgsodium.crypto_aead_det_encrypt(%s::bytea, pg_catalog.convert_to((%s)::text, 'utf8'), + %s::uuid, + %s + ) END END$f$, + 'new.' || quote_ident(m.attname), + 'new.' || quote_ident(m.attname), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + 'new.' || quote_ident(m.attname), + COALESCE(pgsodium.quote_assoc(m.associated_columns, true), quote_literal('')), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + COALESCE('new.' || quote_ident(m.nonce_column), 'NULL') + ); + END IF; + comma := E';\n '; + RETURN expression; +END +$$ + LANGUAGE plpgsql + VOLATILE + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * encrypted_columns(oid) + */ +CREATE FUNCTION pgsodium.encrypted_columns(relid OID) + RETURNS TEXT AS $$ +DECLARE + m RECORD; + expression TEXT; + comma TEXT; +BEGIN + expression := ''; + comma := E' '; + FOR m IN SELECT * FROM pgsodium.mask_columns where attrelid = relid LOOP + IF m.key_id IS NULL AND m.key_id_column is NULL THEN + CONTINUE; + ELSE + expression := expression || comma; + IF m.format_type = 'text' THEN + expression := expression || format( + $f$%s = CASE WHEN %s IS NULL THEN NULL ELSE + CASE WHEN %s IS NULL THEN NULL ELSE pg_catalog.encode( + pgsodium.crypto_aead_det_encrypt( + pg_catalog.convert_to(%s, 'utf8'), + pg_catalog.convert_to((%s)::text, 'utf8'), + %s::uuid, + %s + ), + 'base64') END END$f$, + 'new.' || quote_ident(m.attname), + 'new.' || quote_ident(m.attname), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + 'new.' || quote_ident(m.attname), + COALESCE(pgsodium.quote_assoc(m.associated_columns, true), quote_literal('')), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + COALESCE('new.' || quote_ident(m.nonce_column), 'NULL') + ); + ELSIF m.format_type = 'bytea' THEN + expression := expression || format( + $f$%s = CASE WHEN %s IS NULL THEN NULL ELSE + CASE WHEN %s IS NULL THEN NULL ELSE + pgsodium.crypto_aead_det_encrypt(%s::bytea, pg_catalog.convert_to((%s)::text, 'utf8'), + %s::uuid, + %s + ) END END$f$, + 'new.' || quote_ident(m.attname), + 'new.' || quote_ident(m.attname), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + 'new.' || quote_ident(m.attname), + COALESCE(pgsodium.quote_assoc(m.associated_columns, true), quote_literal('')), + COALESCE('new.' || quote_ident(m.key_id_column), quote_literal(m.key_id)), + COALESCE('new.' || quote_ident(m.nonce_column), 'NULL') + ); + END IF; + END IF; + comma := E';\n '; + END LOOP; + RETURN expression; +END +$$ + LANGUAGE plpgsql + VOLATILE + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * get_key_by_id(uuid) + */ +CREATE FUNCTION pgsodium.get_key_by_id(uuid) + RETURNS pgsodium.valid_key + AS $$ + SELECT * from pgsodium.valid_key WHERE id = $1; +$$ + SECURITY DEFINER + LANGUAGE sql + SET search_path = ''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * get_key_by_name(text) + */ +CREATE FUNCTION pgsodium.get_key_by_name(text) + RETURNS pgsodium.valid_key + AS $$ + SELECT * from pgsodium.valid_key WHERE name = $1; +$$ + SECURITY DEFINER + LANGUAGE sql + SET search_path = ''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * get_named_keys(text) + */ +CREATE FUNCTION pgsodium.get_named_keys(filter text='%') + RETURNS SETOF pgsodium.valid_key + AS $$ + SELECT * from pgsodium.valid_key vk WHERE vk.name ILIKE filter; +$$ + SECURITY DEFINER + LANGUAGE sql + SET search_path = ''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * has_mask(regrole, text) + */ +CREATE FUNCTION pgsodium.has_mask(role regrole, source_name text) + RETURNS boolean AS $$ + SELECT EXISTS( + SELECT 1 + FROM pg_shseclabel + WHERE objoid = role + AND provider = 'pgsodium' + AND label ilike 'ACCESS%' || source_name || '%') + $$ LANGUAGE sql; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * mask_role(regrole, text, text) + */ +CREATE FUNCTION pgsodium.mask_role(masked_role regrole, source_name text, view_name text) + RETURNS void AS $$ +BEGIN + EXECUTE format( + 'GRANT SELECT ON pgsodium.key TO %s', + masked_role); + + EXECUTE format( + 'GRANT pgsodium_keyiduser, pgsodium_keyholder TO %s', + masked_role); + + EXECUTE format( + 'GRANT ALL ON %s TO %s', + view_name, + masked_role); + RETURN; +END +$$ + LANGUAGE plpgsql + SECURITY DEFINER + SET search_path='pg_catalog'; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * pgsodium_derive(bigint, integer, bytea + */ +CREATE FUNCTION pgsodium.pgsodium_derive(key_id bigint, key_len integer = 32, context bytea = decode('pgsodium', 'escape')) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_derive' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.pgsodium_derive FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.pgsodium_derive TO pgsodium_keymaker; + +/* + * quote_assoc(text, boolean) + */ +CREATE FUNCTION pgsodium.quote_assoc(text, boolean = false) + RETURNS text + AS $$ + WITH a AS (SELECT array_agg(CASE WHEN $2 THEN + 'new.' || quote_ident(trim(v)) + ELSE quote_ident(trim(v)) END) as r + FROM regexp_split_to_table($1, '\s*,\s*') as v) + SELECT array_to_string(a.r, '::text || ') || '::text' FROM a; +$$ + LANGUAGE sql; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * randombytes_buf(integer) + */ +CREATE FUNCTION pgsodium.randombytes_buf(size integer) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_randombytes_buf' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.randombytes_buf FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.randombytes_buf TO pgsodium_keyiduser; + +/* + * randombytes_buf_deterministic(integer, bytea) + */ +CREATE FUNCTION pgsodium.randombytes_buf_deterministic(size integer, seed bytea) + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_randombytes_buf_deterministic' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.randombytes_buf_deterministic FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.randombytes_buf_deterministic TO pgsodium_keyiduser, pgsodium_keymaker; + +/* + * randombytes_new_seed() + */ +CREATE FUNCTION pgsodium.randombytes_new_seed() + RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_randombytes_new_seed' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.randombytes_new_seed FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.randombytes_new_seed TO pgsodium_keymaker; + +/* + * randombytes_random() + */ +CREATE FUNCTION pgsodium.randombytes_random() + RETURNS integer + AS '$libdir/pgsodium', 'pgsodium_randombytes_random' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.randombytes_random FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.randombytes_random TO pgsodium_keyiduser; + +/* + * randombytes_uniform(integer) + */ +CREATE FUNCTION pgsodium.randombytes_uniform(upper_bound integer) + RETURNS integer + AS '$libdir/pgsodium', 'pgsodium_randombytes_uniform' + LANGUAGE C + VOLATILE; + +-- FIXME: owner? +REVOKE ALL ON FUNCTION pgsodium.randombytes_uniform FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgsodium.randombytes_uniform TO pgsodium_keyiduser; + +/* + * sodium_base642bin(text) + */ +CREATE FUNCTION pgsodium.sodium_base642bin(base64 text) RETURNS bytea + AS '$libdir/pgsodium', 'pgsodium_sodium_base642bin' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * sodium_bin2base64(bytea) + */ +CREATE FUNCTION pgsodium.sodium_bin2base64(bin bytea) RETURNS text + AS '$libdir/pgsodium', 'pgsodium_sodium_bin2base64' + LANGUAGE C + IMMUTABLE; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * update_mask(oid, boolean) + */ +CREATE FUNCTION pgsodium.update_mask(target oid, debug boolean = false) +RETURNS void AS + $$ +BEGIN + PERFORM pgsodium.disable_security_label_trigger(); + PERFORM pgsodium.create_mask_view(objoid, objsubid, debug) + FROM pg_catalog.pg_seclabel sl + WHERE sl.objoid = target + AND sl.label ILIKE 'ENCRYPT%' + AND sl.provider = 'pgsodium'; + PERFORM pgsodium.enable_security_label_trigger(); + RETURN; +END +$$ + LANGUAGE plpgsql + SECURITY DEFINER + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * update_masks(boolean) + */ +CREATE FUNCTION pgsodium.update_masks(debug boolean = false) + RETURNS void AS + $$ +BEGIN + PERFORM pgsodium.update_mask(objoid, debug) + FROM pg_catalog.pg_seclabel sl + JOIN pg_catalog.pg_class cl ON (cl.oid = sl.objoid) + WHERE label ilike 'ENCRYPT%' + AND cl.relowner = session_user::regrole::oid + AND provider = 'pgsodium' + AND objoid::regclass != 'pgsodium.key'::regclass + ; + RETURN; +END +$$ + LANGUAGE plpgsql + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +/* + * version() + */ +CREATE FUNCTION pgsodium.version() + RETURNS text + AS $$ SELECT extversion FROM pg_extension WHERE extname = 'pgsodium' $$ + LANGUAGE sql + SET search_path=''; + +-- FIXME: owner? +-- FIXME: revoke? +-- FIXME: grant? + +--============================================================================== +-- MAINTENANCES +--============================================================================== + + +SECURITY LABEL FOR pgsodium ON COLUMN pgsodium.key.raw_key + IS 'ENCRYPT WITH KEY COLUMN parent_key ASSOCIATED (id, associated_data) NONCE raw_key_nonce'; + +SELECT * FROM pgsodium.update_mask('pgsodium.key'::regclass::oid); + +-- FIXME: should we really keep it as keyholder has been deprecated in the same +-- release decrypted_key appeared?? +GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.decrypted_key TO pgsodium_keyholder; From 990c48e0fd9995842e1f4cf9f14035ff5656ba8a Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 15:41:51 +0200 Subject: [PATCH 06/12] Rename constraint name to match the one from 3.2.0 full script --- sql/pgsodium--3.1.7--3.2.0.sql | 7 +++++ test/pgsodium_schema.sql | 50 +++++++++++++++++----------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index e33dd84..41fbf82 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -16,3 +16,10 @@ DROP FUNCTION IF EXISTS pgsodium.mask_columns(oid); * and the old view? */ DROP SCHEMA IF EXISTS pgsodium_masks; + +/* + * change: constraint names generated by the create table pgsodium.key in + * pgsodium--3.2.0.sql are different from the older ones. + */ +ALTER TABLE pgsodium.key RENAME CONSTRAINT "pgsodium_raw" TO "key_check"; +ALTER INDEX pgsodium.pgsodium_key_unique_name RENAME TO key_name_key; diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index 02f98b5..1e22498 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -330,31 +330,31 @@ SELECT results_eq( WHERE n.nspname = 'pgsodium' AND r.relname = 'key' ORDER BY c.contype, c.conname $q$, ARRAY[ + 'key_check', 'key_key_context_check', - 'pgsodium_raw', 'key_parent_key_fkey', 'key_pkey', - 'pgsodium_key_unique_name' + 'key_name_key' ]::name[], $$Event trigger list is ok$$); --- constraint 'key_key_context_check' on 'key' -SELECT is(pg_catalog.pg_get_constraintdef(c.oid, true),'CHECK (length(key_context) = 8)', $$Definition of constraint 'key_key_context_check'$$) -FROM pg_catalog.pg_constraint c -JOIN pg_catalog.pg_class r ON c.conrelid = r.oid -JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace -WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'key_key_context_check'; - --- constraint 'pgsodium_raw' on 'key' +-- constraint 'key_check' on 'key' SELECT is(pg_catalog.pg_get_constraintdef(c.oid, true),'CHECK ( CASE WHEN raw_key IS NOT NULL THEN key_id IS NULL AND key_context IS NULL AND parent_key IS NOT NULL ELSE key_id IS NOT NULL AND key_context IS NOT NULL AND parent_key IS NULL -END)', $$Definition of constraint 'pgsodium_raw'$$) +END)', $$Definition of constraint 'key_check'$$) +FROM pg_catalog.pg_constraint c +JOIN pg_catalog.pg_class r ON c.conrelid = r.oid +JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace +WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'key_check'; + +-- constraint 'key_key_context_check' on 'key' +SELECT is(pg_catalog.pg_get_constraintdef(c.oid, true),'CHECK (length(key_context) = 8)', $$Definition of constraint 'key_key_context_check'$$) FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class r ON c.conrelid = r.oid JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace -WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'pgsodium_raw'; +WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'key_key_context_check'; -- constraint 'key_parent_key_fkey' on 'key' SELECT is(pg_catalog.pg_get_constraintdef(c.oid, true),'FOREIGN KEY (parent_key) REFERENCES pgsodium.key(id)', $$Definition of constraint 'key_parent_key_fkey'$$) @@ -370,20 +370,20 @@ JOIN pg_catalog.pg_class r ON c.conrelid = r.oid JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'key_pkey'; --- constraint 'pgsodium_key_unique_name' on 'key' -SELECT is(pg_catalog.pg_get_constraintdef(c.oid, true),'UNIQUE (name)', $$Definition of constraint 'pgsodium_key_unique_name'$$) +-- constraint 'key_name_key' on 'key' +SELECT is(pg_catalog.pg_get_constraintdef(c.oid, true),'UNIQUE (name)', $$Definition of constraint 'key_name_key'$$) FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class r ON c.conrelid = r.oid JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace -WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'pgsodium_key_unique_name'; +WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.conname = 'key_name_key'; -- indexes of table key SELECT indexes_are('pgsodium'::name, 'key'::name, ARRAY[ 'key_key_id_key_context_key_type_idx', + 'key_name_key', 'key_pkey', 'key_status_idx', - 'key_status_idx1', - 'pgsodium_key_unique_name' + 'key_status_idx1' ]::name[]); -- index 'key_key_id_key_context_key_type_idx' on key @@ -394,6 +394,14 @@ JOIN pg_catalog.pg_class r ON i.indrelid = r.oid JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.relname = 'key_key_id_key_context_key_type_idx'; +-- index 'key_name_key' on key +SELECT is(pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),'CREATE UNIQUE INDEX key_name_key ON pgsodium.key USING btree (name)', $$Definition of index 'key_name_key'$$) +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON c.oid = i.indexrelid +JOIN pg_catalog.pg_class r ON i.indrelid = r.oid +JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace +WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.relname = 'key_name_key'; + -- index 'key_pkey' on key SELECT is(pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),'CREATE UNIQUE INDEX key_pkey ON pgsodium.key USING btree (id)', $$Definition of index 'key_pkey'$$) FROM pg_catalog.pg_class c @@ -419,14 +427,6 @@ JOIN pg_catalog.pg_class r ON i.indrelid = r.oid JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.relname = 'key_status_idx1'; --- index 'pgsodium_key_unique_name' on key -SELECT is(pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),'CREATE UNIQUE INDEX pgsodium_key_unique_name ON pgsodium.key USING btree (name)', $$Definition of index 'pgsodium_key_unique_name'$$) -FROM pg_catalog.pg_class c -JOIN pg_catalog.pg_index i ON c.oid = i.indexrelid -JOIN pg_catalog.pg_class r ON i.indrelid = r.oid -JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace -WHERE n.nspname = 'pgsodium' AND r.relname = 'key' AND c.relname = 'pgsodium_key_unique_name'; - -- triggers of relation key SELECT triggers_are('pgsodium', 'key', ARRAY[ 'key_encrypt_secret_trigger_raw_key' From df73592c75f00f15f90c58b5f2da46a8040f1729 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 16:33:06 +0200 Subject: [PATCH 07/12] Add missing column user_data to the decrypted_key view --- sql/pgsodium--3.1.7--3.2.0.sql | 6 ++++++ test/pgsodium_schema.sql | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index 41fbf82..162aecf 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -23,3 +23,9 @@ DROP SCHEMA IF EXISTS pgsodium_masks; */ ALTER TABLE pgsodium.key RENAME CONSTRAINT "pgsodium_raw" TO "key_check"; ALTER INDEX pgsodium.pgsodium_key_unique_name RENAME TO key_name_key; + +/* + * change: force regenerating the decrypted_key view to add the missing column + * "user_data" to the view. + */ +SELECT * FROM pgsodium.update_mask('pgsodium.key'::regclass::oid); diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index 1e22498..39c4db2 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -474,7 +474,8 @@ SELECT columns_are('pgsodium'::name, 'decrypted_key'::name, ARRAY[ 'decrypted_raw_key', 'raw_key_nonce', 'parent_key', - 'comment' + 'comment', + 'user_data' ]::name[]); SELECT has_column( 'pgsodium', 'decrypted_key', 'id' , 'has column decrypted_key.id'); @@ -547,6 +548,11 @@ SELECT col_type_is( 'pgsodium', 'decrypted_key', 'comment' , 'text', SELECT col_is_null( 'pgsodium', 'decrypted_key', 'comment' , 'col_is_null( decrypted_key.comment )'); SELECT col_hasnt_default('pgsodium', 'decrypted_key', 'comment' , 'col_hasnt_default( decrypted_key.comment )'); +SELECT has_column( 'pgsodium', 'decrypted_key', 'user_data' , 'has column decrypted_key.user_data'); +SELECT col_type_is( 'pgsodium', 'decrypted_key', 'user_data' , 'text', 'type of column decrypted_key.user_data is text'); +SELECT col_is_null( 'pgsodium', 'decrypted_key', 'user_data' , 'col_is_null( decrypted_key.user_data )'); +SELECT col_hasnt_default('pgsodium', 'decrypted_key', 'user_data' , 'col_hasnt_default( decrypted_key.user_data )'); + -- owner of view decrypted_key SELECT view_owner_is('pgsodium'::name, 'decrypted_key'::name, 'postgres'::name); From 6ea0ad2f7ef3493e7cc078f6bd7fb9ba89dccf2e Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 20:55:13 +0200 Subject: [PATCH 08/12] Fix privileges on key and decrypted_keys --- sql/pgsodium--3.1.7--3.2.0.sql | 14 ++++++++++++++ test/pgsodium_schema.sql | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index 162aecf..8e55ebb 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -29,3 +29,17 @@ ALTER INDEX pgsodium.pgsodium_key_unique_name RENAME TO key_name_key; * "user_data" to the view. */ SELECT * FROM pgsodium.update_mask('pgsodium.key'::regclass::oid); + +/* + * Fix privileges + */ + +REVOKE ALL ON pgsodium.key FROM pgsodium_keyiduser; + +REVOKE ALL ON pgsodium.key FROM pgsodium_keymaker; +GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.key TO pgsodium_keymaker; +REVOKE ALL ON pgsodium.decrypted_key FROM pgsodium_keymaker; +GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.decrypted_key TO pgsodium_keymaker; + +REVOKE ALL ON pgsodium.decrypted_key FROM pgsodium_keyholder; +GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.decrypted_key TO pgsodium_keyholder; diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index 39c4db2..cb2a5e3 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -440,7 +440,7 @@ SELECT table_owner_is('pgsodium'::name, 'key'::name, 'postgres'::name); -- privs of relation key -SELECT table_privs_are('pgsodium'::name, 'key'::name, 'pgsodium_keymaker' ::name, '{DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE}'::text[]); +SELECT table_privs_are('pgsodium'::name, 'key'::name, 'pgsodium_keymaker' ::name, '{DELETE,INSERT,SELECT,UPDATE}'::text[]); SELECT table_privs_are('pgsodium'::name, 'key'::name, 'postgres' ::name, '{DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE}'::text[]); SELECT table_privs_are('pgsodium'::name, 'key'::name, rolname, '{}'::text[]) FROM pg_catalog.pg_roles @@ -559,8 +559,8 @@ SELECT view_owner_is('pgsodium'::name, 'decrypted_key'::name, 'postgres'::name); -- privs of relation decrypted_key -SELECT table_privs_are('pgsodium'::name, 'decrypted_key'::name, 'pgsodium_keyholder' ::name, '{DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE}'::text[]); -SELECT table_privs_are('pgsodium'::name, 'decrypted_key'::name, 'pgsodium_keymaker' ::name, '{DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE}'::text[]); +SELECT table_privs_are('pgsodium'::name, 'decrypted_key'::name, 'pgsodium_keyholder' ::name, '{DELETE,INSERT,SELECT,UPDATE}'::text[]); +SELECT table_privs_are('pgsodium'::name, 'decrypted_key'::name, 'pgsodium_keymaker' ::name, '{DELETE,INSERT,SELECT,UPDATE}'::text[]); SELECT table_privs_are('pgsodium'::name, 'decrypted_key'::name, 'postgres' ::name, '{DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE}'::text[]); SELECT table_privs_are('pgsodium'::name, 'decrypted_key'::name, rolname, '{}'::text[]) FROM pg_catalog.pg_roles From aad3d33b2b534986c5cd09ee0f3216af0dcf5c73 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 9 Jun 2023 23:38:59 +0200 Subject: [PATCH 09/12] Revoke default permission on pgsodium from pgsodium_keyholder --- pgsodium_tapgen.pl | 39 ++++++++++++++++++++++++++++++++++ sql/pgsodium--3.1.7--3.2.0.sql | 3 +++ 2 files changed, 42 insertions(+) diff --git a/pgsodium_tapgen.pl b/pgsodium_tapgen.pl index 57ec545..c87d0a6 100755 --- a/pgsodium_tapgen.pl +++ b/pgsodium_tapgen.pl @@ -115,6 +115,45 @@ printf "SELECT is_member_of( %s, %s );\n", $r->[0], $r->[1]; } +$rs = $dbh->selectcol_arrayref(q{ +SELECT format('(%L::text, %L::text, %L::text, %L::text)', + pg_catalog.pg_get_userbyid(d.defaclrole), n.nspname, + CASE d.defaclobjtype + WHEN 'r' THEN 'table' + WHEN 'S' THEN 'sequence' + WHEN 'f' THEN 'function' + WHEN 'T' THEN 'type' + WHEN 'n' THEN 'schema' + END, + pg_catalog.array_to_string(d.defaclacl, E'\n')) +FROM pg_catalog.pg_default_acl d +LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace +ORDER BY 1 +}) or die; + +if (scalar @$rs) { + print "\n\n\n---- DEFAULT PRIVS\n\n"; + print q{SELECT result_eq($$ + SELECT pg_catalog.pg_get_userbyid(d.defaclrole)::text, n.nspname::text, + CASE d.defaclobjtype + WHEN 'r' THEN 'table' + WHEN 'S' THEN 'sequence' + WHEN 'f' THEN 'function' + WHEN 'T' THEN 'type' + WHEN 'n' THEN 'schema' + END, + pg_catalog.array_to_string(d.defaclacl, E'\n')::text + FROM pg_catalog.pg_default_acl d + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace + ORDER BY 1, 2, 3$$, + $$ VALUES + }, + join(",\n ", @$rs), q{ + $$, + 'Check default privileges'); +}; +} + print "\n\n\n---- SCHEMAS\n\n"; $rs = $dbh->selectall_arrayref(q{ diff --git a/sql/pgsodium--3.1.7--3.2.0.sql b/sql/pgsodium--3.1.7--3.2.0.sql index 8e55ebb..9331e08 100644 --- a/sql/pgsodium--3.1.7--3.2.0.sql +++ b/sql/pgsodium--3.1.7--3.2.0.sql @@ -43,3 +43,6 @@ GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.decrypted_key TO pgsodium_keyma REVOKE ALL ON pgsodium.decrypted_key FROM pgsodium_keyholder; GRANT SELECT, INSERT, UPDATE, DELETE ON pgsodium.decrypted_key TO pgsodium_keyholder; + +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON TABLES FROM pgsodium_keyholder; +ALTER DEFAULT PRIVILEGES IN SCHEMA pgsodium REVOKE ALL ON SEQUENCES FROM pgsodium_keyholder; From e702c98bacd46313341daa2dc3fb519f883c8b5b Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Sat, 10 Jun 2023 00:40:41 +0200 Subject: [PATCH 10/12] Makes Dockerfile less chatty --- Dockerfile | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 08de39f..e8a2065 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,9 @@ ARG version ARG DEBIAN_FRONTEND=noninteractive # install base dependences -RUN apt-get update && \ - apt-get install -y make cmake git curl build-essential m4 sudo gdbserver \ - gdb libreadline-dev bison flex zlib1g-dev tmux zile zip vim gawk wget +RUN apt-get -qq update && \ + apt-get -qq install -y make cmake git curl build-essential m4 sudo gdbserver \ + gdb libreadline-dev bison flex zlib1g-dev tmux zile zip vim gawk wget > /dev/null # add postgres user and make data dir RUN groupadd -r postgres && useradd --no-log-init -r -m -s /bin/bash -g postgres -G sudo postgres @@ -15,27 +15,29 @@ WORKDIR "/home/postgres" # get postgres source and compile with debug and no optimization RUN git clone --branch REL_${version}_STABLE https://github.com/postgres/postgres.git --depth=1 && \ - cd postgres && ./configure \ + cd postgres && echo "Installing pgsql..." && ( ./configure \ --prefix=/usr/ \ --enable-debug \ --enable-depend --enable-cassert --enable-profiling \ CFLAGS="-ggdb -Og -g3 -fno-omit-frame-pointer" \ -# CFLAGS="-O3" \ - && make -j 4 && make install + && make -j 4 && make install ) > /dev/null +# CFLAGS="-O3" RUN chown postgres:postgres /home/postgres -RUN curl -s -L https://github.com/theory/pgtap/archive/v1.2.0.tar.gz | tar zxvf - && cd pgtap-1.2.0 && make && make install -RUN curl -s -L https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz | tar zxvf - && cd libsodium-1.0.18 && ./configure && make check && make -j 4 install -RUN cpan App::cpanminus && cpan TAP::Parser::SourceHandler::pgTAP && cpan App::prove +RUN curl -s -L https://github.com/theory/pgtap/archive/v1.2.0.tar.gz | tar zxf - && cd pgtap-1.2.0 && (make && make install) > /dev/null +RUN curl -s -L https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz | tar zxf - && cd libsodium-1.0.18 && (./configure && make check && make -j 4 install) > /dev/null +RUN cpan App::cpanminus > /dev/null +RUN cpan TAP::Parser::SourceHandler::pgTAP > /dev/null +RUN cpan App::prove > /dev/null -RUN git clone --depth 1 https://github.com/lacanoid/pgddl.git -RUN cd pgddl && make && make install && cd .. +RUN git clone --depth 1 https://github.com/lacanoid/pgddl.git && \ + (cd pgddl && make && make install && cd ..) > /dev/null RUN mkdir "/home/postgres/pgsodium" WORKDIR "/home/postgres/pgsodium" COPY . . -RUN make -j 4 && make install +RUN echo "Installing pgsodium..." && (make -j 4 && make install) > /dev/null RUN ldconfig RUN cd `pg_config --sharedir`/extension/ RUN cp getkey_scripts/pgsodium_getkey_urandom.sh `pg_config --sharedir`/extension/pgsodium_getkey @@ -53,6 +55,6 @@ RUN echo "postgres ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \ # start the database USER postgres -RUN initdb -D "$PGDATA" +RUN initdb -D "$PGDATA" > /dev/null EXPOSE 5432 CMD ["/usr/bin/postgres"] From eba57867e64dad71836b887db4d4edcc58cee185 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Sat, 10 Jun 2023 00:41:48 +0200 Subject: [PATCH 11/12] Test both full script and incremental script --- test.sh | 11 +++++++++-- test/test.sql | 26 +++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/test.sh b/test.sh index 9a6d7e6..68e88ab 100755 --- a/test.sh +++ b/test.sh @@ -26,8 +26,15 @@ do echo waiting for database to accept connections sleep 3; echo running tests - - $EXEC pg_prove -U "$SU" /home/postgres/pgsodium/test/test.sql + + # test using inscremental script + $EXEC createdb inc + $EXEC psql -d inc -c 'CREATE EXTENSION pgsodium VERSION "3.1.0"' + $EXEC pg_prove -d inc -U "$SU" /home/postgres/pgsodium/test/test.sql + + # test using full script + $EXEC createdb full + $EXEC pg_prove -d full -U "$SU" /home/postgres/pgsodium/test/test.sql echo destroying test container and image docker rm --force "$DB_HOST" diff --git a/test/test.sql b/test/test.sql index b18e81b..b37f764 100644 --- a/test/test.sql +++ b/test/test.sql @@ -16,7 +16,31 @@ SELECT EXISTS (SELECT * FROM pg_settings CREATE EXTENSION IF NOT EXISTS pgtap; -CREATE EXTENSION IF NOT EXISTS pgsodium; +SELECT diag('Existing pgsodium version: '|| extversion) +FROM pg_catalog.pg_extension +WHERE extname = 'pgsodium'; + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_extension WHERE extname = 'pgsodium') THEN + EXECUTE 'CREATE EXTENSION pgsodium'; + ELSE + EXECUTE 'ALTER EXTENSION pgsodium UPDATE'; + END IF; +END +$$; + +SELECT diag('Installed or updated version of pgsodium: '|| extversion) +FROM pg_catalog.pg_extension +WHERE extname = 'pgsodium'; + +SELECT diag('Running tests on ' || pg_catalog.version()); + +SELECT diag(format('Parameter %s = %s', name, setting)) +FROM pg_settings +WHERE name IN ('shared_preload_libraries', 'pgsodium.getkey_script'); + +SELECT diag('Running tests in database ' || current_database()); BEGIN; CREATE ROLE bobo with login password 'foo'; From b5da330c7003e2a2bc44178697334b0a6ed45630 Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Sat, 10 Jun 2023 01:09:32 +0200 Subject: [PATCH 12/12] Avoid rebuilding the docker image when possible --- test.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test.sh b/test.sh index 68e88ab..cbcdab7 100755 --- a/test.sh +++ b/test.sh @@ -6,16 +6,17 @@ versions=${1:-13 14 15} for version in $versions do + TAG="pgsodium/test-$version" + DB_HOST="pgsodium-test-db-$version" + + echo building test image $DB_HOST + docker build . -t $TAG --build-arg "version=$version" + for config in '-c shared_preload_libraries=pgsodium' '-c shared_preload_libraries=pgsodium -c pgsodium.getkey_script=/getkey' '' do - DB_HOST="pgsodium-test-db-$version" DB_NAME="postgres" SU="postgres" EXEC="docker exec -i $DB_HOST" - TAG="pgsodium/test-$version" - - echo building test image $DB_HOST - docker build . -t $TAG --build-arg "version=$version" echo running test container docker run --rm -e POSTGRES_HOST_AUTH_METHOD=trust -d \