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