openGauss-server/contrib/pgcrypto/pgp-pgsql.cpp

814 lines
20 KiB
C++

/*
* pgp-pgsql.c
* PostgreSQL wrappers for pgp.
*
* Copyright (c) 2005 Marko Kreen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* contrib/pgcrypto/pgp-pgsql.c
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
#include "mbuf.h"
#include "px.h"
#include "pgp.h"
/*
* public functions
*/
extern "C" Datum pgp_sym_encrypt_text(PG_FUNCTION_ARGS);
extern "C" Datum pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS);
extern "C" Datum pgp_sym_decrypt_text(PG_FUNCTION_ARGS);
extern "C" Datum pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS);
extern "C" Datum pgp_pub_encrypt_text(PG_FUNCTION_ARGS);
extern "C" Datum pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS);
extern "C" Datum pgp_pub_decrypt_text(PG_FUNCTION_ARGS);
extern "C" Datum pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS);
extern "C" Datum pgp_key_id_w(PG_FUNCTION_ARGS);
extern "C" Datum pg_armor(PG_FUNCTION_ARGS);
extern "C" Datum pg_dearmor(PG_FUNCTION_ARGS);
/* function headers */
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
/*
* Mix a block of data into RNG.
*/
static void add_block_entropy(PX_MD* md, text* data)
{
uint8 sha1[20];
px_md_reset(md);
px_md_update(md, (uint8*)VARDATA(data), VARSIZE(data) - VARHDRSZ);
px_md_finish(md, sha1);
px_add_entropy(sha1, 20);
memset(sha1, 0, 20);
}
/*
* Mix user data into RNG. It is for user own interests to have
* RNG state shuffled.
*/
static void add_entropy(text* data1, text* data2, text* data3)
{
PX_MD* md = NULL;
uint8 rnd[3];
if (!data1 && !data2 && !data3)
return;
if (px_get_random_bytes(rnd, 3) < 0)
return;
if (px_find_digest("sha1", &md) < 0)
return;
/*
* Try to make the feeding unpredictable.
*
* Prefer data over keys, as it's rather likely that key is same in
* several calls.
*/
/* chance: 7/8 */
if (data1 && rnd[0] >= 32)
add_block_entropy(md, data1);
/* chance: 5/8 */
if (data2 && rnd[1] >= 160)
add_block_entropy(md, data2);
/* chance: 5/8 */
if (data3 && rnd[2] >= 160)
add_block_entropy(md, data3);
px_md_free(md);
memset(rnd, 0, sizeof(rnd));
}
/*
* returns src in case of no conversion or error
*/
static text* convert_charset(text* src, int cset_from, int cset_to)
{
int src_len = VARSIZE(src) - VARHDRSZ;
unsigned char* dst = NULL;
unsigned char* csrc = (unsigned char*)VARDATA(src);
text* res = NULL;
dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to);
if (dst == csrc)
return src;
res = cstring_to_text((char*)dst);
pfree(dst);
return res;
}
static text* convert_from_utf8(text* src)
{
return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
}
static text* convert_to_utf8(text* src)
{
return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
}
static void clear_and_pfree(text* p)
{
memset(p, 0, VARSIZE(p));
pfree(p);
}
/*
* expect-* arguments storage
*/
struct debug_expect {
int debug;
int expect;
int cipher_algo;
int s2k_mode;
int s2k_cipher_algo;
int s2k_digest_algo;
int compress_algo;
int use_sess_key;
int disable_mdc;
int unicode_mode;
};
static void fill_expect(struct debug_expect* ex, int text_mode)
{
ex->debug = 0;
ex->expect = 0;
ex->cipher_algo = -1;
ex->s2k_mode = -1;
ex->s2k_cipher_algo = -1;
ex->s2k_digest_algo = -1;
ex->compress_algo = -1;
ex->use_sess_key = -1;
ex->disable_mdc = -1;
ex->unicode_mode = -1;
}
#define EX_MSG(arg) \
ereport(NOTICE, (errmsg("pgp_decrypt: unexpected %s: expected %d got %d", CppAsString(arg), ex->arg, ctx->arg)))
#define EX_CHECK(arg) \
do { \
if (ex->arg >= 0 && ex->arg != ctx->arg) \
EX_MSG(arg); \
} while (0)
static void check_expect(PGP_Context* ctx, struct debug_expect* ex)
{
EX_CHECK(cipher_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
if (ctx->use_sess_key)
EX_CHECK(s2k_cipher_algo);
EX_CHECK(disable_mdc);
EX_CHECK(compress_algo);
EX_CHECK(unicode_mode);
}
static void show_debug(const char* msg)
{
ereport(NOTICE, (errmsg("dbg: %s", msg)));
}
static int set_arg(PGP_Context* ctx, char* key, char* val, struct debug_expect* ex)
{
int res = 0;
if (strcmp(key, "cipher-algo") == 0)
res = pgp_set_cipher_algo(ctx, val);
else if (strcmp(key, "disable-mdc") == 0)
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key") == 0)
res = pgp_set_sess_key(ctx, atoi(val));
else if (strcmp(key, "s2k-mode") == 0)
res = pgp_set_s2k_mode(ctx, atoi(val));
else if (strcmp(key, "s2k-digest-algo") == 0)
res = pgp_set_s2k_digest_algo(ctx, val);
else if (strcmp(key, "s2k-cipher-algo") == 0)
res = pgp_set_s2k_cipher_algo(ctx, val);
else if (strcmp(key, "compress-algo") == 0)
res = pgp_set_compress_algo(ctx, atoi(val));
else if (strcmp(key, "compress-level") == 0)
res = pgp_set_compress_level(ctx, atoi(val));
else if (strcmp(key, "convert-crlf") == 0)
res = pgp_set_convert_crlf(ctx, atoi(val));
else if (strcmp(key, "unicode-mode") == 0)
res = pgp_set_unicode_mode(ctx, atoi(val));
/* decrypt debug */
else if (ex != NULL && strcmp(key, "debug") == 0)
ex->debug = atoi(val);
else if (ex != NULL && strcmp(key, "expect-cipher-algo") == 0) {
ex->expect = 1;
ex->cipher_algo = pgp_get_cipher_code(val);
} else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0) {
ex->expect = 1;
ex->disable_mdc = atoi(val);
} else if (ex != NULL && strcmp(key, "expect-sess-key") == 0) {
ex->expect = 1;
ex->use_sess_key = atoi(val);
} else if (ex != NULL && strcmp(key, "expect-s2k-mode") == 0) {
ex->expect = 1;
ex->s2k_mode = atoi(val);
} else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0) {
ex->expect = 1;
ex->s2k_digest_algo = pgp_get_digest_code(val);
} else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo") == 0) {
ex->expect = 1;
ex->s2k_cipher_algo = pgp_get_cipher_code(val);
} else if (ex != NULL && strcmp(key, "expect-compress-algo") == 0) {
ex->expect = 1;
ex->compress_algo = atoi(val);
} else if (ex != NULL && strcmp(key, "expect-unicode-mode") == 0) {
ex->expect = 1;
ex->unicode_mode = atoi(val);
} else
res = PXE_ARGUMENT_ERROR;
return res;
}
/*
* Find next word. Handle ',' and '=' as words. Skip whitespace.
* Put word info into res_p, res_len.
* Returns ptr to next word.
*/
static char* getword(char* p, char** res_p, int* res_len)
{
/* whitespace at start */
while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
p++;
/* word data */
*res_p = p;
if (*p == '=' || *p == ',')
p++;
else
while (*p && !(*p == ' ' || *p == '\t' || *p == '\n' || *p == '=' || *p == ','))
p++;
/* word end */
*res_len = p - *res_p;
/* whitespace at end */
while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
p++;
return p;
}
/*
* Convert to lowercase asciiz string.
*/
static char* downcase_convert(const uint8* s, int len)
{
int c, i;
char* res = (char*)palloc(len + 1);
for (i = 0; i < len; i++) {
c = s[i];
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';
res[i] = c;
}
res[len] = 0;
return res;
}
static int parse_args(PGP_Context* ctx, uint8* args, int arg_len, struct debug_expect* ex)
{
char* str = downcase_convert(args, arg_len);
char *key, *val;
int key_len, val_len;
int res = 0;
char* p = str;
while (*p) {
res = PXE_ARGUMENT_ERROR;
p = getword(p, &key, &key_len);
if (*p++ != '=')
break;
p = getword(p, &val, &val_len);
if (*p == '\0')
;
else if (*p++ != ',')
break;
if (*key == 0 || *val == 0 || val_len == 0)
break;
key[key_len] = 0;
val[val_len] = 0;
res = set_arg(ctx, key, val, ex);
if (res < 0)
break;
}
pfree(str);
return res;
}
static MBuf* create_mbuf_from_vardata(text* data)
{
return mbuf_create_from_data((uint8*)VARDATA(data), VARSIZE(data) - VARHDRSZ);
}
static void init_work(PGP_Context** ctx_p, int is_text, text* args, struct debug_expect* ex)
{
int err = pgp_init(ctx_p);
fill_expect(ex, is_text);
if (err == 0 && args != NULL)
err = parse_args(*ctx_p, (uint8*)VARDATA(args), VARSIZE(args) - VARHDRSZ, ex);
if (err) {
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("%s", px_strerror(err))));
}
if (ex->debug)
px_set_debug_handler(show_debug);
pgp_set_text_mode(*ctx_p, is_text);
}
static bytea* encrypt_internal(int is_pubenc, int is_text, text* data, text* key, text* args)
{
MBuf *src, *dst;
uint8 tmp[VARHDRSZ];
uint8* restmp = NULL;
bytea* res = NULL;
int res_len;
PGP_Context* ctx = NULL;
int err;
struct debug_expect ex;
text* tmp_data = NULL;
/*
* Add data and key info RNG.
*/
add_entropy(data, key, NULL);
init_work(&ctx, is_text, args, &ex);
if (is_text && pgp_get_unicode_mode(ctx)) {
tmp_data = convert_to_utf8(data);
if (tmp_data == data)
tmp_data = NULL;
else
data = tmp_data;
}
src = create_mbuf_from_vardata(data);
dst = mbuf_create(VARSIZE(data) + 128);
/*
* reserve room for header
*/
mbuf_append(dst, tmp, VARHDRSZ);
/*
* set key
*/
if (is_pubenc) {
MBuf* kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf, NULL, 0, 0);
mbuf_free(kbuf);
} else
err = pgp_set_symkey(ctx, (uint8*)VARDATA(key), VARSIZE(key) - VARHDRSZ);
/*
* encrypt
*/
if (err >= 0)
err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err) {
if (ex.debug)
px_set_debug_handler(NULL);
if (tmp_data)
clear_and_pfree(tmp_data);
pgp_free(ctx);
mbuf_free(src);
mbuf_free(dst);
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("%s", px_strerror(err))));
}
/* res_len includes VARHDRSZ */
res_len = mbuf_steal_data(dst, &restmp);
res = (bytea*)restmp;
SET_VARSIZE(res, res_len);
if (tmp_data)
clear_and_pfree(tmp_data);
pgp_free(ctx);
mbuf_free(src);
mbuf_free(dst);
px_set_debug_handler(NULL);
return res;
}
static bytea* decrypt_internal(int is_pubenc, int need_text, text* data, text* key, text* keypsw, text* args)
{
int err;
MBuf *src = NULL, *dst = NULL;
uint8 tmp[VARHDRSZ];
uint8* restmp = NULL;
bytea* res = NULL;
int res_len;
PGP_Context* ctx = NULL;
struct debug_expect ex;
int got_unicode = 0;
init_work(&ctx, need_text, args, &ex);
src = mbuf_create_from_data((uint8*)VARDATA(data), VARSIZE(data) - VARHDRSZ);
dst = mbuf_create(VARSIZE(data) + 2048);
/*
* reserve room for header
*/
mbuf_append(dst, tmp, VARHDRSZ);
/*
* set key
*/
if (is_pubenc) {
uint8* psw = NULL;
int psw_len = 0;
MBuf* kbuf = NULL;
if (keypsw) {
psw = (uint8*)VARDATA(keypsw);
psw_len = VARSIZE(keypsw) - VARHDRSZ;
}
kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
mbuf_free(kbuf);
} else
err = pgp_set_symkey(ctx, (uint8*)VARDATA(key), VARSIZE(key) - VARHDRSZ);
/*
* decrypt
*/
if (err >= 0)
err = pgp_decrypt(ctx, src, dst);
/*
* failed?
*/
if (err < 0)
goto out;
if (ex.expect)
check_expect(ctx, &ex);
/* remember the setting */
got_unicode = pgp_get_unicode_mode(ctx);
out:
if (src)
mbuf_free(src);
if (ctx)
pgp_free(ctx);
if (err) {
px_set_debug_handler(NULL);
if (dst)
mbuf_free(dst);
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("%s", px_strerror(err))));
}
res_len = mbuf_steal_data(dst, &restmp);
mbuf_free(dst);
/* res_len includes VARHDRSZ */
res = (bytea*)restmp;
SET_VARSIZE(res, res_len);
if (need_text && got_unicode) {
text* utf = convert_from_utf8(res);
if (utf != res) {
clear_and_pfree(res);
res = utf;
}
}
px_set_debug_handler(NULL);
/*
* add successful decryptions also into RNG
*/
add_entropy(res, key, keypsw);
return res;
}
/*
* Wrappers for symmetric-key functions
*/
Datum pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text* arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
res = encrypt_internal(0, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(arg, 2);
PG_RETURN_TEXT_P(res);
}
Datum pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text* arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
res = encrypt_internal(0, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(arg, 2);
PG_RETURN_TEXT_P(res);
}
Datum pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text* arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
res = decrypt_internal(0, 0, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(arg, 2);
PG_RETURN_TEXT_P(res);
}
Datum pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text* arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
res = decrypt_internal(0, 1, data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(arg, 2);
PG_RETURN_TEXT_P(res);
}
/*
* Wrappers for public-key functions
*/
Datum pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text* arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
res = encrypt_internal(1, 0, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(arg, 2);
PG_RETURN_TEXT_P(res);
}
Datum pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text* arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
arg = PG_GETARG_BYTEA_P(2);
res = encrypt_internal(1, 1, data, key, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(arg, 2);
PG_RETURN_TEXT_P(res);
}
Datum pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text *psw = NULL, *arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
psw = PG_GETARG_BYTEA_P(2);
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
res = decrypt_internal(1, 0, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(psw, 2);
if (PG_NARGS() > 3)
PG_FREE_IF_COPY(arg, 3);
PG_RETURN_TEXT_P(res);
}
Datum pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
{
bytea *data, *key;
text *psw = NULL, *arg = NULL;
text* res = NULL;
data = PG_GETARG_BYTEA_P(0);
key = PG_GETARG_BYTEA_P(1);
if (PG_NARGS() > 2)
psw = PG_GETARG_BYTEA_P(2);
if (PG_NARGS() > 3)
arg = PG_GETARG_BYTEA_P(3);
res = decrypt_internal(1, 1, data, key, psw, arg);
PG_FREE_IF_COPY(data, 0);
PG_FREE_IF_COPY(key, 1);
if (PG_NARGS() > 2)
PG_FREE_IF_COPY(psw, 2);
if (PG_NARGS() > 3)
PG_FREE_IF_COPY(arg, 3);
PG_RETURN_TEXT_P(res);
}
/*
* Wrappers for PGP ascii armor
*/
Datum pg_armor(PG_FUNCTION_ARGS)
{
bytea* data = NULL;
text* res = NULL;
int data_len, res_len, guess_len;
data = PG_GETARG_BYTEA_P(0);
data_len = VARSIZE(data) - VARHDRSZ;
guess_len = pgp_armor_enc_len(data_len);
res = (text*)palloc(VARHDRSZ + guess_len);
res_len = pgp_armor_encode((uint8*)VARDATA(data), data_len, (uint8*)VARDATA(res));
if (res_len > guess_len)
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("Overflow - encode estimate too small")));
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
Datum pg_dearmor(PG_FUNCTION_ARGS)
{
text* data = NULL;
bytea* res = NULL;
int data_len, res_len, guess_len;
data = PG_GETARG_TEXT_P(0);
data_len = VARSIZE(data) - VARHDRSZ;
guess_len = pgp_armor_dec_len(data_len);
res = (bytea*)palloc(VARHDRSZ + guess_len);
res_len = pgp_armor_decode((uint8*)VARDATA(data), data_len, (uint8*)VARDATA(res));
if (res_len < 0)
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("%s", px_strerror(res_len))));
if (res_len > guess_len)
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("Overflow - decode estimate too small")));
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}
/*
* Wrappers for PGP key id
*/
Datum pgp_key_id_w(PG_FUNCTION_ARGS)
{
bytea* data = NULL;
text* res = NULL;
int res_len;
MBuf* buf = NULL;
data = PG_GETARG_BYTEA_P(0);
buf = create_mbuf_from_vardata(data);
res = (text*)palloc(VARHDRSZ + 17);
res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("%s", px_strerror(res_len))));
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res);
}