Skip to content

Commit 1dcfb8d

Browse files
committed
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
1 parent 56a312a commit 1dcfb8d

File tree

3 files changed

+59
-73
lines changed

3 files changed

+59
-73
lines changed

contrib/pgcrypto/pgp-armor.c

+34-43
Original file line numberDiff line numberDiff line change
@@ -203,38 +203,33 @@ crc24(const uint8 *data, unsigned len)
203203
return crc & 0xffffffL;
204204
}
205205

206-
int
207-
pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst)
206+
void
207+
pgp_armor_encode(const uint8 *src, int len, StringInfo dst)
208208
{
209-
int n;
210-
uint8 *pos = dst;
209+
int res;
210+
unsigned b64len;
211211
unsigned crc = crc24(src, len);
212212

213-
n = strlen(armor_header);
214-
memcpy(pos, armor_header, n);
215-
pos += n;
216-
217-
n = b64_encode(src, len, pos);
218-
pos += n;
213+
appendStringInfoString(dst, armor_header);
219214

220-
if (*(pos - 1) != '\n')
221-
*pos++ = '\n';
215+
/* make sure we have enough room to b64_encode() */
216+
b64len = b64_enc_len(len);
217+
enlargeStringInfo(dst, (int) b64len);
218+
res = b64_encode(src, len, (uint8 *) dst->data + dst->len);
219+
if (res > b64len)
220+
elog(FATAL, "overflow - encode estimate too small");
221+
dst->len += res;
222222

223-
*pos++ = '=';
224-
pos[3] = _base64[crc & 0x3f];
225-
crc >>= 6;
226-
pos[2] = _base64[crc & 0x3f];
227-
crc >>= 6;
228-
pos[1] = _base64[crc & 0x3f];
229-
crc >>= 6;
230-
pos[0] = _base64[crc & 0x3f];
231-
pos += 4;
223+
if (*(dst->data + dst->len - 1) != '\n')
224+
appendStringInfoChar(dst, '\n');
232225

233-
n = strlen(armor_footer);
234-
memcpy(pos, armor_footer, n);
235-
pos += n;
226+
appendStringInfoChar(dst, '=');
227+
appendStringInfoChar(dst, _base64[(crc >> 18) & 0x3f]);
228+
appendStringInfoChar(dst, _base64[(crc >> 12) & 0x3f]);
229+
appendStringInfoChar(dst, _base64[(crc >> 6) & 0x3f]);
230+
appendStringInfoChar(dst, _base64[crc & 0x3f]);
236231

237-
return pos - dst;
232+
appendStringInfoString(dst, armor_footer);
238233
}
239234

240235
static const uint8 *
@@ -309,7 +304,7 @@ find_header(const uint8 *data, const uint8 *datend,
309304
}
310305

311306
int
312-
pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
307+
pgp_armor_decode(const uint8 *src, int len, StringInfo dst)
313308
{
314309
const uint8 *p = src;
315310
const uint8 *data_end = src + len;
@@ -319,6 +314,7 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
319314
const uint8 *base64_end = NULL;
320315
uint8 buf[4];
321316
int hlen;
317+
int blen;
322318
int res = PXE_PGP_CORRUPT_ARMOR;
323319

324320
/* armor start */
@@ -360,23 +356,18 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
360356
crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
361357

362358
/* decode data */
363-
res = b64_decode(base64_start, base64_end - base64_start, dst);
364-
365-
/* check crc */
366-
if (res >= 0 && crc24(dst, res) != crc)
367-
res = PXE_PGP_CORRUPT_ARMOR;
359+
blen = (int) b64_dec_len(len);
360+
enlargeStringInfo(dst, blen);
361+
res = b64_decode(base64_start, base64_end - base64_start, (uint8 *) dst->data);
362+
if (res > blen)
363+
elog(FATAL, "overflow - decode estimate too small");
364+
if (res >= 0)
365+
{
366+
if (crc24((uint8 *) dst->data, res) == crc)
367+
dst->len += res;
368+
else
369+
res = PXE_PGP_CORRUPT_ARMOR;
370+
}
368371
out:
369372
return res;
370373
}
371-
372-
unsigned
373-
pgp_armor_enc_len(unsigned len)
374-
{
375-
return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
376-
}
377-
378-
unsigned
379-
pgp_armor_dec_len(unsigned len)
380-
{
381-
return b64_dec_len(len);
382-
}

contrib/pgcrypto/pgp-pgsql.c

+21-26
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include "postgres.h"
3333

34+
#include "lib/stringinfo.h"
3435
#include "mb/pg_wchar.h"
3536
#include "utils/builtins.h"
3637

@@ -820,23 +821,20 @@ pg_armor(PG_FUNCTION_ARGS)
820821
{
821822
bytea *data;
822823
text *res;
823-
int data_len,
824-
res_len,
825-
guess_len;
824+
int data_len;
825+
StringInfoData buf;
826826

827827
data = PG_GETARG_BYTEA_P(0);
828828
data_len = VARSIZE(data) - VARHDRSZ;
829829

830-
guess_len = pgp_armor_enc_len(data_len);
831-
res = palloc(VARHDRSZ + guess_len);
830+
initStringInfo(&buf);
832831

833-
res_len = pgp_armor_encode((uint8 *) VARDATA(data), data_len,
834-
(uint8 *) VARDATA(res));
835-
if (res_len > guess_len)
836-
ereport(ERROR,
837-
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
838-
errmsg("Overflow - encode estimate too small")));
839-
SET_VARSIZE(res, VARHDRSZ + res_len);
832+
pgp_armor_encode((uint8 *) VARDATA(data), data_len, &buf);
833+
834+
res = palloc(VARHDRSZ + buf.len);
835+
SET_VARSIZE(res, VARHDRSZ + buf.len);
836+
memcpy(VARDATA(res), buf.data, buf.len);
837+
pfree(buf.data);
840838

841839
PG_FREE_IF_COPY(data, 0);
842840
PG_RETURN_TEXT_P(res);
@@ -847,27 +845,24 @@ pg_dearmor(PG_FUNCTION_ARGS)
847845
{
848846
text *data;
849847
bytea *res;
850-
int data_len,
851-
res_len,
852-
guess_len;
848+
int data_len;
849+
int ret;
850+
StringInfoData buf;
853851

854852
data = PG_GETARG_TEXT_P(0);
855853
data_len = VARSIZE(data) - VARHDRSZ;
856854

857-
guess_len = pgp_armor_dec_len(data_len);
858-
res = palloc(VARHDRSZ + guess_len);
855+
initStringInfo(&buf);
859856

860-
res_len = pgp_armor_decode((uint8 *) VARDATA(data), data_len,
861-
(uint8 *) VARDATA(res));
862-
if (res_len < 0)
857+
ret = pgp_armor_decode((uint8 *) VARDATA(data), data_len, &buf);
858+
if (ret < 0)
863859
ereport(ERROR,
864860
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
865-
errmsg("%s", px_strerror(res_len))));
866-
if (res_len > guess_len)
867-
ereport(ERROR,
868-
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
869-
errmsg("Overflow - decode estimate too small")));
870-
SET_VARSIZE(res, VARHDRSZ + res_len);
861+
errmsg("%s", px_strerror(ret))));
862+
res = palloc(VARHDRSZ + buf.len);
863+
SET_VARSIZE(res, VARHDRSZ + buf.len);
864+
memcpy(VARDATA(res), buf.data, buf.len);
865+
pfree(buf.data);
871866

872867
PG_FREE_IF_COPY(data, 0);
873868
PG_RETURN_TEXT_P(res);

contrib/pgcrypto/pgp.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
* contrib/pgcrypto/pgp.h
3030
*/
3131

32+
#include "lib/stringinfo.h"
33+
3234
#include "mbuf.h"
3335
#include "px.h"
3436

@@ -274,10 +276,8 @@ void pgp_cfb_free(PGP_CFB *ctx);
274276
int pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
275277
int pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
276278

277-
int pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst);
278-
int pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst);
279-
unsigned pgp_armor_enc_len(unsigned len);
280-
unsigned pgp_armor_dec_len(unsigned len);
279+
void pgp_armor_encode(const uint8 *src, int len, StringInfo dst);
280+
int pgp_armor_decode(const uint8 *src, int len, StringInfo dst);
281281

282282
int pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst);
283283
int pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src);

0 commit comments

Comments
 (0)