diff options
author | Bruce Momjian | 2005-07-10 13:46:29 +0000 |
---|---|---|
committer | Bruce Momjian | 2005-07-10 13:46:29 +0000 |
commit | e94dd6ab9100961511e3407fea9e5b191dec7165 (patch) | |
tree | 996841b24c245441daa2dc5b1476dce0294e5bd9 /contrib/pgcrypto/pgp-pgsql.c | |
parent | 42e7b0f02fe1975a03853190bd9211a6faf22c84 (diff) |
Add missing pgcrypto files from previous commit.
Diffstat (limited to 'contrib/pgcrypto/pgp-pgsql.c')
-rw-r--r-- | contrib/pgcrypto/pgp-pgsql.c | 901 |
1 files changed, 901 insertions, 0 deletions
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c new file mode 100644 index 00000000000..c17d952b39d --- /dev/null +++ b/contrib/pgcrypto/pgp-pgsql.c @@ -0,0 +1,901 @@ +/* + * 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pgsql.c,v 1.1 2005/07/10 13:46:29 momjian Exp $ + */ + +#include <postgres.h> +#include <fmgr.h> +#include <parser/scansup.h> +#include <mb/pg_wchar.h> + +#include "mbuf.h" +#include "px.h" +#include "pgp.h" + +/* + * public functions + */ +Datum pgp_sym_encrypt_text(PG_FUNCTION_ARGS); +Datum pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS); +Datum pgp_sym_decrypt_text(PG_FUNCTION_ARGS); +Datum pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS); + +Datum pgp_pub_encrypt_text(PG_FUNCTION_ARGS); +Datum pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS); +Datum pgp_pub_decrypt_text(PG_FUNCTION_ARGS); +Datum pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS); + +Datum pgp_key_id_w(PG_FUNCTION_ARGS); + +Datum pg_armor(PG_FUNCTION_ARGS); +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); + +/* + * check for NULL arguments + */ +#define CHECK_ARGS() \ + do { \ + int a; \ + for (a = 0; a < PG_NARGS(); a++) { \ + if (PG_ARGISNULL(a)) \ + PG_RETURN_NULL(); \ + } \ + } while (0) + +/* + * 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; + uint8 sha1[20]; + int res; + + if (!data1 && !data2 && !data3) + return; + + res = px_find_digest("sha1", &md); + if (res < 0) + return; + + if (data1) + px_md_update(md, VARDATA(data1), VARSIZE(data1) - VARHDRSZ); + if (data2) + px_md_update(md, VARDATA(data2), VARSIZE(data2) - VARHDRSZ); + if (data3) + px_md_update(md, VARDATA(data3), VARSIZE(data3) - VARHDRSZ); + + px_md_finish(md, sha1); + px_md_free(md); + + res = px_add_entropy(sha1, 20); + memset(sha1, 0, 20); + + if (res < 0) + ereport(NOTICE, (errmsg("add_entropy: %s", px_strerror(res)))); +} + +/* + * 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; + int dst_len; + unsigned char *dst; + unsigned char *csrc = VARDATA(src); + text *res; + + dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to); + if (dst == csrc) + return src; + + dst_len = strlen(dst); + res = palloc(dst_len + VARHDRSZ); + memcpy(VARDATA(res), dst, dst_len); + VARATT_SIZEP(res) = VARHDRSZ + dst_len; + 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 = 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(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, 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; + bytea *res; + int res_len; + PGP_Context *ctx; + 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, 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("pgp_encrypt error: %s", px_strerror(err)))); + } + + /* res_len includes VARHDRSZ */ + res_len = mbuf_steal_data(dst, &restmp); + res = (bytea *) restmp; + VARATT_SIZEP(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; + bytea *res; + 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(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; + if (keypsw) + { + psw = 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, 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("pgp_decrypt error: %s", px_strerror(err)))); + } + + res_len = mbuf_steal_data(dst, &restmp); + mbuf_free(dst); + + /* res_len includes VARHDRSZ */ + res = (bytea *) restmp; + VARATT_SIZEP(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 successfull 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + + CHECK_ARGS(); + 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; + text *res; + int data_len, + res_len, + guess_len; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + data = PG_GETARG_BYTEA_P(0); + data_len = VARSIZE(data) - VARHDRSZ; + + guess_len = pgp_armor_enc_len(data_len); + res = palloc(VARHDRSZ + guess_len); + + res_len = pgp_armor_encode(VARDATA(data), data_len, VARDATA(res)); + if (res_len > guess_len) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("Overflow - encode estimate too small"))); + VARATT_SIZEP(res) = VARHDRSZ + res_len; + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} + +Datum +pg_dearmor(PG_FUNCTION_ARGS) +{ + text *data; + bytea *res; + int data_len, + res_len, + guess_len; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + data = PG_GETARG_TEXT_P(0); + data_len = VARSIZE(data) - VARHDRSZ; + + guess_len = pgp_armor_dec_len(data_len); + res = palloc(VARHDRSZ + guess_len); + + res_len = pgp_armor_decode(VARDATA(data), data_len, VARDATA(res)); + if (res_len < 0) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("dearmor: %s", px_strerror(res_len)))); + if (res_len > guess_len) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("Overflow - decode estimate too small"))); + VARATT_SIZEP(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; + text *res; + int res_len; + MBuf *buf; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + data = PG_GETARG_BYTEA_P(0); + buf = create_mbuf_from_vardata(data); + res = palloc(VARHDRSZ + 17); + + px_set_debug_handler(show_debug); + res_len = pgp_get_keyid(buf, VARDATA(res)); + px_set_debug_handler(NULL); + mbuf_free(buf); + if (res_len < 0) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + errmsg("%s", px_strerror(res_len)))); + VARATT_SIZEP(res) = VARHDRSZ + res_len; + + PG_FREE_IF_COPY(data, 0); + PG_RETURN_TEXT_P(res); +} + |