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