1 /*
2 * pgp-pgsql.c
3 * PostgreSQL wrappers for pgp.
4 *
5 * Copyright (c) 2005 Marko Kreen
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * contrib/pgcrypto/pgp-pgsql.c
30 */
31
32 #include "postgres.h"
33
34 #include "lib/stringinfo.h"
35 #include "catalog/pg_type.h"
36 #include "mb/pg_wchar.h"
37 #include "utils/builtins.h"
38 #include "utils/array.h"
39 #include "funcapi.h"
40
41 #include "mbuf.h"
42 #include "px.h"
43 #include "pgp.h"
44
45 /*
46 * public functions
47 */
48 PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
49 PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
50 PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
51 PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
52
53 PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
54 PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
55 PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
56 PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
57
58 PG_FUNCTION_INFO_V1(pgp_key_id_w);
59
60 PG_FUNCTION_INFO_V1(pg_armor);
61 PG_FUNCTION_INFO_V1(pg_dearmor);
62 PG_FUNCTION_INFO_V1(pgp_armor_headers);
63
64 /*
65 * Mix a block of data into RNG.
66 */
67 static void
add_block_entropy(PX_MD * md,text * data)68 add_block_entropy(PX_MD *md, text *data)
69 {
70 uint8 sha1[20];
71
72 px_md_reset(md);
73 px_md_update(md, (uint8 *) VARDATA(data), VARSIZE(data) - VARHDRSZ);
74 px_md_finish(md, sha1);
75
76 px_add_entropy(sha1, 20);
77
78 px_memset(sha1, 0, 20);
79 }
80
81 /*
82 * Mix user data into RNG. It is for user own interests to have
83 * RNG state shuffled.
84 */
85 static void
add_entropy(text * data1,text * data2,text * data3)86 add_entropy(text *data1, text *data2, text *data3)
87 {
88 PX_MD *md;
89 uint8 rnd[3];
90
91 if (!data1 && !data2 && !data3)
92 return;
93
94 if (px_get_random_bytes(rnd, 3) < 0)
95 return;
96
97 if (px_find_digest("sha1", &md) < 0)
98 return;
99
100 /*
101 * Try to make the feeding unpredictable.
102 *
103 * Prefer data over keys, as it's rather likely that key is same in
104 * several calls.
105 */
106
107 /* chance: 7/8 */
108 if (data1 && rnd[0] >= 32)
109 add_block_entropy(md, data1);
110
111 /* chance: 5/8 */
112 if (data2 && rnd[1] >= 160)
113 add_block_entropy(md, data2);
114
115 /* chance: 5/8 */
116 if (data3 && rnd[2] >= 160)
117 add_block_entropy(md, data3);
118
119 px_md_free(md);
120 px_memset(rnd, 0, sizeof(rnd));
121 }
122
123 /*
124 * returns src in case of no conversion or error
125 */
126 static text *
convert_charset(text * src,int cset_from,int cset_to)127 convert_charset(text *src, int cset_from, int cset_to)
128 {
129 int src_len = VARSIZE(src) - VARHDRSZ;
130 unsigned char *dst;
131 unsigned char *csrc = (unsigned char *) VARDATA(src);
132 text *res;
133
134 dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to);
135 if (dst == csrc)
136 return src;
137
138 res = cstring_to_text((char *) dst);
139 pfree(dst);
140 return res;
141 }
142
143 static text *
convert_from_utf8(text * src)144 convert_from_utf8(text *src)
145 {
146 return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
147 }
148
149 static text *
convert_to_utf8(text * src)150 convert_to_utf8(text *src)
151 {
152 return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
153 }
154
155 static bool
string_is_ascii(const char * str)156 string_is_ascii(const char *str)
157 {
158 const char *p;
159
160 for (p = str; *p; p++)
161 {
162 if (IS_HIGHBIT_SET(*p))
163 return false;
164 }
165 return true;
166 }
167
168 static void
clear_and_pfree(text * p)169 clear_and_pfree(text *p)
170 {
171 px_memset(p, 0, VARSIZE(p));
172 pfree(p);
173 }
174
175 /*
176 * expect-* arguments storage
177 */
178 struct debug_expect
179 {
180 int debug;
181 int expect;
182 int cipher_algo;
183 int s2k_mode;
184 int s2k_count;
185 int s2k_cipher_algo;
186 int s2k_digest_algo;
187 int compress_algo;
188 int use_sess_key;
189 int disable_mdc;
190 int unicode_mode;
191 };
192
193 static void
fill_expect(struct debug_expect * ex,int text_mode)194 fill_expect(struct debug_expect * ex, int text_mode)
195 {
196 ex->debug = 0;
197 ex->expect = 0;
198 ex->cipher_algo = -1;
199 ex->s2k_mode = -1;
200 ex->s2k_count = -1;
201 ex->s2k_cipher_algo = -1;
202 ex->s2k_digest_algo = -1;
203 ex->compress_algo = -1;
204 ex->use_sess_key = -1;
205 ex->disable_mdc = -1;
206 ex->unicode_mode = -1;
207 }
208
209 #define EX_MSG(arg) \
210 ereport(NOTICE, (errmsg( \
211 "pgp_decrypt: unexpected %s: expected %d got %d", \
212 CppAsString(arg), ex->arg, ctx->arg)))
213
214 #define EX_CHECK(arg) do { \
215 if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
216 } while (0)
217
218 static void
check_expect(PGP_Context * ctx,struct debug_expect * ex)219 check_expect(PGP_Context *ctx, struct debug_expect * ex)
220 {
221 EX_CHECK(cipher_algo);
222 EX_CHECK(s2k_mode);
223 EX_CHECK(s2k_count);
224 EX_CHECK(s2k_digest_algo);
225 EX_CHECK(use_sess_key);
226 if (ctx->use_sess_key)
227 EX_CHECK(s2k_cipher_algo);
228 EX_CHECK(disable_mdc);
229 EX_CHECK(compress_algo);
230 EX_CHECK(unicode_mode);
231 }
232
233 static void
show_debug(const char * msg)234 show_debug(const char *msg)
235 {
236 ereport(NOTICE, (errmsg("dbg: %s", msg)));
237 }
238
239 static int
set_arg(PGP_Context * ctx,char * key,char * val,struct debug_expect * ex)240 set_arg(PGP_Context *ctx, char *key, char *val,
241 struct debug_expect * ex)
242 {
243 int res = 0;
244
245 if (strcmp(key, "cipher-algo") == 0)
246 res = pgp_set_cipher_algo(ctx, val);
247 else if (strcmp(key, "disable-mdc") == 0)
248 res = pgp_disable_mdc(ctx, atoi(val));
249 else if (strcmp(key, "sess-key") == 0)
250 res = pgp_set_sess_key(ctx, atoi(val));
251 else if (strcmp(key, "s2k-mode") == 0)
252 res = pgp_set_s2k_mode(ctx, atoi(val));
253 else if (strcmp(key, "s2k-count") == 0)
254 res = pgp_set_s2k_count(ctx, atoi(val));
255 else if (strcmp(key, "s2k-digest-algo") == 0)
256 res = pgp_set_s2k_digest_algo(ctx, val);
257 else if (strcmp(key, "s2k-cipher-algo") == 0)
258 res = pgp_set_s2k_cipher_algo(ctx, val);
259 else if (strcmp(key, "compress-algo") == 0)
260 res = pgp_set_compress_algo(ctx, atoi(val));
261 else if (strcmp(key, "compress-level") == 0)
262 res = pgp_set_compress_level(ctx, atoi(val));
263 else if (strcmp(key, "convert-crlf") == 0)
264 res = pgp_set_convert_crlf(ctx, atoi(val));
265 else if (strcmp(key, "unicode-mode") == 0)
266 res = pgp_set_unicode_mode(ctx, atoi(val));
267
268 /*
269 * The remaining options are for debugging/testing and are therefore not
270 * documented in the user-facing docs.
271 */
272 else if (ex != NULL && strcmp(key, "debug") == 0)
273 ex->debug = atoi(val);
274 else if (ex != NULL && strcmp(key, "expect-cipher-algo") == 0)
275 {
276 ex->expect = 1;
277 ex->cipher_algo = pgp_get_cipher_code(val);
278 }
279 else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
280 {
281 ex->expect = 1;
282 ex->disable_mdc = atoi(val);
283 }
284 else if (ex != NULL && strcmp(key, "expect-sess-key") == 0)
285 {
286 ex->expect = 1;
287 ex->use_sess_key = atoi(val);
288 }
289 else if (ex != NULL && strcmp(key, "expect-s2k-mode") == 0)
290 {
291 ex->expect = 1;
292 ex->s2k_mode = atoi(val);
293 }
294 else if (ex != NULL && strcmp(key, "expect-s2k-count") == 0)
295 {
296 ex->expect = 1;
297 ex->s2k_count = atoi(val);
298 }
299 else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0)
300 {
301 ex->expect = 1;
302 ex->s2k_digest_algo = pgp_get_digest_code(val);
303 }
304 else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo") == 0)
305 {
306 ex->expect = 1;
307 ex->s2k_cipher_algo = pgp_get_cipher_code(val);
308 }
309 else if (ex != NULL && strcmp(key, "expect-compress-algo") == 0)
310 {
311 ex->expect = 1;
312 ex->compress_algo = atoi(val);
313 }
314 else if (ex != NULL && strcmp(key, "expect-unicode-mode") == 0)
315 {
316 ex->expect = 1;
317 ex->unicode_mode = atoi(val);
318 }
319 else
320 res = PXE_ARGUMENT_ERROR;
321
322 return res;
323 }
324
325 /*
326 * Find next word. Handle ',' and '=' as words. Skip whitespace.
327 * Put word info into res_p, res_len.
328 * Returns ptr to next word.
329 */
330 static char *
getword(char * p,char ** res_p,int * res_len)331 getword(char *p, char **res_p, int *res_len)
332 {
333 /* whitespace at start */
334 while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
335 p++;
336
337 /* word data */
338 *res_p = p;
339 if (*p == '=' || *p == ',')
340 p++;
341 else
342 while (*p && !(*p == ' ' || *p == '\t' || *p == '\n'
343 || *p == '=' || *p == ','))
344 p++;
345
346 /* word end */
347 *res_len = p - *res_p;
348
349 /* whitespace at end */
350 while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
351 p++;
352
353 return p;
354 }
355
356 /*
357 * Convert to lowercase asciiz string.
358 */
359 static char *
downcase_convert(const uint8 * s,int len)360 downcase_convert(const uint8 *s, int len)
361 {
362 int c,
363 i;
364 char *res = palloc(len + 1);
365
366 for (i = 0; i < len; i++)
367 {
368 c = s[i];
369 if (c >= 'A' && c <= 'Z')
370 c += 'a' - 'A';
371 res[i] = c;
372 }
373 res[len] = 0;
374 return res;
375 }
376
377 static int
parse_args(PGP_Context * ctx,uint8 * args,int arg_len,struct debug_expect * ex)378 parse_args(PGP_Context *ctx, uint8 *args, int arg_len,
379 struct debug_expect * ex)
380 {
381 char *str = downcase_convert(args, arg_len);
382 char *key,
383 *val;
384 int key_len,
385 val_len;
386 int res = 0;
387 char *p = str;
388
389 while (*p)
390 {
391 res = PXE_ARGUMENT_ERROR;
392 p = getword(p, &key, &key_len);
393 if (*p++ != '=')
394 break;
395 p = getword(p, &val, &val_len);
396 if (*p == '\0')
397 ;
398 else if (*p++ != ',')
399 break;
400
401 if (*key == 0 || *val == 0 || val_len == 0)
402 break;
403
404 key[key_len] = 0;
405 val[val_len] = 0;
406
407 res = set_arg(ctx, key, val, ex);
408 if (res < 0)
409 break;
410 }
411 pfree(str);
412 return res;
413 }
414
415 static MBuf *
create_mbuf_from_vardata(text * data)416 create_mbuf_from_vardata(text *data)
417 {
418 return mbuf_create_from_data((uint8 *) VARDATA(data),
419 VARSIZE(data) - VARHDRSZ);
420 }
421
422 static void
init_work(PGP_Context ** ctx_p,int is_text,text * args,struct debug_expect * ex)423 init_work(PGP_Context **ctx_p, int is_text,
424 text *args, struct debug_expect * ex)
425 {
426 int err = pgp_init(ctx_p);
427
428 fill_expect(ex, is_text);
429
430 if (err == 0 && args != NULL)
431 err = parse_args(*ctx_p, (uint8 *) VARDATA(args),
432 VARSIZE(args) - VARHDRSZ, ex);
433
434 if (err)
435 {
436 ereport(ERROR,
437 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
438 errmsg("%s", px_strerror(err))));
439 }
440
441 if (ex->debug)
442 px_set_debug_handler(show_debug);
443
444 pgp_set_text_mode(*ctx_p, is_text);
445 }
446
447 static bytea *
encrypt_internal(int is_pubenc,int is_text,text * data,text * key,text * args)448 encrypt_internal(int is_pubenc, int is_text,
449 text *data, text *key, text *args)
450 {
451 MBuf *src,
452 *dst;
453 uint8 tmp[VARHDRSZ];
454 uint8 *restmp;
455 bytea *res;
456 int res_len;
457 PGP_Context *ctx;
458 int err;
459 struct debug_expect ex;
460 text *tmp_data = NULL;
461
462 /*
463 * Add data and key info RNG.
464 */
465 add_entropy(data, key, NULL);
466
467 init_work(&ctx, is_text, args, &ex);
468
469 if (is_text && pgp_get_unicode_mode(ctx))
470 {
471 tmp_data = convert_to_utf8(data);
472 if (tmp_data == data)
473 tmp_data = NULL;
474 else
475 data = tmp_data;
476 }
477
478 src = create_mbuf_from_vardata(data);
479 dst = mbuf_create(VARSIZE(data) + 128);
480
481 /*
482 * reserve room for header
483 */
484 mbuf_append(dst, tmp, VARHDRSZ);
485
486 /*
487 * set key
488 */
489 if (is_pubenc)
490 {
491 MBuf *kbuf = create_mbuf_from_vardata(key);
492
493 err = pgp_set_pubkey(ctx, kbuf,
494 NULL, 0, 0);
495 mbuf_free(kbuf);
496 }
497 else
498 err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
499 VARSIZE(key) - VARHDRSZ);
500
501 /*
502 * encrypt
503 */
504 if (err >= 0)
505 err = pgp_encrypt(ctx, src, dst);
506
507 /*
508 * check for error
509 */
510 if (err)
511 {
512 if (ex.debug)
513 px_set_debug_handler(NULL);
514 if (tmp_data)
515 clear_and_pfree(tmp_data);
516 pgp_free(ctx);
517 mbuf_free(src);
518 mbuf_free(dst);
519 ereport(ERROR,
520 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
521 errmsg("%s", px_strerror(err))));
522 }
523
524 /* res_len includes VARHDRSZ */
525 res_len = mbuf_steal_data(dst, &restmp);
526 res = (bytea *) restmp;
527 SET_VARSIZE(res, res_len);
528
529 if (tmp_data)
530 clear_and_pfree(tmp_data);
531 pgp_free(ctx);
532 mbuf_free(src);
533 mbuf_free(dst);
534
535 px_set_debug_handler(NULL);
536
537 return res;
538 }
539
540 static bytea *
decrypt_internal(int is_pubenc,int need_text,text * data,text * key,text * keypsw,text * args)541 decrypt_internal(int is_pubenc, int need_text, text *data,
542 text *key, text *keypsw, text *args)
543 {
544 int err;
545 MBuf *src = NULL,
546 *dst = NULL;
547 uint8 tmp[VARHDRSZ];
548 uint8 *restmp;
549 bytea *res;
550 int res_len;
551 PGP_Context *ctx = NULL;
552 struct debug_expect ex;
553 int got_unicode = 0;
554
555
556 init_work(&ctx, need_text, args, &ex);
557
558 src = mbuf_create_from_data((uint8 *) VARDATA(data),
559 VARSIZE(data) - VARHDRSZ);
560 dst = mbuf_create(VARSIZE(data) + 2048);
561
562 /*
563 * reserve room for header
564 */
565 mbuf_append(dst, tmp, VARHDRSZ);
566
567 /*
568 * set key
569 */
570 if (is_pubenc)
571 {
572 uint8 *psw = NULL;
573 int psw_len = 0;
574 MBuf *kbuf;
575
576 if (keypsw)
577 {
578 psw = (uint8 *) VARDATA(keypsw);
579 psw_len = VARSIZE(keypsw) - VARHDRSZ;
580 }
581 kbuf = create_mbuf_from_vardata(key);
582 err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
583 mbuf_free(kbuf);
584 }
585 else
586 err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
587 VARSIZE(key) - VARHDRSZ);
588
589 /* decrypt */
590 if (err >= 0)
591 {
592 err = pgp_decrypt(ctx, src, dst);
593
594 if (ex.expect)
595 check_expect(ctx, &ex);
596
597 /* remember the setting */
598 got_unicode = pgp_get_unicode_mode(ctx);
599 }
600
601 mbuf_free(src);
602 pgp_free(ctx);
603
604 if (err)
605 {
606 px_set_debug_handler(NULL);
607 mbuf_free(dst);
608 ereport(ERROR,
609 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
610 errmsg("%s", px_strerror(err))));
611 }
612
613 res_len = mbuf_steal_data(dst, &restmp);
614 mbuf_free(dst);
615
616 /* res_len includes VARHDRSZ */
617 res = (bytea *) restmp;
618 SET_VARSIZE(res, res_len);
619
620 if (need_text && got_unicode)
621 {
622 text *utf = convert_from_utf8(res);
623
624 if (utf != res)
625 {
626 clear_and_pfree(res);
627 res = utf;
628 }
629 }
630 px_set_debug_handler(NULL);
631
632 /*
633 * add successful decryptions also into RNG
634 */
635 add_entropy(res, key, keypsw);
636
637 return res;
638 }
639
640 /*
641 * Wrappers for symmetric-key functions
642 */
643 Datum
pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)644 pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
645 {
646 bytea *data,
647 *key;
648 text *arg = NULL;
649 text *res;
650
651 data = PG_GETARG_BYTEA_P(0);
652 key = PG_GETARG_BYTEA_P(1);
653 if (PG_NARGS() > 2)
654 arg = PG_GETARG_BYTEA_P(2);
655
656 res = encrypt_internal(0, 0, data, key, arg);
657
658 PG_FREE_IF_COPY(data, 0);
659 PG_FREE_IF_COPY(key, 1);
660 if (PG_NARGS() > 2)
661 PG_FREE_IF_COPY(arg, 2);
662 PG_RETURN_TEXT_P(res);
663 }
664
665 Datum
pgp_sym_encrypt_text(PG_FUNCTION_ARGS)666 pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
667 {
668 bytea *data,
669 *key;
670 text *arg = NULL;
671 text *res;
672
673 data = PG_GETARG_BYTEA_P(0);
674 key = PG_GETARG_BYTEA_P(1);
675 if (PG_NARGS() > 2)
676 arg = PG_GETARG_BYTEA_P(2);
677
678 res = encrypt_internal(0, 1, data, key, arg);
679
680 PG_FREE_IF_COPY(data, 0);
681 PG_FREE_IF_COPY(key, 1);
682 if (PG_NARGS() > 2)
683 PG_FREE_IF_COPY(arg, 2);
684 PG_RETURN_TEXT_P(res);
685 }
686
687
688 Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)689 pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
690 {
691 bytea *data,
692 *key;
693 text *arg = NULL;
694 text *res;
695
696 data = PG_GETARG_BYTEA_P(0);
697 key = PG_GETARG_BYTEA_P(1);
698 if (PG_NARGS() > 2)
699 arg = PG_GETARG_BYTEA_P(2);
700
701 res = decrypt_internal(0, 0, data, key, NULL, arg);
702
703 PG_FREE_IF_COPY(data, 0);
704 PG_FREE_IF_COPY(key, 1);
705 if (PG_NARGS() > 2)
706 PG_FREE_IF_COPY(arg, 2);
707 PG_RETURN_TEXT_P(res);
708 }
709
710 Datum
pgp_sym_decrypt_text(PG_FUNCTION_ARGS)711 pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
712 {
713 bytea *data,
714 *key;
715 text *arg = NULL;
716 text *res;
717
718 data = PG_GETARG_BYTEA_P(0);
719 key = PG_GETARG_BYTEA_P(1);
720 if (PG_NARGS() > 2)
721 arg = PG_GETARG_BYTEA_P(2);
722
723 res = decrypt_internal(0, 1, data, key, NULL, arg);
724
725 PG_FREE_IF_COPY(data, 0);
726 PG_FREE_IF_COPY(key, 1);
727 if (PG_NARGS() > 2)
728 PG_FREE_IF_COPY(arg, 2);
729 PG_RETURN_TEXT_P(res);
730 }
731
732 /*
733 * Wrappers for public-key functions
734 */
735
736 Datum
pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)737 pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
738 {
739 bytea *data,
740 *key;
741 text *arg = NULL;
742 text *res;
743
744 data = PG_GETARG_BYTEA_P(0);
745 key = PG_GETARG_BYTEA_P(1);
746 if (PG_NARGS() > 2)
747 arg = PG_GETARG_BYTEA_P(2);
748
749 res = encrypt_internal(1, 0, data, key, arg);
750
751 PG_FREE_IF_COPY(data, 0);
752 PG_FREE_IF_COPY(key, 1);
753 if (PG_NARGS() > 2)
754 PG_FREE_IF_COPY(arg, 2);
755 PG_RETURN_TEXT_P(res);
756 }
757
758 Datum
pgp_pub_encrypt_text(PG_FUNCTION_ARGS)759 pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
760 {
761 bytea *data,
762 *key;
763 text *arg = NULL;
764 text *res;
765
766 data = PG_GETARG_BYTEA_P(0);
767 key = PG_GETARG_BYTEA_P(1);
768 if (PG_NARGS() > 2)
769 arg = PG_GETARG_BYTEA_P(2);
770
771 res = encrypt_internal(1, 1, data, key, arg);
772
773 PG_FREE_IF_COPY(data, 0);
774 PG_FREE_IF_COPY(key, 1);
775 if (PG_NARGS() > 2)
776 PG_FREE_IF_COPY(arg, 2);
777 PG_RETURN_TEXT_P(res);
778 }
779
780
781 Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)782 pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
783 {
784 bytea *data,
785 *key;
786 text *psw = NULL,
787 *arg = NULL;
788 text *res;
789
790 data = PG_GETARG_BYTEA_P(0);
791 key = PG_GETARG_BYTEA_P(1);
792 if (PG_NARGS() > 2)
793 psw = PG_GETARG_BYTEA_P(2);
794 if (PG_NARGS() > 3)
795 arg = PG_GETARG_BYTEA_P(3);
796
797 res = decrypt_internal(1, 0, data, key, psw, arg);
798
799 PG_FREE_IF_COPY(data, 0);
800 PG_FREE_IF_COPY(key, 1);
801 if (PG_NARGS() > 2)
802 PG_FREE_IF_COPY(psw, 2);
803 if (PG_NARGS() > 3)
804 PG_FREE_IF_COPY(arg, 3);
805 PG_RETURN_TEXT_P(res);
806 }
807
808 Datum
pgp_pub_decrypt_text(PG_FUNCTION_ARGS)809 pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
810 {
811 bytea *data,
812 *key;
813 text *psw = NULL,
814 *arg = NULL;
815 text *res;
816
817 data = PG_GETARG_BYTEA_P(0);
818 key = PG_GETARG_BYTEA_P(1);
819 if (PG_NARGS() > 2)
820 psw = PG_GETARG_BYTEA_P(2);
821 if (PG_NARGS() > 3)
822 arg = PG_GETARG_BYTEA_P(3);
823
824 res = decrypt_internal(1, 1, data, key, psw, arg);
825
826 PG_FREE_IF_COPY(data, 0);
827 PG_FREE_IF_COPY(key, 1);
828 if (PG_NARGS() > 2)
829 PG_FREE_IF_COPY(psw, 2);
830 if (PG_NARGS() > 3)
831 PG_FREE_IF_COPY(arg, 3);
832 PG_RETURN_TEXT_P(res);
833 }
834
835
836 /*
837 * Wrappers for PGP ascii armor
838 */
839
840 /*
841 * Helper function for pgp_armor. Converts arrays of keys and values into
842 * plain C arrays, and checks that they don't contain invalid characters.
843 */
844 static int
parse_key_value_arrays(ArrayType * key_array,ArrayType * val_array,char *** p_keys,char *** p_values)845 parse_key_value_arrays(ArrayType *key_array, ArrayType *val_array,
846 char ***p_keys, char ***p_values)
847 {
848 int nkdims = ARR_NDIM(key_array);
849 int nvdims = ARR_NDIM(val_array);
850 char **keys,
851 **values;
852 Datum *key_datums,
853 *val_datums;
854 bool *key_nulls,
855 *val_nulls;
856 int key_count,
857 val_count;
858 int i;
859
860 if (nkdims > 1 || nkdims != nvdims)
861 ereport(ERROR,
862 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
863 errmsg("wrong number of array subscripts")));
864 if (nkdims == 0)
865 return 0;
866
867 deconstruct_array(key_array,
868 TEXTOID, -1, false, 'i',
869 &key_datums, &key_nulls, &key_count);
870
871 deconstruct_array(val_array,
872 TEXTOID, -1, false, 'i',
873 &val_datums, &val_nulls, &val_count);
874
875 if (key_count != val_count)
876 ereport(ERROR,
877 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
878 errmsg("mismatched array dimensions")));
879
880 keys = (char **) palloc(sizeof(char *) * key_count);
881 values = (char **) palloc(sizeof(char *) * val_count);
882
883 for (i = 0; i < key_count; i++)
884 {
885 char *v;
886
887 /* Check that the key doesn't contain anything funny */
888 if (key_nulls[i])
889 ereport(ERROR,
890 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
891 errmsg("null value not allowed for header key")));
892
893 v = TextDatumGetCString(key_datums[i]);
894
895 if (!string_is_ascii(v))
896 ereport(ERROR,
897 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
898 errmsg("header key must not contain non-ASCII characters")));
899 if (strstr(v, ": "))
900 ereport(ERROR,
901 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
902 errmsg("header key must not contain \": \"")));
903 if (strchr(v, '\n'))
904 ereport(ERROR,
905 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
906 errmsg("header key must not contain newlines")));
907 keys[i] = v;
908
909 /* And the same for the value */
910 if (val_nulls[i])
911 ereport(ERROR,
912 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
913 errmsg("null value not allowed for header value")));
914
915 v = TextDatumGetCString(val_datums[i]);
916
917 if (!string_is_ascii(v))
918 ereport(ERROR,
919 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
920 errmsg("header value must not contain non-ASCII characters")));
921 if (strchr(v, '\n'))
922 ereport(ERROR,
923 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
924 errmsg("header value must not contain newlines")));
925
926 values[i] = v;
927 }
928
929 *p_keys = keys;
930 *p_values = values;
931 return key_count;
932 }
933
934 Datum
pg_armor(PG_FUNCTION_ARGS)935 pg_armor(PG_FUNCTION_ARGS)
936 {
937 bytea *data;
938 text *res;
939 int data_len;
940 StringInfoData buf;
941 int num_headers;
942 char **keys = NULL,
943 **values = NULL;
944
945 data = PG_GETARG_BYTEA_P(0);
946 data_len = VARSIZE(data) - VARHDRSZ;
947 if (PG_NARGS() == 3)
948 {
949 num_headers = parse_key_value_arrays(PG_GETARG_ARRAYTYPE_P(1),
950 PG_GETARG_ARRAYTYPE_P(2),
951 &keys, &values);
952 }
953 else if (PG_NARGS() == 1)
954 num_headers = 0;
955 else
956 elog(ERROR, "unexpected number of arguments %d", PG_NARGS());
957
958 initStringInfo(&buf);
959
960 pgp_armor_encode((uint8 *) VARDATA(data), data_len, &buf,
961 num_headers, keys, values);
962
963 res = palloc(VARHDRSZ + buf.len);
964 SET_VARSIZE(res, VARHDRSZ + buf.len);
965 memcpy(VARDATA(res), buf.data, buf.len);
966 pfree(buf.data);
967
968 PG_FREE_IF_COPY(data, 0);
969 PG_RETURN_TEXT_P(res);
970 }
971
972 Datum
pg_dearmor(PG_FUNCTION_ARGS)973 pg_dearmor(PG_FUNCTION_ARGS)
974 {
975 text *data;
976 bytea *res;
977 int data_len;
978 int ret;
979 StringInfoData buf;
980
981 data = PG_GETARG_TEXT_P(0);
982 data_len = VARSIZE(data) - VARHDRSZ;
983
984 initStringInfo(&buf);
985
986 ret = pgp_armor_decode((uint8 *) VARDATA(data), data_len, &buf);
987 if (ret < 0)
988 ereport(ERROR,
989 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
990 errmsg("%s", px_strerror(ret))));
991 res = palloc(VARHDRSZ + buf.len);
992 SET_VARSIZE(res, VARHDRSZ + buf.len);
993 memcpy(VARDATA(res), buf.data, buf.len);
994 pfree(buf.data);
995
996 PG_FREE_IF_COPY(data, 0);
997 PG_RETURN_TEXT_P(res);
998 }
999
1000 /* cross-call state for pgp_armor_headers */
1001 typedef struct
1002 {
1003 int nheaders;
1004 char **keys;
1005 char **values;
1006 } pgp_armor_headers_state;
1007
1008 Datum
pgp_armor_headers(PG_FUNCTION_ARGS)1009 pgp_armor_headers(PG_FUNCTION_ARGS)
1010 {
1011 FuncCallContext *funcctx;
1012 pgp_armor_headers_state *state;
1013 char *utf8key;
1014 char *utf8val;
1015 HeapTuple tuple;
1016 TupleDesc tupdesc;
1017 AttInMetadata *attinmeta;
1018
1019 if (SRF_IS_FIRSTCALL())
1020 {
1021 text *data = PG_GETARG_TEXT_PP(0);
1022 int res;
1023 MemoryContext oldcontext;
1024
1025 funcctx = SRF_FIRSTCALL_INIT();
1026
1027 /* we need the state allocated in the multi call context */
1028 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1029
1030 /* Build a tuple descriptor for our result type */
1031 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1032 elog(ERROR, "return type must be a row type");
1033
1034 attinmeta = TupleDescGetAttInMetadata(tupdesc);
1035 funcctx->attinmeta = attinmeta;
1036
1037 state = (pgp_armor_headers_state *) palloc(sizeof(pgp_armor_headers_state));
1038
1039 res = pgp_extract_armor_headers((uint8 *) VARDATA_ANY(data),
1040 VARSIZE_ANY_EXHDR(data),
1041 &state->nheaders, &state->keys,
1042 &state->values);
1043 if (res < 0)
1044 ereport(ERROR,
1045 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
1046 errmsg("%s", px_strerror(res))));
1047
1048 MemoryContextSwitchTo(oldcontext);
1049 funcctx->user_fctx = state;
1050 }
1051
1052 funcctx = SRF_PERCALL_SETUP();
1053 state = (pgp_armor_headers_state *) funcctx->user_fctx;
1054
1055 if (funcctx->call_cntr >= state->nheaders)
1056 SRF_RETURN_DONE(funcctx);
1057 else
1058 {
1059 char *values[2];
1060
1061 /* we assume that the keys (and values) are in UTF-8. */
1062 utf8key = state->keys[funcctx->call_cntr];
1063 utf8val = state->values[funcctx->call_cntr];
1064
1065 values[0] = pg_any_to_server(utf8key, strlen(utf8key), PG_UTF8);
1066 values[1] = pg_any_to_server(utf8val, strlen(utf8val), PG_UTF8);
1067
1068 /* build a tuple */
1069 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
1070 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
1071 }
1072 }
1073
1074
1075
1076 /*
1077 * Wrappers for PGP key id
1078 */
1079
1080 Datum
pgp_key_id_w(PG_FUNCTION_ARGS)1081 pgp_key_id_w(PG_FUNCTION_ARGS)
1082 {
1083 bytea *data;
1084 text *res;
1085 int res_len;
1086 MBuf *buf;
1087
1088 data = PG_GETARG_BYTEA_P(0);
1089 buf = create_mbuf_from_vardata(data);
1090 res = palloc(VARHDRSZ + 17);
1091
1092 res_len = pgp_get_keyid(buf, VARDATA(res));
1093 mbuf_free(buf);
1094 if (res_len < 0)
1095 ereport(ERROR,
1096 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
1097 errmsg("%s", px_strerror(res_len))));
1098 SET_VARSIZE(res, VARHDRSZ + res_len);
1099
1100 PG_FREE_IF_COPY(data, 0);
1101 PG_RETURN_TEXT_P(res);
1102 }
1103