Commit 1dcfb8da authored by Heikki Linnakangas's avatar Heikki Linnakangas

Refactor space allocation for base64 encoding/decoding in pgcrypto.

Instead of trying to accurately calculate the space needed, use a StringInfo
that's enlarged as needed. This is just moving things around currently - the
old code was not wrong - but this is in preparation for a patch that adds
support for extra armor headers, and would make the space calculation more
complicated.

Marko Tiikkaja
parent 56a312aa
...@@ -203,38 +203,33 @@ crc24(const uint8 *data, unsigned len) ...@@ -203,38 +203,33 @@ crc24(const uint8 *data, unsigned len)
return crc & 0xffffffL; return crc & 0xffffffL;
} }
int void
pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst) pgp_armor_encode(const uint8 *src, int len, StringInfo dst)
{ {
int n; int res;
uint8 *pos = dst; unsigned b64len;
unsigned crc = crc24(src, len); unsigned crc = crc24(src, len);
n = strlen(armor_header); appendStringInfoString(dst, armor_header);
memcpy(pos, armor_header, n);
pos += n;
n = b64_encode(src, len, pos);
pos += n;
if (*(pos - 1) != '\n') /* make sure we have enough room to b64_encode() */
*pos++ = '\n'; b64len = b64_enc_len(len);
enlargeStringInfo(dst, (int) b64len);
res = b64_encode(src, len, (uint8 *) dst->data + dst->len);
if (res > b64len)
elog(FATAL, "overflow - encode estimate too small");
dst->len += res;
*pos++ = '='; if (*(dst->data + dst->len - 1) != '\n')
pos[3] = _base64[crc & 0x3f]; appendStringInfoChar(dst, '\n');
crc >>= 6;
pos[2] = _base64[crc & 0x3f];
crc >>= 6;
pos[1] = _base64[crc & 0x3f];
crc >>= 6;
pos[0] = _base64[crc & 0x3f];
pos += 4;
n = strlen(armor_footer); appendStringInfoChar(dst, '=');
memcpy(pos, armor_footer, n); appendStringInfoChar(dst, _base64[(crc >> 18) & 0x3f]);
pos += n; appendStringInfoChar(dst, _base64[(crc >> 12) & 0x3f]);
appendStringInfoChar(dst, _base64[(crc >> 6) & 0x3f]);
appendStringInfoChar(dst, _base64[crc & 0x3f]);
return pos - dst; appendStringInfoString(dst, armor_footer);
} }
static const uint8 * static const uint8 *
...@@ -309,7 +304,7 @@ find_header(const uint8 *data, const uint8 *datend, ...@@ -309,7 +304,7 @@ find_header(const uint8 *data, const uint8 *datend,
} }
int int
pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst) pgp_armor_decode(const uint8 *src, int len, StringInfo dst)
{ {
const uint8 *p = src; const uint8 *p = src;
const uint8 *data_end = src + len; const uint8 *data_end = src + len;
...@@ -319,6 +314,7 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst) ...@@ -319,6 +314,7 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
const uint8 *base64_end = NULL; const uint8 *base64_end = NULL;
uint8 buf[4]; uint8 buf[4];
int hlen; int hlen;
int blen;
int res = PXE_PGP_CORRUPT_ARMOR; int res = PXE_PGP_CORRUPT_ARMOR;
/* armor start */ /* armor start */
...@@ -360,23 +356,18 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst) ...@@ -360,23 +356,18 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2]; crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
/* decode data */ /* decode data */
res = b64_decode(base64_start, base64_end - base64_start, dst); blen = (int) b64_dec_len(len);
enlargeStringInfo(dst, blen);
/* check crc */ res = b64_decode(base64_start, base64_end - base64_start, (uint8 *) dst->data);
if (res >= 0 && crc24(dst, res) != crc) if (res > blen)
res = PXE_PGP_CORRUPT_ARMOR; elog(FATAL, "overflow - decode estimate too small");
if (res >= 0)
{
if (crc24((uint8 *) dst->data, res) == crc)
dst->len += res;
else
res = PXE_PGP_CORRUPT_ARMOR;
}
out: out:
return res; return res;
} }
unsigned
pgp_armor_enc_len(unsigned len)
{
return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
}
unsigned
pgp_armor_dec_len(unsigned len)
{
return b64_dec_len(len);
}
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "postgres.h" #include "postgres.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -820,23 +821,20 @@ pg_armor(PG_FUNCTION_ARGS) ...@@ -820,23 +821,20 @@ pg_armor(PG_FUNCTION_ARGS)
{ {
bytea *data; bytea *data;
text *res; text *res;
int data_len, int data_len;
res_len, StringInfoData buf;
guess_len;
data = PG_GETARG_BYTEA_P(0); data = PG_GETARG_BYTEA_P(0);
data_len = VARSIZE(data) - VARHDRSZ; data_len = VARSIZE(data) - VARHDRSZ;
guess_len = pgp_armor_enc_len(data_len); initStringInfo(&buf);
res = palloc(VARHDRSZ + guess_len);
res_len = pgp_armor_encode((uint8 *) VARDATA(data), data_len, pgp_armor_encode((uint8 *) VARDATA(data), data_len, &buf);
(uint8 *) VARDATA(res));
if (res_len > guess_len) res = palloc(VARHDRSZ + buf.len);
ereport(ERROR, SET_VARSIZE(res, VARHDRSZ + buf.len);
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), memcpy(VARDATA(res), buf.data, buf.len);
errmsg("Overflow - encode estimate too small"))); pfree(buf.data);
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0); PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res); PG_RETURN_TEXT_P(res);
...@@ -847,27 +845,24 @@ pg_dearmor(PG_FUNCTION_ARGS) ...@@ -847,27 +845,24 @@ pg_dearmor(PG_FUNCTION_ARGS)
{ {
text *data; text *data;
bytea *res; bytea *res;
int data_len, int data_len;
res_len, int ret;
guess_len; StringInfoData buf;
data = PG_GETARG_TEXT_P(0); data = PG_GETARG_TEXT_P(0);
data_len = VARSIZE(data) - VARHDRSZ; data_len = VARSIZE(data) - VARHDRSZ;
guess_len = pgp_armor_dec_len(data_len); initStringInfo(&buf);
res = palloc(VARHDRSZ + guess_len);
res_len = pgp_armor_decode((uint8 *) VARDATA(data), data_len, ret = pgp_armor_decode((uint8 *) VARDATA(data), data_len, &buf);
(uint8 *) VARDATA(res)); if (ret < 0)
if (res_len < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
errmsg("%s", px_strerror(res_len)))); errmsg("%s", px_strerror(ret))));
if (res_len > guess_len) res = palloc(VARHDRSZ + buf.len);
ereport(ERROR, SET_VARSIZE(res, VARHDRSZ + buf.len);
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), memcpy(VARDATA(res), buf.data, buf.len);
errmsg("Overflow - decode estimate too small"))); pfree(buf.data);
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0); PG_FREE_IF_COPY(data, 0);
PG_RETURN_TEXT_P(res); PG_RETURN_TEXT_P(res);
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
* contrib/pgcrypto/pgp.h * contrib/pgcrypto/pgp.h
*/ */
#include "lib/stringinfo.h"
#include "mbuf.h" #include "mbuf.h"
#include "px.h" #include "px.h"
...@@ -274,10 +276,8 @@ void pgp_cfb_free(PGP_CFB *ctx); ...@@ -274,10 +276,8 @@ void pgp_cfb_free(PGP_CFB *ctx);
int pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst); int pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
int pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst); int pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
int pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst); void pgp_armor_encode(const uint8 *src, int len, StringInfo dst);
int pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst); int pgp_armor_decode(const uint8 *src, int len, StringInfo dst);
unsigned pgp_armor_enc_len(unsigned len);
unsigned pgp_armor_dec_len(unsigned len);
int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst); int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst);
int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src); int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment