Skip to content

Commit 32984d8

Browse files
committed
Add functions for dealing with PGP armor header lines to pgcrypto.
This add a new pgp_armor_headers function to extract armor headers from an ASCII-armored blob, and a new overloaded variant of the armor function, for constructing an ASCII-armor with extra headers. Marko Tiikkaja and me.
1 parent 0ef3c29 commit 32984d8

11 files changed

+804
-7
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ README.* conflict-marker-size=32
1414
# Certain data files that contain special whitespace, and other special cases
1515
*.data -whitespace
1616
contrib/tsearch2/sql/tsearch2.sql whitespace=space-before-tab,blank-at-eof,-blank-at-eol
17+
contrib/pgcrypto/sql/pgp-armor.sql whitespace=-blank-at-eol
1718
doc/bug.template whitespace=space-before-tab,-blank-at-eof,blank-at-eol
1819
src/backend/catalog/sql_features.txt whitespace=space-before-tab,blank-at-eof,-blank-at-eol
1920
src/backend/tsearch/hunspell_sample.affix whitespace=-blank-at-eof

contrib/pgcrypto/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ MODULE_big = pgcrypto
2626
OBJS = $(SRCS:.c=.o) $(WIN32RES)
2727

2828
EXTENSION = pgcrypto
29-
DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
29+
DATA = pgcrypto--1.2.sql pgcrypto--1.1--1.2.sql pgcrypto--1.0--1.1.sql \
30+
pgcrypto--unpackaged--1.0.sql
3031
PGFILEDESC = "pgcrypto - cryptographic functions"
3132

3233
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \

contrib/pgcrypto/expected/pgp-armor.out

+268
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,271 @@ em9va2E=
102102
-----END PGP MESSAGE-----
103103
');
104104
ERROR: Corrupt ascii-armor
105+
-- corrupt (no space after the colon)
106+
select * from pgp_armor_headers('
107+
-----BEGIN PGP MESSAGE-----
108+
foo:
109+
110+
em9va2E=
111+
=ZZZZ
112+
-----END PGP MESSAGE-----
113+
');
114+
ERROR: Corrupt ascii-armor
115+
-- corrupt (no empty line)
116+
select * from pgp_armor_headers('
117+
-----BEGIN PGP MESSAGE-----
118+
em9va2E=
119+
=ZZZZ
120+
-----END PGP MESSAGE-----
121+
');
122+
ERROR: Corrupt ascii-armor
123+
-- no headers
124+
select * from pgp_armor_headers('
125+
-----BEGIN PGP MESSAGE-----
126+
127+
em9va2E=
128+
=ZZZZ
129+
-----END PGP MESSAGE-----
130+
');
131+
key | value
132+
-----+-------
133+
(0 rows)
134+
135+
-- header with empty value
136+
select * from pgp_armor_headers('
137+
-----BEGIN PGP MESSAGE-----
138+
foo:
139+
140+
em9va2E=
141+
=ZZZZ
142+
-----END PGP MESSAGE-----
143+
');
144+
key | value
145+
-----+-------
146+
foo |
147+
(1 row)
148+
149+
-- simple
150+
select * from pgp_armor_headers('
151+
-----BEGIN PGP MESSAGE-----
152+
fookey: foovalue
153+
barkey: barvalue
154+
155+
em9va2E=
156+
=ZZZZ
157+
-----END PGP MESSAGE-----
158+
');
159+
key | value
160+
--------+----------
161+
fookey | foovalue
162+
barkey | barvalue
163+
(2 rows)
164+
165+
-- insane keys, part 1
166+
select * from pgp_armor_headers('
167+
-----BEGIN PGP MESSAGE-----
168+
insane:key :
169+
170+
em9va2E=
171+
=ZZZZ
172+
-----END PGP MESSAGE-----
173+
');
174+
key | value
175+
-------------+-------
176+
insane:key |
177+
(1 row)
178+
179+
-- insane keys, part 2
180+
select * from pgp_armor_headers('
181+
-----BEGIN PGP MESSAGE-----
182+
insane:key : text value here
183+
184+
em9va2E=
185+
=ZZZZ
186+
-----END PGP MESSAGE-----
187+
');
188+
key | value
189+
-------------+-----------------
190+
insane:key | text value here
191+
(1 row)
192+
193+
-- long value
194+
select * from pgp_armor_headers('
195+
-----BEGIN PGP MESSAGE-----
196+
long: this value is more than 76 characters long, but it should still parse correctly as that''s permitted by RFC 4880
197+
198+
em9va2E=
199+
=ZZZZ
200+
-----END PGP MESSAGE-----
201+
');
202+
key | value
203+
------+-----------------------------------------------------------------------------------------------------------------
204+
long | this value is more than 76 characters long, but it should still parse correctly as that's permitted by RFC 4880
205+
(1 row)
206+
207+
-- long value, split up
208+
select * from pgp_armor_headers('
209+
-----BEGIN PGP MESSAGE-----
210+
long: this value is more than 76 characters long, but it should still
211+
long: parse correctly as that''s permitted by RFC 4880
212+
213+
em9va2E=
214+
=ZZZZ
215+
-----END PGP MESSAGE-----
216+
');
217+
key | value
218+
------+------------------------------------------------------------------
219+
long | this value is more than 76 characters long, but it should still
220+
long | parse correctly as that's permitted by RFC 4880
221+
(2 rows)
222+
223+
-- long value, split up, part 2
224+
select * from pgp_armor_headers('
225+
-----BEGIN PGP MESSAGE-----
226+
long: this value is more than
227+
long: 76 characters long, but it should still
228+
long: parse correctly as that''s permitted by RFC 4880
229+
230+
em9va2E=
231+
=ZZZZ
232+
-----END PGP MESSAGE-----
233+
');
234+
key | value
235+
------+-------------------------------------------------
236+
long | this value is more than
237+
long | 76 characters long, but it should still
238+
long | parse correctly as that's permitted by RFC 4880
239+
(3 rows)
240+
241+
-- long value, split up, part 3
242+
select * from pgp_armor_headers('
243+
-----BEGIN PGP MESSAGE-----
244+
emptykey:
245+
long: this value is more than
246+
emptykey:
247+
long: 76 characters long, but it should still
248+
emptykey:
249+
long: parse correctly as that''s permitted by RFC 4880
250+
emptykey:
251+
252+
em9va2E=
253+
=ZZZZ
254+
-----END PGP MESSAGE-----
255+
');
256+
key | value
257+
----------+-------------------------------------------------
258+
emptykey |
259+
long | this value is more than
260+
emptykey |
261+
long | 76 characters long, but it should still
262+
emptykey |
263+
long | parse correctly as that's permitted by RFC 4880
264+
emptykey |
265+
(7 rows)
266+
267+
select * from pgp_armor_headers('
268+
-----BEGIN PGP MESSAGE-----
269+
Comment: dat1.blowfish.sha1.mdc.s2k3.z0
270+
271+
jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS
272+
yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE=
273+
=JcP+
274+
-----END PGP MESSAGE-----
275+
');
276+
key | value
277+
---------+--------------------------------
278+
Comment | dat1.blowfish.sha1.mdc.s2k3.z0
279+
(1 row)
280+
281+
-- test CR+LF line endings
282+
select * from pgp_armor_headers(replace('
283+
-----BEGIN PGP MESSAGE-----
284+
fookey: foovalue
285+
barkey: barvalue
286+
287+
em9va2E=
288+
=ZZZZ
289+
-----END PGP MESSAGE-----
290+
', E'\n', E'\r\n'));
291+
key | value
292+
--------+----------
293+
fookey | foovalue
294+
barkey | barvalue
295+
(2 rows)
296+
297+
-- test header generation
298+
select armor('zooka', array['foo'], array['bar']);
299+
armor
300+
-----------------------------
301+
-----BEGIN PGP MESSAGE-----+
302+
foo: bar +
303+
+
304+
em9va2E= +
305+
=D5cR +
306+
-----END PGP MESSAGE----- +
307+
308+
(1 row)
309+
310+
select armor('zooka', array['Version', 'Comment'], array['Created by pgcrypto', 'PostgreSQL, the world''s most advanced open source database']);
311+
armor
312+
---------------------------------------------------------------------
313+
-----BEGIN PGP MESSAGE----- +
314+
Version: Created by pgcrypto +
315+
Comment: PostgreSQL, the world's most advanced open source database+
316+
+
317+
em9va2E= +
318+
=D5cR +
319+
-----END PGP MESSAGE----- +
320+
321+
(1 row)
322+
323+
select * from pgp_armor_headers(
324+
armor('zooka', array['Version', 'Comment'],
325+
array['Created by pgcrypto', 'PostgreSQL, the world''s most advanced open source database']));
326+
key | value
327+
---------+------------------------------------------------------------
328+
Version | Created by pgcrypto
329+
Comment | PostgreSQL, the world's most advanced open source database
330+
(2 rows)
331+
332+
-- error/corner cases
333+
select armor('', array['foo'], array['too', 'many']);
334+
ERROR: mismatched array dimensions
335+
select armor('', array['too', 'many'], array['foo']);
336+
ERROR: mismatched array dimensions
337+
select armor('', array[['']], array['foo']);
338+
ERROR: wrong number of array subscripts
339+
select armor('', array['foo'], array[['']]);
340+
ERROR: wrong number of array subscripts
341+
select armor('', array[null], array['foo']);
342+
ERROR: null value not allowed for header key
343+
select armor('', array['foo'], array[null]);
344+
ERROR: null value not allowed for header value
345+
select armor('', '[0:0]={"foo"}', array['foo']);
346+
armor
347+
-----------------------------
348+
-----BEGIN PGP MESSAGE-----+
349+
foo: foo +
350+
+
351+
=twTO +
352+
-----END PGP MESSAGE----- +
353+
354+
(1 row)
355+
356+
select armor('', array['foo'], '[0:0]={"foo"}');
357+
armor
358+
-----------------------------
359+
-----BEGIN PGP MESSAGE-----+
360+
foo: foo +
361+
+
362+
=twTO +
363+
-----END PGP MESSAGE----- +
364+
365+
(1 row)
366+
367+
select armor('', array[E'embedded\nnewline'], array['foo']);
368+
ERROR: header key must not contain newlines
369+
select armor('', array['foo'], array[E'embedded\nnewline']);
370+
ERROR: header value must not contain newlines
371+
select armor('', array['embedded: colon+space'], array['foo']);
372+
ERROR: header key must not contain ": "
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
5+
6+
CREATE FUNCTION armor(bytea, text[], text[])
7+
RETURNS text
8+
AS 'MODULE_PATHNAME', 'pg_armor'
9+
LANGUAGE C IMMUTABLE STRICT;
10+
11+
CREATE FUNCTION pgp_armor_headers(text, key OUT text, value OUT text)
12+
RETURNS SETOF record
13+
AS 'MODULE_PATHNAME', 'pgp_armor_headers'
14+
LANGUAGE C IMMUTABLE STRICT;

contrib/pgcrypto/pgcrypto--1.1.sql contrib/pgcrypto/pgcrypto--1.2.sql

+10
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,17 @@ RETURNS text
201201
AS 'MODULE_PATHNAME', 'pg_armor'
202202
LANGUAGE C IMMUTABLE STRICT;
203203

204+
CREATE FUNCTION armor(bytea, text[], text[])
205+
RETURNS text
206+
AS 'MODULE_PATHNAME', 'pg_armor'
207+
LANGUAGE C IMMUTABLE STRICT;
208+
204209
CREATE FUNCTION dearmor(text)
205210
RETURNS bytea
206211
AS 'MODULE_PATHNAME', 'pg_dearmor'
207212
LANGUAGE C IMMUTABLE STRICT;
213+
214+
CREATE FUNCTION pgp_armor_headers(text, key OUT text, value OUT text)
215+
RETURNS SETOF record
216+
AS 'MODULE_PATHNAME', 'pgp_armor_headers'
217+
LANGUAGE C IMMUTABLE STRICT;

contrib/pgcrypto/pgcrypto.control

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pgcrypto extension
22
comment = 'cryptographic functions'
3-
default_version = '1.1'
3+
default_version = '1.2'
44
module_pathname = '$libdir/pgcrypto'
55
relocatable = true

0 commit comments

Comments
 (0)