LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-pgsql.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 404 466 86.7 %
Date: 2020-06-01 09:07:10 Functions: 37 41 90.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13