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