pgcrypto: PGP signatures
Hi hackers,
Attached is a patch to add support for PGP signatures in encrypted
messages into pgcrypto.
Currently, the list of limitations is the following:
- It only knows how to generate one signature per message. I don't
see that as a problem.
- If a message has been signed with multiple keys which have the
same keyid as the one specified to verify the message, an error is
returned. Naively, it seems that we should try all of them and return
"OK" if even one of them matches, but that seems icky.
- Only RSA signatures are supported. It wouldn't be too hard for
someone familiar with DSA to add it in, but I'm not volunteering to do
it. Personally I think supporting RSA is better than no support at all.
As per usual, I'll also add this to the upcoming commitfest. Any
feedback appreciated before that, of course.
.marko
Attachments:
pgcrypto_sigs.v1.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v1.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,39 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 20,39 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.2.sql pgcrypto--1.0--1.1.sql pgcrypto--1.1--1.2.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,313 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signature_keys.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signature_keys(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa
+ (1 row)
+
+ select pgp_pub_signature_keys.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signature_keys(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha512 | rsa
+ (1 row)
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ select * from pgp_sym_signature_keys((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha512 | rsa
+ 9DCF8E9C9BD31F24 | sha512 | rsa
+ (2 rows)
+
+ select * from pgp_pub_signature_keys((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha1 | rsa
+ 9DCF8E9C9BD31F24 | sha1 | rsa
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ for (;;)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 0 ****
--- 1,192 ----
+ /* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signature_keys(data, psw)
+ --
+ CREATE FUNCTION pgp_sym_signature_keys(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 0 ****
--- 1,394 ----
+ /* contrib/pgcrypto/pgcrypto--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+ CREATE FUNCTION digest(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION digest(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION crypt(text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_crypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_salt(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_salt(text, int4)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION encrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_random_bytes(int4)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_random_bytes'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_random_uuid()
+ RETURNS uuid
+ AS 'MODULE_PATHNAME', 'pg_random_uuid'
+ LANGUAGE C VOLATILE;
+
+ --
+ -- pgp_sym_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- PGP key ID
+ --
+ CREATE FUNCTION pgp_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
+ --
+ -- pgp_sym_signature_keys(data, psw)
+ --
+ CREATE FUNCTION pgp_sym_signature_keys(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
+ --
+ -- pgp armor
+ --
+ CREATE FUNCTION armor(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_armor'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION dearmor(text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_dearmor'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto.control
--- b/contrib/pgcrypto/pgcrypto.control
***************
*** 1,5 ****
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.1'
module_pathname = '$libdir/pgcrypto'
relocatable = true
--- 1,5 ----
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.2'
module_pathname = '$libdir/pgcrypto'
relocatable = true
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1153,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static void
+ sig_compute_free(void *priv)
+ {
+ PX_MD *md = priv;
+
+ px_md_free(md);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, sig_compute_free
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization, if there is one.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,285 ----
return 8 * 2;
}
! typedef int (*sig_key_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signature_keys(PGP_Context *ctx, PullFilter *src, void *opaque,
! sig_key_cb_type sig_key_cb, int allow_compr);
!
!
! static int
! read_signature_keys_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, sig_key_cb_type sig_key_cb)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signature_keys(ctx, pf_decompr, opaque, sig_key_cb, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signature_keys(ctx, pf_decompr, opaque, sig_key_cb, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signature_keys_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signature_keys_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signature_keys(PGP_Context *ctx, PullFilter *src, void *opaque,
! sig_key_cb_type sig_key_cb, int allow_compr)
! {
! int res;
! PGP_Signature *sig = NULL;
! PullFilter *pkt = NULL;
! int len;
! uint8 tag;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_key_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signature_keys_from_compressed_data(ctx, pkt, opaque, sig_key_cb);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! elog(WARNING, "broken tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and to extract out all the
! * signatures.
*/
! static int
! read_signature_keys_from_data(PGP_Context *ctx, PullFilter *pkt, int tag,
! void *opaque, sig_key_cb_type sig_key_cb)
! {
! int res;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
! int resync;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("extract_signature_keys: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signature_keys(ctx, pf_prefix, opaque, sig_key_cb, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! sig_key_cb_type sig_key_cb)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 292,298 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
! {
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else
res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 312,373 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
res = PXE_PGP_MULTIPLE_KEYS;
+ else
+ {
+ got_main_key = 1;
+ if (want_main_key)
+ res = read_pubkey_keyid(pkt, keyid_buf);
+ else
+ res = pgp_skip_packet(pkt);
+ }
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_key_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_key_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_key_cb)
+ res = read_signature_keys_from_data(ctx, pkt, tag, opaque, sig_key_cb);
break;
case PGP_PKT_SIGNATURE:
+ if (sig_key_cb)
+ {
+ res = pgp_parse_signature(ctx, &sig, pkt, NULL);
+ if (res >= 0)
+ res = sig_key_cb(opaque, sig);
+ }
+ else
+ res = pgp_skip_packet(pkt);
+ break;
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 382,390 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
! }
! else if (got_symenc_key)
! {
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
else
! res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 410,497 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
else
! {
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
! }
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL);
+ }
+
+ struct GetSignatureKeyCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ };
+
+ static int
+ get_signature_key_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureKeyCtx *ctx = opaque;
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signature_keys(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid))
+ {
+ struct GetSignatureKeyCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL, get_signature_key_cb);
+ }
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 33,38 ****
--- 33,41 ----
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+ #include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 43,57 ****
--- 46,71 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signature_keys_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signature_keys_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 162,167 **** struct debug_expect
--- 176,182 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 177,182 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 192,198 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 199,204 **** static void
--- 215,221 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 223,228 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 240,247 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 249,254 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 268,278 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 414,420 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 438,445 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 459,480 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 484,529 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 507,513 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 556,562 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 547,571 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* decrypt
*/
! if (err >= 0)
! err = pgp_decrypt(ctx, src, dst);
!
! /*
! * failed?
! */
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 596,642 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
+
/*
* decrypt
*/
! err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 615,620 **** out:
--- 686,826 ----
return res;
}
+ struct MaterializeSignatureKeyCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_key_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureKeyCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[3];
+ bool isnull[3] = { false, false, false };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signature_keys(int is_pubenc, text *data, text *key, text *keypsw,
+ Tuplestorestate *tupstore, TupleDesc tupdesc)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureKeyCtx cbctx;
+
+ init_work(&ctx, 0, NULL, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signature_keys(ctx, src, &cbctx, materialize_signature_key_cb);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ signature_keys_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ ReturnSetInfo *rsinfo)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 3)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signature_keys(is_pubenc, data, key, keypsw, tupstore, tupdesc);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 631,637 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 837,843 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 653,659 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 859,865 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 662,667 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 868,933 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 676,682 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 942,948 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 698,704 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 964,970 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 707,712 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 973,1038 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 724,730 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1050,1056 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 746,752 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1072,1078 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 755,760 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1081,1145 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 772,778 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1157,1163 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 799,805 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1184,1190 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 810,815 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1195,1259 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 874,880 **** pg_dearmor(PG_FUNCTION_ARGS)
}
/*
! * Wrappers for PGP key id
*/
Datum
--- 1318,1324 ----
}
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 889,895 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1333,1339 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 900,902 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1344,1423 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signature_keys_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw;
+ int err;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+
+ err = signature_keys_internal(0, data, psw, NULL,
+ (ReturnSetInfo *) fcinfo->resultinfo);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signature_keys_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL;
+ int err;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+
+ err = signature_keys_internal(1, data, key, keypsw,
+ (ReturnSetInfo *) fcinfo->resultinfo);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 29,38 ****
--- 29,42 ----
* contrib/pgcrypto/pgp-pubenc.c
*/
#include "postgres.h"
+ #include "c.h"
#include "px.h"
#include "pgp.h"
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
/*
* padded msg: 02 || non-zero pad bytes || 00 || msg
*/
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 206,212 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
!
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,807 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, sig->creation_time);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, sig->creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+
+ struct SigSubPktParserState pstate;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ for (;;)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, sig->creation_time);
+ if (res < 0)
+ goto err;
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ res = PXE_PGP_CORRUPT_DATA;
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 230,235 **** pgp_free(PGP_Context *ctx)
--- 290,317 ----
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 396,412 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 45,50 **** enum PGP_PKT_TYPE
--- 45,51 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 107,121 **** enum PGP_DIGEST_TYPE
PGP_DIGEST_SHA512 = 10
};
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
struct PGP_S2K
{
--- 108,136 ----
PGP_DIGEST_SHA512 = 10
};
! enum PGP_SIGNATURE_TYPE
! {
! PGP_SIGTYP_BINARY = 0,
! PGP_SIGTYP_TEXT = 1
! };
!
! enum PGP_SIGNATURE_SUBPKT_TYPE
! {
! PGP_SIGNATURE_CREATION_TIME = 2,
! PGP_ISSUER_ID = 16
! };
!
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_MAX_DIGEST_ASN1_PREFIX 20
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 139,144 **** struct PGP_Context
--- 154,160 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 156,163 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 172,184 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 227,243 **** struct PGP_PubKey
--- 248,286 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint8 creation_time[4];
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 251,260 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 294,309 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signature_keys(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid));
/* internal functions */
***************
*** 286,291 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 335,342 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 298,303 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 349,362 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 314,316 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 373,376 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,199 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signature_keys.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signature_keys(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signature_keys.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signature_keys(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ select * from pgp_sym_signature_keys((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signature_keys((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 535,565 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 573,591 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 596,608 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce a error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 619,648 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, the
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 661,679 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 683,695 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 747,808 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signature_keys</> and <function>pgp_pub_signature_keys</>
+ if you want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signature_keys()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signature_keys</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signature_keys(data bytea, key text) returns setof (keyid text, digest text, pubkeyalgo text)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signature_keys</> extracts the list of signatures present
+ in the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signature_keys()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signature_keys</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signature_keys(data bytea, key bytea [ , psw text]) returns setof (keyid text, digest text, pubkeyalgo text)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signature_keys</> extracts the list of signatures present
+ in the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 786,791 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 909,927 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 929,942 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1065,1073 ----
<itemizedlist>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
On 8/6/14 2:46 PM, I wrote:
Attached is a patch to add support for PGP signatures in encrypted
messages into pgcrypto.
Here's v2 of the patch. I've changed the info-extracting code to not
look for signatures beyond the data, which also meant that it had to
parse one-pass signatures (which it didn't do before). This matches the
behaviour of the main decryption code.
.marko
Attachments:
pgcrypto_sigs.v2.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v2.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,39 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 20,39 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.2.sql pgcrypto--1.0--1.1.sql pgcrypto--1.1--1.2.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,313 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signature_keys.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signature_keys(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa
+ (1 row)
+
+ select pgp_pub_signature_keys.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signature_keys(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha512 | rsa
+ (1 row)
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ select * from pgp_sym_signature_keys((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa
+ C899EA9344195559 | sha512 | rsa
+ (2 rows)
+
+ select * from pgp_pub_signature_keys((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa
+ C899EA9344195559 | sha1 | rsa
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ for (;;)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 0 ****
--- 1,192 ----
+ /* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signature_keys(data, psw)
+ --
+ CREATE FUNCTION pgp_sym_signature_keys(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 0 ****
--- 1,394 ----
+ /* contrib/pgcrypto/pgcrypto--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+ CREATE FUNCTION digest(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION digest(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION crypt(text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_crypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_salt(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_salt(text, int4)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION encrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_random_bytes(int4)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_random_bytes'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_random_uuid()
+ RETURNS uuid
+ AS 'MODULE_PATHNAME', 'pg_random_uuid'
+ LANGUAGE C VOLATILE;
+
+ --
+ -- pgp_sym_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- PGP key ID
+ --
+ CREATE FUNCTION pgp_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
+ --
+ -- pgp_sym_signature_keys(data, psw)
+ --
+ CREATE FUNCTION pgp_sym_signature_keys(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
+ --
+ -- pgp armor
+ --
+ CREATE FUNCTION armor(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_armor'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION dearmor(text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_dearmor'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto.control
--- b/contrib/pgcrypto/pgcrypto.control
***************
*** 1,5 ****
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.1'
module_pathname = '$libdir/pgcrypto'
relocatable = true
--- 1,5 ----
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.2'
module_pathname = '$libdir/pgcrypto'
relocatable = true
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1153,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static void
+ sig_compute_free(void *priv)
+ {
+ PX_MD *md = priv;
+
+ px_md_free(md);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, sig_compute_free
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization, if there is one.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,299 ----
return 8 * 2;
}
! typedef int (*sig_key_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signature_keys(PGP_Context *ctx, PullFilter *src, void *opaque,
! sig_key_cb_type sig_key_cb, int allow_compr);
!
!
! static int
! read_signature_keys_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, sig_key_cb_type sig_key_cb)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signature_keys(ctx, pf_decompr, opaque, sig_key_cb, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signature_keys(ctx, pf_decompr, opaque, sig_key_cb, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signature_keys_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signature_keys_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signature_keys(PGP_Context *ctx, PullFilter *src, void *opaque,
! sig_key_cb_type sig_key_cb, int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_key_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_key_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signature_keys_from_compressed_data(ctx, pkt, opaque, sig_key_cb);
! /* fallthrough */
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * We never look for signatures beyond the data, as the
! * decryption code doesn't, either. We're also assuming that
! * there will only ever be a single data packet, compressed or
! * otherwise.
! */
! done = 1;
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signature_keys: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and to extract out all the
! * signatures.
*/
! static int
! read_signature_keys_from_data(PGP_Context *ctx, PullFilter *pkt, int tag,
! void *opaque, sig_key_cb_type sig_key_cb)
! {
! int res;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
! int resync;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("extract_signature_keys: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signature_keys(ctx, pf_prefix, opaque, sig_key_cb, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! sig_key_cb_type sig_key_cb)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 306,312 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 326,387 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_key_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_key_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_key_cb)
+ res = read_signature_keys_from_data(ctx, pkt, tag, opaque, sig_key_cb);
break;
case PGP_PKT_SIGNATURE:
+ if (sig_key_cb)
+ {
+ res = pgp_parse_signature(ctx, &sig, pkt, NULL);
+ if (res >= 0)
+ res = sig_key_cb(opaque, sig);
+ }
+ else
+ res = pgp_skip_packet(pkt);
+ break;
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 396,404 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 424,511 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL);
+ }
+
+ struct GetSignatureKeyCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ };
+
+ static int
+ get_signature_key_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureKeyCtx *ctx = opaque;
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signature_keys(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid))
+ {
+ struct GetSignatureKeyCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL, get_signature_key_cb);
+ }
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 33,38 ****
--- 33,41 ----
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+ #include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 43,57 ****
--- 46,71 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signature_keys_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signature_keys_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 162,167 **** struct debug_expect
--- 176,182 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 177,182 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 192,198 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 199,204 **** static void
--- 215,221 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 223,228 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 240,247 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 249,254 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 268,278 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 414,420 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 438,445 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 459,480 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 484,529 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 507,513 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 556,562 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 547,571 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 596,642 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 615,620 **** out:
--- 686,826 ----
return res;
}
+ struct MaterializeSignatureKeyCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_key_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureKeyCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[3];
+ bool isnull[3] = { false, false, false };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signature_keys(int is_pubenc, text *data, text *key, text *keypsw,
+ Tuplestorestate *tupstore, TupleDesc tupdesc)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureKeyCtx cbctx;
+
+ init_work(&ctx, 0, NULL, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signature_keys(ctx, src, &cbctx, materialize_signature_key_cb);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ signature_keys_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ ReturnSetInfo *rsinfo)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 3)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signature_keys(is_pubenc, data, key, keypsw, tupstore, tupdesc);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 631,637 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 837,843 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 653,659 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 859,865 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 662,667 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 868,933 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 676,682 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 942,948 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 698,704 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 964,970 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 707,712 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 973,1038 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 724,730 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1050,1056 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 746,752 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1072,1078 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 755,760 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1081,1145 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 772,778 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1157,1163 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 799,805 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1184,1190 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 810,815 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1195,1259 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 874,880 **** pg_dearmor(PG_FUNCTION_ARGS)
}
/*
! * Wrappers for PGP key id
*/
Datum
--- 1318,1324 ----
}
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 889,895 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1333,1363 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
! mbuf_free(buf);
! if (res_len < 0)
! ereport(ERROR,
! (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
! errmsg("%s", px_strerror(res_len))));
! SET_VARSIZE(res, VARHDRSZ + res_len);
!
! PG_FREE_IF_COPY(data, 0);
! PG_RETURN_TEXT_P(res);
! }
!
! Datum
! pgp_main_key_id_w(PG_FUNCTION_ARGS)
! {
! bytea *data;
! text *res;
! int res_len;
! MBuf *buf;
!
! data = PG_GETARG_BYTEA_P(0);
! buf = create_mbuf_from_vardata(data);
! res = palloc(VARHDRSZ + 17);
!
! res_len = pgp_get_keyid(1, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 900,902 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1368,1423 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+
+ Datum
+ pgp_sym_signature_keys_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw;
+ int err;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+
+ err = signature_keys_internal(0, data, psw, NULL,
+ (ReturnSetInfo *) fcinfo->resultinfo);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signature_keys_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL;
+ int err;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+
+ err = signature_keys_internal(1, data, key, keypsw,
+ (ReturnSetInfo *) fcinfo->resultinfo);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 29,38 ****
--- 29,42 ----
* contrib/pgcrypto/pgp-pubenc.c
*/
#include "postgres.h"
+ #include "c.h"
#include "px.h"
#include "pgp.h"
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
/*
* padded msg: 02 || non-zero pad bytes || 00 || msg
*/
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 206,212 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,810 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, sig->creation_time);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, sig->creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+
+ struct SigSubPktParserState pstate;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ for (;;)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, sig->creation_time);
+ if (res < 0)
+ goto err;
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 230,235 **** pgp_free(PGP_Context *ctx)
--- 290,317 ----
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 396,412 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 45,50 **** enum PGP_PKT_TYPE
--- 45,51 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 107,121 **** enum PGP_DIGEST_TYPE
PGP_DIGEST_SHA512 = 10
};
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
struct PGP_S2K
{
--- 108,136 ----
PGP_DIGEST_SHA512 = 10
};
! enum PGP_SIGNATURE_TYPE
! {
! PGP_SIGTYP_BINARY = 0,
! PGP_SIGTYP_TEXT = 1
! };
!
! enum PGP_SIGNATURE_SUBPKT_TYPE
! {
! PGP_SIGNATURE_CREATION_TIME = 2,
! PGP_ISSUER_ID = 16
! };
!
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_MAX_DIGEST_ASN1_PREFIX 20
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 139,144 **** struct PGP_Context
--- 154,160 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 156,163 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 172,184 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 227,243 **** struct PGP_PubKey
--- 248,286 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint8 creation_time[4];
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 251,260 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 294,309 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signature_keys(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid));
/* internal functions */
***************
*** 286,291 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 335,342 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 298,303 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 349,362 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 314,316 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 373,376 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,199 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signature_keys.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signature_keys(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signature_keys.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signature_keys(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ select * from pgp_sym_signature_keys((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signature_keys((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 535,565 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 573,591 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 596,608 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce a error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 619,648 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, the
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 661,679 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 683,695 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 747,808 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signature_keys</> and <function>pgp_pub_signature_keys</>
+ if you want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signature_keys()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signature_keys</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signature_keys(data bytea, key text) returns setof (keyid text, digest text, pubkeyalgo text)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signature_keys</> extracts the list of signatures present
+ in the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signature_keys()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signature_keys</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signature_keys(data bytea, key bytea [ , psw text]) returns setof (keyid text, digest text, pubkeyalgo text)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signature_keys</> extracts the list of signatures present
+ in the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 786,791 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 909,927 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 929,942 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1065,1073 ----
<itemizedlist>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
Hi,
On 8/7/14 12:15 PM, I wrote:
Here's v2 of the patch. I've changed the info-extracting code to not
look for signatures beyond the data, which also meant that it had to
parse one-pass signatures (which it didn't do before). This matches the
behaviour of the main decryption code.
Here's the latest version where I've added the option to extract the
creation time from the signatures.
.marko
Attachments:
pgcrypto_sigs.v3.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v3.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,39 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 20,39 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.2.sql pgcrypto--1.0--1.1.sql pgcrypto--1.1--1.2.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,337 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ (1 row)
+
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ C899EA9344195559 | sha512 | rsa |
+ (1 row)
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+ NOTICE: dbg: key_id's does not match
+ ERROR: Wrong key
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ C899EA9344195559 | sha512 | rsa |
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa |
+ C899EA9344195559 | sha1 | rsa |
+ (2 rows)
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ 9DCF8E9C9BD31F24 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ for (;;)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 0 ****
--- 1,224 ----
+ /* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 0 ****
--- 1,424 ----
+ /* contrib/pgcrypto/pgcrypto--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+ CREATE FUNCTION digest(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION digest(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION crypt(text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_crypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_salt(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_salt(text, int4)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION encrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_random_bytes(int4)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_random_bytes'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_random_uuid()
+ RETURNS uuid
+ AS 'MODULE_PATHNAME', 'pg_random_uuid'
+ LANGUAGE C VOLATILE;
+
+ --
+ -- pgp_sym_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- PGP key ID
+ --
+ CREATE FUNCTION pgp_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp armor
+ --
+ CREATE FUNCTION armor(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_armor'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION dearmor(text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_dearmor'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto.control
--- b/contrib/pgcrypto/pgcrypto.control
***************
*** 1,5 ****
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.1'
module_pathname = '$libdir/pgcrypto'
relocatable = true
--- 1,5 ----
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.2'
module_pathname = '$libdir/pgcrypto'
relocatable = true
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1153,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static void
+ sig_compute_free(void *priv)
+ {
+ PX_MD *md = priv;
+
+ px_md_free(md);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, sig_compute_free
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization, if there is one.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,317 ----
return 8 * 2;
}
! typedef int (*signature_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr);
!
!
! static int
! read_signatures_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signatures_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signatures_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signatures_from_compressed_data(ctx, pkt, opaque,
! sig_cb, extract_details);
! /*
! * We're assuming that there will only ever be a single data
! * packet, compressed or otherwise.
! */
! if (!extract_details)
! done = 1;
! break;
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * If extract_details is not specified, we never look for
! * signatures beyond the data as the decryption code doesn't,
! * either.
! */
! if (!extract_details)
! done = 1;
! else
! res = pgp_skip_packet(pkt);
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signatures: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and extract information about
! * the signatures.
*/
! static int
! read_signatures_from_data(PGP_Context *ctx, PullFilter *pkt, int tag, void *opaque,
! signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! int resync;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("read_signature_from_data: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signatures(ctx, pf_prefix, opaque, sig_key_cb, extract_details, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! signature_cb_type sig_cb,
! int extract_details)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 324,330 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 344,400 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_cb)
+ res = read_signatures_from_data(ctx, pkt, tag, opaque, sig_cb, extract_details);
break;
case PGP_PKT_SIGNATURE:
+ /*
+ * We ignore signatures not part of the encrypted data since we
+ * won't use them anyway.
+ */
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 409,417 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 437,542 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL, 0);
+ }
+
+ struct GetSignatureInfoCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ int extract_details;
+ };
+
+ static int
+ get_signature_info_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureInfoCtx *ctx = opaque;
+
+ /* ignore signatures not used for literal data */
+ if (sig->type != PGP_SIGTYP_BINARY &&
+ sig->type != PGP_SIGTYP_TEXT)
+ return 0;
+
+ /*
+ * Also skip one-pass signatures if we're extracting details; there should
+ * be a corresponding signature packet after the data with all the details.
+ */
+ if (sig->onepass && ctx->extract_details)
+ return 0;
+
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
+ int extract_details)
+ {
+ struct GetSignatureInfoCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ cbctx.extract_details = extract_details;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL,
+ get_signature_info_cb, extract_details);
+ }
+
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 33,38 ****
--- 33,42 ----
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+ #include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "utils/timestamp.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 43,57 ****
--- 47,72 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signatures_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signatures_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 162,167 **** struct debug_expect
--- 177,183 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 177,182 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 193,199 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 199,204 **** static void
--- 216,222 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 223,228 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 241,248 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 249,254 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 269,279 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 414,420 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 439,446 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 459,480 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 485,530 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 507,513 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 557,563 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 547,571 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 597,643 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 615,620 **** out:
--- 687,846 ----
return res;
}
+ struct MaterializeSignatureCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[4];
+ bool isnull[4] = { false, false, false, true };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ /*
+ * If this isn't a one-pass signature, we also know the creation time of
+ * the signature.
+ */
+ if (!sig->onepass)
+ {
+ time_t t;
+
+ isnull[3] = false;
+ /* unsigned big endian */
+ t = sig->creation_time[0] << 24;
+ t += sig->creation_time[1] << 16;
+ t += sig->creation_time[2] << 8;
+ t += sig->creation_time[3];
+ values[3] = time_t_to_timestamptz(t);
+ }
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signatures(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, Tuplestorestate *tupstore, TupleDesc tupdesc,
+ int extract_details)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureCtx cbctx;
+
+ init_work(&ctx, 0, arg, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signatures(ctx, src, &cbctx, materialize_signature_cb,
+ extract_details);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ extract_signatures_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, ReturnSetInfo *rsinfo, int extract_details)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 4)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signatures(is_pubenc, data, key, keypsw,
+ arg, tupstore, tupdesc, extract_details);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 631,637 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 857,863 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 653,659 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 879,885 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 662,667 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 888,953 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 676,682 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 962,968 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 698,704 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 984,990 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 707,712 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 993,1058 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 724,730 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1070,1076 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 746,752 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1092,1098 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 755,760 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1101,1165 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 772,778 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1177,1183 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 799,805 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1204,1210 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 810,815 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1215,1279 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 874,880 **** pg_dearmor(PG_FUNCTION_ARGS)
}
/*
! * Wrappers for PGP key id
*/
Datum
--- 1338,1344 ----
}
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 889,895 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1353,1359 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 900,902 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1364,1463 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+ if (PG_NARGS() > 2)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(2));
+ if (PG_NARGS() > 3)
+ arg = PG_GETARG_BYTEA_P(3);
+
+ err = extract_signatures_internal(0, data, psw, NULL, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(3));
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ err = extract_signatures_internal(1, data, key, keypsw, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 202,208 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,811 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, sig->creation_time);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, sig->creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ struct SigSubPktParserState pstate;
+ int res;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ for (;;)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, sig->creation_time);
+ if (res < 0)
+ goto err;
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+ (void) last;
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->onepass = 0;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 230,235 **** pgp_free(PGP_Context *ctx)
--- 290,317 ----
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 396,412 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 45,50 **** enum PGP_PKT_TYPE
--- 45,51 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 107,121 **** enum PGP_DIGEST_TYPE
PGP_DIGEST_SHA512 = 10
};
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
struct PGP_S2K
{
--- 108,136 ----
PGP_DIGEST_SHA512 = 10
};
! enum PGP_SIGNATURE_TYPE
! {
! PGP_SIGTYP_BINARY = 0,
! PGP_SIGTYP_TEXT = 1
! };
!
! enum PGP_SIGNATURE_SUBPKT_TYPE
! {
! PGP_SIGNATURE_CREATION_TIME = 2,
! PGP_ISSUER_ID = 16
! };
!
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_MAX_DIGEST_ASN1_PREFIX 20
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 139,144 **** struct PGP_Context
--- 154,160 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 156,163 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 172,184 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 227,243 **** struct PGP_PubKey
--- 248,286 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint8 creation_time[4];
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 251,260 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
!
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 294,310 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
!
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
! int extract_details);
/* internal functions */
***************
*** 286,291 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 336,343 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 298,303 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 350,363 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 314,316 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 374,377 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,211 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 535,565 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 573,591 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 596,608 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce a error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 619,648 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, the
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 661,679 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 683,695 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 747,817 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signatures</> and <function>pgp_pub_signatures</> if you
+ want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signatures(data bytea, key text [, details boolean [, options text ]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>. If details is
+ <literal>true</>, creation_time is set to the time recorded in the
+ signature. The default is <literal>false</>, since in most cases this
+ means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signatures(data bytea, key bytea [, psw text [, details boolean [, options text ]]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>. If there is no password, but you want to specify
+ <parameter>details</> or <parameter>options</>, you need to give an empty
+ password. If details is <literal>true</>, creation_time is set to the time
+ recorded in the signature. The default is <literal>false</>, since in most
+ cases this means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 786,791 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 918,936 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 929,942 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1074,1082 ----
<itemizedlist>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
On Thu, 2014-08-07 at 12:15 +0200, Marko Tiikkaja wrote:
On 8/6/14 2:46 PM, I wrote:
Attached is a patch to add support for PGP signatures in encrypted
messages into pgcrypto.Here's v2 of the patch. I've changed the info-extracting code to not
look for signatures beyond the data, which also meant that it had to
parse one-pass signatures (which it didn't do before). This matches the
behaviour of the main decryption code.
There is a compiler warning:
pgp-sig.c: In function ‘pgp_parse_onepass_signature’:
pgp-sig.c:715:8: error: variable ‘last’ set but not used [-Werror=unused-but-set-variable]
uint8 last;
^
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Aug 6, 2014 at 2:46 PM, Marko Tiikkaja <marko@joh.to> wrote:
Hi hackers,
Attached is a patch to add support for PGP signatures in encrypted messages
into pgcrypto.
I noticed Heikki wanted to check if there is any interested for the
patches in the current commitfest.
Yes, our company Trustly are very interested in the two PGP additions
to pgcrypto.
We currently use these patches in production in a separate database,
but if they would be part of standard postgres, we wouldn't need to
run the application using the functionality in a separate database
server, which would simplify things a lot.
Without these patches, there is no way to deal with PGP signatures.
Since signatures is a crucial component of OpenPGP, the existing
encryption/decryption features are useful, but not nearly as useful as
if you also have the capabilities to generate and verify PGP
signatures.
We use the PGP functionality in a system called BankAPI, which is open
source and available here: https://github.com/trustly/bankapi
Also, in the documentation, it has already been acknowledged the lack
of signing is a current limitation:
"F.25.3.9. Limitations of PGP Code
No support for signing. That also means that it is not checked whether
the encryption subkey belongs to the master key."
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 09/03/2014 02:51 PM, Joel Jacobson wrote:
On Wed, Aug 6, 2014 at 2:46 PM, Marko Tiikkaja <marko@joh.to> wrote:
Hi hackers,
Attached is a patch to add support for PGP signatures in encrypted messages
into pgcrypto.I noticed Heikki wanted to check if there is any interested for the
patches in the current commitfest.Yes, our company Trustly are very interested in the two PGP additions
to pgcrypto.
Cool. Please sign up as a reviewer then, so that we can get these
patches reviewed and committed.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Aug 15, 2014 at 12:55 AM, Marko Tiikkaja <marko@joh.to> wrote:
Hi,
On 8/7/14 12:15 PM, I wrote:
Here's v2 of the patch. I've changed the info-extracting code to not
look for signatures beyond the data, which also meant that it had to
parse one-pass signatures (which it didn't do before). This matches the
behaviour of the main decryption code.Here's the latest version where I've added the option to extract the
creation time from the signatures.
There is trivial sgml patch application conflict due to a grammar
correction in 05258761bf12a64befc9caec1947b254cdeb74c5
I wanted to start simple so I have a file which is signed, but not
encrypted. I can't figure out what to do with it. All of the functions
seem to require that it also be encrypted. I tried providing an empty
password for pgp_sym_signatures but it didn't work.
Is there a way to deal with this situation?
Thanks
Jeff
On 2014-09-03 9:36 PM, Jeff Janes wrote:
I wanted to start simple so I have a file which is signed, but not
encrypted. I can't figure out what to do with it. All of the functions
seem to require that it also be encrypted. I tried providing an empty
password for pgp_sym_signatures but it didn't work.
Right. This patch only adds support for signing data when encrypting it
at the same time. There's no support for detached signatures, nor is
there support for anything other than signatures of encrypted data. I
should have been more clear on that in my initial email. :-(
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Sep 3, 2014 at 12:43 PM, Marko Tiikkaja <marko@joh.to> wrote:
On 2014-09-03 9:36 PM, Jeff Janes wrote:
I wanted to start simple so I have a file which is signed, but not
encrypted. I can't figure out what to do with it. All of the functions
seem to require that it also be encrypted. I tried providing an empty
password for pgp_sym_signatures but it didn't work.Right. This patch only adds support for signing data when encrypting it
at the same time. There's no support for detached signatures, nor is there
support for anything other than signatures of encrypted data. I should
have been more clear on that in my initial email. :-(
OK, thanks. How hard do you think it would to allow NULL (or empty
string?) passwords to gpg_sym_signatures and gpg_sym_decrypt_verify to
accommodate this?
I think docs section F.25.3 needs to be re-titled and expanded to reflect
signatures as well as encryption, and an explanation added about signatures
only being processed on encrypted data if that restriction can't be removed.
I've switched to using a signed plus symmetrically encrypted message for
testing.
One surprising thing so far is that the 3rd argument to
gpg_sym_decrypt_verify must be dearmored. I thought it would detect and
dearmor automatically.
Once I wrap it in dearmor, I get the ERROR: No signature matching the key
id present in the message
The public key block I am giving it is for the keyid that is reported
by pgp_sym_signatures, so I don't know what the problem might be.
When I get more time, I'll look at your examples from the regression tests
to see if I can figure it out.
Thanks,
Jeff
On 2014-09-03 10:33 PM, Jeff Janes wrote:
On Wed, Sep 3, 2014 at 12:43 PM, Marko Tiikkaja <marko@joh.to> wrote:
Right. This patch only adds support for signing data when encrypting it
at the same time. There's no support for detached signatures, nor is there
support for anything other than signatures of encrypted data. I should
have been more clear on that in my initial email. :-(OK, thanks. How hard do you think it would to allow NULL (or empty
string?) passwords to gpg_sym_signatures and gpg_sym_decrypt_verify to
accommodate this?
To sign without encrypting? I think those should really be a different
set of functions altogether. But this patch is already humongous (on my
standards, at least), so I think that should be done separately.
I think docs section F.25.3 needs to be re-titled and expanded to reflect
signatures as well as encryption, and an explanation added about signatures
only being processed on encrypted data if that restriction can't be removed.
I don't have an objection to that. I fully acknowledge that the
documentation doesn't state the limitations of signing should this patch
be applied.
I've switched to using a signed plus symmetrically encrypted message for
testing.One surprising thing so far is that the 3rd argument to
gpg_sym_decrypt_verify must be dearmored. I thought it would detect and
dearmor automatically.
I can't see that as an improvement to be honest.
Once I wrap it in dearmor, I get the ERROR: No signature matching the key
id present in the messageThe public key block I am giving it is for the keyid that is reported
by pgp_sym_signatures, so I don't know what the problem might be.
Have you tried with the debug=1 option? (It's undocumented, but it was
like that before this patch and I didn't touch it).
When I get more time, I'll look at your examples from the regression tests
to see if I can figure it out.
Thanks! I'm happy to help if you run into any trouble!
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Marko, et al,
This is a review of the pgcrypto PGP signatures patch:
/messages/by-id/53EDBCF0.9070205@joh.to
There hasn't been any discussion, at least that I've been able to find.
Contents & Purpose
==================
This patch add functions to create, verify and extract infromation
from OpenPGP signatures. Previously pgcrypto only peformed
PGP encrypt/decrypt, not sign/verify. This is a painful limitation
since a very common use-case for OpenPGP is the signature-part,
where two parties want to verify messages originate from each other,
and not only encrypt the messages.
Included in the patch are updated regression test cases and documentation.
Initial Run
===========
The patch applies cleanly to HEAD after changing a single line in the patch:
< ! Giving this function a secret key will produce an error.
---
! Giving this function a secret key will produce a error.
This grammar fix was already fixed in 05258761bf12a64befc9caec1947b254cdeb74c5,
and therefore caused the conflict.
The 144 regression tests all pass successfully against the new patch.
Conclusion
==========
Since I'm using these functions in the BankAPI project,
https://github.com/trustly/bankapi, I have tested them
by actually using them in production, in addition to the provided
regression tests, which is a good sign they are working not just
in theory.
+1 for committer review after the changes suggested by Jeff Janes and
Thomas Munro.
On Fri, Aug 15, 2014 at 9:55 AM, Marko Tiikkaja <marko@joh.to> wrote:
Hi,
On 8/7/14 12:15 PM, I wrote:
Here's v2 of the patch. I've changed the info-extracting code to not
look for signatures beyond the data, which also meant that it had to
parse one-pass signatures (which it didn't do before). This matches the
behaviour of the main decryption code.Here's the latest version where I've added the option to extract the
creation time from the signatures..marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi all,
I've updated the patch with a number of changes:
1) I've documented the current limitations of signatures
2) I've expanded section F.25.3 to add information about signatures
(though I'm not sure why this part is in the user-facing documentation
in the first place).
3) I've changed the code to use ntohl() and pg_time_t as per Thomas'
comments.
4) I've changed the code to consistently use "while (1)" instead of
"for (;;)" (except for the math library, but I didn't touch that at all)
I've also changed the behaviour when passing a message with a signature
to the decrypt functions which don't verify signatures. They now report
"ERROR: Wrong key or corrupt data" instead of decrypting and silently
ignoring the signature. The behaviour is now backwards compatible, but
I see two ways we could possibly possibly improve this:
1) Produce a better error message (I'm sure most people don't know
about the hidden debug=1 setting)
2) Provide an option to ignore the signature if decrypting the data
is desirable even if the signature can't be verified
Any thoughts, comments appreciated.
.marko
Attachments:
pgcrypto_sigs.v3.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v3.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,39 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 20,39 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.2.sql pgcrypto--1.0--1.1.sql pgcrypto--1.1--1.2.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,326 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ (1 row)
+
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ C899EA9344195559 | sha512 | rsa |
+ (1 row)
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+ NOTICE: dbg: key_id's does not match
+ ERROR: Wrong key
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Wrong key or corrupt data
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Wrong key or corrupt data
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ ERROR: Wrong key or corrupt data
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ C899EA9344195559 | sha512 | rsa |
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa |
+ C899EA9344195559 | sha1 | rsa |
+ (2 rows)
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ 9DCF8E9C9BD31F24 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ while (1)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 0 ****
--- 1,224 ----
+ /* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 0 ****
--- 1,424 ----
+ /* contrib/pgcrypto/pgcrypto--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+ CREATE FUNCTION digest(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION digest(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION crypt(text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_crypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_salt(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_salt(text, int4)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION encrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_random_bytes(int4)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_random_bytes'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_random_uuid()
+ RETURNS uuid
+ AS 'MODULE_PATHNAME', 'pg_random_uuid'
+ LANGUAGE C VOLATILE;
+
+ --
+ -- pgp_sym_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- PGP key ID
+ --
+ CREATE FUNCTION pgp_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp armor
+ --
+ CREATE FUNCTION armor(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_armor'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION dearmor(text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_dearmor'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto.control
--- b/contrib/pgcrypto/pgcrypto.control
***************
*** 1,5 ****
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.1'
module_pathname = '$libdir/pgcrypto'
relocatable = true
--- 1,5 ----
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.2'
module_pathname = '$libdir/pgcrypto'
relocatable = true
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1077 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ if (!ctx->sig_key)
+ {
+ px_debug("process_data_packets: found one-pass signature packet but "
+ "not verifying the signature");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ else
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ if (!ctx->sig_key)
+ {
+ px_debug("process_data_packets: found signature packet but "
+ "not verifying the signature");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ else
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1120,1126 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1167,1173 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1267,1273 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1315,1318 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static void
+ sig_compute_free(void *priv)
+ {
+ PX_MD *md = priv;
+
+ px_md_free(md);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, sig_compute_free
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization, if there is one.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,317 ----
return 8 * 2;
}
! typedef int (*signature_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr);
!
!
! static int
! read_signatures_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signatures_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signatures_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signatures_from_compressed_data(ctx, pkt, opaque,
! sig_cb, extract_details);
! /*
! * We're assuming that there will only ever be a single data
! * packet, compressed or otherwise.
! */
! if (!extract_details)
! done = 1;
! break;
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * If extract_details is not specified, we never look for
! * signatures beyond the data as the decryption code doesn't,
! * either.
! */
! if (!extract_details)
! done = 1;
! else
! res = pgp_skip_packet(pkt);
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signatures: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and extract information about
! * the signatures.
*/
! static int
! read_signatures_from_data(PGP_Context *ctx, PullFilter *pkt, int tag, void *opaque,
! signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! int resync;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("read_signature_from_data: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signatures(ctx, pf_prefix, opaque, sig_key_cb, extract_details, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! signature_cb_type sig_cb,
! int extract_details)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 324,330 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 344,400 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_cb)
+ res = read_signatures_from_data(ctx, pkt, tag, opaque, sig_cb, extract_details);
break;
case PGP_PKT_SIGNATURE:
+ /*
+ * We ignore signatures not part of the encrypted data since we
+ * won't use them anyway.
+ */
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 409,417 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 437,542 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL, 0);
+ }
+
+ struct GetSignatureInfoCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ int extract_details;
+ };
+
+ static int
+ get_signature_info_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureInfoCtx *ctx = opaque;
+
+ /* ignore signatures not used for literal data */
+ if (sig->type != PGP_SIGTYP_BINARY &&
+ sig->type != PGP_SIGTYP_TEXT)
+ return 0;
+
+ /*
+ * Also skip one-pass signatures if we're extracting details; there should
+ * be a corresponding signature packet after the data with all the details.
+ */
+ if (sig->onepass && ctx->extract_details)
+ return 0;
+
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
+ int extract_details)
+ {
+ struct GetSignatureInfoCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ cbctx.extract_details = extract_details;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL,
+ get_signature_info_cb, extract_details);
+ }
+
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 33,38 ****
--- 33,42 ----
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+ #include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "utils/timestamp.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 43,57 ****
--- 47,72 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signatures_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signatures_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 162,167 **** struct debug_expect
--- 177,183 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 177,182 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 193,199 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 199,204 **** static void
--- 216,222 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 223,228 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 241,248 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 249,254 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 269,279 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 414,420 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 439,446 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 459,480 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 485,530 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 507,513 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 557,563 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 547,571 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 597,643 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 615,620 **** out:
--- 687,839 ----
return res;
}
+ struct MaterializeSignatureCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[4];
+ bool isnull[4] = { false, false, false, true };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ /*
+ * If this isn't a one-pass signature, we also know the creation time of
+ * the signature.
+ */
+ if (!sig->onepass)
+ {
+ isnull[3] = false;
+ values[3] = time_t_to_timestamptz((pg_time_t) sig->creation_time);
+ }
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signatures(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, Tuplestorestate *tupstore, TupleDesc tupdesc,
+ int extract_details)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureCtx cbctx;
+
+ init_work(&ctx, 0, arg, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signatures(ctx, src, &cbctx, materialize_signature_cb,
+ extract_details);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ extract_signatures_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, ReturnSetInfo *rsinfo, int extract_details)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 4)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signatures(is_pubenc, data, key, keypsw,
+ arg, tupstore, tupdesc, extract_details);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 631,637 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 850,856 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 653,659 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 872,878 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 662,667 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 881,946 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 676,682 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 955,961 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 698,704 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 977,983 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 707,712 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 986,1051 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 724,730 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1063,1069 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 746,752 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1085,1091 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 755,760 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1094,1158 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 772,778 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1170,1176 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 799,805 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1197,1203 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 810,815 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1208,1272 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 874,880 **** pg_dearmor(PG_FUNCTION_ARGS)
}
/*
! * Wrappers for PGP key id
*/
Datum
--- 1331,1337 ----
}
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 889,895 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1346,1352 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 900,902 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1357,1456 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+ if (PG_NARGS() > 2)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(2));
+ if (PG_NARGS() > 3)
+ arg = PG_GETARG_BYTEA_P(3);
+
+ err = extract_signatures_internal(0, data, psw, NULL, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(3));
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ err = extract_signatures_internal(1, data, key, keypsw, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 202,208 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,815 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+ uint8_t creation_time[4];
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, creation_time);
+ if (res < 0)
+ return res;
+ sig->creation_time = ntohl(*((uint32_t *) creation_time));
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ struct SigSubPktParserState pstate;
+ int res;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+ uint32_t creation_time;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ while (1)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, (uint8_t *) &creation_time);
+ if (res < 0)
+ goto err;
+ sig->creation_time = ntohl(creation_time);
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+ (void) last;
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->onepass = 0;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 230,235 **** pgp_free(PGP_Context *ctx)
--- 290,317 ----
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 396,412 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 45,50 **** enum PGP_PKT_TYPE
--- 45,51 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 107,121 **** enum PGP_DIGEST_TYPE
--- 108,136 ----
PGP_DIGEST_SHA512 = 10
};
+ enum PGP_SIGNATURE_TYPE
+ {
+ PGP_SIGTYP_BINARY = 0,
+ PGP_SIGTYP_TEXT = 1
+ };
+
+ enum PGP_SIGNATURE_SUBPKT_TYPE
+ {
+ PGP_SIGNATURE_CREATION_TIME = 2,
+ PGP_ISSUER_ID = 16
+ };
+
#define PGP_MAX_KEY (256/8)
#define PGP_MAX_BLOCK (256/8)
#define PGP_MAX_DIGEST (512/8)
+ #define PGP_MAX_DIGEST_ASN1_PREFIX 20
#define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 139,144 **** struct PGP_Context
--- 154,160 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 156,163 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 172,184 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 227,243 **** struct PGP_PubKey
--- 248,286 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint32_t creation_time;
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 251,260 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
!
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 294,310 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
!
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
! int extract_details);
/* internal functions */
***************
*** 286,291 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 336,343 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 298,303 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 350,363 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 314,316 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 374,377 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,211 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 433,438 **** gen_salt(type text [, iter_count integer ]) returns text
--- 433,440 ----
<para>
The functions here implement the encryption part of the OpenPGP (RFC 4880)
standard. Supported are both symmetric-key and public-key encryption.
+ Also signing the data when encrypting and verifying the signature when
+ decrypting is supported.
</para>
<para>
***************
*** 524,529 **** gen_salt(type text [, iter_count integer ]) returns text
--- 526,579 ----
</listitem>
</orderedlist>
+ <para>
+ If the data is also signed, two more packets are added into the message:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <firstterm>one-pass signature packet</> is written before the encrypted
+ data, containing information about the algorithms used for the signature.
+ This allows the party decrypting the message to calculate the message
+ while decrypting it, in a single pass over the data.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After the encrypted data packet has been written, the signature itself is
+ written into a <firstterm>signature packet</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The signature is calculated as follows:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Optional data-manipulation: compression, conversion to UTF-8, and/or conversion of line-endings.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A hash of the entire message is calculated, using the algorithm specified
+ by the <literal>digest-algo</> setting.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A trailer containing additional information, such as the signature
+ creation time, is hashed in the same context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The resulting hash is put into the signature packet.
+ </para>
+ </listitem>
+ </orderedlist>
+
<sect3>
<title><function>pgp_sym_encrypt()</function></title>
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 585,615 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 623,641 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 646,658 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce an error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 669,698 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, these
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 711,729 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 733,745 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 797,867 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signatures</> and <function>pgp_pub_signatures</> if you
+ want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signatures(data bytea, key text [, details boolean [, options text ]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>. If details is
+ <literal>true</>, creation_time is set to the time recorded in the
+ signature. The default is <literal>false</>, since in most cases this
+ means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signatures(data bytea, key bytea [, psw text [, details boolean [, options text ]]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>. If there is no password, but you want to specify
+ <parameter>details</> or <parameter>options</>, you need to give an empty
+ password. If details is <literal>true</>, creation_time is set to the time
+ recorded in the signature. The default is <literal>false</>, since in most
+ cases this means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 786,791 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 968,986 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 929,942 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
</para>
</listitem>
<listitem>
<para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1124,1143 ----
<itemizedlist>
<listitem>
<para>
! No support for detached signatures. Additionally, none of the functions
! check that the encryption subkey has been signed by the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! Signing is only supported using RSA keys.
</para>
</listitem>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
On 2014-09-05 1:38 PM, I wrote:
3) I've changed the code to use ntohl() and pg_time_t as per Thomas'
comments.
sig->creation_time = ntohl(*((uint32_t *) creation_time));
This is probably a horrible idea due to strict aliasing rules and
alignment, though. I think I'll just hide the bit shifts behind a
function instead.
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Sep 3, 2014 at 2:13 PM, Marko Tiikkaja <marko@joh.to> wrote:
On 2014-09-03 10:33 PM, Jeff Janes wrote:
On Wed, Sep 3, 2014 at 12:43 PM, Marko Tiikkaja <marko@joh.to> wrote:
Right. This patch only adds support for signing data when encrypting it
at the same time. There's no support for detached signatures, nor is
there
support for anything other than signatures of encrypted data. I should
have been more clear on that in my initial email. :-(OK, thanks. How hard do you think it would to allow NULL (or empty
string?) passwords to gpg_sym_signatures and gpg_sym_decrypt_verify to
accommodate this?To sign without encrypting?
To verify signatures of things that are not encrypted. I'm not really
interested in storing private keys in PostgreSQL, just things that can be
done with public keys. (But I will make a dummy private key for testing if
I get that far.)
...
Once I wrap it in dearmor, I get the ERROR: No signature matching the key
id present in the message
The public key block I am giving it is for the keyid that is reported
by pgp_sym_signatures, so I don't know what the problem might be.Have you tried with the debug=1 option? (It's undocumented, but it was
like that before this patch and I didn't touch it).
I have now, but it didn't produce any output for this situation. I have
two theories for the problem. My test signed message was signed with a
keyring that had a signing subkey, so it was signed with that, not with the
master. Maybe it doesn't like that. Also, I created the signed message in
gpg, then imported it to PostgreSQL, and maybe it doesn't like that.
I've never used the pgp functions of pgcrypto before, so I decided to take
a step back and try some of the functions that predate the proposed patch.
And I can't get them to work well, either.
If I use pgp_sym_encrypt to encrypt a message with AES, then
pgp_sym_decrypt will decrypt, and so will gpg command line tool. But if I
use gpg to encrypt a message, pgp_sym_decrypt will not decrypt it.
select pgp_sym_decrypt(dearmor('-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Password: foobar
jA0EBwMCqywsAv/hXJ7D0j8BWsD+9H7DY4KhrIIw2oV/6tBueVQ28+VDjBw9rGiy
3JRPmyXNN4wRTZXIyTVzK3LylWLomD9pQkao4hrQwSs=
=02RI
-----END PGP MESSAGE-----
'),'foobar','debug=1');
NOTICE: dbg: parse_literal_data: data type=b
ERROR: Not text data
So I don't know if I am doing something wrong, or if the PostgreSQL
implementation of pgp is just not interoperable with other implementations.
That makes it hard to test the new features if I can't make the old ones
work.
The two messages I am working with are:
Created: echo -n 'a message'|gpg -c --armor --cipher-algo AES -
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Password: foobar
jA0EBwMCqywsAv/hXJ7D0j8BWsD+9H7DY4KhrIIw2oV/6tBueVQ28+VDjBw9rGiy
3JRPmyXNN4wRTZXIyTVzK3LylWLomD9pQkao4hrQwSs=
=02RI
-----END PGP MESSAGE-----
and
Created: select armor(pgp_sym_encrypt('a message','foobar'));
-----BEGIN PGP MESSAGE-----
ww0EBwMCYzgp4dU3zCJ30joBViH28prwc9jIHhzUyXt31omiHao7NeOuLhCR0/uhAB6GRfYAXWVa
x+FTsW27F46/W7dlRjxCuzcu
=jQGZ
-----END PGP MESSAGE-----
Cheers,
Jeff
On 2014-09-07 19:28, Jeff Janes wrote:
On Wed, Sep 3, 2014 at 2:13 PM, Marko Tiikkaja <marko@joh.to> wrote:
To sign without encrypting?
To verify signatures of things that are not encrypted. I'm not really
interested in storing private keys in PostgreSQL, just things that can be
done with public keys. (But I will make a dummy private key for testing if
I get that far.)
Right. That functionality might be useful, but I think it should be a
separate patch completely. (And I doubt I have any interest in
implementing it).
Once I wrap it in dearmor, I get the ERROR: No signature matching the key
id present in the message
The public key block I am giving it is for the keyid that is reported
by pgp_sym_signatures, so I don't know what the problem might be.Have you tried with the debug=1 option? (It's undocumented, but it was
like that before this patch and I didn't touch it).I have now, but it didn't produce any output for this situation. I have
two theories for the problem. My test signed message was signed with a
keyring that had a signing subkey, so it was signed with that, not with the
master. Maybe it doesn't like that.
Yeah, this patch only supports signing and verifying signatures with
main keys.
Also, I created the signed message in
gpg, then imported it to PostgreSQL, and maybe it doesn't like that.
That should not be a problem. I used gpg extensively when testing the
patch.
I've never used the pgp functions of pgcrypto before, so I decided to take
a step back and try some of the functions that predate the proposed patch.
And I can't get them to work well, either.If I use pgp_sym_encrypt to encrypt a message with AES, then
pgp_sym_decrypt will decrypt, and so will gpg command line tool. But if I
use gpg to encrypt a message, pgp_sym_decrypt will not decrypt it.select pgp_sym_decrypt(dearmor('-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Password: foobarjA0EBwMCqywsAv/hXJ7D0j8BWsD+9H7DY4KhrIIw2oV/6tBueVQ28+VDjBw9rGiy
3JRPmyXNN4wRTZXIyTVzK3LylWLomD9pQkao4hrQwSs=
=02RI
-----END PGP MESSAGE-----
'),'foobar','debug=1');
NOTICE: dbg: parse_literal_data: data type=b
ERROR: Not text dataSo I don't know if I am doing something wrong, or if the PostgreSQL
implementation of pgp is just not interoperable with other implementations.
That makes it hard to test the new features if I can't make the old ones
work.
The NOTICE here says what's wrong: the message has been marked to
contain binary data, not text. You should be able to decrypt it with
pgp_sym_decrypt_bytea() (and you can use convert_from() to get a text
value out).
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Sep 7, 2014 at 10:36 AM, Marko Tiikkaja <marko@joh.to> wrote:
On 2014-09-07 19:28, Jeff Janes wrote:
select pgp_sym_decrypt(dearmor('-----BEGIN PGP MESSAGE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Password: foobarjA0EBwMCqywsAv/hXJ7D0j8BWsD+9H7DY4KhrIIw2oV/6tBueVQ28+VDjBw9rGiy
3JRPmyXNN4wRTZXIyTVzK3LylWLomD9pQkao4hrQwSs=
=02RI
-----END PGP MESSAGE-----
'),'foobar','debug=1');
NOTICE: dbg: parse_literal_data: data type=b
ERROR: Not text dataSo I don't know if I am doing something wrong, or if the PostgreSQL
implementation of pgp is just not interoperable with other
implementations.
That makes it hard to test the new features if I can't make the old ones
work.The NOTICE here says what's wrong: the message has been marked to contain
binary data, not text. You should be able to decrypt it with
pgp_sym_decrypt_bytea() (and you can use convert_from() to get a text value
out).
OK, thanks. That is obvious in retrospect. I'll put it on my todo list to
try to clean up some of documentation and error messages to make it more
obvious to the naive user, but that is not part of this patch.
One problem I've run into now is that if I try to sign a message
with pgp_pub_encrypt_sign but give it the public, not private, key as the
3rd argument, it generates this message:
ERROR: Cannot decrypt with public key
Should be 'sign', not 'decrypt'.
Similarly for verification:
ERROR: Refusing to encrypt with secret key
'encrypt' should be 'verify signature'.
Cheers,
Jeff
On Fri, Sep 5, 2014 at 4:38 AM, Marko Tiikkaja <marko@joh.to> wrote:
Hi all,
I've updated the patch with a number of changes:
1) I've documented the current limitations of signatures
2) I've expanded section F.25.3 to add information about signatures
(though I'm not sure why this part is in the user-facing documentation in
the first place).
3) I've changed the code to use ntohl() and pg_time_t as per Thomas'
comments.
4) I've changed the code to consistently use "while (1)" instead of "for
(;;)" (except for the math library, but I didn't touch that at all)I've also changed the behaviour when passing a message with a signature to
the decrypt functions which don't verify signatures. They now report
"ERROR: Wrong key or corrupt data" instead of decrypting and silently
ignoring the signature. The behaviour is now backwards compatible, but I
see two ways we could possibly possibly improve this:
1) Produce a better error message (I'm sure most people don't know about
the hidden debug=1 setting)
2) Provide an option to ignore the signature if decrypting the data is
desirable even if the signature can't be verified
If i understand the sequence here: The current git HEAD is that
pgp_pub_decrypt would throw an error if given a signed and encrypted
message, and earlier version of your patch changed that to decrypt the
message and ignore the signature, and the current version went back to
throwing an error.
I think I prefer the middle of those behaviors. The original behavior
seems like a bug to me, and I don't think we need to be backwards
compatible with bugs. Why should a function called "decrypt" care if the
message is also signed? That is not its job.
If we decide to throw the error, a better error message certainly wouldn't
hurt. And the output of 'debug=1' is generally not comprehensible unless
you are familiar with the source code, so that is not a substitute.
(By the way, there are now 2 patches in this series named
pgcrypto_sigs.v3.patch--so be careful which one you look it.)
There seems to be a memory leak in pgp_sym_decrypt_verify that does not
exist in pgp_sym_decrypt. It is about 58 bytes per decryption.
Perl test script:
my $dbh=connect(...);
my $pub=`cat public.asc`;
my $pri=`cat private.asc`;
my $enc= $dbh->prepare("select
armor(pgp_sym_encrypt_sign('asdlkfjsldkfjsadf',?,dearmor(?),'debug=1'))");
my $dec= $dbh->prepare("select
pgp_sym_decrypt_verify(dearmor(?),?,dearmor(?),'debug=1')");
my $i=1;
$enc->execute("foobar$i",$pri);
my ($message)=$enc->fetchrow();
foreach my $ii (1..1000000) {
## my $i=$ii;
$dec->execute($message,"foobar$i",$pub);
my ($message2)=$dec->fetchrow();
die unless $message2 eq "asdlkfjsldkfjsadf";
warn "$i\t", time() if $i%1000 ==0;
};
Cheers,
Jeff
On 2014-09-08 7:30 PM, Jeff Janes wrote:
On Fri, Sep 5, 2014 at 4:38 AM, Marko Tiikkaja <marko@joh.to> wrote:
I've also changed the behaviour when passing a message with a signature to
the decrypt functions which don't verify signatures. They now report
"ERROR: Wrong key or corrupt data" instead of decrypting and silently
ignoring the signature. The behaviour is now backwards compatible, but I
see two ways we could possibly possibly improve this:
1) Produce a better error message (I'm sure most people don't know about
the hidden debug=1 setting)
2) Provide an option to ignore the signature if decrypting the data is
desirable even if the signature can't be verifiedIf i understand the sequence here: The current git HEAD is that
pgp_pub_decrypt would throw an error if given a signed and encrypted
message, and earlier version of your patch changed that to decrypt the
message and ignore the signature, and the current version went back to
throwing an error.
You got that right, yes.
I think I prefer the middle of those behaviors. The original behavior
seems like a bug to me, and I don't think we need to be backwards
compatible with bugs. Why should a function called "decrypt" care if the
message is also signed? That is not its job.
Yeah, that seems reasonable, I guess. I'm kind of torn between the two
behaviours to be honest. But perhaps it would make sense to change the
previous behaviour (i.e. go back to way this patch was earlier) and
document that somewhere.
There seems to be a memory leak in pgp_sym_decrypt_verify that does not
exist in pgp_sym_decrypt. It is about 58 bytes per decryption.
Interesting. Thanks! I'll have a look.
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi Jeff,
On 9/8/14 7:30 PM, Jeff Janes wrote:
There seems to be a memory leak in pgp_sym_decrypt_verify that does not
exist in pgp_sym_decrypt. It is about 58 bytes per decryption.
Thanks. There seemed to have been a small confusion about the ownership
of ctx->sig_digest_ctx. I've fixed that now and the test case you
provided doesn't appear to be leaking memory anymore. I also added some
other missing free calls to pgp_free().
I've attached a patch with this problem fixed, in case you still want to
keep testing (all your work so far very much appreciated, btw!) The
attached also fixes the ntohl() problem I pointed out in my previous
patch, and now AFAIK there aren't any outstanding technical issues.
However..
If i understand the sequence here: The current git HEAD is that
pgp_pub_decrypt would throw an error if given a signed and encrypted
message, and earlier version of your patch changed that to decrypt the
message and ignore the signature, and the current version went back to
throwing an error.I think I prefer the middle of those behaviors. The original behavior
seems like a bug to me, and I don't think we need to be backwards
compatible with bugs. Why should a function called "decrypt" care if the
message is also signed? That is not its job.
I haven't updated the patch yet because I don't want to waste my time
going back and forth until we have a consensus, but I think I prefer
Jeff's suggestion here to make the _decrypt() functions ignore
signatures. Does anyone else want to voice their opinion?
.marko
Attachments:
pgcrypto_sigs.v5.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v5.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,39 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 20,39 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.2.sql pgcrypto--1.0--1.1.sql pgcrypto--1.1--1.2.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,326 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ (1 row)
+
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ C899EA9344195559 | sha512 | rsa |
+ (1 row)
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+ NOTICE: dbg: key_id's does not match
+ ERROR: Wrong key
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Wrong key or corrupt data
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Wrong key or corrupt data
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ ERROR: Wrong key or corrupt data
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ C899EA9344195559 | sha512 | rsa |
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa |
+ C899EA9344195559 | sha1 | rsa |
+ (2 rows)
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ 9DCF8E9C9BD31F24 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ while (1)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 0 ****
--- 1,224 ----
+ /* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 0 ****
--- 1,424 ----
+ /* contrib/pgcrypto/pgcrypto--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+ CREATE FUNCTION digest(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION digest(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION crypt(text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_crypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_salt(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_salt(text, int4)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION encrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_random_bytes(int4)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_random_bytes'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_random_uuid()
+ RETURNS uuid
+ AS 'MODULE_PATHNAME', 'pg_random_uuid'
+ LANGUAGE C VOLATILE;
+
+ --
+ -- pgp_sym_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- PGP key ID
+ --
+ CREATE FUNCTION pgp_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp armor
+ --
+ CREATE FUNCTION armor(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_armor'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION dearmor(text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_dearmor'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto.control
--- b/contrib/pgcrypto/pgcrypto.control
***************
*** 1,5 ****
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.1'
module_pathname = '$libdir/pgcrypto'
relocatable = true
--- 1,5 ----
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.2'
module_pathname = '$libdir/pgcrypto'
relocatable = true
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1077 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ if (!ctx->sig_key)
+ {
+ px_debug("process_data_packets: found one-pass signature packet but "
+ "not verifying the signature");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ else
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ if (!ctx->sig_key)
+ {
+ px_debug("process_data_packets: found signature packet but "
+ "not verifying the signature");
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+ else
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1120,1126 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1167,1173 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1267,1273 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1315,1318 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ *
+ * This filter only computes the literal data packet's contents into
+ * ctx->sig_digest_ctx. No signature is written (since we wouldn't be able to
+ * write it into the correct place in the flush callback).
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ /*
+ * Load the digest into sig_digest_ctx for everyone to use. It'll also be
+ * freed in pgp_sig_free, not when this filter is done.
+ */
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, NULL
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization, if there is one.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,317 ----
return 8 * 2;
}
! typedef int (*signature_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr);
!
!
! static int
! read_signatures_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signatures_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signatures_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signatures_from_compressed_data(ctx, pkt, opaque,
! sig_cb, extract_details);
! /*
! * We're assuming that there will only ever be a single data
! * packet, compressed or otherwise.
! */
! if (!extract_details)
! done = 1;
! break;
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * If extract_details is not specified, we never look for
! * signatures beyond the data as the decryption code doesn't,
! * either.
! */
! if (!extract_details)
! done = 1;
! else
! res = pgp_skip_packet(pkt);
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signatures: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and extract information about
! * the signatures.
*/
! static int
! read_signatures_from_data(PGP_Context *ctx, PullFilter *pkt, int tag, void *opaque,
! signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! int resync;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("read_signature_from_data: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signatures(ctx, pf_prefix, opaque, sig_key_cb, extract_details, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! signature_cb_type sig_cb,
! int extract_details)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 324,330 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 344,400 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_cb)
+ res = read_signatures_from_data(ctx, pkt, tag, opaque, sig_cb, extract_details);
break;
case PGP_PKT_SIGNATURE:
+ /*
+ * We ignore signatures not part of the encrypted data since we
+ * won't use them anyway.
+ */
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 409,417 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 437,542 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL, 0);
+ }
+
+ struct GetSignatureInfoCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ int extract_details;
+ };
+
+ static int
+ get_signature_info_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureInfoCtx *ctx = opaque;
+
+ /* ignore signatures not used for literal data */
+ if (sig->type != PGP_SIGTYP_BINARY &&
+ sig->type != PGP_SIGTYP_TEXT)
+ return 0;
+
+ /*
+ * Also skip one-pass signatures if we're extracting details; there should
+ * be a corresponding signature packet after the data with all the details.
+ */
+ if (sig->onepass && ctx->extract_details)
+ return 0;
+
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
+ int extract_details)
+ {
+ struct GetSignatureInfoCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ cbctx.extract_details = extract_details;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL,
+ get_signature_info_cb, extract_details);
+ }
+
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 33,38 ****
--- 33,42 ----
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+ #include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "utils/timestamp.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 43,57 ****
--- 47,72 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signatures_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signatures_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 162,167 **** struct debug_expect
--- 177,183 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 177,182 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 193,199 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 199,204 **** static void
--- 216,222 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 223,228 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 241,248 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 249,254 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 269,279 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 414,420 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 439,446 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 459,480 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 485,530 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 507,513 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 557,563 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 547,571 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 597,643 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 615,620 **** out:
--- 687,839 ----
return res;
}
+ struct MaterializeSignatureCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[4];
+ bool isnull[4] = { false, false, false, true };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ /*
+ * If this isn't a one-pass signature, we also know the creation time of
+ * the signature.
+ */
+ if (!sig->onepass)
+ {
+ isnull[3] = false;
+ values[3] = time_t_to_timestamptz((pg_time_t) sig->creation_time);
+ }
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signatures(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, Tuplestorestate *tupstore, TupleDesc tupdesc,
+ int extract_details)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureCtx cbctx;
+
+ init_work(&ctx, 0, arg, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signatures(ctx, src, &cbctx, materialize_signature_cb,
+ extract_details);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ extract_signatures_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, ReturnSetInfo *rsinfo, int extract_details)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 4)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signatures(is_pubenc, data, key, keypsw,
+ arg, tupstore, tupdesc, extract_details);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 631,637 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 850,856 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 653,659 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 872,878 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 662,667 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 881,946 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 676,682 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 955,961 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 698,704 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 977,983 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 707,712 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 986,1051 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 724,730 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1063,1069 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 746,752 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1085,1091 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 755,760 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1094,1158 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 772,778 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1170,1176 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 799,805 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1197,1203 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 810,815 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1208,1272 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 874,880 **** pg_dearmor(PG_FUNCTION_ARGS)
}
/*
! * Wrappers for PGP key id
*/
Datum
--- 1331,1337 ----
}
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 889,895 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1346,1352 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 900,902 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1357,1456 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+ if (PG_NARGS() > 2)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(2));
+ if (PG_NARGS() > 3)
+ arg = PG_GETARG_BYTEA_P(3);
+
+ err = extract_signatures_internal(0, data, psw, NULL, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(3));
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ err = extract_signatures_internal(1, data, key, keypsw, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 202,208 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,815 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+ uint32 creation_time;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ return res;
+ sig->creation_time = ntohl(creation_time);
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, (uint8 *) &creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ struct SigSubPktParserState pstate;
+ int res;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+ uint32 creation_time;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ while (1)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ goto err;
+ sig->creation_time = ntohl(creation_time);
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+ (void) last;
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->onepass = 0;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 224,235 **** pgp_free(PGP_Context *ctx)
--- 284,325 ----
{
if (ctx->pub_key)
pgp_key_free(ctx->pub_key);
+ if (ctx->sig_key)
+ pgp_key_free(ctx->sig_key);
+ if (ctx->sig_onepass)
+ pgp_sig_free(ctx->sig_onepass);
+ if (ctx->sig_expected)
+ pgp_sig_free(ctx->sig_expected);
+ if (ctx->sig_digest_ctx)
+ px_md_free(ctx->sig_digest_ctx);
px_memset(ctx, 0, sizeof *ctx);
px_free(ctx);
return 0;
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 404,420 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 45,50 **** enum PGP_PKT_TYPE
--- 45,51 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 107,121 **** enum PGP_DIGEST_TYPE
--- 108,136 ----
PGP_DIGEST_SHA512 = 10
};
+ enum PGP_SIGNATURE_TYPE
+ {
+ PGP_SIGTYP_BINARY = 0,
+ PGP_SIGTYP_TEXT = 1
+ };
+
+ enum PGP_SIGNATURE_SUBPKT_TYPE
+ {
+ PGP_SIGNATURE_CREATION_TIME = 2,
+ PGP_ISSUER_ID = 16
+ };
+
#define PGP_MAX_KEY (256/8)
#define PGP_MAX_BLOCK (256/8)
#define PGP_MAX_DIGEST (512/8)
+ #define PGP_MAX_DIGEST_ASN1_PREFIX 20
#define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 139,144 **** struct PGP_Context
--- 154,160 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 156,163 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 172,184 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 227,243 **** struct PGP_PubKey
--- 248,286 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint32 creation_time;
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 251,260 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
!
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 294,310 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
!
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
! int extract_details);
/* internal functions */
***************
*** 286,291 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 336,343 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 298,303 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 350,363 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 314,316 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 374,377 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,211 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 433,438 **** gen_salt(type text [, iter_count integer ]) returns text
--- 433,440 ----
<para>
The functions here implement the encryption part of the OpenPGP (RFC 4880)
standard. Supported are both symmetric-key and public-key encryption.
+ Also signing the data when encrypting and verifying the signature when
+ decrypting is supported.
</para>
<para>
***************
*** 524,529 **** gen_salt(type text [, iter_count integer ]) returns text
--- 526,579 ----
</listitem>
</orderedlist>
+ <para>
+ If the data is also signed, two more packets are added into the message:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <firstterm>one-pass signature packet</> is written before the encrypted
+ data, containing information about the algorithms used for the signature.
+ This allows the party decrypting the message to calculate the message
+ while decrypting it, in a single pass over the data.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After the encrypted data packet has been written, the signature itself is
+ written into a <firstterm>signature packet</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The signature is calculated as follows:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Optional data-manipulation: compression, conversion to UTF-8, and/or conversion of line-endings.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A hash of the entire message is calculated, using the algorithm specified
+ by the <literal>digest-algo</> setting.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A trailer containing additional information, such as the signature
+ creation time, is hashed in the same context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The resulting hash is put into the signature packet.
+ </para>
+ </listitem>
+ </orderedlist>
+
<sect3>
<title><function>pgp_sym_encrypt()</function></title>
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 585,615 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 623,641 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 646,658 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce an error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 669,698 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, these
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 711,729 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 733,745 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 797,867 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signatures</> and <function>pgp_pub_signatures</> if you
+ want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signatures(data bytea, key text [, details boolean [, options text ]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>. If details is
+ <literal>true</>, creation_time is set to the time recorded in the
+ signature. The default is <literal>false</>, since in most cases this
+ means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signatures(data bytea, key bytea [, psw text [, details boolean [, options text ]]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>. If there is no password, but you want to specify
+ <parameter>details</> or <parameter>options</>, you need to give an empty
+ password. If details is <literal>true</>, creation_time is set to the time
+ recorded in the signature. The default is <literal>false</>, since in most
+ cases this means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 786,791 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 968,986 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 929,942 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
</para>
</listitem>
<listitem>
<para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1124,1143 ----
<itemizedlist>
<listitem>
<para>
! No support for detached signatures. Additionally, none of the functions
! check that the encryption subkey has been signed by the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! Signing is only supported using RSA keys.
</para>
</listitem>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
Marko Tiikkaja wrote:
On 9/8/14 7:30 PM, Jeff Janes wrote:
If i understand the sequence here: The current git HEAD is that
pgp_pub_decrypt would throw an error if given a signed and encrypted
message, and earlier version of your patch changed that to decrypt the
message and ignore the signature, and the current version went back to
throwing an error.I think I prefer the middle of those behaviors. The original behavior
seems like a bug to me, and I don't think we need to be backwards
compatible with bugs. Why should a function called "decrypt" care if the
message is also signed? That is not its job.I haven't updated the patch yet because I don't want to waste my
time going back and forth until we have a consensus, but I think I
prefer Jeff's suggestion here to make the _decrypt() functions
ignore signatures. Does anyone else want to voice their opinion?
+1 for ignoring sigs. If somebody want to check sigs, that's a
separate step. Maybe we could have an optional boolean flag, default
false, to enable checking sigs, but that seems material for a future
patch.
That said, I do wonder if it's a behavior change with security
implications: if somebody is relying on the current behavior of throwing
an error when sigs don't match, they wouldn't be thrilled to hear that
their security checks now fail to detect a problem because we don't
verify signatures when decrypting. In other words, is this established
practice already? If not, it's okay; otherwise, hmm.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
(I have't read the patch, or even earlier correspondence in this
thread, so I apologise for just jumping in.)
At 2014-09-12 12:50:45 -0300, alvherre@2ndquadrant.com wrote:
+1 for ignoring sigs. If somebody want to check sigs, that's a
separate step.
For what it's worth, although it seems logical to split up cryptographic
primitives like this, I think it's widely recognised these days to have
contributed to plenty of bad crypto implementations. These seems to be
general trend of moving towards higher-level interfaces that require
fewer decisions and can be relied upon do the Right Thing.
I don't like the idea of ignoring signature verification errors any more
than I would like "if somebody wants to check the HMAC before decypting,
that's a separate step".
Of course, all that is an aside. If the function ever threw an error on
signature verification failures, I would strongly object to changing it
to ignore such errors for exactly the reasons you mention already.
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Sep 12, 2014 at 8:50 AM, Alvaro Herrera <alvherre@2ndquadrant.com>
wrote:
Marko Tiikkaja wrote:
On 9/8/14 7:30 PM, Jeff Janes wrote:
If i understand the sequence here: The current git HEAD is that
pgp_pub_decrypt would throw an error if given a signed and encrypted
message, and earlier version of your patch changed that to decrypt the
message and ignore the signature, and the current version went back to
throwing an error.I think I prefer the middle of those behaviors. The original behavior
seems like a bug to me, and I don't think we need to be backwards
compatible with bugs. Why should a function called "decrypt" care ifthe
message is also signed? That is not its job.
I haven't updated the patch yet because I don't want to waste my
time going back and forth until we have a consensus, but I think I
prefer Jeff's suggestion here to make the _decrypt() functions
ignore signatures. Does anyone else want to voice their opinion?+1 for ignoring sigs. If somebody want to check sigs, that's a
separate step. Maybe we could have an optional boolean flag, default
false, to enable checking sigs, but that seems material for a future
patch.That said, I do wonder if it's a behavior change with security
implications: if somebody is relying on the current behavior of throwing
an error when sigs don't match, they wouldn't be thrilled to hear that
their security checks now fail to detect a problem because we don't
verify signatures when decrypting. In other words, is this established
practice already? If not, it's okay; otherwise, hmm.
If it is established practise, I think the only security model that could
be used to justify it is "The bad guys will be nice enough to always sign
their attacks, while the good guys will refrain from signing them." It is
not clear why the bad guys would cooperate with that.
Anyone who can produce an encrypted and signed attack message could also
produce an encrypted and unsigned one, couldn't they?
Cheers,
Jeff
On 9/12/14, 8:22 PM, Abhijit Menon-Sen wrote:
(I have't read the patch, or even earlier correspondence in this
thread, so I apologise for just jumping in.)At 2014-09-12 12:50:45 -0300, alvherre@2ndquadrant.com wrote:
+1 for ignoring sigs. If somebody want to check sigs, that's a
separate step.For what it's worth, although it seems logical to split up cryptographic
primitives like this, I think it's widely recognised these days to have
contributed to plenty of bad crypto implementations. These seems to be
general trend of moving towards higher-level interfaces that require
fewer decisions and can be relied upon do the Right Thing.I don't like the idea of ignoring signature verification errors any more
than I would like "if somebody wants to check the HMAC before decypting,
that's a separate step".Of course, all that is an aside. If the function ever threw an error on
signature verification failures, I would strongly object to changing it
to ignore such errors for exactly the reasons you mention already.
I'm not sure we're talking about the same thing. Currently, we throw an
error if *any* signature was present, valid or otherwise. The "decrypt
only" functions don't have enough information to verify the validity of
the signature, so we must either ignore the signatures or throw an error
in their presence.
The only downside of ignoring signatures here as far as I can tell is a
scenario where you're sending messages to someone, and they accept your
signed messages. You might get the impression that the receiving party
is actually validating the signature, but I guess that's trivial to
test, and relying on such unwritten contracts is a bit suspicious anyway
when it comes to cryptography.
I've changed the patch back to ignore signatures when not using the
decrypt_verify() functions in the attached.
.marko
Attachments:
pgcrypto_sigs.v6.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v6.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,39 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 20,39 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
EXTENSION = pgcrypto
! DATA = pgcrypto--1.2.sql pgcrypto--1.0--1.1.sql pgcrypto--1.1--1.2.sql pgcrypto--unpackaged--1.0.sql
PGFILEDESC = "pgcrypto - cryptographic functions"
REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,338 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ (1 row)
+
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ C899EA9344195559 | sha512 | rsa |
+ (1 row)
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+ NOTICE: dbg: key_id's does not match
+ ERROR: Wrong key
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ C899EA9344195559 | sha512 | rsa |
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa |
+ C899EA9344195559 | sha1 | rsa |
+ (2 rows)
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ 9DCF8E9C9BD31F24 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ while (1)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 0 ****
--- 1,224 ----
+ /* contrib/pgcrypto/pgcrypto--1.1--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** /dev/null
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 0 ****
--- 1,424 ----
+ /* contrib/pgcrypto/pgcrypto--1.2.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+ CREATE FUNCTION digest(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION digest(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_digest'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION hmac(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_hmac'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION crypt(text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_crypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_salt(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_salt(text, int4)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION encrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION gen_random_bytes(int4)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_random_bytes'
+ LANGUAGE C VOLATILE STRICT;
+
+ CREATE FUNCTION gen_random_uuid()
+ RETURNS uuid
+ AS 'MODULE_PATHNAME', 'pg_random_uuid'
+ LANGUAGE C VOLATILE;
+
+ --
+ -- pgp_sym_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt(data, key, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt(data, key, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- PGP key ID
+ --
+ CREATE FUNCTION pgp_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp armor
+ --
+ CREATE FUNCTION armor(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pg_armor'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION dearmor(text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pg_dearmor'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto.control
--- b/contrib/pgcrypto/pgcrypto.control
***************
*** 1,5 ****
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.1'
module_pathname = '$libdir/pgcrypto'
relocatable = true
--- 1,5 ----
# pgcrypto extension
comment = 'cryptographic functions'
! default_version = '1.2'
module_pathname = '$libdir/pgcrypto'
relocatable = true
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1153,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ *
+ * This filter only computes the literal data packet's contents into
+ * ctx->sig_digest_ctx. No signature is written (since we wouldn't be able to
+ * write it into the correct place in the flush callback).
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ /*
+ * Load the digest into sig_digest_ctx for everyone to use. It'll also be
+ * freed in pgp_sig_free, not when this filter is done.
+ */
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, NULL
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,317 ----
return 8 * 2;
}
! typedef int (*signature_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr);
!
!
! static int
! read_signatures_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signatures_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signatures_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signatures_from_compressed_data(ctx, pkt, opaque,
! sig_cb, extract_details);
! /*
! * We're assuming that there will only ever be a single data
! * packet, compressed or otherwise.
! */
! if (!extract_details)
! done = 1;
! break;
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * If extract_details is not specified, we never look for
! * signatures beyond the data as the decryption code doesn't,
! * either.
! */
! if (!extract_details)
! done = 1;
! else
! res = pgp_skip_packet(pkt);
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signatures: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and extract information about
! * the signatures.
*/
! static int
! read_signatures_from_data(PGP_Context *ctx, PullFilter *pkt, int tag, void *opaque,
! signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! int resync;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("read_signature_from_data: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signatures(ctx, pf_prefix, opaque, sig_key_cb, extract_details, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! signature_cb_type sig_cb,
! int extract_details)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 324,330 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 344,400 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_cb)
+ res = read_signatures_from_data(ctx, pkt, tag, opaque, sig_cb, extract_details);
break;
case PGP_PKT_SIGNATURE:
+ /*
+ * We ignore signatures not part of the encrypted data since we
+ * won't use them anyway.
+ */
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 409,417 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 437,542 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL, 0);
+ }
+
+ struct GetSignatureInfoCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ int extract_details;
+ };
+
+ static int
+ get_signature_info_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureInfoCtx *ctx = opaque;
+
+ /* ignore signatures not used for literal data */
+ if (sig->type != PGP_SIGTYP_BINARY &&
+ sig->type != PGP_SIGTYP_TEXT)
+ return 0;
+
+ /*
+ * Also skip one-pass signatures if we're extracting details; there should
+ * be a corresponding signature packet after the data with all the details.
+ */
+ if (sig->onepass && ctx->extract_details)
+ return 0;
+
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
+ int extract_details)
+ {
+ struct GetSignatureInfoCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ cbctx.extract_details = extract_details;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL,
+ get_signature_info_cb, extract_details);
+ }
+
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 33,38 ****
--- 33,42 ----
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+ #include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "utils/timestamp.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 43,57 ****
--- 47,72 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signatures_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signatures_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 162,167 **** struct debug_expect
--- 177,183 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 177,182 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 193,199 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 199,204 **** static void
--- 216,222 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 223,228 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 241,248 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 249,254 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 269,279 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 414,420 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 439,446 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 459,480 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 485,530 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 507,513 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 557,563 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 547,571 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 597,643 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 615,620 **** out:
--- 687,839 ----
return res;
}
+ struct MaterializeSignatureCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[4];
+ bool isnull[4] = { false, false, false, true };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ /*
+ * If this isn't a one-pass signature, we also know the creation time of
+ * the signature.
+ */
+ if (!sig->onepass)
+ {
+ isnull[3] = false;
+ values[3] = time_t_to_timestamptz((pg_time_t) sig->creation_time);
+ }
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signatures(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, Tuplestorestate *tupstore, TupleDesc tupdesc,
+ int extract_details)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureCtx cbctx;
+
+ init_work(&ctx, 0, arg, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signatures(ctx, src, &cbctx, materialize_signature_cb,
+ extract_details);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ extract_signatures_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, ReturnSetInfo *rsinfo, int extract_details)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 4)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signatures(is_pubenc, data, key, keypsw,
+ arg, tupstore, tupdesc, extract_details);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 631,637 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 850,856 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 653,659 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 872,878 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 662,667 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 881,946 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 676,682 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 955,961 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 698,704 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 977,983 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 707,712 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 986,1051 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 724,730 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1063,1069 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 746,752 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1085,1091 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 755,760 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1094,1158 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 772,778 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1170,1176 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 799,805 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1197,1203 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 810,815 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1208,1272 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 874,880 **** pg_dearmor(PG_FUNCTION_ARGS)
}
/*
! * Wrappers for PGP key id
*/
Datum
--- 1331,1337 ----
}
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 889,895 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1346,1352 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 900,902 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1357,1456 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+ if (PG_NARGS() > 2)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(2));
+ if (PG_NARGS() > 3)
+ arg = PG_GETARG_BYTEA_P(3);
+
+ err = extract_signatures_internal(0, data, psw, NULL, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(3));
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ err = extract_signatures_internal(1, data, key, keypsw, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 202,208 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,815 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+ uint32 creation_time;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ return res;
+ sig->creation_time = ntohl(creation_time);
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, (uint8 *) &creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ struct SigSubPktParserState pstate;
+ int res;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+ uint32 creation_time;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ while (1)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ goto err;
+ sig->creation_time = ntohl(creation_time);
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+ (void) last;
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->onepass = 0;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 224,235 **** pgp_free(PGP_Context *ctx)
--- 284,325 ----
{
if (ctx->pub_key)
pgp_key_free(ctx->pub_key);
+ if (ctx->sig_key)
+ pgp_key_free(ctx->sig_key);
+ if (ctx->sig_onepass)
+ pgp_sig_free(ctx->sig_onepass);
+ if (ctx->sig_expected)
+ pgp_sig_free(ctx->sig_expected);
+ if (ctx->sig_digest_ctx)
+ px_md_free(ctx->sig_digest_ctx);
px_memset(ctx, 0, sizeof *ctx);
px_free(ctx);
return 0;
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 404,420 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 45,50 **** enum PGP_PKT_TYPE
--- 45,51 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 107,121 **** enum PGP_DIGEST_TYPE
--- 108,136 ----
PGP_DIGEST_SHA512 = 10
};
+ enum PGP_SIGNATURE_TYPE
+ {
+ PGP_SIGTYP_BINARY = 0,
+ PGP_SIGTYP_TEXT = 1
+ };
+
+ enum PGP_SIGNATURE_SUBPKT_TYPE
+ {
+ PGP_SIGNATURE_CREATION_TIME = 2,
+ PGP_ISSUER_ID = 16
+ };
+
#define PGP_MAX_KEY (256/8)
#define PGP_MAX_BLOCK (256/8)
#define PGP_MAX_DIGEST (512/8)
+ #define PGP_MAX_DIGEST_ASN1_PREFIX 20
#define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 139,144 **** struct PGP_Context
--- 154,160 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 156,163 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 172,184 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 227,243 **** struct PGP_PubKey
--- 248,286 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint32 creation_time;
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 251,260 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
!
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 294,310 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
!
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
! int extract_details);
/* internal functions */
***************
*** 286,291 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 336,343 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 298,303 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 350,363 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 314,316 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 374,377 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,211 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 433,438 **** gen_salt(type text [, iter_count integer ]) returns text
--- 433,440 ----
<para>
The functions here implement the encryption part of the OpenPGP (RFC 4880)
standard. Supported are both symmetric-key and public-key encryption.
+ Also signing the data when encrypting and verifying the signature when
+ decrypting is supported.
</para>
<para>
***************
*** 524,529 **** gen_salt(type text [, iter_count integer ]) returns text
--- 526,579 ----
</listitem>
</orderedlist>
+ <para>
+ If the data is also signed, two more packets are added into the message:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <firstterm>one-pass signature packet</> is written before the encrypted
+ data, containing information about the algorithms used for the signature.
+ This allows the party decrypting the message to calculate the message
+ while decrypting it, in a single pass over the data.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After the encrypted data packet has been written, the signature itself is
+ written into a <firstterm>signature packet</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The signature is calculated as follows:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Optional data-manipulation: compression, conversion to UTF-8, and/or conversion of line-endings.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A hash of the entire message is calculated, using the algorithm specified
+ by the <literal>digest-algo</> setting.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A trailer containing additional information, such as the signature
+ creation time, is hashed in the same context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The resulting hash is put into the signature packet.
+ </para>
+ </listitem>
+ </orderedlist>
+
<sect3>
<title><function>pgp_sym_encrypt()</function></title>
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 585,615 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 623,641 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 646,658 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce an error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 669,698 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, these
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 711,729 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 733,745 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 797,867 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signatures</> and <function>pgp_pub_signatures</> if you
+ want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signatures(data bytea, key text [, details boolean [, options text ]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>. If details is
+ <literal>true</>, creation_time is set to the time recorded in the
+ signature. The default is <literal>false</>, since in most cases this
+ means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signatures(data bytea, key bytea [, psw text [, details boolean [, options text ]]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>. If there is no password, but you want to specify
+ <parameter>details</> or <parameter>options</>, you need to give an empty
+ password. If details is <literal>true</>, creation_time is set to the time
+ recorded in the signature. The default is <literal>false</>, since in most
+ cases this means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 786,791 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 968,986 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 929,942 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
</para>
</listitem>
<listitem>
<para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1124,1143 ----
<itemizedlist>
<listitem>
<para>
! No support for detached signatures. Additionally, none of the functions
! check that the encryption subkey has been signed by the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! Signing is only supported using RSA keys.
</para>
</listitem>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
At 2014-09-15 13:37:48 +0200, marko@joh.to wrote:
I'm not sure we're talking about the same thing.
No, we weren't. I was under the impression that the signatures
could be validated. Sorry for the noise.
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
I looked at this briefly, and was surprised that there is no support for
signing a message without encrypting it. Is that intentional? Instead of
adding a function to encrypt and sign a message, I would have expected
this to just add a new function for signing, and you could then pass it
an already-encrypted blob, or plaintext.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/2/14 1:47 PM, Heikki Linnakangas wrote:
I looked at this briefly, and was surprised that there is no support for
signing a message without encrypting it. Is that intentional? Instead of
adding a function to encrypt and sign a message, I would have expected
this to just add a new function for signing, and you could then pass it
an already-encrypted blob, or plaintext.
Yes, that's intentional. The signatures are part of the encrypted data
here, so you can't look at a message and determine who sent it.
There was brief discussion about this upthread (though no one probably
added any links to those discussions into the commit fest app), and I
still think that both types of signing would probably be valuable. But
this patch is already quite big, and I really have no desire to work on
this "sign anything" functionality. The pieces are there, though, so if
someone wants to do it, I don't see why they couldn't.
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Sep 15, 2014 at 4:37 AM, Marko Tiikkaja <marko@joh.to> wrote:
I've changed the patch back to ignore signatures when not using the
decrypt_verify() functions in the attached.
Hi Marko,
This patch needs a rebase now that the armor header patch has been
committed.
Thanks,
Jeff
Hi,
On 10/17/14, 9:56 PM, Jeff Janes wrote:
This patch needs a rebase now that the armor header patch has been
committed.
Thanks. Will fix that shortly.
I'm guessing there's no need to bump the pgcrypto version to 1.3, since
there hasn't been a release with the 1.2 version?
.marko
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Oct 20, 2014 at 6:27 AM, Marko Tiikkaja <marko@joh.to> wrote:
I'm guessing there's no need to bump the pgcrypto version to 1.3, since
there hasn't been a release with the 1.2 version?
Yep. One version bump by major release is fine for a contrib module.
--
Michael
Hi,
Here's the rebased patch -- as promised -- in a v7.
.marko
Attachments:
pgcrypto_sigs.v7.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v7.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,26 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
--- 20,26 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
***************
*** 34,40 **** REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 34,40 ----
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,313 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signature_keys.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signature_keys(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa
+ (1 row)
+
+ select pgp_pub_signature_keys.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signature_keys(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha512 | rsa
+ (1 row)
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ select * from pgp_sym_signature_keys((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha512 | rsa
+ 9DCF8E9C9BD31F24 | sha512 | rsa
+ (2 rows)
+
+ select * from pgp_pub_signature_keys((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo
+ ------------------+--------+------------
+ C899EA9344195559 | sha1 | rsa
+ 9DCF8E9C9BD31F24 | sha1 | rsa
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ for (;;)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** a/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 3,8 ****
--- 3,195 ----
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.2'" to load this file. \quit
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signature_keys(data, psw)
+ --
+ CREATE FUNCTION pgp_sym_signature_keys(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+
CREATE FUNCTION armor(bytea, text[], text[])
RETURNS text
AS 'MODULE_PATHNAME', 'pg_armor'
*** a/contrib/pgcrypto/pgcrypto--1.2.sql
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 95,100 **** AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
--- 95,139 ----
LANGUAGE C STRICT;
--
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
-- pgp_sym_decrypt(data, key)
--
CREATE FUNCTION pgp_sym_decrypt(bytea, text)
***************
*** 121,126 **** AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
--- 160,204 ----
LANGUAGE C IMMUTABLE STRICT;
--
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
-- pgp_pub_encrypt(data, key)
--
CREATE FUNCTION pgp_pub_encrypt(text, bytea)
***************
*** 147,152 **** AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
--- 225,269 ----
LANGUAGE C STRICT;
--
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
-- pgp_pub_decrypt(data, key)
--
CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
***************
*** 186,191 **** AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
--- 303,347 ----
LANGUAGE C IMMUTABLE STRICT;
--
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
-- PGP key ID
--
CREATE FUNCTION pgp_key_id(bytea)
***************
*** 193,198 **** RETURNS text
--- 349,385 ----
AS 'MODULE_PATHNAME', 'pgp_key_id_w'
LANGUAGE C IMMUTABLE STRICT;
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
+ --
+ -- pgp_sym_signature_keys(data, psw)
+ --
+ CREATE FUNCTION pgp_sym_signature_keys(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signature_keys(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signature_keys(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signature_keys_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
--
-- pgp armor
--
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1153,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static void
+ sig_compute_free(void *priv)
+ {
+ PX_MD *md = priv;
+
+ px_md_free(md);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, sig_compute_free
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization, if there is one.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,285 ----
return 8 * 2;
}
! typedef int (*sig_key_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signature_keys(PGP_Context *ctx, PullFilter *src, void *opaque,
! sig_key_cb_type sig_key_cb, int allow_compr);
!
!
! static int
! read_signature_keys_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, sig_key_cb_type sig_key_cb)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signature_keys(ctx, pkt, opaque, sig_key_cb, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signature_keys(ctx, pf_decompr, opaque, sig_key_cb, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signature_keys_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signature_keys_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signature_keys(PGP_Context *ctx, PullFilter *src, void *opaque,
! sig_key_cb_type sig_key_cb, int allow_compr)
! {
! int res;
! PGP_Signature *sig = NULL;
! PullFilter *pkt = NULL;
! int len;
! uint8 tag;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_key_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signature_keys_from_compressed_data(ctx, pkt, opaque, sig_key_cb);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! elog(WARNING, "broken tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and to extract out all the
! * signatures.
*/
! static int
! read_signature_keys_from_data(PGP_Context *ctx, PullFilter *pkt, int tag,
! void *opaque, sig_key_cb_type sig_key_cb)
! {
! int res;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
! int resync;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("extract_signature_keys: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signature_keys(ctx, pf_prefix, opaque, sig_key_cb, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! sig_key_cb_type sig_key_cb)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 292,298 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 312,373 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_key_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_key_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_key_cb)
+ res = read_signature_keys_from_data(ctx, pkt, tag, opaque, sig_key_cb);
break;
case PGP_PKT_SIGNATURE:
+ if (sig_key_cb)
+ {
+ res = pgp_parse_signature(ctx, &sig, pkt, NULL);
+ if (res >= 0)
+ res = sig_key_cb(opaque, sig);
+ }
+ else
+ res = pgp_skip_packet(pkt);
+ break;
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 382,390 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 410,497 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL);
+ }
+
+ struct GetSignatureKeyCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ };
+
+ static int
+ get_signature_key_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureKeyCtx *ctx = opaque;
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signature_keys(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid))
+ {
+ struct GetSignatureKeyCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL, get_signature_key_cb);
+ }
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 34,42 ****
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
- #include "utils/builtins.h"
#include "utils/array.h"
#include "funcapi.h"
#include "mbuf.h"
#include "px.h"
--- 34,44 ----
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
#include "utils/array.h"
+ #include "utils/builtins.h"
#include "funcapi.h"
+ #include "utils/memutils.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 47,61 ****
--- 49,74 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signature_keys_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signature_keys_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 180,185 **** struct debug_expect
--- 193,199 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 195,200 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 209,215 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 217,222 **** static void
--- 232,238 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 241,246 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 257,264 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 267,272 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 285,295 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 432,438 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 455,462 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 477,498 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 501,546 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 525,531 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 573,579 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 565,589 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 613,659 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 633,638 **** out:
--- 703,843 ----
return res;
}
+ struct MaterializeSignatureKeyCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_key_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureKeyCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[3];
+ bool isnull[3] = { false, false, false };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signature_keys(int is_pubenc, text *data, text *key, text *keypsw,
+ Tuplestorestate *tupstore, TupleDesc tupdesc)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureKeyCtx cbctx;
+
+ init_work(&ctx, 0, NULL, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signature_keys(ctx, src, &cbctx, materialize_signature_key_cb);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ signature_keys_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ ReturnSetInfo *rsinfo)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 3)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signature_keys(is_pubenc, data, key, keypsw, tupstore, tupdesc);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 649,655 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 854,860 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 671,677 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 876,882 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 680,685 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 885,950 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 694,700 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 959,965 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 716,722 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 981,987 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 725,730 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 990,1055 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 742,748 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1067,1073 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 764,770 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1089,1095 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 773,778 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1098,1162 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 790,796 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1174,1180 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 817,823 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1201,1207 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 828,833 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1212,1276 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 1070,1076 **** pgp_armor_headers(PG_FUNCTION_ARGS)
/*
! * Wrappers for PGP key id
*/
Datum
--- 1513,1519 ----
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 1085,1091 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1528,1558 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
! mbuf_free(buf);
! if (res_len < 0)
! ereport(ERROR,
! (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
! errmsg("%s", px_strerror(res_len))));
! SET_VARSIZE(res, VARHDRSZ + res_len);
!
! PG_FREE_IF_COPY(data, 0);
! PG_RETURN_TEXT_P(res);
! }
!
! Datum
! pgp_main_key_id_w(PG_FUNCTION_ARGS)
! {
! bytea *data;
! text *res;
! int res_len;
! MBuf *buf;
!
! data = PG_GETARG_BYTEA_P(0);
! buf = create_mbuf_from_vardata(data);
! res = palloc(VARHDRSZ + 17);
!
! res_len = pgp_get_keyid(1, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 1096,1098 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1563,1618 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+
+ Datum
+ pgp_sym_signature_keys_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw;
+ int err;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+
+ err = signature_keys_internal(0, data, psw, NULL,
+ (ReturnSetInfo *) fcinfo->resultinfo);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signature_keys_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL;
+ int err;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+
+ err = signature_keys_internal(1, data, key, keypsw,
+ (ReturnSetInfo *) fcinfo->resultinfo);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 29,38 ****
--- 29,42 ----
* contrib/pgcrypto/pgp-pubenc.c
*/
#include "postgres.h"
+ #include "c.h"
#include "px.h"
#include "pgp.h"
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
/*
* padded msg: 02 || non-zero pad bytes || 00 || msg
*/
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 206,212 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,807 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, sig->creation_time);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, sig->creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+
+ struct SigSubPktParserState pstate;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ for (;;)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, sig->creation_time);
+ if (res < 0)
+ goto err;
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ res = PXE_PGP_CORRUPT_DATA;
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 230,235 **** pgp_free(PGP_Context *ctx)
--- 290,317 ----
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 396,412 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 47,52 **** enum PGP_PKT_TYPE
--- 47,53 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 109,123 **** enum PGP_DIGEST_TYPE
PGP_DIGEST_SHA512 = 10
};
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
struct PGP_S2K
{
--- 110,138 ----
PGP_DIGEST_SHA512 = 10
};
! enum PGP_SIGNATURE_TYPE
! {
! PGP_SIGTYP_BINARY = 0,
! PGP_SIGTYP_TEXT = 1
! };
!
! enum PGP_SIGNATURE_SUBPKT_TYPE
! {
! PGP_SIGNATURE_CREATION_TIME = 2,
! PGP_ISSUER_ID = 16
! };
!
! #define PGP_MAX_KEY (256/8)
! #define PGP_MAX_BLOCK (256/8)
! #define PGP_MAX_DIGEST (512/8)
! #define PGP_MAX_DIGEST_ASN1_PREFIX 20
! #define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 141,146 **** struct PGP_Context
--- 156,162 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 158,165 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 174,186 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 229,245 **** struct PGP_PubKey
--- 250,288 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint8 creation_time[4];
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 253,262 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 296,311 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signature_keys(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid));
/* internal functions */
***************
*** 289,294 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 338,345 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 301,306 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 352,365 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 317,319 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 376,379 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,199 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signature_keys.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signature_keys(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signature_keys.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signature_keys(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ select * from pgp_sym_signature_keys((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signature_keys((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 535,565 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 573,591 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 596,608 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce an error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 619,648 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, these
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 661,679 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 683,695 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 747,808 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signature_keys</> and <function>pgp_pub_signature_keys</>
+ if you want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signature_keys()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signature_keys</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signature_keys(data bytea, key text) returns setof (keyid text, digest text, pubkeyalgo text)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signature_keys</> extracts the list of signatures present
+ in the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signature_keys()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signature_keys</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signature_keys(data bytea, key bytea [ , psw text]) returns setof (keyid text, digest text, pubkeyalgo text)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signature_keys</> extracts the list of signatures present
+ in the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 812,817 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 935,953 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 955,968 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1091,1099 ----
<itemizedlist>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
On Mon, Oct 20, 2014 at 3:32 PM, Marko Tiikkaja <marko@joh.to> wrote:
Hi,
Here's the rebased patch -- as promised -- in a v7.
Hi Marko,
Using the same script as for the memory leak, I am getting seg faults using
this patch.
24425 2014-10-27 15:42:11.819 PDT LOG: server process (PID 24452) was
terminated by signal 11: Segmentation fault
24425 2014-10-27 15:42:11.819 PDT DETAIL: Failed process was running:
select pgp_sym_decrypt_verify(dearmor($1),$2,dearmor($3),'debug=1')
gdb backtrace:
#0 pfree (pointer=0x0) at mcxt.c:749
#1 0x00007f617d7973e7 in pgp_sym_decrypt_verify_text (fcinfo=0x1d7f1f0) at
pgp-pgsql.c:1047
#2 0x000000000059f185 in ExecMakeFunctionResultNoSets (fcache=0x1d7f180,
econtext=0x1d7fb00, isNull=0x7fff02e902bf "", isDone=<value optimized out>)
at execQual.c:1992
#3 0x000000000059ae0c in ExecEvalExprSwitchContext (expression=<value
optimized out>, econtext=<value optimized out>, isNull=<value optimized
out>,
isDone=<value optimized out>) at execQual.c:4320
Cheers,
Jeff
On 10/27/14, 11:57 PM, Jeff Janes wrote:
Using the same script as for the memory leak, I am getting seg faults using
this patch.gdb backtrace:
#0 pfree (pointer=0x0) at mcxt.c:749
#1 0x00007f617d7973e7 in pgp_sym_decrypt_verify_text (fcinfo=0x1d7f1f0) at
pgp-pgsql.c:1047
Huh. That's weird. I seem to have somehow rebased an older version of
the patch from my git history. This is the copy-paste mistake Thomas
(IIRC) pointed out and I fixed weeks, if not months, ago.
I have no idea what happened so I just threw away the git history and
rebased v6 of the patch on top of master. I've also verified that the
script runs and does not leak memory. The resulting patch, v8, attached.
My apologies for wasting your time, but thanks for testing!
.marko
Attachments:
pgcrypto_sigs.v8.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v8.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,26 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
--- 20,26 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
***************
*** 34,40 **** REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 34,40 ----
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,338 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ (1 row)
+
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ C899EA9344195559 | sha512 | rsa |
+ (1 row)
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+ NOTICE: dbg: key_id's does not match
+ ERROR: Wrong key
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ C899EA9344195559 | sha512 | rsa |
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa |
+ C899EA9344195559 | sha1 | rsa |
+ (2 rows)
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ 9DCF8E9C9BD31F24 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ while (1)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** a/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 12,14 **** CREATE FUNCTION pgp_armor_headers(text, key OUT text, value OUT text)
--- 12,234 ----
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'pgp_armor_headers'
LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto--1.2.sql
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 95,100 **** AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
--- 95,139 ----
LANGUAGE C STRICT;
--
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
-- pgp_sym_decrypt(data, key)
--
CREATE FUNCTION pgp_sym_decrypt(bytea, text)
***************
*** 121,126 **** AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
--- 160,204 ----
LANGUAGE C IMMUTABLE STRICT;
--
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
-- pgp_pub_encrypt(data, key)
--
CREATE FUNCTION pgp_pub_encrypt(text, bytea)
***************
*** 147,152 **** AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
--- 225,269 ----
LANGUAGE C STRICT;
--
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
-- pgp_pub_decrypt(data, key)
--
CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
***************
*** 186,191 **** AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
--- 303,347 ----
LANGUAGE C IMMUTABLE STRICT;
--
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
-- PGP key ID
--
CREATE FUNCTION pgp_key_id(bytea)
***************
*** 193,198 **** RETURNS text
--- 349,415 ----
AS 'MODULE_PATHNAME', 'pgp_key_id_w'
LANGUAGE C IMMUTABLE STRICT;
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
--
-- pgp armor
--
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1039,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1153,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ *
+ * This filter only computes the literal data packet's contents into
+ * ctx->sig_digest_ctx. No signature is written (since we wouldn't be able to
+ * write it into the correct place in the flush callback).
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ /*
+ * Load the digest into sig_digest_ctx for everyone to use. It'll also be
+ * freed in pgp_sig_free, not when this filter is done.
+ */
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, NULL
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,317 ----
return 8 * 2;
}
! typedef int (*signature_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr);
!
!
! static int
! read_signatures_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signatures_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signatures_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! /*
! * We don't need to care about the special handling for PKG_CONTEXT
! * length in SYMENC_MDC packets because we skip over the data and never
! * check the MDC.
! */
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signatures_from_compressed_data(ctx, pkt, opaque,
! sig_cb, extract_details);
! /*
! * We're assuming that there will only ever be a single data
! * packet, compressed or otherwise.
! */
! if (!extract_details)
! done = 1;
! break;
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * If extract_details is not specified, we never look for
! * signatures beyond the data as the decryption code doesn't,
! * either.
! */
! if (!extract_details)
! done = 1;
! else
! res = pgp_skip_packet(pkt);
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signatures: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and extract information about
! * the signatures.
*/
! static int
! read_signatures_from_data(PGP_Context *ctx, PullFilter *pkt, int tag, void *opaque,
! signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! int resync;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
!
! if (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("read_signature_from_data: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
!
! res = extract_signatures(ctx, pf_prefix, opaque, sig_key_cb, extract_details, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! signature_cb_type sig_cb,
! int extract_details)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 324,330 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 344,400 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_cb)
+ res = read_signatures_from_data(ctx, pkt, tag, opaque, sig_cb, extract_details);
break;
case PGP_PKT_SIGNATURE:
+ /*
+ * We ignore signatures not part of the encrypted data since we
+ * won't use them anyway.
+ */
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 409,417 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 437,542 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL, 0);
+ }
+
+ struct GetSignatureInfoCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ int extract_details;
+ };
+
+ static int
+ get_signature_info_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureInfoCtx *ctx = opaque;
+
+ /* ignore signatures not used for literal data */
+ if (sig->type != PGP_SIGTYP_BINARY &&
+ sig->type != PGP_SIGTYP_TEXT)
+ return 0;
+
+ /*
+ * Also skip one-pass signatures if we're extracting details; there should
+ * be a corresponding signature packet after the data with all the details.
+ */
+ if (sig->onepass && ctx->extract_details)
+ return 0;
+
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
+ int extract_details)
+ {
+ struct GetSignatureInfoCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ cbctx.extract_details = extract_details;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL,
+ get_signature_info_cb, extract_details);
+ }
+
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 34,42 ****
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
- #include "utils/builtins.h"
#include "utils/array.h"
#include "funcapi.h"
#include "mbuf.h"
#include "px.h"
--- 34,44 ----
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
#include "utils/array.h"
+ #include "utils/builtins.h"
+ #include "utils/timestamp.h"
#include "funcapi.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 47,61 ****
--- 49,74 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signatures_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signatures_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 180,185 **** struct debug_expect
--- 193,199 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 195,200 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 209,215 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 217,222 **** static void
--- 232,238 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 241,246 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 257,264 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 267,272 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 285,295 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 432,438 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 455,462 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 477,498 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 501,546 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 525,531 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 573,579 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 565,589 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 613,659 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 633,638 **** out:
--- 703,855 ----
return res;
}
+ struct MaterializeSignatureCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[4];
+ bool isnull[4] = { false, false, false, true };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ /*
+ * If this isn't a one-pass signature, we also know the creation time of
+ * the signature.
+ */
+ if (!sig->onepass)
+ {
+ isnull[3] = false;
+ values[3] = time_t_to_timestamptz((pg_time_t) sig->creation_time);
+ }
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signatures(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, Tuplestorestate *tupstore, TupleDesc tupdesc,
+ int extract_details)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureCtx cbctx;
+
+ init_work(&ctx, 0, arg, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signatures(ctx, src, &cbctx, materialize_signature_cb,
+ extract_details);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ extract_signatures_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, ReturnSetInfo *rsinfo, int extract_details)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 4)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signatures(is_pubenc, data, key, keypsw,
+ arg, tupstore, tupdesc, extract_details);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 649,655 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 866,872 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 671,677 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 888,894 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 680,685 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 897,962 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 694,700 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 971,977 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 716,722 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 993,999 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 725,730 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 1002,1067 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 742,748 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1079,1085 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 764,770 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1101,1107 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 773,778 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1110,1174 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 790,796 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1186,1192 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 817,823 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1213,1219 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 828,833 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1224,1288 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 1070,1076 **** pgp_armor_headers(PG_FUNCTION_ARGS)
/*
! * Wrappers for PGP key id
*/
Datum
--- 1525,1531 ----
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 1085,1091 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1540,1546 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 1096,1098 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1551,1650 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+ if (PG_NARGS() > 2)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(2));
+ if (PG_NARGS() > 3)
+ arg = PG_GETARG_BYTEA_P(3);
+
+ err = extract_signatures_internal(0, data, psw, NULL, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(3));
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ err = extract_signatures_internal(1, data, key, keypsw, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 202,208 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,815 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+ uint32 creation_time;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ return res;
+ sig->creation_time = ntohl(creation_time);
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, (uint8 *) &creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ struct SigSubPktParserState pstate;
+ int res;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+ uint32 creation_time;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ while (1)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ goto err;
+ sig->creation_time = ntohl(creation_time);
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+ (void) last;
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->onepass = 0;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 224,235 **** pgp_free(PGP_Context *ctx)
--- 284,325 ----
{
if (ctx->pub_key)
pgp_key_free(ctx->pub_key);
+ if (ctx->sig_key)
+ pgp_key_free(ctx->sig_key);
+ if (ctx->sig_onepass)
+ pgp_sig_free(ctx->sig_onepass);
+ if (ctx->sig_expected)
+ pgp_sig_free(ctx->sig_expected);
+ if (ctx->sig_digest_ctx)
+ px_md_free(ctx->sig_digest_ctx);
px_memset(ctx, 0, sizeof *ctx);
px_free(ctx);
return 0;
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 404,420 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 47,52 **** enum PGP_PKT_TYPE
--- 47,53 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 109,123 **** enum PGP_DIGEST_TYPE
--- 110,138 ----
PGP_DIGEST_SHA512 = 10
};
+ enum PGP_SIGNATURE_TYPE
+ {
+ PGP_SIGTYP_BINARY = 0,
+ PGP_SIGTYP_TEXT = 1
+ };
+
+ enum PGP_SIGNATURE_SUBPKT_TYPE
+ {
+ PGP_SIGNATURE_CREATION_TIME = 2,
+ PGP_ISSUER_ID = 16
+ };
+
#define PGP_MAX_KEY (256/8)
#define PGP_MAX_BLOCK (256/8)
#define PGP_MAX_DIGEST (512/8)
+ #define PGP_MAX_DIGEST_ASN1_PREFIX 20
#define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 141,146 **** struct PGP_Context
--- 156,162 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 158,165 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 174,186 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 229,245 **** struct PGP_PubKey
--- 250,288 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint32 creation_time;
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 253,262 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
!
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 296,312 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
!
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
! int extract_details);
/* internal functions */
***************
*** 289,294 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 339,346 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 301,306 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 353,366 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 317,319 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 377,380 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,211 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 433,438 **** gen_salt(type text [, iter_count integer ]) returns text
--- 433,440 ----
<para>
The functions here implement the encryption part of the OpenPGP (RFC 4880)
standard. Supported are both symmetric-key and public-key encryption.
+ Also signing the data when encrypting and verifying the signature when
+ decrypting is supported.
</para>
<para>
***************
*** 524,529 **** gen_salt(type text [, iter_count integer ]) returns text
--- 526,579 ----
</listitem>
</orderedlist>
+ <para>
+ If the data is also signed, two more packets are added into the message:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <firstterm>one-pass signature packet</> is written before the encrypted
+ data, containing information about the algorithms used for the signature.
+ This allows the party decrypting the message to calculate the message
+ while decrypting it, in a single pass over the data.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After the encrypted data packet has been written, the signature itself is
+ written into a <firstterm>signature packet</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The signature is calculated as follows:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Optional data-manipulation: compression, conversion to UTF-8, and/or conversion of line-endings.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A hash of the entire message is calculated, using the algorithm specified
+ by the <literal>digest-algo</> setting.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A trailer containing additional information, such as the signature
+ creation time, is hashed in the same context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The resulting hash is put into the signature packet.
+ </para>
+ </listitem>
+ </orderedlist>
+
<sect3>
<title><function>pgp_sym_encrypt()</function></title>
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 585,615 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 623,641 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 646,658 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce an error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 669,698 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, these
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 711,729 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 733,745 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 797,867 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signatures</> and <function>pgp_pub_signatures</> if you
+ want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signatures(data bytea, key text [, details boolean [, options text ]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>. If details is
+ <literal>true</>, creation_time is set to the time recorded in the
+ signature. The default is <literal>false</>, since in most cases this
+ means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signatures(data bytea, key bytea [, psw text [, details boolean [, options text ]]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>. If there is no password, but you want to specify
+ <parameter>details</> or <parameter>options</>, you need to give an empty
+ password. If details is <literal>true</>, creation_time is set to the time
+ recorded in the signature. The default is <literal>false</>, since in most
+ cases this means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 812,817 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 994,1012 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 955,968 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
</para>
</listitem>
<listitem>
<para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1150,1169 ----
<itemizedlist>
<listitem>
<para>
! No support for detached signatures. Additionally, none of the functions
! check that the encryption subkey has been signed by the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! Signing is only supported using RSA keys.
</para>
</listitem>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
Hi,
I discovered a problem with the lack of MDC handling in the signature
info extraction code, so I've fixed that and added a test message. v9 here.
.marko
Attachments:
pgcrypto_sigs.v9.patchtext/plain; charset=UTF-8; name=pgcrypto_sigs.v9.patch; x-mac-creator=0; x-mac-type=0Download
*** a/contrib/pgcrypto/Makefile
--- b/contrib/pgcrypto/Makefile
***************
*** 20,26 **** SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c \
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
--- 20,26 ----
mbuf.c pgp.c pgp-armor.c pgp-cfb.c pgp-compress.c \
pgp-decrypt.c pgp-encrypt.c pgp-info.c pgp-mpi.c \
pgp-pubdec.c pgp-pubenc.c pgp-pubkey.c pgp-s2k.c \
! pgp-sig.c pgp-pgsql.c
MODULE_big = pgcrypto
OBJS = $(SRCS:.c=.o) $(WIN32RES)
***************
*** 34,40 **** REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info
EXTRA_CLEAN = gen-rtab
--- 34,40 ----
$(CF_TESTS) \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
! pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info pgp-sign
EXTRA_CLEAN = gen-rtab
*** a/contrib/pgcrypto/expected/pgp-encrypt.out
--- b/contrib/pgcrypto/expected/pgp-encrypt.out
***************
*** 16,22 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
pgp_sym_decrypt
-----------------
--- 16,23 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
pgp_sym_decrypt
-----------------
***************
*** 30,38 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
--- 31,41 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
+ NOTICE: pgp_decrypt: unexpected digest_algo: expected 1 got 10
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
*** a/contrib/pgcrypto/expected/pgp-info.out
--- b/contrib/pgcrypto/expected/pgp-info.out
***************
*** 76,78 **** from encdata order by id;
--- 76,151 ----
FD0206C409B74875
(4 rows)
+ -- pgp_main_key_id
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ pgp_main_key_id
+ ------------------
+ 48E9CD56FEA668DB
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ pgp_main_key_id
+ ------------------
+ 63F875F63F6774A0
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ pgp_main_key_id
+ ------------------
+ 9DCF8E9C9BD31F24
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ pgp_main_key_id
+ ------------------
+ 1C29BC0D18177364
+ (1 row)
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
+ pgp_main_key_id
+ ------------------
+ C899EA9344195559
+ (1 row)
+
*** /dev/null
--- b/contrib/pgcrypto/expected/pgp-sign.out
***************
*** 0 ****
--- 1,365 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ (1 row)
+
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ C899EA9344195559 | sha512 | rsa |
+ (1 row)
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+ NOTICE: dbg: key_id's does not match
+ ERROR: Wrong key
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_bytea
+ -----------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No signature matching the key id present in the message
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: No signature matching the key id present in the message
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_bytea
+ -----------------------
+ hello world
+ (1 row)
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha512 | rsa |
+ C899EA9344195559 | sha512 | rsa |
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+---------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa |
+ C899EA9344195559 | sha1 | rsa |
+ (2 rows)
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ 9DCF8E9C9BD31F24 | sha512 | rsa | Mon Aug 04 05:29:15 2014 PDT
+ (2 rows)
+
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ C899EA9344195559 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Mon Aug 04 05:22:57 2014 PDT
+ (2 rows)
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ hello world
+ (1 row)
+
+ -- test for MDC filter in pgp-info
+ insert into encdata(id, data) values (8, '
+ -----BEGIN PGP MESSAGE-----
+
+ hQEMA/0CBsQJt0h1AQf9Ft3w02xcBLxXvKhlQwpngOr3+yYwvUNf2Cup9eDuk52RR0dQ8A/lAW5Q
+ 6xvidlsUqpym7dG7l1siiit8xWv4wqlk+Aoyf5AOIa90nptKm9m/s7PPLjySRSy4Upyb/lm4686R
+ Yw/DtOMV5Y8CDj1W0KzSy4RJFDh3F5e0wlPfci2fpfjz6j4Ac/XQWyBXz0bEqAhGa7U1slO1Z2af
+ 0F4fbSu17XG20erPPfusoKjkFfcQTxO34uj5HUQbjKbOgWcTnsdz7OLZFZ3fjEbQqG4YtEwvQ5dC
+ XVN2rST6WQRIMMlr95WoX0agI3ykEZ/vy8Sh+Iji5PPM6UOaQqS5Aw1fvdLpAeYo7yNjAaIfx5xH
+ b+fhfgGgKjSGQJYv8Dp5b3uXN7o3I0YSGyLDRkAgZD+d+5w75P+oJESYLLzlDrcaJ+0YvDEzbalV
+ +0vp9cKIGXsQ82FEzAq6RrlRM9HBVwyMMvMAo18py5ruSDckLdLuS05GobtiZvZpV+j+/TSr+GXn
+ /1B8XwCE829Ty4PT2GrD9e3oa1yedM17FPDtesMFLlxpVKeP89jWbn1U0gTvp5QFiLINyka5Uh71
+ 5xsBy8KG7+ZQ1bppvgH8sSos7s8VkbyS5/3C6nWoUN7ylzVh4d2Jb60Nqx+rtHOpdOfH7e+55Dux
+ NwU0nNni5msv++QQoKwr5guMQ+j0CofQlW8VA82S/fmYQEyifuCVA/qb0OK4qBN9gne8hePEbplV
+ pNcuodLkeBPiRSK2G+zdp0yYEpeMV5C1hxYVMS1ea0BoKMq5n57jwmnnLwJijjUw6CjGodtBF7mT
+ aEHeff1OPHgjbFtXojDuPAaN86RTRXqN6HSOrv/V8eW78KoEUENcOVDLvoOYpUlqGdmSp0HGpuDZ
+ U1Hp14vpvabDrjZ45VxZKSdLGeywyVkYkV4ZeXXsurbOCGwUzgZBodHcaG1fSF7NBTDPrXNfkr1n
+ oDruf0xBGr6adDlBmXWCo6AeKdCfuJJ9s0KUi0LbNaewpuyYiT8t3ziqdjcCnUs=
+ =26/O
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=8), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', TRUE);
+ keyid | digest | pubkeyalgo | creation_time
+ ------------------+--------+------------+------------------------------
+ 9DCF8E9C9BD31F24 | sha1 | rsa | Sat Nov 01 03:02:52 2014 PDT
+ (1 row)
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: No sign key found
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ ERROR: Not text data
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ ERROR: Not text data
+ -- encrypt in text, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify_bytea
+ ------------------------------
+ Secret.\015\012
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret. +
+
+ (1 row)
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.
+ (1 row)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+ pgp_sym_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+ pgp_pub_decrypt_verify
+ ------------------------
+ Secret.\r +
+
+ (1 row)
+
*** a/contrib/pgcrypto/mbuf.c
--- b/contrib/pgcrypto/mbuf.c
***************
*** 332,337 **** pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
--- 332,379 ----
}
/*
+ * pullf_discard discards max bytes from src. Reaching EOF before max bytes
+ * have been read will return PXE_MBUF_SHORT_READ. If max is -1, all bytes
+ * until EOF are discarded. Returns the number of bytes discarded on success,
+ * < 0 otherwise.
+ */
+ int
+ pullf_discard(PullFilter *src, int max)
+ {
+ int res;
+ uint8 *tmp;
+ int read = 0;
+
+ if (max == -1)
+ {
+ while (1)
+ {
+ res = pullf_read(src, 8192, &tmp);
+ if (res == 0)
+ return read;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ if (read == max)
+ return read;
+
+ res = pullf_read(src, max - read, &tmp);
+ if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ else if (res < 0)
+ return res;
+ read += res;
+ }
+ }
+ }
+
+ /*
* read from MBuf
*/
static int
***************
*** 353,358 **** pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
--- 395,477 ----
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
+ /*
+ * reader with a limit
+ */
+
+ static int
+ limited_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ int *limit = arg;
+ int res;
+
+ if (*limit == 0)
+ return 0;
+ if (len > *limit)
+ return PXE_MBUF_SHORT_READ;
+ res = pullf_read(src, len, data_p);
+ if (res > 0)
+ {
+ *limit -= res;
+ if (*limit < 0)
+ return PXE_MBUF_SHORT_READ;
+ }
+ else if (res == 0)
+ return PXE_MBUF_SHORT_READ;
+ return res;
+ }
+
+ static const struct PullFilterOps limited_reader = {
+ NULL, limited_reader_pull, NULL
+ };
+
+ /*
+ * Creates a new PullFilter which reads *limit bytes from src. The caller
+ * should make sure the memory limit points to stays alive until the reader is
+ * destroyed. The value of *limit is updated after every read. While reading,
+ * if an EOF is encountered before consuming *limit bytes from src or the
+ * caller tries to read more than *limit bytes in total, PXE_MBUF_SHORT_READ is
+ * returned.
+ */
+ int
+ pullf_create_limited_reader(PullFilter **mp_p, PullFilter *src, int *limit)
+ {
+ return pullf_create(mp_p, &limited_reader, limit, src);
+ }
+
+ /*
+ * reader which writes a copy to an mbuf
+ */
+ static int
+ tee_reader_pull(void *arg, PullFilter *src, int len,
+ uint8 **data_p, uint8 *buf, int buflen)
+ {
+ MBuf *mbuf = arg;
+ int res;
+ int res2;
+
+ res = pullf_read(src, len, data_p);
+ if (res <= 0)
+ return res;
+ res2 = mbuf_append(mbuf, *data_p, res);
+ if (res2 < 0)
+ return res2;
+ /* return the number of bytes read */
+ return res;
+ }
+
+ static const struct PullFilterOps tee_reader = {
+ NULL, tee_reader_pull, NULL
+ };
+
+ int
+ pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf)
+ {
+ return pullf_create(mp_p, &tee_reader, buf, src);
+ }
+
+
/*
* PushFilter
*** a/contrib/pgcrypto/mbuf.h
--- b/contrib/pgcrypto/mbuf.h
***************
*** 109,115 **** int pullf_read_max(PullFilter *mp, int len,
--- 109,118 ----
uint8 **data_p, uint8 *tmpbuf);
void pullf_free(PullFilter *mp);
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst);
+ int pullf_discard(PullFilter *src, int max);
+ int pullf_create_limited_reader(PullFilter **pf_p, PullFilter *src, int *limit);
+ int pullf_create_tee_reader(PullFilter **mp_p, PullFilter *src, MBuf *buf);
int pullf_create_mbuf_reader(PullFilter **pf_p, MBuf *mbuf);
#define GETBYTE(pf, dst) \
*** a/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
--- b/contrib/pgcrypto/pgcrypto--1.1--1.2.sql
***************
*** 12,14 **** CREATE FUNCTION pgp_armor_headers(text, key OUT text, value OUT text)
--- 12,234 ----
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'pgp_armor_headers'
LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_main_key_id(key)
+ --
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
*** a/contrib/pgcrypto/pgcrypto--1.2.sql
--- b/contrib/pgcrypto/pgcrypto--1.2.sql
***************
*** 95,100 **** AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
--- 95,139 ----
LANGUAGE C STRICT;
--
+ -- pgp_sym_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_sym_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_encrypt_sign(text, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_sym_encrypt_sign_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
-- pgp_sym_decrypt(data, key)
--
CREATE FUNCTION pgp_sym_decrypt(bytea, text)
***************
*** 121,126 **** AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
--- 160,204 ----
LANGUAGE C IMMUTABLE STRICT;
--
+ -- pgp_sym_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_decrypt_verify(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_sym_decrypt_verify(bytea, text, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_sym_decrypt_verify_bytea(bytea, text, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
-- pgp_pub_encrypt(data, key)
--
CREATE FUNCTION pgp_pub_encrypt(text, bytea)
***************
*** 147,152 **** AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
--- 225,269 ----
LANGUAGE C STRICT;
--
+ -- pgp_pub_encrypt_sign(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
+ -- pgp_pub_encrypt_sign(data, key, sigkey, psw, args)
+ --
+ CREATE FUNCTION pgp_pub_encrypt_sign(text, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_text'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION pgp_pub_encrypt_sign_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_sign_bytea'
+ LANGUAGE C STRICT;
+
+ --
-- pgp_pub_decrypt(data, key)
--
CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
***************
*** 186,191 **** AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
--- 303,347 ----
LANGUAGE C IMMUTABLE STRICT;
--
+ -- pgp_pub_decrypt_verify(data, key, sigkey)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_decrypt_verify(data, key, sigkey, psw, arg)
+ --
+ CREATE FUNCTION pgp_pub_decrypt_verify(bytea, bytea, bytea, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_text'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION pgp_pub_decrypt_verify_bytea(bytea, bytea, bytea, text, text)
+ RETURNS bytea
+ AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_verify_bytea'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
-- PGP key ID
--
CREATE FUNCTION pgp_key_id(bytea)
***************
*** 193,198 **** RETURNS text
--- 349,415 ----
AS 'MODULE_PATHNAME', 'pgp_key_id_w'
LANGUAGE C IMMUTABLE STRICT;
+ CREATE FUNCTION pgp_main_key_id(bytea)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'pgp_main_key_id_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_sym_signatures(data, key, details, args)
+ --
+ CREATE FUNCTION pgp_sym_signatures(bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_sym_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- pgp_pub_signatures(data, key, psw, details, args)
+ --
+ CREATE FUNCTION pgp_pub_signatures(bytea, bytea, text, boolean, text)
+ RETURNS TABLE (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ AS 'MODULE_PATHNAME', 'pgp_pub_signatures_w'
+ LANGUAGE C IMMUTABLE STRICT;
+
--
-- pgp armor
--
*** a/contrib/pgcrypto/pgp-decrypt.c
--- b/contrib/pgcrypto/pgp-decrypt.c
***************
*** 155,161 **** pgp_parse_pkt_hdr(PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
else
res = parse_old_len(src, len_p, lentype);
}
--- 155,169 ----
lentype = *p & 3;
*tag = (*p >> 2) & 0x0F;
if (lentype == 3)
! {
! if (!allow_ctx)
! {
! px_debug("pgp_parse_pkt_hdr: lentype==3 but allow_context is false");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = PKT_CONTEXT;
! }
else
res = parse_old_len(src, len_p, lentype);
}
***************
*** 284,290 **** prefix_init(void **priv_p, void *arg, PullFilter *src)
return 0;
}
! static struct PullFilterOps prefix_filter = {
prefix_init, NULL, NULL
};
--- 292,298 ----
return 0;
}
! struct PullFilterOps pgp_prefix_filter = {
prefix_init, NULL, NULL
};
***************
*** 433,439 **** mdc_read(void *priv, PullFilter *src, int len,
return res;
}
! static struct PullFilterOps mdc_filter = {
mdc_init, mdc_read, mdc_free
};
--- 441,447 ----
return res;
}
! struct PullFilterOps pgp_mdc_filter = {
mdc_init, mdc_read, mdc_free
};
***************
*** 597,603 **** mdcbuf_free(void *priv)
px_free(st);
}
! static struct PullFilterOps mdcbuf_filter = {
mdcbuf_init, mdcbuf_read, mdcbuf_free
};
--- 605,611 ----
px_free(st);
}
! struct PullFilterOps pgp_mdcbuf_filter = {
mdcbuf_init, mdcbuf_read, mdcbuf_free
};
***************
*** 638,645 **** decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
/*
* Handle key packet
*/
! static int
! parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
--- 646,653 ----
/*
* Handle key packet
*/
! int
! pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src)
{
uint8 *p;
int res;
***************
*** 805,810 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 813,822 ----
ctx->unicode_mode = (type == 'u') ? 1 : 0;
+ /* if verifying, a hashing context should have been set up for us */
+ if (ctx->sig_key && ctx->sig_digest_ctx == NULL)
+ return PXE_BUG;
+
/* read data */
while (1)
{
***************
*** 812,817 **** parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 824,832 ----
if (res <= 0)
break;
+ if (ctx->sig_digest_ctx)
+ px_md_update(ctx->sig_digest_ctx, buf, res);
+
if (ctx->text_mode && ctx->convert_crlf)
res = copy_crlf(dst, buf, res, &got_cr);
else
***************
*** 869,874 **** parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
--- 884,973 ----
}
static int
+ parse_onepass_signature(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_onepass_signature(ctx, &sig, pkt);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_onepass)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_onepass = sig;
+ }
+ else
+ res = pgp_sig_free(sig);
+ return res;
+ }
+
+ static int
+ parse_signature(PGP_Context *ctx, PullFilter *pkt)
+ {
+ int res;
+ PGP_Signature *sig;
+
+ /* don't bother if we weren't asked to verify signatures */
+ if (!ctx->sig_key)
+ return pgp_skip_packet(pkt);
+
+ res = pgp_parse_signature(ctx, &sig, pkt, ctx->sig_key->key_id);
+ if (res < 0)
+ return res;
+
+ if (memcmp(sig->keyid, ctx->sig_key->key_id, 8) == 0 &&
+ sig->algo == ctx->sig_key->algo &&
+ (sig->type == PGP_SIGTYP_BINARY ||
+ sig->type == PGP_SIGTYP_TEXT))
+ {
+ if (ctx->sig_expected)
+ res = PXE_PGP_MULTIPLE_SIGNATURES;
+ else if (ctx->sig_onepass)
+ {
+ if (ctx->sig_onepass->algo != sig->algo ||
+ ctx->sig_onepass->digest_algo != sig->digest_algo)
+ res = PXE_PGP_CONFLICTING_SIGNATURES;
+ }
+ else
+ {
+ /* if there was no one-pass signature, load sig_digest_ctx now */
+ if (ctx->sig_digest_ctx)
+ res = PXE_BUG;
+ else
+ res = pgp_load_digest(sig->digest_algo, &ctx->sig_digest_ctx);
+ }
+
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ ctx->sig_expected = sig;
+ }
+ else
+ pgp_sig_free(sig);
+
+ return res;
+ }
+
+
+ static int
process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
int allow_compr, int need_mdc)
{
***************
*** 897,903 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
/* context length inside SYMENC_MDC needs special handling */
if (need_mdc && res == PKT_CONTEXT)
! res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
else
res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
if (res < 0)
--- 996,1002 ----
/* context length inside SYMENC_MDC needs special handling */
if (need_mdc && res == PKT_CONTEXT)
! res = pullf_create(&pkt, &pgp_mdcbuf_filter, ctx, src);
else
res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
if (res < 0)
***************
*** 906,913 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
--- 1005,1021 ----
switch (tag)
{
case PGP_PKT_LITERAL_DATA:
! if (ctx->sig_key && !ctx->sig_onepass && !ctx->sig_expected)
! {
! px_debug("process_data_packets: no signature or one-pass "
! "signature before literal data");
! res = PXE_PGP_NO_SIGNATURE;
! }
! else
! {
! got_data = 1;
! res = parse_literal_data(ctx, dst, pkt);
! }
break;
case PGP_PKT_COMPRESSED_DATA:
if (allow_compr == 0)
***************
*** 944,949 **** process_data_packets(PGP_Context *ctx, MBuf *dst, PullFilter *src,
--- 1052,1063 ----
if (res > 0)
got_mdc = 1;
break;
+ case PGP_PKT_ONEPASS_SIGNATURE:
+ res = parse_onepass_signature(ctx, dst, pkt);
+ break;
+ case PGP_PKT_SIGNATURE:
+ res = parse_signature(ctx, pkt);
+ break;
default:
px_debug("process_data_packets: unexpected pkt tag=%d", tag);
res = PXE_PGP_CORRUPT_DATA;
***************
*** 992,998 **** parse_symenc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
--- 1106,1112 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
***************
*** 1035,1045 **** parse_symenc_mdc_data(PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
if (res < 0)
goto out;
! res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
--- 1149,1159 ----
if (res < 0)
goto out;
! res = pullf_create(&pf_mdc, &pgp_mdc_filter, ctx, pf_decrypt);
if (res < 0)
goto out;
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, pf_mdc);
if (res < 0)
goto out;
***************
*** 1139,1145 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
else
{
got_key = 1;
! res = parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
--- 1253,1259 ----
else
{
got_key = 1;
! res = pgp_parse_symenc_sesskey(ctx, pkt);
}
break;
case PGP_PKT_SYMENCRYPTED_DATA:
***************
*** 1187,1189 **** pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
--- 1301,1304 ----
return res;
}
+
*** a/contrib/pgcrypto/pgp-encrypt.c
--- b/contrib/pgcrypto/pgp-encrypt.c
***************
*** 144,149 **** static const PushFilterOps mdc_filter = {
--- 144,236 ----
mdc_init, mdc_write, mdc_flush, mdc_free
};
+ /*
+ * Signature writer filter
+ */
+
+ static int
+ sig_writer_flush(PushFilter *dst, void *priv)
+ {
+ int res;
+ int len;
+ PGP_Context *ctx = priv;
+ MBuf *buf = NULL;
+ PushFilter *pf = NULL;
+ uint8 *data = NULL;
+
+ /*
+ * Capture all the data into an mbuf so we don't have to worry about the
+ * length of the packet.
+ */
+ buf = mbuf_create(0);
+ res = pushf_create_mbuf_writer(&pf, buf);
+ if (res < 0)
+ goto err;
+
+ res = pgp_write_signature(ctx, pf);
+ if (res < 0)
+ goto err;
+
+ len = mbuf_grab(buf, mbuf_avail(buf), &data);
+ res = write_normal_header(dst, PGP_PKT_SIGNATURE, len);
+ if (res < 0)
+ goto err;
+
+ res = pushf_write(dst, data, len);
+
+ err:
+ if (pf)
+ pushf_free(pf);
+ if (buf)
+ mbuf_free(buf);
+ return res;
+ }
+
+ static const PushFilterOps sig_writer_filter = {
+ NULL, NULL, sig_writer_flush, NULL
+ };
+
+
+ /*
+ * Signature computation filter
+ *
+ * This filter only computes the literal data packet's contents into
+ * ctx->sig_digest_ctx. No signature is written (since we wouldn't be able to
+ * write it into the correct place in the flush callback).
+ */
+
+ static int
+ sig_compute_init(PushFilter *dst, void *init_arg, void **priv_p)
+ {
+ int res;
+ PGP_Context *ctx = init_arg;
+
+ /*
+ * Load the digest into sig_digest_ctx for everyone to use. It'll also be
+ * freed in pgp_sig_free, not when this filter is done.
+ */
+ res = pgp_load_digest(ctx->digest_algo, &ctx->sig_digest_ctx);
+ if (res < 0)
+ return res;
+
+ *priv_p = ctx->sig_digest_ctx;
+ return 0;
+ }
+
+ static int
+ sig_compute_write(PushFilter *dst, void *priv, const uint8 *data, int len)
+ {
+ PX_MD *md = priv;
+
+ px_md_update(md, data, len);
+ return pushf_write(dst, data, len);
+ }
+
+ static const PushFilterOps sig_compute_filter = {
+ sig_compute_init, sig_compute_write, NULL, NULL
+ };
+
+
/*
* Encrypted pkt writer
***************
*** 495,500 **** write_prefix(PGP_Context *ctx, PushFilter *dst)
--- 582,628 ----
}
/*
+ * Initializes one-pass signature state and writes the one-pass signature
+ * packet. The packet contains enough information for the reader to decrypt
+ * and verify the signature in a single pass over the encrypted data.
+ */
+ static int
+ init_onepass_signature(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ uint8 hdr[4];
+ uint8 ver = 3;
+ uint8 last = 1;
+
+ res = write_normal_header(dst, PGP_PKT_ONEPASS_SIGNATURE, 4 + 8 + 1);
+ if (res < 0)
+ return res;
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = ctx->digest_algo;
+ hdr[3] = ctx->sig_key->algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+
+ res = pushf_write(dst, ctx->sig_key->key_id, 8);
+ if (res < 0)
+ return res;
+ /* we only support one signature per message */
+ res = pushf_write(dst, &last, 1);
+ if (res < 0)
+ return res;
+ return pushf_create(pf_res, &sig_writer_filter, ctx, dst);
+ }
+
+
+ /*
* write symmetrically encrypted session key packet
*/
***************
*** 678,689 **** pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
--- 806,837 ----
pf = pf_tmp;
}
+ /* one-pass signature signature */
+ if (ctx->sig_key)
+ {
+ res = init_onepass_signature(&pf_tmp, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
+
/* data streamer */
res = init_litdata_packet(&pf_tmp, ctx, pf);
if (res < 0)
goto out;
pf = pf_tmp;
+ /*
+ * If we're writing a signature, also add the signature computation filter
+ * right after the text mode canonicalization.
+ */
+ if (ctx->sig_key)
+ {
+ res = pushf_create(&pf_tmp, &sig_compute_filter, ctx, pf);
+ if (res < 0)
+ goto out;
+ pf = pf_tmp;
+ }
/* text conversion? */
if (ctx->text_mode && ctx->convert_crlf)
*** a/contrib/pgcrypto/pgp-info.c
--- b/contrib/pgcrypto/pgp-info.c
***************
*** 49,65 **** read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
if (res < 0)
goto err;
- /* is it encryption key */
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = 0;
}
err:
--- 49,66 ----
if (res < 0)
goto err;
switch (pk->algo)
{
case PGP_PUB_ELG_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT:
case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_DSA_SIGN:
memcpy(keyid_buf, pk->key_id, 8);
res = 1;
break;
default:
! res = PXE_PGP_UNSUPPORTED_PUBALGO;
}
err:
***************
*** 102,115 **** print_key(uint8 *keyid, char *dst)
return 8 * 2;
}
! static const uint8 any_key[] =
! {0, 0, 0, 0, 0, 0, 0, 0};
/*
! * dst should have room for 17 bytes
*/
! int
! pgp_get_keyid(MBuf *pgp_data, char *dst)
{
int res;
PullFilter *src;
--- 103,333 ----
return 8 * 2;
}
! typedef int (*signature_cb_type)(void *opaque, PGP_Signature *sig);
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int need_mdc,
! int allow_compr);
!
!
! static int
! read_signatures_from_compressed_data(PGP_Context *ctx, PullFilter *pkt,
! void *opaque, signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! uint8 type;
! PullFilter *pf_decompr;
!
! GETBYTE(pkt, type);
!
! ctx->compress_algo = type;
! switch (type)
! {
! case PGP_COMPR_NONE:
! res = extract_signatures(ctx, pkt, opaque,
! sig_key_cb, extract_details, 0, 0);
! break;
!
! case PGP_COMPR_ZIP:
! case PGP_COMPR_ZLIB:
! res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
! if (res >= 0)
! {
! res = extract_signatures(ctx, pf_decompr, opaque,
! sig_key_cb, extract_details, 0, 0);
! pullf_free(pf_decompr);
! }
! break;
!
! case PGP_COMPR_BZIP2:
! px_debug("read_signatures_from_compressed_data: bzip2 unsupported");
! res = PXE_PGP_UNSUPPORTED_COMPR;
! break;
!
! default:
! px_debug("read_signatures_from_compressed_data: unknown compr type");
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! return res;
! }
!
! // "Context length" type packet
! #define PKT_CONTEXT 3
!
! static int
! extract_signatures(PGP_Context *ctx, PullFilter *src, void *opaque,
! signature_cb_type sig_cb,
! int extract_details,
! int need_mdc,
! int allow_compr)
! {
! int res;
! int len;
! uint8 tag;
! int done = 0;
! PullFilter *pkt = NULL;
! PGP_Signature *sig = NULL;
!
! while (1)
! {
! res = pgp_parse_pkt_hdr(src, &tag, &len, 1);
! if (res <= 0)
! break;
!
! /* context length inside SYMENC_MDC needs special handling */
! if (need_mdc && res == PKT_CONTEXT)
! res = pullf_create(&pkt, &pgp_mdcbuf_filter, ctx, src);
! else
! res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
! if (res < 0)
! break;
!
! switch (tag)
! {
! case PGP_PKT_SIGNATURE:
! res = pgp_parse_signature(ctx, &sig, pkt, NULL);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_ONEPASS_SIGNATURE:
! res = pgp_parse_onepass_signature(ctx, &sig, pkt);
! if (res >= 0)
! res = sig_cb(opaque, sig);
! break;
! case PGP_PKT_COMPRESSED_DATA:
! if (!allow_compr)
! {
! px_debug("extract_signature_keys: unexpected compression");
! res = PXE_PGP_CORRUPT_DATA;
! }
! else
! res = read_signatures_from_compressed_data(ctx, pkt, opaque,
! sig_cb, extract_details);
! /*
! * We're assuming that there will only ever be a single data
! * packet, compressed or otherwise.
! */
! if (!extract_details)
! done = 1;
! break;
! case PGP_PKT_LITERAL_DATA:
! case PGP_PKT_MDC:
! /*
! * If extract_details is not specified, we never look for
! * signatures beyond the data as the decryption code doesn't,
! * either.
! */
! if (!extract_details)
! done = 1;
! else
! res = pgp_skip_packet(pkt);
! break;
!
! case PGP_PKT_TRUST:
! res = pgp_skip_packet(pkt);
! break;
! default:
! px_debug("extract_signatures: unexpected tag %d", tag);
! res = PXE_PGP_CORRUPT_DATA;
! }
!
! if (pkt)
! pullf_free(pkt);
! pkt = NULL;
! if (sig)
! pgp_sig_free(sig);
! sig = NULL;
!
! if (res < 0 || done)
! break;
! }
!
! return res;
! }
!
/*
! * Set up everything needed to decrypt the data and extract information about
! * the signatures.
*/
! static int
! read_signatures_from_data(PGP_Context *ctx, PullFilter *pkt, int tag, void *opaque,
! signature_cb_type sig_key_cb,
! int extract_details)
! {
! int res;
! int resync;
! PGP_CFB *cfb = NULL;
! PullFilter *pf_decrypt = NULL;
! PullFilter *pf_prefix = NULL;
! PullFilter *pf_mdc = NULL;
! PullFilter *chain_head;
! int need_mdc = (tag == PGP_PKT_SYMENCRYPTED_DATA_MDC);
!
! if (need_mdc)
! {
! uint8 ver;
!
! GETBYTE(pkt, ver);
! if (ver != 1)
! {
! px_debug("read_signature_from_data: pkt ver != 1");
! return PXE_PGP_CORRUPT_DATA;
! }
! resync = 0;
! }
! else
! resync = 1;
!
! res = pgp_cfb_create(&cfb, ctx->cipher_algo,
! ctx->sess_key, ctx->sess_key_len, resync, NULL);
! if (res < 0)
! goto out;
!
! res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
! if (res < 0)
! goto out;
!
! if (need_mdc)
! {
! res = pullf_create(&pf_mdc, &pgp_mdc_filter, ctx, pf_decrypt);
! if (res < 0)
! goto out;
! chain_head = pf_mdc;
! }
! else
! chain_head = pf_decrypt;
!
! res = pullf_create(&pf_prefix, &pgp_prefix_filter, ctx, chain_head);
! if (res < 0)
! goto out;
!
! res = extract_signatures(ctx, pf_prefix, opaque, sig_key_cb, extract_details, need_mdc, 1);
!
! out:
! if (pf_prefix)
! pullf_free(pf_prefix);
! if (pf_mdc)
! pullf_free(pf_mdc);
! if (pf_decrypt)
! pullf_free(pf_decrypt);
! if (cfb)
! pgp_cfb_free(cfb);
!
! return res;
! }
!
! static int
! get_key_information(PGP_Context *ctx, MBuf *pgp_data, int want_main_key,
! void *opaque,
! int (*key_cb)(void *opaque, uint8 keyid[8]),
! signature_cb_type sig_cb,
! int extract_details)
{
int res;
PullFilter *src;
***************
*** 122,127 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 340,346 ----
int got_data = 0;
uint8 keyid_buf[8];
int got_main_key = 0;
+ PGP_Signature *sig = NULL;
res = pullf_create_mbuf_reader(&src, pgp_data);
***************
*** 141,176 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! /* main key is for signing, so ignore it */
! if (!got_main_key)
{
got_main_key = 1;
! res = pgp_skip_packet(pkt);
}
- else
- res = PXE_PGP_MULTIPLE_KEYS;
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res < 0)
! break;
! if (res > 0)
! got_pub_key++;
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /* don't skip it, just stop */
got_data = 1;
break;
- case PGP_PKT_SYMENCRYPTED_SESSKEY:
- got_symenc_key++;
- /* fallthru */
case PGP_PKT_SIGNATURE:
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
--- 360,416 ----
{
case PGP_PKT_SECRET_KEY:
case PGP_PKT_PUBLIC_KEY:
! if (got_main_key)
! res = PXE_PGP_MULTIPLE_KEYS;
! else
{
got_main_key = 1;
! if (want_main_key)
! res = read_pubkey_keyid(pkt, keyid_buf);
! else
! res = pgp_skip_packet(pkt);
}
break;
case PGP_PKT_SECRET_SUBKEY:
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_main_key)
! res = pgp_skip_packet(pkt);
! else
! {
! res = read_pubkey_keyid(pkt, keyid_buf);
! if (res > 0)
! got_pub_key++;
! }
! break;
! case PGP_PKT_SYMENCRYPTED_SESSKEY:
! got_symenc_key++;
! if (sig_cb)
! res = pgp_parse_symenc_sesskey(ctx, pkt);
! else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBENCRYPTED_SESSKEY:
got_pubenc_key++;
! if (sig_cb)
! res = pgp_parse_pubenc_sesskey(ctx, pkt);
! else
! res = read_pubenc_keyid(pkt, keyid_buf);
break;
case PGP_PKT_SYMENCRYPTED_DATA:
case PGP_PKT_SYMENCRYPTED_DATA_MDC:
! /*
! * If there's a key callback, read all the keys from the
! * encrypted data. Otherwise we're done.
! */
got_data = 1;
+ if (sig_cb)
+ res = read_signatures_from_data(ctx, pkt, tag, opaque, sig_cb, extract_details);
break;
case PGP_PKT_SIGNATURE:
+ /*
+ * We ignore signatures not part of the encrypted data since we
+ * won't use them anyway.
+ */
case PGP_PKT_MARKER:
case PGP_PKT_TRUST:
case PGP_PKT_USER_ID:
***************
*** 185,190 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
--- 425,433 ----
if (pkt)
pullf_free(pkt);
pkt = NULL;
+ if (sig)
+ pgp_sig_free(sig);
+ sig = NULL;
if (res < 0 || got_data)
break;
***************
*** 210,235 **** pgp_get_keyid(MBuf *pgp_data, char *dst)
/*
* if still ok, look what we got
*/
! if (res >= 0)
{
! if (got_pubenc_key || got_pub_key)
{
! if (memcmp(keyid_buf, any_key, 8) == 0)
! {
! memcpy(dst, "ANYKEY", 7);
! res = 6;
! }
else
! res = print_key(keyid_buf, dst);
}
! else if (got_symenc_key)
{
! memcpy(dst, "SYMKEY", 7);
! res = 6;
}
- else
- res = PXE_PGP_NO_USABLE_KEY;
}
return res;
}
--- 453,558 ----
/*
* if still ok, look what we got
*/
! if (res < 0)
! return res;
!
! if (key_cb)
{
! if (want_main_key)
{
! if (got_main_key)
! res = key_cb(opaque, keyid_buf);
else
! res = PXE_PGP_NO_SIGN_KEY;
}
! else
{
! if (got_pubenc_key || got_pub_key)
! res = key_cb(opaque, keyid_buf);
! else if (got_symenc_key)
! res = key_cb(opaque, NULL);
! else
! res = PXE_PGP_NO_USABLE_KEY;
}
}
return res;
}
+
+ static const uint8 any_key[] =
+ {0, 0, 0, 0, 0, 0, 0, 0};
+
+ static int
+ get_keyid_cb(void *opaque, uint8 keyid[8])
+ {
+ char *dst = (char *) opaque;
+ if (keyid == NULL)
+ {
+ memcpy(dst, "SYMKEY", 7);
+ return 6;
+ }
+ else if (memcmp(keyid, any_key, 8) == 0)
+ {
+ memcpy(dst, "ANYKEY", 7);
+ return 6;
+ }
+ else
+ return print_key(keyid, dst);
+ }
+
+ /*
+ * dst should have room for 17 bytes
+ */
+ int
+ pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst)
+ {
+ return get_key_information(NULL, pgp_data, want_main_key, dst, get_keyid_cb, NULL, 0);
+ }
+
+ struct GetSignatureInfoCtx
+ {
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid);
+ void *opaque;
+ int extract_details;
+ };
+
+ static int
+ get_signature_info_cb(void *opaque, PGP_Signature *sig)
+ {
+ char keyid[17];
+ struct GetSignatureInfoCtx *ctx = opaque;
+
+ /* ignore signatures not used for literal data */
+ if (sig->type != PGP_SIGTYP_BINARY &&
+ sig->type != PGP_SIGTYP_TEXT)
+ return 0;
+
+ /*
+ * Also skip one-pass signatures if we're extracting details; there should
+ * be a corresponding signature packet after the data with all the details.
+ */
+ if (sig->onepass && ctx->extract_details)
+ return 0;
+
+ if (memcmp(sig->keyid, any_key, 8) == 0)
+ memcpy(keyid, "ANYKEY", 7);
+ else
+ print_key(sig->keyid, keyid);
+ return ctx->cb(ctx->opaque, sig, keyid);
+ }
+
+ int
+ pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
+ int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
+ int extract_details)
+ {
+ struct GetSignatureInfoCtx cbctx;
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.cb = cb;
+ cbctx.opaque = opaque;
+ cbctx.extract_details = extract_details;
+ return get_key_information(ctx, pgp_data, 0, &cbctx, NULL,
+ get_signature_info_cb, extract_details);
+ }
+
*** a/contrib/pgcrypto/pgp-pgsql.c
--- b/contrib/pgcrypto/pgp-pgsql.c
***************
*** 34,42 ****
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
- #include "utils/builtins.h"
#include "utils/array.h"
#include "funcapi.h"
#include "mbuf.h"
#include "px.h"
--- 34,44 ----
#include "lib/stringinfo.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
#include "utils/array.h"
+ #include "utils/builtins.h"
+ #include "utils/timestamp.h"
#include "funcapi.h"
+ #include "miscadmin.h"
#include "mbuf.h"
#include "px.h"
***************
*** 47,61 ****
--- 49,74 ----
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_sym_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_encrypt_sign_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_bytea);
+ PG_FUNCTION_INFO_V1(pgp_pub_decrypt_verify_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_main_key_id_w);
+ PG_FUNCTION_INFO_V1(pgp_sym_signatures_w);
+ PG_FUNCTION_INFO_V1(pgp_pub_signatures_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
***************
*** 180,185 **** struct debug_expect
--- 193,199 ----
int debug;
int expect;
int cipher_algo;
+ int digest_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
***************
*** 195,200 **** fill_expect(struct debug_expect * ex, int text_mode)
--- 209,215 ----
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
+ ex->digest_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
***************
*** 217,222 **** static void
--- 232,238 ----
check_expect(PGP_Context *ctx, struct debug_expect * ex)
{
EX_CHECK(cipher_algo);
+ EX_CHECK(digest_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
***************
*** 241,246 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 257,264 ----
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
+ else if (strcmp(key, "digest-algo") == 0)
+ res = pgp_set_digest_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
***************
*** 267,272 **** set_arg(PGP_Context *ctx, char *key, char *val,
--- 285,295 ----
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
}
+ else if (ex != NULL && strcmp(key, "expect-digest-algo") == 0)
+ {
+ ex->expect = 1;
+ ex->digest_algo = pgp_get_digest_code(val);
+ }
else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
{
ex->expect = 1;
***************
*** 432,438 **** init_work(PGP_Context **ctx_p, int is_text,
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *args)
{
MBuf *src,
*dst;
--- 455,462 ----
static bytea *
encrypt_internal(int is_pubenc, int is_text,
! text *data, text *key, text *sigkey,
! text *keypsw, text *args)
{
MBuf *src,
*dst;
***************
*** 477,498 **** encrypt_internal(int is_pubenc, int is_text,
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
! if (err >= 0)
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
--- 501,546 ----
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
! NULL, 0, 0, 1);
mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ uint8 *psw = NULL;
+ int psw_len = 0;
+ MBuf *kbuf;
+
+ if (keypsw)
+ {
+ psw = (uint8 *) VARDATA(keypsw);
+ psw_len = VARSIZE(keypsw) - VARHDRSZ;
+ }
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, psw, psw_len, 1, 0);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
/*
* encrypt
*/
! err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
+ out:
if (err)
{
if (ex.debug)
***************
*** 525,531 **** encrypt_internal(int is_pubenc, int is_text,
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
--- 573,579 ----
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
! text *key, text *sigkey, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
***************
*** 565,589 **** decrypt_internal(int is_pubenc, int need_text, text *data,
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
- /*
- * decrypt
- */
- if (err >= 0)
- err = pgp_decrypt(ctx, src, dst);
/*
! * failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
--- 613,659 ----
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
! err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1, 1);
mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
}
else
+ {
err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ if (sigkey)
+ {
+ MBuf *kbuf;
+
+ kbuf = create_mbuf_from_vardata(sigkey);
+ err = pgp_set_sigkey(ctx, kbuf, NULL, 0, 0, 0);
+ mbuf_free(kbuf);
+
+ if (err < 0)
+ goto out;
+ }
/*
! * decrypt
*/
+ err = pgp_decrypt(ctx, src, dst);
if (err < 0)
goto out;
+ if (ctx->sig_key)
+ {
+ err = pgp_verify_signature(ctx);
+ if (err < 0)
+ goto out;
+ }
+
if (ex.expect)
check_expect(ctx, &ex);
***************
*** 633,638 **** out:
--- 703,855 ----
return res;
}
+ struct MaterializeSignatureCtx
+ {
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+ };
+
+ static int
+ materialize_signature_cb(void *opaque, PGP_Signature *sig, char *keyid)
+ {
+ struct MaterializeSignatureCtx *ctx = opaque;
+ const char *digestalgo;
+ const char *pubkeyalgo;
+ Datum values[4];
+ bool isnull[4] = { false, false, false, true };
+
+ digestalgo = pgp_get_digest_name(sig->digest_algo);
+ if (!digestalgo)
+ return PXE_PGP_UNSUPPORTED_HASH;
+
+ switch (sig->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ pubkeyalgo = "rsa";
+ break;
+ case PGP_PUB_DSA_SIGN:
+ pubkeyalgo = "dsa";
+ break;
+ default:
+ return PXE_PGP_UNSUPPORTED_PUBALGO;
+ }
+
+ values[0] = CStringGetTextDatum(keyid);
+ values[1] = CStringGetTextDatum(digestalgo);
+ values[2] = CStringGetTextDatum(pubkeyalgo);
+ /*
+ * If this isn't a one-pass signature, we also know the creation time of
+ * the signature.
+ */
+ if (!sig->onepass)
+ {
+ isnull[3] = false;
+ values[3] = time_t_to_timestamptz((pg_time_t) sig->creation_time);
+ }
+ tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, isnull);
+ return 0;
+ }
+
+ static int
+ materialize_signatures(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, Tuplestorestate *tupstore, TupleDesc tupdesc,
+ int extract_details)
+ {
+ PGP_Context *ctx = NULL;
+ MBuf *src = NULL;
+ int err;
+ struct debug_expect ex;
+ struct MaterializeSignatureCtx cbctx;
+
+ init_work(&ctx, 0, arg, &ex);
+ if (is_pubenc)
+ {
+ MBuf *kbuf = create_mbuf_from_vardata(key);
+
+ err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 1, 1);
+ mbuf_free(kbuf);
+ if (err < 0)
+ goto out;
+ }
+ else
+ {
+ err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
+ VARSIZE(key) - VARHDRSZ);
+ if (err < 0)
+ goto out;
+ }
+
+ memset(&cbctx, 0, sizeof(cbctx));
+ cbctx.tupstore = tupstore;
+ cbctx.tupdesc = tupdesc;
+
+ src = create_mbuf_from_vardata(data);
+ err = pgp_get_signatures(ctx, src, &cbctx, materialize_signature_cb,
+ extract_details);
+
+ out:
+ if (src)
+ mbuf_free(src);
+ if (ctx)
+ pgp_free(ctx);
+ if (err < 0)
+ {
+ if (ex.debug)
+ px_set_debug_handler(NULL);
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+ return 0;
+ }
+
+ static int
+ extract_signatures_internal(int is_pubenc, text *data, text *key, text *keypsw,
+ text *arg, ReturnSetInfo *rsinfo, int extract_details)
+ {
+ MemoryContext oldcxt;
+ int res;
+ Tuplestorestate *tupstore;
+ TupleDesc tupdesc;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* switch to long-lived memory context */
+ oldcxt = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
+
+ /* get the requested return tuple description */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ if (tupdesc->natts != 4)
+ elog(ERROR, "unexpected natts %d", tupdesc->natts);
+
+ tupstore =
+ tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+
+ res = materialize_signatures(is_pubenc, data, key, keypsw,
+ arg, tupstore, tupdesc, extract_details);
+ if (res < 0)
+ return PXE_BUG;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return 0;
+ }
+
/*
* Wrappers for symmetric-key functions
*/
***************
*** 649,655 **** pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 866,872 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 671,677 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 888,894 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 680,685 **** pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
--- 897,962 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 694,700 **** pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 971,977 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 716,722 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 993,999 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = decrypt_internal(0, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 725,730 **** pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
--- 1002,1067 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_sym_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_sym_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(0, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
/*
* Wrappers for public-key functions
*/
***************
*** 742,748 **** pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1079,1085 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 0, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 764,770 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1101,1107 ----
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
! res = encrypt_internal(1, 1, data, key, NULL, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 773,778 **** pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
--- 1110,1174 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_encrypt_sign_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_encrypt_sign_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = encrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
***************
*** 790,796 **** pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1186,1192 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 0, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 817,823 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
--- 1213,1219 ----
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
! res = decrypt_internal(1, 1, data, key, NULL, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
***************
*** 828,833 **** pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
--- 1224,1288 ----
PG_RETURN_TEXT_P(res);
}
+ Datum
+ pgp_pub_decrypt_verify_bytea(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 0, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
+
+ Datum
+ pgp_pub_decrypt_verify_text(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key,
+ *sigkey;
+ text *psw = NULL,
+ *arg = NULL;
+ text *res;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ sigkey = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ psw = PG_GETARG_BYTEA_P(3);
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ res = decrypt_internal(1, 1, data, key, sigkey, psw, arg);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ PG_FREE_IF_COPY(sigkey, 2);
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(psw, 3);
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+ PG_RETURN_TEXT_P(res);
+ }
/*
* Wrappers for PGP ascii armor
***************
*** 1070,1076 **** pgp_armor_headers(PG_FUNCTION_ARGS)
/*
! * Wrappers for PGP key id
*/
Datum
--- 1525,1531 ----
/*
! * Wrappers for PGP key ids
*/
Datum
***************
*** 1085,1091 **** pgp_key_id_w(PG_FUNCTION_ARGS)
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
--- 1540,1546 ----
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17);
! res_len = pgp_get_keyid(0, buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR,
***************
*** 1096,1098 **** pgp_key_id_w(PG_FUNCTION_ARGS)
--- 1551,1650 ----
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
+
+ Datum
+ pgp_main_key_id_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *res;
+ int res_len;
+ MBuf *buf;
+
+ data = PG_GETARG_BYTEA_P(0);
+ buf = create_mbuf_from_vardata(data);
+ res = palloc(VARHDRSZ + 17);
+
+ res_len = pgp_get_keyid(1, buf, VARDATA(res));
+ mbuf_free(buf);
+ if (res_len < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(res_len))));
+ SET_VARSIZE(res, VARHDRSZ + res_len);
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_RETURN_TEXT_P(res);
+ }
+
+
+ Datum
+ pgp_sym_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data;
+ text *psw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ psw = PG_GETARG_TEXT_P(1);
+ if (PG_NARGS() > 2)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(2));
+ if (PG_NARGS() > 3)
+ arg = PG_GETARG_BYTEA_P(3);
+
+ err = extract_signatures_internal(0, data, psw, NULL, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(psw, 1);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 3)
+ PG_FREE_IF_COPY(arg, 3);
+ return (Datum) 0;
+ }
+
+ Datum
+ pgp_pub_signatures_w(PG_FUNCTION_ARGS)
+ {
+ bytea *data,
+ *key;
+ text *keypsw = NULL,
+ *arg = NULL;
+ int err;
+ int extract_details = 0;
+
+ data = PG_GETARG_BYTEA_P(0);
+ key = PG_GETARG_BYTEA_P(1);
+ if (PG_NARGS() > 2)
+ keypsw = PG_GETARG_BYTEA_P(2);
+ if (PG_NARGS() > 3)
+ extract_details = (int) DatumGetBool(PG_GETARG_BOOL(3));
+ if (PG_NARGS() > 4)
+ arg = PG_GETARG_BYTEA_P(4);
+
+ err = extract_signatures_internal(1, data, key, keypsw, arg,
+ (ReturnSetInfo *) fcinfo->resultinfo,
+ extract_details);
+
+ if (err < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+
+ PG_FREE_IF_COPY(data, 0);
+ PG_FREE_IF_COPY(key, 1);
+ if (PG_NARGS() > 2)
+ PG_FREE_IF_COPY(keypsw, 2);
+ /* no need to free the boolean */
+ if (PG_NARGS() > 4)
+ PG_FREE_IF_COPY(arg, 4);
+
+ return (Datum) 0;
+ }
*** a/contrib/pgcrypto/pgp-pubdec.c
--- b/contrib/pgcrypto/pgp-pubdec.c
***************
*** 161,167 **** pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("no pubkey?");
return PXE_BUG;
}
--- 161,167 ----
pk = ctx->pub_key;
if (pk == NULL)
{
! px_debug("pgp_parse_pubenc_sesskey: no pubkey?");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubenc.c
--- b/contrib/pgcrypto/pgp-pubenc.c
***************
*** 202,208 **** pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
if (pk == NULL)
{
! px_debug("no pubkey?\n");
return PXE_BUG;
}
--- 202,208 ----
if (pk == NULL)
{
! px_debug("pgp_write_pubenc_sesskey: no pubkey?\n");
return PXE_BUG;
}
*** a/contrib/pgcrypto/pgp-pubkey.c
--- b/contrib/pgcrypto/pgp-pubkey.c
***************
*** 457,476 **** process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Search for encryption key.
! *
! * Error out on anything fancy.
*/
while (1)
{
--- 457,479 ----
static int
internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
! const uint8 *psw, int psw_len, int pubtype,
! int want_encrypt)
{
PullFilter *pkt = NULL;
int res;
uint8 tag;
int len;
PGP_PubKey *enc_key = NULL;
+ PGP_PubKey *sig_key = NULL;
PGP_PubKey *pk = NULL;
int got_main_key = 0;
/*
! * Find the key to use for encryption, decryption, signing or verifying
! * from src, and place it into *pk_p. An error is returned if the input
! * has multiple main keys or if asked for an encryption key and there are
! * multiple subkeys capable of encryption.
*/
while (1)
{
***************
*** 485,511 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (got_main_key)
{
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
}
- got_main_key = 1;
- res = pgp_skip_packet(pkt);
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
else
! res = _pgp_read_public_key(pkt, &pk);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
else
! res = process_secret_key(pkt, &pk, psw, psw_len);
break;
case PGP_PKT_SIGNATURE:
--- 488,541 ----
{
case PGP_PKT_PUBLIC_KEY:
case PGP_PKT_SECRET_KEY:
! if (want_encrypt)
{
! if (got_main_key)
! {
! res = PXE_PGP_MULTIPLE_KEYS;
! break;
! }
! got_main_key = 1;
! res = pgp_skip_packet(pkt);
! }
! else if (tag == PGP_PKT_PUBLIC_KEY)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
! else
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
}
break;
case PGP_PKT_PUBLIC_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 0)
! res = PXE_PGP_EXPECT_SECRET_KEY;
! else
! res = _pgp_read_public_key(pkt, &pk);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SECRET_SUBKEY:
! if (want_encrypt)
! {
! if (pubtype != 1)
! res = PXE_PGP_EXPECT_PUBLIC_KEY;
! else
! res = process_secret_key(pkt, &pk, psw, psw_len);
! }
else
! res = pgp_skip_packet(pkt);
break;
case PGP_PKT_SIGNATURE:
***************
*** 525,531 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
if (pk != NULL)
{
! if (res >= 0 && pk->can_encrypt)
{
if (enc_key == NULL)
{
--- 555,561 ----
if (pk != NULL)
{
! if (res >= 0 && want_encrypt && pk->can_encrypt)
{
if (enc_key == NULL)
{
***************
*** 535,540 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
--- 565,580 ----
else
res = PXE_PGP_MULTIPLE_SUBKEYS;
}
+ else if (res >= 0 && !want_encrypt)
+ {
+ if (sig_key == NULL)
+ {
+ sig_key = pk;
+ pk = NULL;
+ }
+ else
+ res = PXE_PGP_MULTIPLE_KEYS;
+ }
if (pk)
pgp_key_free(pk);
***************
*** 552,570 **** internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
{
if (enc_key)
pgp_key_free(enc_key);
return res;
}
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
else
! *pk_p = enc_key;
return res;
}
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype)
{
int res;
PullFilter *src;
--- 592,622 ----
{
if (enc_key)
pgp_key_free(enc_key);
+ if (sig_key)
+ pgp_key_free(sig_key);
return res;
}
! if (want_encrypt)
! {
! if (!enc_key)
! res = PXE_PGP_NO_USABLE_KEY;
! else
! *pk_p = enc_key;
! }
else
! {
! if (!sig_key)
! res = PXE_PGP_NO_SIGN_KEY;
! else
! *pk_p = sig_key;
! }
return res;
}
! static int
! set_key(MBuf *keypkt, const uint8 *key, int key_len,
! int pubtype, int encrypt, PGP_PubKey **pk_p)
{
int res;
PullFilter *src;
***************
*** 574,584 **** pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype);
pullf_free(src);
if (res >= 0)
! ctx->pub_key = pk;
! return res < 0 ? res : 0;
}
--- 626,663 ----
if (res < 0)
return res;
! res = internal_read_key(src, &pk, key, key_len, pubtype, encrypt);
pullf_free(src);
if (res >= 0)
! {
! *pk_p = pk;
! return 0;
! }
! return res;
! }
! int
! pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! int res;
!
! res = set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->sig_key);
! if (res < 0)
! return res;
! if (ctx->sig_key->algo != PGP_PUB_RSA_ENCRYPT_SIGN &&
! ctx->sig_key->algo != PGP_PUB_RSA_SIGN &&
! ctx->sig_key->algo != PGP_PUB_DSA_SIGN)
! return PXE_PGP_UNSUPPORTED_PUBALGO;
! return 0;
! }
!
! int
! pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int key_len, int pubtype,
! int encrypt)
! {
! return set_key(keypkt, key, key_len, pubtype, encrypt, &ctx->pub_key);
}
*** /dev/null
--- b/contrib/pgcrypto/pgp-sig.c
***************
*** 0 ****
--- 1,815 ----
+ /*
+ * pgp-sig.c
+ * Creating and verifying signatures.
+ *
+ * Copyright (c) 2005 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * contrib/pgcrypto/pgp-sig.c
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include <time.h>
+
+ #include "px.h"
+ #include "pgp.h"
+
+
+ #define HASHED_SUBPKT_LENGTH 8
+ #define SIGNATURE_PKT_HEADER_LENGTH 4
+
+ /*
+ * padded msg: 01 || padded bytes (FF) || 00 || msg
+ */
+ static int
+ pad_emsa_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
+ {
+ uint8 *buf;
+ int pad_len = res_len - 2 - data_len;
+
+ if (pad_len < 8)
+ return PXE_BUG;
+
+ buf = px_alloc(res_len);
+ buf[0] = 0x01;
+ memset(buf+1, 0xFF, pad_len);
+ buf[pad_len + 1] = 0x00;
+ memcpy(buf + pad_len + 2, data, data_len);
+ *res_p = buf;
+
+ return 0;
+ }
+
+ /*
+ * padded msg = 01 || PS || 00 || M
+ * PS - pad bytes (FF)
+ * M - msg
+ */
+ static uint8 *
+ check_emsa_pkcs1_v15(uint8 *data, int len)
+ {
+ uint8 *data_end = data + len;
+ uint8 *p = data;
+ int pad = 0;
+
+ if (len < 1 + 8 + 1)
+ return NULL;
+
+ if (*p++ != 1)
+ return NULL;
+
+ while (p < data_end && *p == 0xFF)
+ {
+ p++;
+ pad++;
+ }
+
+ if (p == data_end)
+ return NULL;
+ if (*p != 0)
+ return NULL;
+ if (pad < 8)
+ return NULL;
+ return p + 1;
+ }
+
+ static int
+ create_signature_vessel(PGP_Context *ctx, uint8 *data, int klen, PGP_MPI **msg_p, int full_bytes)
+ {
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+ uint8 *vessel;
+ uint8 *padded = NULL;
+ int res;
+ PGP_MPI *m = NULL;
+
+ prefix_len = pgp_get_digest_asn1_prefix(ctx->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ return prefix_len;
+
+ vessel = px_alloc(klen + prefix_len);
+
+ memcpy(vessel, asn1_prefix, prefix_len);
+ memcpy(vessel + prefix_len, data, klen);
+
+ res = pad_emsa_pkcs1_v15(vessel, klen + prefix_len, full_bytes, &padded);
+ if (res >= 0)
+ {
+ int full_bits = full_bytes * 8 - 7;
+ res = pgp_mpi_create(padded, full_bits, &m);
+ }
+ if (padded)
+ {
+ px_memset(padded, 0, full_bytes);
+ px_free(padded);
+ }
+ px_memset(vessel, 0, klen + 1);
+ px_free(vessel);
+
+ if (res >= 0)
+ *msg_p = m;
+
+ return res;
+ }
+
+ static int
+ sign_and_write_rsa(PGP_Context *ctx, uint8 *digest, int digest_len, PGP_PubKey *pk, PushFilter *pkt)
+ {
+ int res;
+ PGP_MPI *m = NULL,
+ *c = NULL;
+
+ /* create padded msg */
+ res = create_signature_vessel(ctx, digest, digest_len, &m, pk->pub.rsa.n->bytes - 1);
+ if (res < 0)
+ goto err;
+
+ /* sign it */
+ res = pgp_rsa_decrypt(pk, m, &c);
+ if (res < 0)
+ goto err;
+
+ /* write out */
+ res = pgp_mpi_write(pkt, c);
+
+ err:
+ pgp_mpi_free(m);
+ pgp_mpi_free(c);
+ return res;
+ }
+
+ static int
+ decrypt_rsa_signature(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
+ {
+ int res;
+ PGP_MPI *c;
+
+ if (pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN
+ && pk->algo != PGP_PUB_RSA_SIGN)
+ return PXE_PGP_WRONG_KEY;
+
+ /* read rsa encrypted data */
+ res = pgp_mpi_read(pkt, &c);
+ if (res < 0)
+ return res;
+
+ /* encrypted using a private key */
+ res = pgp_rsa_encrypt(pk, c, m_p);
+
+ pgp_mpi_free(c);
+ return res;
+ }
+
+
+ /*
+ * Writes both the hashed and unhashed subpackets of the signature packet into
+ * pkt, and updates md accordingly.
+ */
+ static int
+ write_signature_subpackets(PGP_Context *ctx, PX_MD *md, PushFilter *pkt)
+ {
+ uint32 t;
+ uint8 hashed[HASHED_SUBPKT_LENGTH];
+ uint8 unhashed_hdr[4];
+ int res;
+
+ /* hashed subpkt length, two octets */
+ hashed[0] = 0x00;
+ hashed[1] = 0x06;
+ /* header: length 5, type Signature Creation Time */
+ hashed[2] = 0x05;
+ hashed[3] = 2;
+ /* creation time */
+ t = (uint32) time(NULL);
+ hashed[4] = (t >> 24) & 255;
+ hashed[5] = (t >> 16) & 255;
+ hashed[6] = (t >> 8) & 255;
+ hashed[7] = t & 255;
+
+ res = pushf_write(pkt, hashed, sizeof(hashed));
+ if (res < 0)
+ return res;
+ px_md_update(md, hashed, sizeof(hashed));
+
+ /* unhashed subpackets below; not part of the signature hash */
+
+ /* length, two octets */
+ unhashed_hdr[0] = 0x00;
+ unhashed_hdr[1] = 0x0A;
+ /* length 9, type Issuer */
+ unhashed_hdr[2] = 0x09;
+ unhashed_hdr[3] = 16;
+ res = pushf_write(pkt, unhashed_hdr, sizeof(unhashed_hdr));
+ if (res < 0)
+ return res;
+ return pushf_write(pkt, ctx->sig_key->key_id, 8);
+ }
+
+ /* Hashes the signature with the v4 "final trailer" */
+ static void
+ digest_v4_final_trailer(PX_MD *md, int trailer_len)
+ {
+ uint8 b;
+
+ /* two magic octets, per spec */
+ b = 0x04;
+ px_md_update(md, &b, 1);
+ b = 0xFF;
+ px_md_update(md, &b, 1);
+
+ /* length of trailer, four octets in big endian */
+ b = (trailer_len >> 24);
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 16) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = (trailer_len >> 8) & 0xFF;
+ px_md_update(md, &b, 1);
+ b = trailer_len & 0xFF;
+ px_md_update(md, &b, 1);
+ }
+
+ int
+ pgp_write_signature(PGP_Context *ctx, PushFilter *dst)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ uint8 ver = 4;
+ uint8 digest[PGP_MAX_DIGEST];
+ int digest_len;
+ uint8 hdr[SIGNATURE_PKT_HEADER_LENGTH];
+
+ if (pk == NULL)
+ {
+ px_debug("no private key?\n");
+ return PXE_BUG;
+ }
+ else if (ctx->sig_digest_ctx == NULL)
+ {
+ px_debug("no sig ctx?\n");
+ return PXE_BUG;
+ }
+
+ hdr[0] = ver;
+
+ if (ctx->text_mode && ctx->convert_crlf)
+ hdr[1] = PGP_SIGTYP_TEXT;
+ else
+ hdr[1] = PGP_SIGTYP_BINARY;
+
+ hdr[2] = pk->algo;
+ hdr[3] = ctx->digest_algo;
+ res = pushf_write(dst, hdr, sizeof(hdr));
+ if (res < 0)
+ return res;
+ px_md_update(ctx->sig_digest_ctx, hdr, sizeof(hdr));
+
+ res = write_signature_subpackets(ctx, ctx->sig_digest_ctx, dst);
+ if (res < 0)
+ return res;
+
+ digest_v4_final_trailer(ctx->sig_digest_ctx,
+ SIGNATURE_PKT_HEADER_LENGTH + HASHED_SUBPKT_LENGTH);
+
+ px_md_finish(ctx->sig_digest_ctx, digest);
+ digest_len = px_md_result_size(ctx->sig_digest_ctx);
+
+ /* write out the first two bytes of the digest */
+ res = pushf_write(dst, digest, 2);
+ if (res < 0)
+ return res;
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ case PGP_PUB_RSA_SIGN:
+ res = sign_and_write_rsa(ctx, digest, digest_len, pk, dst);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+
+ return res;
+ }
+
+
+ /*
+ * Parses a one, two or five-octet length from a packet. Partial Body Lengths
+ * are not supported. Returns 0 if EOF was reached when trying to read the
+ * first byte, 1 if the length was read successfully, or < 0 if something went
+ * wrong.
+ */
+ static int
+ parse_packet_len(PullFilter *src, int *len_p)
+ {
+ uint8 b;
+ uint8 *tmpbuf;
+ int len;
+ int res;
+
+ res = pullf_read(src, 1, &tmpbuf);
+ if (res <= 0)
+ return res;
+ b = *tmpbuf;
+ if (b <= 191)
+ len = b;
+ else if (b >= 192 && b < 255)
+ {
+ len = ((unsigned) (b) - 192) << 8;
+ GETBYTE(src, b);
+ len += 192 + b;
+ }
+ else
+ {
+ /* b == 255 */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+ }
+
+ *len_p = len;
+ return 1;
+ }
+
+ struct SigSubPktParserState {
+ bool hashed_done;
+ bool done;
+ int lr_len;
+ PullFilter *lr;
+ PullFilter *hashed_src;
+ PullFilter *unhashed_src;
+ };
+
+ struct SigSubPkt {
+ int len;
+ int type;
+ bool hashed;
+ PullFilter *body;
+ };
+
+ static int
+ start_section(struct SigSubPktParserState *pstate, bool hashed)
+ {
+ int res;
+ int len;
+ PullFilter *src;
+ uint8 b;
+
+ if (hashed)
+ src = pstate->hashed_src;
+ else
+ src = pstate->unhashed_src;
+
+ /* read the length of the section; two-octet big endian */
+ GETBYTE(src, b);
+ len = b;
+ GETBYTE(src, b);
+ len = (len << 8) | b;
+
+ /* hashed section MUST be present */
+ if (hashed && len == 0)
+ return PXE_PGP_CORRUPT_DATA;
+ pstate->lr_len = len;
+ res = pullf_create_limited_reader(&pstate->lr, src, &pstate->lr_len);
+ if (res < 0)
+ return res;
+ return 0;
+ }
+
+ /*
+ * Initializes a parser for parsing the subpackets in a version 4 signature
+ * packet. hashed_src is used for parsing the hashed subpackets, and
+ * unhashed_src is used for reading the unhashed ones. Returns < 0 on failure.
+ * The caller never has to worry about releasing the parse state.
+ */
+ static int
+ init_sigsubpkt_parser(PullFilter *hashed_src, PullFilter *unhashed_src, struct SigSubPktParserState *pstate)
+ {
+ pstate->hashed_done = false;
+ pstate->done = false;
+ pstate->lr = NULL;
+ pstate->hashed_src = hashed_src;
+ pstate->unhashed_src = unhashed_src;
+
+ return start_section(pstate, true);
+ }
+
+ /*
+ * Releases any memory allocated by the signature subpacket parser. You only
+ * need to call this function if you want to stop reading before you've reached
+ * the last subpacket.
+ */
+ static void
+ destroy_sigsubpkt_parser(struct SigSubPktParserState *pstate)
+ {
+ if (pstate->lr)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ }
+ }
+
+ /*
+ * Reads the next subpacket's header from state to subpkt. Returns 1 if a
+ * packet was read, 0 if all subpackets have been successfully read from the
+ * signature packet, or < 0 on error.
+ */
+ static int
+ sigsubpkt_parser_next(struct SigSubPktParserState *pstate, struct SigSubPkt *subpkt)
+ {
+ uint8 typ;
+ int len;
+ int res;
+
+ if (pstate->done || pstate->lr == NULL)
+ return PXE_BUG;
+
+ again:
+ res = parse_packet_len(pstate->lr, &len);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ {
+ /* no more subpackets in this section */
+
+ if (pstate->hashed_done)
+ {
+ pstate->done = true;
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return 0;
+ }
+ pstate->hashed_done = true;
+ res = start_section(pstate, false);
+ if (res < 0)
+ goto err;
+ else
+ {
+ /* start again from the first packet of the unhashed section */
+ goto again;
+ }
+ }
+
+ res = pullf_read_fixed(pstate->lr, 1, &typ);
+ if (res < 0)
+ goto err;
+ len--;
+
+ /* done; let the caller read the data */
+ subpkt->len = len;
+ subpkt->type = typ;
+ subpkt->hashed = !pstate->hashed_done;
+ subpkt->body = pstate->lr;
+
+ err:
+ if (res < 0)
+ {
+ pullf_free(pstate->lr);
+ pstate->lr = NULL;
+ return res;
+ }
+ return 1;
+ }
+
+ static int
+ parse_v3_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ uint8 len;
+ uint32 creation_time;
+
+ /* one-octet length, must be 5 */
+ res = pullf_read_fixed(pkt, 1, &len);
+ if (res < 0)
+ return res;
+ if (len != 5)
+ return PXE_PGP_CORRUPT_DATA;
+
+ res = pullf_read_fixed(pkt, 1, &sig->type);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ return res;
+ sig->creation_time = ntohl(creation_time);
+ res = pullf_read_fixed(pkt, 8, sig->keyid);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->algo);
+ if (res < 0)
+ return res;
+ res = pullf_read_fixed(pkt, 1, &sig->digest_algo);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ if (res >= 0)
+ {
+ /* write trailer */
+ mbuf_append(sig->trailer, &sig->type, 1);
+ mbuf_append(sig->trailer, (uint8 *) &creation_time, 4);
+ }
+
+ return res;
+ }
+
+ static int
+ parse_v4_signature_header(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ struct SigSubPktParserState pstate;
+ int res;
+ bool found_creation_time = false;
+ bool found_issuer = false;
+ PullFilter *tr = NULL;
+ uint32 creation_time;
+
+ /*
+ * In a V4 header, we need to store everything up to the end of the hashed
+ * subpackets for the hash trailer.
+ */
+ mbuf_append(sig->trailer, &sig->version, 1);
+ res = pullf_create_tee_reader(&tr, pkt, sig->trailer);
+ if (res < 0)
+ return res;
+
+ res = pullf_read_fixed(tr, 1, &sig->type);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->algo);
+ if (res < 0)
+ goto err;
+ res = pullf_read_fixed(tr, 1, &sig->digest_algo);
+ if (res < 0)
+ goto err;
+
+ res = init_sigsubpkt_parser(tr, pkt, &pstate);
+ if (res < 0)
+ goto err;
+
+ while (1)
+ {
+ struct SigSubPkt subpkt;
+
+ res = sigsubpkt_parser_next(&pstate, &subpkt);
+ if (res < 0)
+ goto err;
+ else if (res == 0)
+ break;
+
+ if (subpkt.hashed && subpkt.type == PGP_SIGNATURE_CREATION_TIME)
+ {
+ if (found_creation_time || subpkt.len != 4)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_creation_time = true;
+ res = pullf_read_fixed(subpkt.body, 4, (uint8 *) &creation_time);
+ if (res < 0)
+ goto err;
+ sig->creation_time = ntohl(creation_time);
+ }
+ else if (subpkt.type == PGP_ISSUER_ID)
+ {
+ if (found_issuer || subpkt.len != 8)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+ found_issuer = true;
+ res = pullf_read_fixed(subpkt.body, 8, sig->keyid);
+ if (res < 0)
+ goto err;
+ }
+ else
+ {
+ /* unknown subpacket; skip over the data */
+ res = pullf_discard(subpkt.body, subpkt.len);
+ if (res < 0)
+ goto err;
+ }
+ }
+
+ if (!found_creation_time)
+ {
+ res = PXE_PGP_CORRUPT_DATA;
+ goto err;
+ }
+
+ res = pullf_read_fixed(pkt, 2, sig->expected_digest_l16);
+
+ err:
+ destroy_sigsubpkt_parser(&pstate);
+ if (tr)
+ pullf_free(tr);
+ if (res < 0)
+ return res;
+
+ return 0;
+ }
+
+
+ static int
+ parse_signature_payload(PGP_Context *ctx, PullFilter *pkt, PGP_Signature *sig)
+ {
+ int res;
+ PGP_PubKey *pk = ctx->sig_key;
+ PGP_MPI *m;
+ uint8 *msg;
+ int msglen;
+ uint8 asn1_prefix[PGP_MAX_DIGEST_ASN1_PREFIX];
+ int prefix_len;
+
+ if (pk == NULL)
+ {
+ px_debug("parse_signature_payload: no pubkey?");
+ return PXE_BUG;
+ }
+
+ switch (pk->algo)
+ {
+ case PGP_PUB_RSA_SIGN:
+ case PGP_PUB_RSA_ENCRYPT_SIGN:
+ res = decrypt_rsa_signature(pk, pkt, &m);
+ break;
+ default:
+ /* only RSA is currently supported */
+ res = PXE_PGP_UNKNOWN_PUBALGO;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * extract message
+ */
+ msg = check_emsa_pkcs1_v15(m->data, m->bytes);
+ if (msg == NULL)
+ {
+ px_debug("check_emsa_pkcs1_v15 failed");
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen = m->bytes - (msg - m->data);
+
+ prefix_len = pgp_get_digest_asn1_prefix(sig->digest_algo, asn1_prefix);
+ if (prefix_len < 0)
+ {
+ px_debug("digest algo %d does not have an ASN1 prefix", sig->digest_algo);
+ res = PXE_PGP_UNSUPPORTED_HASH;
+ goto out;
+ }
+ if (msglen < prefix_len ||
+ memcmp(msg, asn1_prefix, prefix_len) != 0)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ msglen -= prefix_len;
+ if (msglen > PGP_MAX_DIGEST)
+ {
+ res = PXE_PGP_WRONG_KEY;
+ goto out;
+ }
+ memcpy(sig->expected_digest, msg + prefix_len, msglen);
+
+ out:
+ pgp_mpi_free(m);
+ if (res < 0)
+ return res;
+ return pgp_expect_packet_end(pkt);
+ }
+
+ int
+ pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt)
+ {
+ PGP_Signature *sig;
+ uint8 version;
+ uint8 type;
+ uint8 digestalgo;
+ uint8 pubkeyalgo;
+ uint8 last;
+ uint8 keyid[8];
+ int res;
+
+ GETBYTE(pkt, version);
+ GETBYTE(pkt, type);
+ GETBYTE(pkt, digestalgo);
+ GETBYTE(pkt, pubkeyalgo);
+ res = pullf_read_fixed(pkt, 8, keyid);
+ if (res < 0)
+ return res;
+ GETBYTE(pkt, last);
+ (void) last;
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ return res;
+
+ sig->onepass = 1;
+ memcpy(sig->keyid, keyid, 8);
+ sig->version = version;
+ sig->type = type;
+ sig->digest_algo = digestalgo;
+ sig->algo = pubkeyalgo;
+ *sig_p = sig;
+ return 0;
+ }
+
+ int
+ pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p, PullFilter *pkt, uint8 *expected_keyid)
+ {
+ int version;
+ int res;
+ PGP_Signature *sig;
+
+ GETBYTE(pkt, version);
+
+ res = pgp_sig_create(&sig);
+ if (res < 0)
+ goto err;
+ sig->onepass = 0;
+ sig->version = version;
+ if (version == 3)
+ res = parse_v3_signature_header(ctx, pkt, sig);
+ else if (version == 4)
+ res = parse_v4_signature_header(ctx, pkt, sig);
+ else
+ {
+ px_debug("unexpected signature version %d", version);
+ res = PXE_PGP_CORRUPT_DATA;
+ }
+
+ if (res < 0)
+ goto err;
+
+ if (expected_keyid &&
+ memcmp(expected_keyid, sig->keyid, 8) == 0)
+ res = parse_signature_payload(ctx, pkt, sig);
+ else
+ res = pullf_discard(pkt, -1);
+
+ err:
+ if (res < 0)
+ pgp_sig_free(sig);
+ else
+ *sig_p = sig;
+ return res;
+ }
+
+
+ int
+ pgp_verify_signature(PGP_Context *ctx)
+ {
+ int len;
+ uint8 *trailer;
+ uint8 digest[PGP_MAX_DIGEST];
+ PX_MD *md = ctx->sig_digest_ctx;
+ PGP_Signature *sig = ctx->sig_expected;
+
+ if (!md)
+ return PXE_BUG;
+ if (!sig)
+ return PXE_PGP_NO_SIGNATURE;
+ if (sig->version != 3 && sig->version != 4)
+ return PXE_BUG;
+
+ len = mbuf_grab(sig->trailer, mbuf_avail(sig->trailer), &trailer);
+ px_md_update(md, trailer, len);
+ if (sig->version == 4)
+ digest_v4_final_trailer(md, len);
+ px_md_finish(md, digest);
+
+ if (memcmp(digest, sig->expected_digest, px_md_result_size(md)) != 0)
+ return PXE_PGP_INVALID_SIGNATURE;
+
+ return 0;
+ }
+
*** a/contrib/pgcrypto/pgp.c
--- b/contrib/pgcrypto/pgp.c
***************
*** 38,43 ****
--- 38,44 ----
* Defaults.
*/
static int def_cipher_algo = PGP_SYM_AES_128;
+ static int def_digest_algo = PGP_DIGEST_SHA512;
static int def_s2k_cipher_algo = -1;
static int def_s2k_mode = PGP_S2K_ISALTED;
static int def_s2k_digest_algo = PGP_DIGEST_SHA1;
***************
*** 144,149 **** pgp_get_cipher_name(int code)
--- 145,208 ----
}
int
+ pgp_get_digest_asn1_prefix(int code, uint8 *data)
+ {
+ int len;
+
+ uint8 md5_prefix[18] =
+ {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10};
+ uint8 ripemd160_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha1_prefix[15] =
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E,
+ 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
+ uint8 sha256_prefix[19] =
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20};
+ uint8 sha384_prefix[19] =
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30};
+ uint8 sha512_prefix[19] =
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40};
+
+ switch (code)
+ {
+ case PGP_DIGEST_MD5:
+ len = sizeof(md5_prefix);
+ memcpy(data, md5_prefix, len);
+ return len;
+ case PGP_DIGEST_RIPEMD160:
+ len = sizeof(ripemd160_prefix);
+ memcpy(data, ripemd160_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA1:
+ len = sizeof(sha1_prefix);
+ memcpy(data, sha1_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA256:
+ len = sizeof(sha256_prefix);
+ memcpy(data, sha256_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA384:
+ len = sizeof(sha384_prefix);
+ memcpy(data, sha384_prefix, len);
+ return len;
+ case PGP_DIGEST_SHA512:
+ len = sizeof(sha512_prefix);
+ memcpy(data, sha512_prefix, len);
+ return len;
+ }
+ return PXE_PGP_UNSUPPORTED_HASH;
+ }
+
+ int
pgp_get_cipher_key_size(int code)
{
const struct cipher_info *i = get_cipher_info(code);
***************
*** 204,209 **** pgp_init(PGP_Context **ctx_p)
--- 263,269 ----
memset(ctx, 0, sizeof *ctx);
ctx->cipher_algo = def_cipher_algo;
+ ctx->digest_algo = def_digest_algo;
ctx->s2k_cipher_algo = def_s2k_cipher_algo;
ctx->s2k_mode = def_s2k_mode;
ctx->s2k_digest_algo = def_s2k_digest_algo;
***************
*** 224,235 **** pgp_free(PGP_Context *ctx)
--- 284,325 ----
{
if (ctx->pub_key)
pgp_key_free(ctx->pub_key);
+ if (ctx->sig_key)
+ pgp_key_free(ctx->sig_key);
+ if (ctx->sig_onepass)
+ pgp_sig_free(ctx->sig_onepass);
+ if (ctx->sig_expected)
+ pgp_sig_free(ctx->sig_expected);
+ if (ctx->sig_digest_ctx)
+ px_md_free(ctx->sig_digest_ctx);
px_memset(ctx, 0, sizeof *ctx);
px_free(ctx);
return 0;
}
int
+ pgp_sig_create(PGP_Signature **sig_p)
+ {
+ PGP_Signature *sig;
+
+ sig = px_alloc(sizeof(PGP_Signature));
+ memset(sig, 0, sizeof(*sig));
+ sig->trailer = mbuf_create(256);
+ *sig_p = sig;
+ return 1;
+ }
+
+ int
+ pgp_sig_free(PGP_Signature *sig)
+ {
+ if (sig->trailer)
+ mbuf_free(sig->trailer);
+ px_memset(sig, 0, sizeof(*sig));
+ px_free(sig);
+ return 1;
+ }
+
+ int
pgp_disable_mdc(PGP_Context *ctx, int disable)
{
ctx->disable_mdc = disable ? 1 : 0;
***************
*** 314,319 **** pgp_set_cipher_algo(PGP_Context *ctx, const char *name)
--- 404,420 ----
}
int
+ pgp_set_digest_algo(PGP_Context *ctx, const char *name)
+ {
+ int code = pgp_get_digest_code(name);
+
+ if (code < 0)
+ return code;
+ ctx->digest_algo = code;
+ return 0;
+ }
+
+ int
pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name)
{
int code = pgp_get_cipher_code(name);
*** a/contrib/pgcrypto/pgp.h
--- b/contrib/pgcrypto/pgp.h
***************
*** 47,52 **** enum PGP_PKT_TYPE
--- 47,53 ----
PGP_PKT_PUBENCRYPTED_SESSKEY = 1,
PGP_PKT_SIGNATURE = 2,
PGP_PKT_SYMENCRYPTED_SESSKEY = 3,
+ PGP_PKT_ONEPASS_SIGNATURE = 4,
PGP_PKT_SECRET_KEY = 5,
PGP_PKT_PUBLIC_KEY = 6,
PGP_PKT_SECRET_SUBKEY = 7,
***************
*** 109,123 **** enum PGP_DIGEST_TYPE
--- 110,138 ----
PGP_DIGEST_SHA512 = 10
};
+ enum PGP_SIGNATURE_TYPE
+ {
+ PGP_SIGTYP_BINARY = 0,
+ PGP_SIGTYP_TEXT = 1
+ };
+
+ enum PGP_SIGNATURE_SUBPKT_TYPE
+ {
+ PGP_SIGNATURE_CREATION_TIME = 2,
+ PGP_ISSUER_ID = 16
+ };
+
#define PGP_MAX_KEY (256/8)
#define PGP_MAX_BLOCK (256/8)
#define PGP_MAX_DIGEST (512/8)
+ #define PGP_MAX_DIGEST_ASN1_PREFIX 20
#define PGP_S2K_SALT 8
typedef struct PGP_MPI PGP_MPI;
typedef struct PGP_PubKey PGP_PubKey;
typedef struct PGP_Context PGP_Context;
typedef struct PGP_S2K PGP_S2K;
+ typedef struct PGP_Signature PGP_Signature;
struct PGP_S2K
{
***************
*** 141,146 **** struct PGP_Context
--- 156,162 ----
int s2k_digest_algo;
int s2k_cipher_algo;
int cipher_algo;
+ int digest_algo;
int compress_algo;
int compress_level;
int disable_mdc;
***************
*** 158,165 **** struct PGP_Context
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PGP_PubKey *pub_key; /* ctx owns it */
! const uint8 *sym_key; /* ctx does not own it */
int sym_key_len;
/*
--- 174,186 ----
int use_mdcbuf_filter;
PX_MD *mdc_ctx;
! PX_MD *sig_digest_ctx;
! PGP_Signature *sig_onepass;
! PGP_Signature *sig_expected;
!
! PGP_PubKey *pub_key; /* owned by ctx */
! PGP_PubKey *sig_key; /* owned by ctx */
! const uint8 *sym_key; /* not owned by ctx */
int sym_key_len;
/*
***************
*** 229,245 **** struct PGP_PubKey
--- 250,288 ----
int can_encrypt;
};
+ struct PGP_Signature
+ {
+ /* always present */
+ int onepass;
+ uint8 keyid[8];
+ uint8 version;
+ uint8 type;
+ uint8 algo;
+ uint8 digest_algo;
+
+ /* only present if this is not a one-pass signature */
+ uint32 creation_time;
+ uint8 expected_digest[PGP_MAX_DIGEST];
+ uint8 expected_digest_l16[2];
+ MBuf *trailer;
+ };
+
int pgp_init(PGP_Context **ctx);
int pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_decrypt(PGP_Context *ctx, MBuf *src, MBuf *dst);
int pgp_free(PGP_Context *ctx);
+ int pgp_sig_create(PGP_Signature **sig_p);
+ int pgp_sig_free(PGP_Signature *sig);
+
int pgp_get_digest_code(const char *name);
int pgp_get_cipher_code(const char *name);
const char *pgp_get_digest_name(int code);
const char *pgp_get_cipher_name(int code);
+ int pgp_get_digest_asn1_prefix(int code, uint8 *data);
int pgp_set_cipher_algo(PGP_Context *ctx, const char *name);
+ int pgp_set_digest_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_mode(PGP_Context *ctx, int type);
int pgp_set_s2k_cipher_algo(PGP_Context *ctx, const char *name);
int pgp_set_s2k_digest_algo(PGP_Context *ctx, const char *name);
***************
*** 253,262 **** int pgp_set_unicode_mode(PGP_Context *ctx, int mode);
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype);
!
! int pgp_get_keyid(MBuf *pgp_data, char *dst);
/* internal functions */
--- 296,312 ----
int pgp_get_unicode_mode(PGP_Context *ctx);
int pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int klen);
! int pgp_set_sigkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
! int pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
! const uint8 *key, int klen, int pubtype,
! int encrypt);
!
! int pgp_get_keyid(int want_main_key, MBuf *pgp_data, char *dst);
! int pgp_get_signatures(PGP_Context *ctx, MBuf *pgp_data, void *opaque,
! int (*cb)(void *opaque, PGP_Signature *sig, char *keyid),
! int extract_details);
/* internal functions */
***************
*** 289,294 **** int pgp_key_alloc(PGP_PubKey **pk_p);
--- 339,346 ----
void pgp_key_free(PGP_PubKey *pk);
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p);
+ int pgp_parse_symenc_sesskey(PGP_Context *ctx, PullFilter *src);
+
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt);
int pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
int pkttype, PGP_Context *ctx);
***************
*** 301,306 **** int pgp_expect_packet_end(PullFilter *pkt);
--- 353,366 ----
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst);
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p);
+ int pgp_write_signature(PGP_Context *ctx, PushFilter *dst);
+ int pgp_parse_onepass_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt);
+ int pgp_parse_signature(PGP_Context *ctx, PGP_Signature **sig_p,
+ PullFilter *pkt, uint8 *expected_keyid);
+ int pgp_verify_signature(PGP_Context *ctx);
+
+
int pgp_mpi_alloc(int bits, PGP_MPI **mpi);
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi);
int pgp_mpi_free(PGP_MPI *mpi);
***************
*** 317,319 **** int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
--- 377,382 ----
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m);
extern struct PullFilterOps pgp_decrypt_filter;
+ extern struct PullFilterOps pgp_prefix_filter;
+ extern struct PullFilterOps pgp_mdc_filter;
+ extern struct PullFilterOps pgp_mdcbuf_filter;
*** a/contrib/pgcrypto/px.c
--- b/contrib/pgcrypto/px.c
***************
*** 86,91 **** static const struct error_desc px_err_list[] = {
--- 86,96 ----
{PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
{PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
{PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
+ {PXE_PGP_NO_SIGNATURE, "No signature matching the key id present in the message"},
+ {PXE_PGP_INVALID_SIGNATURE, "Signature does not match"},
+ {PXE_PGP_MULTIPLE_SIGNATURES, "Multiple signatures with matching keyid"},
+ {PXE_PGP_CONFLICTING_SIGNATURES, "One-pass signature's options conflict with those of the actual signature"},
+ {PXE_PGP_NO_SIGN_KEY, "No sign key found"},
/* fake this as PXE_PGP_CORRUPT_DATA */
{PXE_MBUF_SHORT_READ, "Corrupt data"},
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
***************
*** 106,111 **** void px_free(void *p);
--- 106,116 ----
#define PXE_PGP_BAD_S2K_MODE -121
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
+ #define PXE_PGP_NO_SIGNATURE -124
+ #define PXE_PGP_INVALID_SIGNATURE -125
+ #define PXE_PGP_MULTIPLE_SIGNATURES -126
+ #define PXE_PGP_CONFLICTING_SIGNATURES -127
+ #define PXE_PGP_NO_SIGN_KEY -128
typedef struct px_digest PX_MD;
*** a/contrib/pgcrypto/sql/pgp-encrypt.sql
--- b/contrib/pgcrypto/sql/pgp-encrypt.sql
***************
*** 13,19 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0
');
-- maybe the expect- stuff simply does not work
--- 13,20 ----
expect-sess-key=0,
expect-s2k-mode=3,
expect-s2k-digest-algo=sha1,
! expect-compress-algo=0,
! expect-digest-algo=sha512
');
-- maybe the expect- stuff simply does not work
***************
*** 23,29 **** select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1
');
-- bytea as text
--- 24,31 ----
expect-sess-key=1,
expect-s2k-mode=0,
expect-s2k-digest-algo=md5,
! expect-compress-algo=1,
! expect-digest-algo=md5
');
-- bytea as text
*** a/contrib/pgcrypto/sql/pgp-info.sql
--- b/contrib/pgcrypto/sql/pgp-info.sql
***************
*** 20,22 **** select pgp_key_id(dearmor(seckey)) from keytbl where id=6;
--- 20,38 ----
select pgp_key_id(dearmor(data)) as data_key_id
from encdata order by id;
+
+ -- pgp_main_key_id
+
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(pubkey)) from keytbl where id=6;
+
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=1;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=2;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=3;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=4;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=5;
+ select pgp_main_key_id(dearmor(seckey)) from keytbl where id=6;
*** /dev/null
--- b/contrib/pgcrypto/sql/pgp-sign.sql
***************
*** 0 ****
--- 1,234 ----
+ --
+ -- PGP sign
+ --
+ -- ensure consistent test output regardless of the default bytea format
+ SET bytea_output TO escape;
+
+ -- list keys
+ select pgp_sym_signatures.* from
+ (select pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsa2048') encrypted,
+ lateral pgp_sym_signatures(encrypted.ciphertext, 'key')
+ ;
+ select pgp_pub_signatures.* from
+ (select seckey, pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, dearmor(encrypted.seckey))
+ ;
+
+ -- test debug mode
+ select pgp_pub_signatures.* from
+ (select pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)) as ciphertext
+ from keytbl where keytbl.name = 'rsaenc2048') encrypted,
+ lateral pgp_pub_signatures(encrypted.ciphertext, (select dearmor(seckey) from keytbl where keytbl.name='elg2048'), '', false, 'debug=1')
+ ;
+
+ -- decrypt without verifying the signature
+ select pgp_sym_decrypt_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- decrypt and verify the signature, wrong key
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(keytbl1.seckey)), 'key', dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(keytbl2.pubkey), dearmor(keytbl1.seckey)), dearmor(keytbl2.seckey), dearmor(keytbl2.pubkey))
+ from keytbl keytbl1, keytbl keytbl2 where keytbl1.name = 'rsa2048' and keytbl2.name = 'rsaenc2048';
+
+ -- complain if no signature is present
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_bytea('Secret.', 'key'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_bytea('Secret.', dearmor(pubkey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- multiple signers
+ insert into encdata(id, data) values (5, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ jA0ECQMCA7SEJlWfWYjUyekWNxFzQ/NFijc61eLTtHEqtxZ36f0XvgV2ZjIgUVq5
+ jSaGcly7rTfy6P9bCNMN+p1B86N+v6P+7zkzhtg4abM7RTbnXfj9VupQE+bTu++A
+ 9xTAOrM79cFlyVzVykkQUOcvw7kNRk2woepREbguRpqLytDwVf8tJKn2Yd00X/Lp
+ IsU5HfT+TcNngx8NFqhKedfAPcyQd0cS7NA0dcUyXcN/fO+PsPavp7iPGt0Q+/JN
+ exkjx4LmJPObkrgN7RYiOlA3vRUt4SuzJAIN6+GkKxveYrpQuaGr1t1M0HfPXw9n
+ gilqUtlwX36tHGfCOYYwlG64LaNsyuTRmXIvV0o8kYaaJtoVKeMGkZCPd6XZoAf9
+ Elluzf7Mxe+T44XRQ/VlO8P9aT0immSdOwGL6wywmV+kITpcVUcthCR3a2Yb2R4M
+ NE0efRop4arfdOGpLdysF32ymwAZgdqNCDHKLTuAKfDlnXl2Tm1QdOhXytILIe64
+ kkzt5YNjrAvw5qmn0ze3xZuUCTuEUbBh3T19o5jrF1oiZ4hqd6o3iUEPnYxWaHl0
+ r7W9BxHpVJexY7K3MGtAnnHKn8f+MmopGe4HDSHTRf+qDjZi7yg9psWChlii4PPs
+ YqmfxGBicnoHQy+GSauoDgVPNy4PPrH5yY4bAByt3op28/vkQ7bQH0tuc6x6J0Rm
+ GYG7s8HPpWFSzS7o25tALBmXIi+DZfdgQ8tQ4MLx5wZPJ1H68A3MTvinuQKiY5yE
+ YezsNH92tGilzM5E0iRA8UTluqhQIkX4apMJnnRT8RJ0by5pUbkYKokbmH4rKTCv
+ nOIu5RYb/9a4Nd4ijZOWM8AmNKVNsLP3cB7jJqupykWNpos=
+ =1JXB
+ -----END PGP MESSAGE-----
+ ');
+ insert into encdata(id, data) values (6, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+
+ hQEMA/0CBsQJt0h1AQf/bAFXphI0ecP5Ba2gKnC9TXz7BWhHn07QBEBoWJ4CHMpp
+ ULwBJ4CgG6ED9QdtIPeteazrn490ORS8ut4mymf+ERolZGI7U4p2lJJIkvpS7Qyq
+ wAEjsZgl48mT6P8JQyp7Xf2MDrONVNS+rsp1+C5Fem8PGprlIu7RRUBYi1eg3lZO
+ Kjl8poBqU28PHT/HaZakccO/cOFKaXBAlq3wZGHgEwNa2LXwNlUOG66u2GrMKcAm
+ R2N68ve5clIa5cUWPB8uvvWkbCjBnf+re4L7hddRCAVNs98WC7ty1876xJLh5OyH
+ cGh8xa03LMOOnBseuOUx/dKVTjc5vFgsfTDJgf6SS9LpAeKts5nMscaVzqU2jgtd
+ YOyhocXn8+kA43iUX0YZvMzfep8vSoHqigV2VQ6OtxQBT1SA7inE/7l3t3xPaSRz
+ HeeXBDSg1BSwLr2p+l/PTvR158MZ4MQX5PvmPJ3M6f/1nDflHGR1pp8Qjv7BGiOz
+ XnjGSK+pRrzT4S2XSOIglcSNqEKa0B0iodv/R593E08/zZMeyGZQL7esJq9CWp4n
+ jT30ATpvIrZ6UvBpxj21G64/JfFSZa8a+v2biC/eOws3Dch/fCa0IU0RNlZaTXoN
+ 888am3HEKlObzst+7PvkRc4TgK91cfF46w311iD3bDi8lsv1LqDmBMqhIEWrg1Sc
+ ntAe+afUzHdUKg/StlMOSloTwU0oP+drj3h30UaR/t0/ykMDfCjW6peEmEB64vDx
+ 3FQk8phKket2EmKhC1pHWZpZsEgITficWwy42l43xAsLNp6cwuhZ5Sz874di73iE
+ oDhIqB5Mftvc1zUiZv/15KsIX9DwxGHWbaUIRro+xYmKj36ljJguTA74NwKljxbE
+ xQ6gLjMs81MCBkPbPjM4iNuF5AqVu78BSUqd7nOKauLm5/a2COr/5fh6Zigph57y
+ FTe54GqFzxlpP4JOqUiS2gd9lRlXujCWpVa8Cexxh99jpG1mF/xuHpnjJvCOPp4h
+ g0IBsNq67xYHubsX+goGnH2edeJsH5eXYwETFqYnUt5kQmKQKPZn4vH01TAidHco
+ Qv9O1DIyvwiwmgaoPT6JCuGfd8lFqmR6W4u+3NM6pbW19AguYIFXRcgzLIOX5t4K
+ E3JVgW8pkQcxBsycFxrwjf66hfaLTu39SsZrWkkaPRMo8kCt08K2jgf4alz/MyhH
+ uRScuAbB94gSEf/VmzTnilt2219be1w5zl35h1fjCbo=
+ =snSk
+ -----END PGP MESSAGE-----
+ ');
+
+ -- multiple signers without verifying the signature
+ select * from pgp_pub_decrypt_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- no details
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- with details; the signatures will appear in reverse order
+ select * from pgp_sym_signatures((select dearmor(data) from encdata where id=5), 'key', true);
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', true);
+
+ -- verify both signatures
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=6), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsaenc2048'));
+
+ -- test v3 signature headers
+ insert into encdata(id, data) values (7, '
+ -----BEGIN PGP MESSAGE-----
+ Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
+ Comment: GPGTools - http://gpgtools.org
+
+ hQEMA/0CBsQJt0h1AQf/TbgfgQgH8QxP6THfNFKOW39TvV+v9Sb2p5Q7JRF6/YxG
+ n2N2ADkO0S63wE9HRH2xHAbxvaxO9nCHX48mTTi6sj/6fRdg3nDn9yvQcE994JaS
+ Wumn3d+7Pe8AqpwAyk6Tn2YSrdv8K3AKB0DuQI0FsXvjET8x7uBvD272c665od4k
+ FhgOzJrgtin6DKCUSVc8UZgDw4ZI/TAHrbf6pxiIX2rLdn1EAcjuPALiQKGvQIyH
+ I/B+Yq7j8sLhL60k3DEKHSjFqHR16LG4wsCKnNjzBM+Dto3nkklTcuy1Qu6D8B38
+ b1yVWO6IoUPf1aKahrzdFfv3J9jnmt7CMbxIfjqeqdLAsAG2e+dtdDu/own6lI6T
+ AM8TqvSCyKpjz8IN6FELe4rJq2LgS+FKJPcuFJV2JJs+eOo4O2PzVfdv8yJklysH
+ epU5tfrpYdkbsrR9pLhsbKGDINDmqENydAhFLUII2xdichVkYvk+gye+GS3E2EPp
+ aniMP/CuetL6qDIht9ADBCstBih8VFE7d7bNB//ldKc8cXKMJ/h1CHJ788sV2QBO
+ RHgHdWFE02JoK8WsDf/Wg5422Yca1JXhfr3wvHUwAvmnnIGzOUBaHbMSTlrgqNsR
+ nerdZxLfaxUQ8CjJ2yobn9OIAj4TAuITipssUsEVypT8m1lwsW2CaTuWUBcE9oC7
+ ULIfPPt+McDf1EYNtp+0UxZASFLETVYsLIfhNQxf8YnXFuVcLzvhdVRQKZ7oMC17
+ +0non8pele5HURJO7e3ULQihtb1i9GPtPXRjhyuR5K3n35NoZJHt4SCQPuRxRJIB
+ I4toPKPYCrND+X25oKaTrTMC
+ =WWPD
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_decrypt_verify_bytea((select dearmor(data) from encdata where id=7), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), (select dearmor(pubkey) from keytbl where keytbl.name = 'rsa2048'));
+
+ -- test for MDC filter in pgp-info
+ insert into encdata(id, data) values (8, '
+ -----BEGIN PGP MESSAGE-----
+
+ hQEMA/0CBsQJt0h1AQf9Ft3w02xcBLxXvKhlQwpngOr3+yYwvUNf2Cup9eDuk52RR0dQ8A/lAW5Q
+ 6xvidlsUqpym7dG7l1siiit8xWv4wqlk+Aoyf5AOIa90nptKm9m/s7PPLjySRSy4Upyb/lm4686R
+ Yw/DtOMV5Y8CDj1W0KzSy4RJFDh3F5e0wlPfci2fpfjz6j4Ac/XQWyBXz0bEqAhGa7U1slO1Z2af
+ 0F4fbSu17XG20erPPfusoKjkFfcQTxO34uj5HUQbjKbOgWcTnsdz7OLZFZ3fjEbQqG4YtEwvQ5dC
+ XVN2rST6WQRIMMlr95WoX0agI3ykEZ/vy8Sh+Iji5PPM6UOaQqS5Aw1fvdLpAeYo7yNjAaIfx5xH
+ b+fhfgGgKjSGQJYv8Dp5b3uXN7o3I0YSGyLDRkAgZD+d+5w75P+oJESYLLzlDrcaJ+0YvDEzbalV
+ +0vp9cKIGXsQ82FEzAq6RrlRM9HBVwyMMvMAo18py5ruSDckLdLuS05GobtiZvZpV+j+/TSr+GXn
+ /1B8XwCE829Ty4PT2GrD9e3oa1yedM17FPDtesMFLlxpVKeP89jWbn1U0gTvp5QFiLINyka5Uh71
+ 5xsBy8KG7+ZQ1bppvgH8sSos7s8VkbyS5/3C6nWoUN7ylzVh4d2Jb60Nqx+rtHOpdOfH7e+55Dux
+ NwU0nNni5msv++QQoKwr5guMQ+j0CofQlW8VA82S/fmYQEyifuCVA/qb0OK4qBN9gne8hePEbplV
+ pNcuodLkeBPiRSK2G+zdp0yYEpeMV5C1hxYVMS1ea0BoKMq5n57jwmnnLwJijjUw6CjGodtBF7mT
+ aEHeff1OPHgjbFtXojDuPAaN86RTRXqN6HSOrv/V8eW78KoEUENcOVDLvoOYpUlqGdmSp0HGpuDZ
+ U1Hp14vpvabDrjZ45VxZKSdLGeywyVkYkV4ZeXXsurbOCGwUzgZBodHcaG1fSF7NBTDPrXNfkr1n
+ oDruf0xBGr6adDlBmXWCo6AeKdCfuJJ9s0KUi0LbNaewpuyYiT8t3ziqdjcCnUs=
+ =26/O
+ -----END PGP MESSAGE-----
+ ');
+ select * from pgp_pub_signatures((select dearmor(data) from encdata where id=8), (select dearmor(seckey) from keytbl where keytbl.name = 'rsaenc2048'), '', TRUE);
+
+ -- pgp_main_key_id() should fail, even on signed data
+ select pgp_main_key_id(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ -- text mode
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in binary, verify signature in text (doesn't work)
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign_bytea('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign_bytea('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey)), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey)), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify signature in binary (works)
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify_bytea(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify_bytea(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify with same (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey), '', 'convert-crlf=1')
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ -- encrypt in text with convert-crlf, verify in text without conversion (works)
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign('Secret.', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign('Secret.', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
+ select pgp_sym_decrypt_verify(pgp_sym_encrypt_sign(E'Secret.\n', 'key', dearmor(seckey), '', 'convert-crlf=1'), 'key', dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsa2048';
+
+ select pgp_pub_decrypt_verify(pgp_pub_encrypt_sign(E'Secret.\n', dearmor(pubkey), dearmor(seckey), '', 'convert-crlf=1'), dearmor(seckey), dearmor(pubkey))
+ from keytbl where keytbl.name = 'rsaenc2048';
+
*** a/doc/src/sgml/pgcrypto.sgml
--- b/doc/src/sgml/pgcrypto.sgml
***************
*** 433,438 **** gen_salt(type text [, iter_count integer ]) returns text
--- 433,440 ----
<para>
The functions here implement the encryption part of the OpenPGP (RFC 4880)
standard. Supported are both symmetric-key and public-key encryption.
+ Also signing the data when encrypting and verifying the signature when
+ decrypting is supported.
</para>
<para>
***************
*** 524,529 **** gen_salt(type text [, iter_count integer ]) returns text
--- 526,579 ----
</listitem>
</orderedlist>
+ <para>
+ If the data is also signed, two more packets are added into the message:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <firstterm>one-pass signature packet</> is written before the encrypted
+ data, containing information about the algorithms used for the signature.
+ This allows the party decrypting the message to calculate the message
+ while decrypting it, in a single pass over the data.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ After the encrypted data packet has been written, the signature itself is
+ written into a <firstterm>signature packet</>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The signature is calculated as follows:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Optional data-manipulation: compression, conversion to UTF-8, and/or conversion of line-endings.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A hash of the entire message is calculated, using the algorithm specified
+ by the <literal>digest-algo</> setting.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A trailer containing additional information, such as the signature
+ creation time, is hashed in the same context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The resulting hash is put into the signature packet.
+ </para>
+ </listitem>
+ </orderedlist>
+
<sect3>
<title><function>pgp_sym_encrypt()</function></title>
***************
*** 535,549 **** gen_salt(type text [, iter_count integer ]) returns text
--- 585,615 ----
<primary>pgp_sym_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign(data text, psw text [, options text ]) returns bytea
+ pgp_sym_encrypt_sign_bytea(data bytea, psw text [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a symmetric PGP key <parameter>psw</>.
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
+ <para>
+ The <literal>sign</> versions also sign the encrypted data using the secret
+ key <parameter>sigkey</>. If this key is password-protected, you must give
+ the password in <parameter>psw</>. If there is no password, but you want
+ to specify options, you need to give an empty password.
+ </para>
</sect3>
<sect3>
***************
*** 557,565 **** pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
--- 623,641 ----
<primary>pgp_sym_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_sym_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
+ pgp_sym_decrypt_verify(msg bytea, psw text, sigkey bytea [, options text ]) returns text
+ pgp_sym_decrypt_verify_bytea(msg bytea, psw text, sigkey bytea [, options text ]) returns bytea
</synopsis>
<para>
Decrypt a symmetric-key-encrypted PGP message.
***************
*** 570,575 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
--- 646,658 ----
originally textual data with <function>pgp_sym_decrypt_bytea</> is fine.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
The <parameter>options</> parameter can contain option settings,
as described below.
</para>
***************
*** 586,598 **** pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! Giving this function a secret key will produce an error.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
--- 669,698 ----
<primary>pgp_pub_encrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_encrypt_sign_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
+ pgp_pub_encrypt_sign(data text, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_encrypt_sign_bytea(data bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Encrypt <parameter>data</> with a public PGP key <parameter>key</>.
! If a secret key is provided as the <parameter>key</> parameter, these
! functions will produce an error.
! </para>
! <para>
! The <literal>sign</> versions also sign the encrypted data using the secret
! key <parameter>sigkey</>. If this key is password-protected, you must give
! the password in <parameter>psw</>. If there is no password, but you want
! to specify options, you need to give an empty password.
</para>
<para>
The <parameter>options</> parameter can contain option settings,
***************
*** 611,619 **** pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
--- 711,729 ----
<primary>pgp_pub_decrypt_bytea</primary>
</indexterm>
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>pgp_pub_decrypt_verify_bytea</primary>
+ </indexterm>
+
<synopsis>
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
+ pgp_pub_decrypt_verify(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns text
+ pgp_pub_decrypt_verify_bytea(msg bytea, key bytea, sigkey bytea [, psw text [, options text ]]) returns bytea
</synopsis>
<para>
Decrypt a public-key-encrypted message. <parameter>key</> must be the
***************
*** 623,628 **** pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) retur
--- 733,745 ----
options, you need to give an empty password.
</para>
<para>
+ The <literal>verify</> versions also verify the signature against the
+ main public key provided in <parameter>sigkey</>. An exception is raised
+ if no signature matching <parameter>sigkey's</> key ID is found or the
+ signature does not match. If multiple signatures matching the key ID are
+ present in the message, an error is raised.
+ </para>
+ <para>
Decrypting <type>bytea</> data with <function>pgp_pub_decrypt</> is disallowed.
This is to avoid outputting invalid character data. Decrypting
originally textual data with <function>pgp_pub_decrypt_bytea</> is fine.
***************
*** 680,685 **** pgp_key_id(bytea) returns text
--- 797,867 ----
</sect3>
<sect3>
+ <title><function>pgp_main_key_id()</function></title>
+
+ <indexterm>
+ <primary>pgp_main_key_id</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_main_key_id(bytea) returns text
+ </synopsis>
+ <para>
+ <function>pgp_main_key_id</> extracts the key ID of the main key of a PGP
+ public or secret key. Unlike <function>pgp_key_id</>, this function only
+ extracts key IDs from keys and not encrypted messages. See
+ <function>pgp_sym_signatures</> and <function>pgp_pub_signatures</> if you
+ want to extract the keys used to sign encrypted data.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_sym_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_sym_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_sym_signatures(data bytea, key text [, details boolean [, options text ]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_sym_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The symmetric PGP key used to encrypt the
+ data should be provided in <parameter>key</>. If details is
+ <literal>true</>, creation_time is set to the time recorded in the
+ signature. The default is <literal>false</>, since in most cases this
+ means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title><function>pgp_pub_signatures()</function></title>
+
+ <indexterm>
+ <primary>pgp_pub_signatures</primary>
+ </indexterm>
+
+ <synopsis>
+ pgp_pub_signatures(data bytea, key bytea [, psw text [, details boolean [, options text ]]])
+ returns setof (keyid text, digest text, pubkeyalgo text, creation_time timestamptz)
+ </synopsis>
+ <para>
+ <function>pgp_pub_signatures</> extracts the list of signatures present in
+ the encrypted data in bytea. The secret key corresponding to the public
+ key used to encrypt the data should be provided in <parameter>key</>. If
+ key is password-protected, the password should be provided in
+ <parameter>psw</>. If there is no password, but you want to specify
+ <parameter>details</> or <parameter>options</>, you need to give an empty
+ password. If details is <literal>true</>, creation_time is set to the time
+ recorded in the signature. The default is <literal>false</>, since in most
+ cases this means having to decrypt the entire message.
+ </para>
+ </sect3>
+
+
+ <sect3>
<title><function>armor()</function>, <function>dearmor()</function></title>
<indexterm>
***************
*** 812,817 **** Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
--- 994,1012 ----
</sect4>
<sect4>
+ <title>digest-algo</title>
+
+ <para>
+ Which digest algorithm to use for generating signatures.
+ </para>
+ <literallayout>
+ Values: md5, sha1, sha256, sha384, sha512
+ Default: sha512
+ Applies to: pgp_sym_encrypt, pgp_pub_encrypt
+ </literallayout>
+ </sect4>
+
+ <sect4>
<title>disable-mdc</title>
<para>
***************
*** 955,968 **** gpg -a --export-secret-keys KEYID > secret.key
<itemizedlist>
<listitem>
<para>
! No support for signing. That also means that it is not checked
! whether the encryption subkey belongs to the master key.
</para>
</listitem>
<listitem>
<para>
! No support for encryption key as master key. As such practice
! is generally discouraged, this should not be a problem.
</para>
</listitem>
<listitem>
--- 1150,1169 ----
<itemizedlist>
<listitem>
<para>
! No support for detached signatures. Additionally, none of the functions
! check that the encryption subkey has been signed by the master key.
! </para>
! </listitem>
! <listitem>
! <para>
! Signing is only supported using RSA keys.
</para>
</listitem>
<listitem>
<para>
! No support for master key as encryption key. As such practice
! is generally discouraged, this should not be a problem. Similarly,
! subkeys are not supported for signing.
</para>
</listitem>
<listitem>
On Sat, Nov 1, 2014 at 7:52 AM, Marko Tiikkaja <marko@joh.to> wrote:
Hi,
I discovered a problem with the lack of MDC handling in the signature info
extraction code, so I've fixed that and added a test message. v9 here.
Hi Marko,
I get a segfault when the length of the message is exactly 16308 bytes, see
attached perl script.
I can't get a backtrace, for some reason it acts as if there were no debug
symbols despite that I built with them. I've not seen that before.
I get this whether or not the bug 11905 patch is applied, so the problem
seems to be related but different.
Cheers,
Jeff
Attachments:
On Wed, Nov 12, 2014 at 7:05 AM, Jeff Janes <jeff.janes@gmail.com> wrote:
On Sat, Nov 1, 2014 at 7:52 AM, Marko Tiikkaja <marko@joh.to> wrote:
Hi,
I discovered a problem with the lack of MDC handling in the signature info
extraction code, so I've fixed that and added a test message. v9 here.Hi Marko,
I get a segfault when the length of the message is exactly 16308 bytes, see
attached perl script.I can't get a backtrace, for some reason it acts as if there were no debug
symbols despite that I built with them. I've not seen that before.I get this whether or not the bug 11905 patch is applied, so the problem
seems to be related but different.
This patch status was "Ready for committer" but it still has visibly
some bugs, and has not been updated in a while as pointed out by Jeff.
So I am switching it as "Returned with feedback".
Regards,
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers