Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions | Variables

pgp-decrypt.c File Reference

#include "postgres.h"
#include "px.h"
#include "mbuf.h"
#include "pgp.h"
Include dependency graph for pgp-decrypt.c:

Go to the source code of this file.

Data Structures

struct  PktData
struct  MDCBufData

Defines

#define NO_CTX_SIZE   0
#define ALLOW_CTX_SIZE   1
#define NO_COMPR   0
#define ALLOW_COMPR   1
#define NO_MDC   0
#define NEED_MDC   1
#define PKT_NORMAL   1
#define PKT_STREAM   2
#define PKT_CONTEXT   3
#define MAX_CHUNK   (16*1024*1024)
#define MDCBUF_LEN   8192

Functions

static int parse_new_len (PullFilter *src, int *len_p)
static int parse_old_len (PullFilter *src, int *len_p, int lentype)
int pgp_parse_pkt_hdr (PullFilter *src, uint8 *tag, int *len_p, int allow_ctx)
static int pktreader_pull (void *priv, PullFilter *src, int len, uint8 **data_p, uint8 *buf, int buflen)
static void pktreader_free (void *priv)
int pgp_create_pkt_reader (PullFilter **pf_p, PullFilter *src, int len, int pkttype, PGP_Context *ctx)
static int prefix_init (void **priv_p, void *arg, PullFilter *src)
static int decrypt_init (void **priv_p, void *arg, PullFilter *src)
static int decrypt_read (void *priv, PullFilter *src, int len, uint8 **data_p, uint8 *buf, int buflen)
static int mdc_init (void **priv_p, void *arg, PullFilter *src)
static void mdc_free (void *priv)
static int mdc_finish (PGP_Context *ctx, PullFilter *src, int len, uint8 **data_p)
static int mdc_read (void *priv, PullFilter *src, int len, uint8 **data_p, uint8 *buf, int buflen)
static int mdcbuf_init (void **priv_p, void *arg, PullFilter *src)
static int mdcbuf_finish (struct MDCBufData *st)
static void mdcbuf_load_data (struct MDCBufData *st, uint8 *src, int len)
static void mdcbuf_load_mdc (struct MDCBufData *st, uint8 *src, int len)
static int mdcbuf_refill (struct MDCBufData *st, PullFilter *src)
static int mdcbuf_read (void *priv, PullFilter *src, int len, uint8 **data_p, uint8 *buf, int buflen)
static void mdcbuf_free (void *priv)
static int decrypt_key (PGP_Context *ctx, const uint8 *src, int len)
static int parse_symenc_sesskey (PGP_Context *ctx, PullFilter *src)
static int copy_crlf (MBuf *dst, uint8 *data, int len, int *got_cr)
static int parse_literal_data (PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
static int process_data_packets (PGP_Context *ctx, MBuf *dst, PullFilter *src, int allow_compr, int need_mdc)
static int parse_compressed_data (PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
static int parse_symenc_data (PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
static int parse_symenc_mdc_data (PGP_Context *ctx, PullFilter *pkt, MBuf *dst)
int pgp_skip_packet (PullFilter *pkt)
int pgp_expect_packet_end (PullFilter *pkt)
int pgp_decrypt (PGP_Context *ctx, MBuf *msrc, MBuf *mdst)

Variables

static struct PullFilterOps pktreader_filter
static struct PullFilterOps prefix_filter
struct PullFilterOps pgp_decrypt_filter
static struct PullFilterOps mdc_filter
static struct PullFilterOps mdcbuf_filter

Define Documentation

#define ALLOW_COMPR   1

Definition at line 41 of file pgp-decrypt.c.

Referenced by parse_symenc_data(), and parse_symenc_mdc_data().

#define ALLOW_CTX_SIZE   1

Definition at line 39 of file pgp-decrypt.c.

Referenced by process_data_packets().

#define MAX_CHUNK   (16*1024*1024)

Definition at line 49 of file pgp-decrypt.c.

Referenced by parse_new_len(), and parse_old_len().

#define MDCBUF_LEN   8192

Definition at line 449 of file pgp-decrypt.c.

#define NEED_MDC   1

Definition at line 43 of file pgp-decrypt.c.

Referenced by parse_symenc_mdc_data().

#define NO_COMPR   0

Definition at line 40 of file pgp-decrypt.c.

Referenced by parse_compressed_data().

#define NO_CTX_SIZE   0

Definition at line 38 of file pgp-decrypt.c.

Referenced by pgp_decrypt().

#define NO_MDC   0

Definition at line 42 of file pgp-decrypt.c.

Referenced by parse_compressed_data(), parse_symenc_data(), and process_data_packets().

#define PKT_CONTEXT   3

Definition at line 47 of file pgp-decrypt.c.

Referenced by pgp_parse_pkt_hdr(), pktreader_pull(), and process_data_packets().

#define PKT_NORMAL   1

Definition at line 45 of file pgp-decrypt.c.

Referenced by pktreader_pull().

#define PKT_STREAM   2

Definition at line 46 of file pgp-decrypt.c.


Function Documentation

static int copy_crlf ( MBuf dst,
uint8 data,
int  len,
int *  got_cr 
) [static]

Definition at line 711 of file pgp-decrypt.c.

References mbuf_append(), and tmpbuf.

Referenced by parse_literal_data().

{
    uint8      *data_end = data + len;
    uint8       tmpbuf[1024];
    uint8      *tmp_end = tmpbuf + sizeof(tmpbuf);
    uint8      *p;
    int         res;

    p = tmpbuf;
    if (*got_cr)
    {
        if (*data != '\n')
            *p++ = '\r';
        *got_cr = 0;
    }
    while (data < data_end)
    {
        if (*data == '\r')
        {
            if (data + 1 < data_end)
            {
                if (*(data + 1) == '\n')
                    data++;
            }
            else
            {
                *got_cr = 1;
                break;
            }
        }
        *p++ = *data++;
        if (p >= tmp_end)
        {
            res = mbuf_append(dst, tmpbuf, p - tmpbuf);
            if (res < 0)
                return res;
            p = tmpbuf;
        }
    }
    if (p - tmpbuf > 0)
    {
        res = mbuf_append(dst, tmpbuf, p - tmpbuf);
        if (res < 0)
            return res;
    }
    return 0;
}

static int decrypt_init ( void **  priv_p,
void *  arg,
PullFilter src 
) [static]

Definition at line 297 of file pgp-decrypt.c.

{
    PGP_CFB    *cfb = arg;

    *priv_p = cfb;

    /* we need to write somewhere, so ask for a buffer */
    return 4096;
}

static int decrypt_key ( PGP_Context ctx,
const uint8 src,
int  len 
) [static]

Definition at line 609 of file pgp-decrypt.c.

References PGP_Context::cipher_algo, PGP_S2K::key, PGP_S2K::key_len, NULL, pgp_cfb_create(), pgp_cfb_decrypt(), pgp_cfb_free(), pgp_get_cipher_key_size(), px_debug(), PGP_Context::s2k, PGP_Context::s2k_cipher_algo, PGP_Context::sess_key, and PGP_Context::sess_key_len.

Referenced by parse_symenc_sesskey().

{
    int         res;
    uint8       algo;
    PGP_CFB    *cfb;

    res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
                         ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
    if (res < 0)
        return res;

    pgp_cfb_decrypt(cfb, src, 1, &algo);
    src++;
    len--;

    pgp_cfb_decrypt(cfb, src, len, ctx->sess_key);
    pgp_cfb_free(cfb);
    ctx->sess_key_len = len;
    ctx->cipher_algo = algo;

    if (pgp_get_cipher_key_size(algo) != len)
    {
        px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
                 algo, pgp_get_cipher_key_size(algo), len);
        return PXE_PGP_CORRUPT_DATA;
    }
    return 0;
}

static int decrypt_read ( void *  priv,
PullFilter src,
int  len,
uint8 **  data_p,
uint8 buf,
int  buflen 
) [static]

Definition at line 308 of file pgp-decrypt.c.

References pgp_cfb_decrypt(), and pullf_read().

{
    PGP_CFB    *cfb = priv;
    uint8      *tmp;
    int         res;

    res = pullf_read(src, len, &tmp);
    if (res > 0)
    {
        pgp_cfb_decrypt(cfb, tmp, res, buf);
        *data_p = buf;
    }
    return res;
}

static int mdc_finish ( PGP_Context ctx,
PullFilter src,
int  len,
uint8 **  data_p 
) [static]

Definition at line 354 of file pgp-decrypt.c.

References hash(), PGP_Context::in_mdc_pkt, PGP_Context::mdc_checked, PGP_Context::mdc_ctx, memcmp(), pullf_read_max(), px_debug(), px_md_finish, and tmpbuf.

Referenced by mdc_read().

{
    int         res;
    uint8       hash[20];
    uint8       tmpbuf[22];

    if (len + 1 > sizeof(tmpbuf))
        return PXE_BUG;

    /* read data */
    res = pullf_read_max(src, len + 1, data_p, tmpbuf);
    if (res < 0)
        return res;
    if (res == 0)
    {
        if (ctx->mdc_checked == 0)
        {
            px_debug("no mdc");
            return PXE_PGP_CORRUPT_DATA;
        }
        return 0;
    }

    /* safety check */
    if (ctx->in_mdc_pkt > 1)
    {
        px_debug("mdc_finish: several times here?");
        return PXE_PGP_CORRUPT_DATA;
    }
    ctx->in_mdc_pkt++;

    /* is the packet sane? */
    if (res != 20)
    {
        px_debug("mdc_finish: read failed, res=%d", res);
        return PXE_PGP_CORRUPT_DATA;
    }

    /*
     * ok, we got the hash, now check
     */
    px_md_finish(ctx->mdc_ctx, hash);
    res = memcmp(hash, *data_p, 20);
    memset(hash, 0, 20);
    memset(tmpbuf, 0, sizeof(tmpbuf));
    if (res != 0)
    {
        px_debug("mdc_finish: mdc failed");
        return PXE_PGP_CORRUPT_DATA;
    }
    ctx->mdc_checked = 1;
    return len;
}

static void mdc_free ( void *  priv  )  [static]

Definition at line 343 of file pgp-decrypt.c.

References PGP_Context::mdc_ctx, px_md_free, and PGP_Context::use_mdcbuf_filter.

{
    PGP_Context *ctx = priv;

    if (ctx->use_mdcbuf_filter)
        return;
    px_md_free(ctx->mdc_ctx);
    ctx->mdc_ctx = NULL;
}

static int mdc_init ( void **  priv_p,
void *  arg,
PullFilter src 
) [static]

Definition at line 334 of file pgp-decrypt.c.

References PGP_Context::mdc_ctx, PGP_DIGEST_SHA1, and pgp_load_digest().

{
    PGP_Context *ctx = arg;

    *priv_p = ctx;
    return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
}

static int mdc_read ( void *  priv,
PullFilter src,
int  len,
uint8 **  data_p,
uint8 buf,
int  buflen 
) [static]

Definition at line 410 of file pgp-decrypt.c.

References PGP_Context::in_mdc_pkt, PGP_Context::mdc_ctx, mdc_finish(), pullf_read(), px_debug(), px_md_update, and PGP_Context::use_mdcbuf_filter.

{
    int         res;
    PGP_Context *ctx = priv;

    /* skip this filter? */
    if (ctx->use_mdcbuf_filter)
        return pullf_read(src, len, data_p);

    if (ctx->in_mdc_pkt)
        return mdc_finish(ctx, src, len, data_p);

    res = pullf_read(src, len, data_p);
    if (res < 0)
        return res;
    if (res == 0)
    {
        px_debug("mdc_read: unexpected eof");
        return PXE_PGP_CORRUPT_DATA;
    }
    px_md_update(ctx->mdc_ctx, *data_p, res);

    return res;
}

static int mdcbuf_finish ( struct MDCBufData st  )  [static]

Definition at line 481 of file pgp-decrypt.c.

References MDCBufData::ctx, MDCBufData::eof, hash(), MDCBufData::mdc_buf, PGP_Context::mdc_ctx, memcmp(), px_debug(), px_md_finish, and px_md_update.

Referenced by mdcbuf_refill().

{
    uint8       hash[20];
    int         res;

    st->eof = 1;

    if (st->mdc_buf[0] != 0xD3 || st->mdc_buf[1] != 0x14)
    {
        px_debug("mdcbuf_finish: bad MDC pkt hdr");
        return PXE_PGP_CORRUPT_DATA;
    }
    px_md_update(st->ctx->mdc_ctx, st->mdc_buf, 2);
    px_md_finish(st->ctx->mdc_ctx, hash);
    res = memcmp(hash, st->mdc_buf + 2, 20);
    memset(hash, 0, 20);
    if (res)
    {
        px_debug("mdcbuf_finish: MDC does not match");
        res = PXE_PGP_CORRUPT_DATA;
    }
    return res;
}

static void mdcbuf_free ( void *  priv  )  [static]

Definition at line 590 of file pgp-decrypt.c.

References MDCBufData::ctx, PGP_Context::mdc_ctx, px_free, and px_md_free.

{
    struct MDCBufData *st = priv;

    px_md_free(st->ctx->mdc_ctx);
    st->ctx->mdc_ctx = NULL;
    memset(st, 0, sizeof(*st));
    px_free(st);
}

static int mdcbuf_init ( void **  priv_p,
void *  arg,
PullFilter src 
) [static]

Definition at line 463 of file pgp-decrypt.c.

References MDCBufData::buf, MDCBufData::buflen, MDCBufData::ctx, px_alloc, and PGP_Context::use_mdcbuf_filter.

{
    PGP_Context *ctx = arg;
    struct MDCBufData *st;

    st = px_alloc(sizeof(*st));
    memset(st, 0, sizeof(*st));
    st->buflen = sizeof(st->buf);
    st->ctx = ctx;
    *priv_p = st;

    /* take over the work of mdc_filter */
    ctx->use_mdcbuf_filter = 1;

    return 0;
}

static void mdcbuf_load_data ( struct MDCBufData st,
uint8 src,
int  len 
) [static]

Definition at line 506 of file pgp-decrypt.c.

References MDCBufData::avail, MDCBufData::ctx, PGP_Context::mdc_ctx, MDCBufData::pos, and px_md_update.

Referenced by mdcbuf_refill().

{
    uint8      *dst = st->pos + st->avail;

    memcpy(dst, src, len);
    px_md_update(st->ctx->mdc_ctx, src, len);
    st->avail += len;
}

static void mdcbuf_load_mdc ( struct MDCBufData st,
uint8 src,
int  len 
) [static]

Definition at line 516 of file pgp-decrypt.c.

References MDCBufData::mdc_avail, MDCBufData::mdc_buf, and memmove.

Referenced by mdcbuf_refill().

{
    memmove(st->mdc_buf + st->mdc_avail, src, len);
    st->mdc_avail += len;
}

static int mdcbuf_read ( void *  priv,
PullFilter src,
int  len,
uint8 **  data_p,
uint8 buf,
int  buflen 
) [static]

Definition at line 567 of file pgp-decrypt.c.

References MDCBufData::avail, MDCBufData::eof, mdcbuf_refill(), and MDCBufData::pos.

{
    struct MDCBufData *st = priv;
    int         res;

    if (!st->eof && len > st->avail)
    {
        res = mdcbuf_refill(st, src);
        if (res < 0)
            return res;
    }

    if (len > st->avail)
        len = st->avail;

    *data_p = st->pos;
    st->pos += len;
    st->avail -= len;
    return len;
}

static int mdcbuf_refill ( struct MDCBufData st,
PullFilter src 
) [static]

Definition at line 523 of file pgp-decrypt.c.

References MDCBufData::avail, MDCBufData::buf, MDCBufData::buflen, MDCBufData::mdc_avail, MDCBufData::mdc_buf, mdcbuf_finish(), mdcbuf_load_data(), mdcbuf_load_mdc(), memmove, MDCBufData::pos, and pullf_read().

Referenced by mdcbuf_read().

{
    uint8      *data;
    int         res;
    int         need;

    /* put avail data in start */
    if (st->avail > 0 && st->pos != st->buf)
        memmove(st->buf, st->pos, st->avail);
    st->pos = st->buf;

    /* read new data */
    need = st->buflen + 22 - st->avail - st->mdc_avail;
    res = pullf_read(src, need, &data);
    if (res < 0)
        return res;
    if (res == 0)
        return mdcbuf_finish(st);

    /* add to buffer */
    if (res >= 22)
    {
        mdcbuf_load_data(st, st->mdc_buf, st->mdc_avail);
        st->mdc_avail = 0;

        mdcbuf_load_data(st, data, res - 22);
        mdcbuf_load_mdc(st, data + res - 22, 22);
    }
    else
    {
        int         canmove = st->mdc_avail + res - 22;

        if (canmove > 0)
        {
            mdcbuf_load_data(st, st->mdc_buf, canmove);
            st->mdc_avail -= canmove;
            memmove(st->mdc_buf, st->mdc_buf + canmove, st->mdc_avail);
        }
        mdcbuf_load_mdc(st, data, res);
    }
    return 0;
}

static int parse_compressed_data ( PGP_Context ctx,
MBuf dst,
PullFilter pkt 
) [static]

Definition at line 831 of file pgp-decrypt.c.

References PGP_Context::compress_algo, GETBYTE, NO_COMPR, NO_MDC, PGP_COMPR_BZIP2, PGP_COMPR_NONE, PGP_COMPR_ZIP, PGP_COMPR_ZLIB, pgp_decompress_filter(), process_data_packets(), pullf_free(), and px_debug().

Referenced by process_data_packets().

{
    int         res;
    uint8       type;
    PullFilter *pf_decompr;

    GETBYTE(pkt, type);

    ctx->compress_algo = type;
    switch (type)
    {
        case PGP_COMPR_NONE:
            res = process_data_packets(ctx, dst, pkt, NO_COMPR, NO_MDC);
            break;

        case PGP_COMPR_ZIP:
        case PGP_COMPR_ZLIB:
            res = pgp_decompress_filter(&pf_decompr, ctx, pkt);
            if (res >= 0)
            {
                res = process_data_packets(ctx, dst, pf_decompr,
                                           NO_COMPR, NO_MDC);
                pullf_free(pf_decompr);
            }
            break;

        case PGP_COMPR_BZIP2:
            px_debug("parse_compressed_data: bzip2 unsupported");
            res = PXE_PGP_UNSUPPORTED_COMPR;
            break;

        default:
            px_debug("parse_compressed_data: unknown compr type");
            res = PXE_PGP_CORRUPT_DATA;
    }

    return res;
}

static int parse_literal_data ( PGP_Context ctx,
MBuf dst,
PullFilter pkt 
) [static]

Definition at line 760 of file pgp-decrypt.c.

References buf, PGP_Context::convert_crlf, copy_crlf(), GETBYTE, mbuf_append(), pullf_read(), pullf_read_max(), px_debug(), PGP_Context::text_mode, tmpbuf, and PGP_Context::unicode_mode.

Referenced by process_data_packets().

{
    int         type;
    int         name_len;
    int         res;
    uint8      *buf;
    uint8       tmpbuf[4];
    int         got_cr = 0;

    GETBYTE(pkt, type);
    GETBYTE(pkt, name_len);

    /* skip name */
    while (name_len > 0)
    {
        res = pullf_read(pkt, name_len, &buf);
        if (res < 0)
            return res;
        if (res == 0)
            break;
        name_len -= res;
    }
    if (name_len > 0)
    {
        px_debug("parse_literal_data: unexpected eof");
        return PXE_PGP_CORRUPT_DATA;
    }

    /* skip date */
    res = pullf_read_max(pkt, 4, &buf, tmpbuf);
    if (res != 4)
    {
        px_debug("parse_literal_data: unexpected eof");
        return PXE_PGP_CORRUPT_DATA;
    }
    memset(tmpbuf, 0, 4);

    /* check if text */
    if (ctx->text_mode)
        if (type != 't' && type != 'u')
        {
            px_debug("parse_literal_data: data type=%c", type);
            return PXE_PGP_NOT_TEXT;
        }

    ctx->unicode_mode = (type == 'u') ? 1 : 0;

    /* read data */
    while (1)
    {
        res = pullf_read(pkt, 32 * 1024, &buf);
        if (res <= 0)
            break;

        if (ctx->text_mode && ctx->convert_crlf)
            res = copy_crlf(dst, buf, res, &got_cr);
        else
            res = mbuf_append(dst, buf, res);
        if (res < 0)
            break;
    }
    if (res >= 0 && got_cr)
        res = mbuf_append(dst, (const uint8 *) "\r", 1);
    return res;
}

static int parse_new_len ( PullFilter src,
int *  len_p 
) [static]

Definition at line 52 of file pgp-decrypt.c.

References GETBYTE, MAX_CHUNK, and px_debug().

Referenced by pgp_parse_pkt_hdr(), and pktreader_pull().

{
    uint8       b;
    int         len;
    int         pkttype = PKT_NORMAL;

    GETBYTE(src, b);
    if (b <= 191)
        len = b;
    else if (b >= 192 && b <= 223)
    {
        len = ((unsigned) (b) - 192) << 8;
        GETBYTE(src, b);
        len += 192 + b;
    }
    else if (b == 255)
    {
        GETBYTE(src, b);
        len = b;
        GETBYTE(src, b);
        len = (len << 8) | b;
        GETBYTE(src, b);
        len = (len << 8) | b;
        GETBYTE(src, b);
        len = (len << 8) | b;
    }
    else
    {
        len = 1 << (b & 0x1F);
        pkttype = PKT_STREAM;
    }

    if (len < 0 || len > MAX_CHUNK)
    {
        px_debug("parse_new_len: weird length");
        return PXE_PGP_CORRUPT_DATA;
    }

    *len_p = len;
    return pkttype;
}

static int parse_old_len ( PullFilter src,
int *  len_p,
int  lentype 
) [static]

Definition at line 95 of file pgp-decrypt.c.

References GETBYTE, MAX_CHUNK, and px_debug().

Referenced by pgp_parse_pkt_hdr().

{
    uint8       b;
    int         len;

    GETBYTE(src, b);
    len = b;

    if (lentype == 1)
    {
        GETBYTE(src, b);
        len = (len << 8) | b;
    }
    else if (lentype == 2)
    {
        GETBYTE(src, b);
        len = (len << 8) | b;
        GETBYTE(src, b);
        len = (len << 8) | b;
        GETBYTE(src, b);
        len = (len << 8) | b;
    }

    if (len < 0 || len > MAX_CHUNK)
    {
        px_debug("parse_old_len: weird length");
        return PXE_PGP_CORRUPT_DATA;
    }
    *len_p = len;
    return PKT_NORMAL;
}

static int parse_symenc_data ( PGP_Context ctx,
PullFilter pkt,
MBuf dst 
) [static]

Definition at line 978 of file pgp-decrypt.c.

References ALLOW_COMPR, PGP_Context::cipher_algo, NO_MDC, NULL, pgp_cfb_create(), pgp_cfb_free(), process_data_packets(), pullf_create(), pullf_free(), PGP_Context::sess_key, and PGP_Context::sess_key_len.

Referenced by pgp_decrypt().

{
    int         res;
    PGP_CFB    *cfb = NULL;
    PullFilter *pf_decrypt = NULL;
    PullFilter *pf_prefix = NULL;

    res = pgp_cfb_create(&cfb, ctx->cipher_algo,
                         ctx->sess_key, ctx->sess_key_len, 1, NULL);
    if (res < 0)
        goto out;

    res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
    if (res < 0)
        goto out;

    res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_decrypt);
    if (res < 0)
        goto out;

    res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NO_MDC);

out:
    if (pf_prefix)
        pullf_free(pf_prefix);
    if (pf_decrypt)
        pullf_free(pf_decrypt);
    if (cfb)
        pgp_cfb_free(cfb);

    return res;
}

static int parse_symenc_mdc_data ( PGP_Context ctx,
PullFilter pkt,
MBuf dst 
) [static]

Definition at line 1012 of file pgp-decrypt.c.

References ALLOW_COMPR, PGP_Context::cipher_algo, GETBYTE, NEED_MDC, NULL, pgp_cfb_create(), pgp_cfb_free(), process_data_packets(), pullf_create(), pullf_free(), px_debug(), PGP_Context::sess_key, and PGP_Context::sess_key_len.

Referenced by pgp_decrypt().

{
    int         res;
    PGP_CFB    *cfb = NULL;
    PullFilter *pf_decrypt = NULL;
    PullFilter *pf_prefix = NULL;
    PullFilter *pf_mdc = NULL;
    uint8       ver;

    GETBYTE(pkt, ver);
    if (ver != 1)
    {
        px_debug("parse_symenc_mdc_data: pkt ver != 1");
        return PXE_PGP_CORRUPT_DATA;
    }

    res = pgp_cfb_create(&cfb, ctx->cipher_algo,
                         ctx->sess_key, ctx->sess_key_len, 0, NULL);
    if (res < 0)
        goto out;

    res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
    if (res < 0)
        goto out;

    res = pullf_create(&pf_mdc, &mdc_filter, ctx, pf_decrypt);
    if (res < 0)
        goto out;

    res = pullf_create(&pf_prefix, &prefix_filter, ctx, pf_mdc);
    if (res < 0)
        goto out;

    res = process_data_packets(ctx, dst, pf_prefix, ALLOW_COMPR, NEED_MDC);

out:
    if (pf_prefix)
        pullf_free(pf_prefix);
    if (pf_mdc)
        pullf_free(pf_mdc);
    if (pf_decrypt)
        pullf_free(pf_decrypt);
    if (cfb)
        pgp_cfb_free(cfb);

    return res;
}

static int parse_symenc_sesskey ( PGP_Context ctx,
PullFilter src 
) [static]

Definition at line 642 of file pgp-decrypt.c.

References PGP_Context::cipher_algo, decrypt_key(), PGP_S2K::digest_algo, GETBYTE, PGP_S2K::key, PGP_S2K::key_len, PGP_S2K::mode, PGP_MAX_KEY, pgp_s2k_process(), pgp_s2k_read(), pullf_read_max(), px_debug(), PGP_Context::s2k, PGP_Context::s2k_cipher_algo, PGP_Context::s2k_digest_algo, PGP_Context::s2k_mode, PGP_Context::sess_key, PGP_Context::sess_key_len, PGP_Context::sym_key, PGP_Context::sym_key_len, tmpbuf, and PGP_Context::use_sess_key.

Referenced by pgp_decrypt().

{
    uint8      *p;
    int         res;
    uint8       tmpbuf[PGP_MAX_KEY + 2];
    uint8       ver;

    GETBYTE(src, ver);
    GETBYTE(src, ctx->s2k_cipher_algo);
    if (ver != 4)
    {
        px_debug("bad key pkt ver");
        return PXE_PGP_CORRUPT_DATA;
    }

    /*
     * read S2K info
     */
    res = pgp_s2k_read(src, &ctx->s2k);
    if (res < 0)
        return res;
    ctx->s2k_mode = ctx->s2k.mode;
    ctx->s2k_digest_algo = ctx->s2k.digest_algo;

    /*
     * generate key from password
     */
    res = pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
                          ctx->sym_key, ctx->sym_key_len);
    if (res < 0)
        return res;

    /*
     * do we have separate session key?
     */
    res = pullf_read_max(src, PGP_MAX_KEY + 2, &p, tmpbuf);
    if (res < 0)
        return res;

    if (res == 0)
    {
        /*
         * no, s2k key is session key
         */
        memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
        ctx->sess_key_len = ctx->s2k.key_len;
        ctx->cipher_algo = ctx->s2k_cipher_algo;
        res = 0;
        ctx->use_sess_key = 0;
    }
    else
    {
        /*
         * yes, decrypt it
         */
        if (res < 17 || res > PGP_MAX_KEY + 1)
        {
            px_debug("expect key, but bad data");
            return PXE_PGP_CORRUPT_DATA;
        }
        ctx->use_sess_key = 1;
        res = decrypt_key(ctx, p, res);
    }

    memset(tmpbuf, 0, sizeof(tmpbuf));
    return res;
}

int pgp_create_pkt_reader ( PullFilter **  pf_p,
PullFilter src,
int  len,
int  pkttype,
PGP_Context ctx 
)

Definition at line 223 of file pgp-decrypt.c.

References PktData::len, pullf_create(), px_alloc, px_free, and PktData::type.

Referenced by internal_read_key(), pgp_decrypt(), pgp_get_keyid(), and process_data_packets().

{
    int         res;
    struct PktData *pkt = px_alloc(sizeof(*pkt));

    pkt->type = pkttype;
    pkt->len = len;
    res = pullf_create(pf_p, &pktreader_filter, pkt, src);
    if (res < 0)
        px_free(pkt);
    return res;
}

int pgp_decrypt ( PGP_Context ctx,
MBuf msrc,
MBuf mdst 
)

Definition at line 1096 of file pgp-decrypt.c.

References PGP_Context::corrupt_prefix, PGP_Context::disable_mdc, NO_CTX_SIZE, parse_symenc_data(), parse_symenc_mdc_data(), parse_symenc_sesskey(), pgp_create_pkt_reader(), pgp_parse_pkt_hdr(), pgp_parse_pubenc_sesskey(), PGP_PKT_MARKER, PGP_PKT_PUBENCRYPTED_SESSKEY, PGP_PKT_SYMENCRYPTED_DATA, PGP_PKT_SYMENCRYPTED_DATA_MDC, PGP_PKT_SYMENCRYPTED_SESSKEY, pgp_skip_packet(), pullf_create_mbuf_reader(), pullf_free(), and px_debug().

Referenced by decrypt_internal().

{
    int         res;
    PullFilter *src = NULL;
    PullFilter *pkt = NULL;
    uint8       tag;
    int         len;
    int         got_key = 0;
    int         got_data = 0;

    res = pullf_create_mbuf_reader(&src, msrc);

    while (res >= 0)
    {
        res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
        if (res <= 0)
            break;

        res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
        if (res < 0)
            break;

        res = PXE_PGP_CORRUPT_DATA;
        switch (tag)
        {
            case PGP_PKT_MARKER:
                res = pgp_skip_packet(pkt);
                break;
            case PGP_PKT_PUBENCRYPTED_SESSKEY:
                /* fixme: skip those */
                res = pgp_parse_pubenc_sesskey(ctx, pkt);
                got_key = 1;
                break;
            case PGP_PKT_SYMENCRYPTED_SESSKEY:
                if (got_key)

                    /*
                     * Theoretically, there could be several keys, both public
                     * and symmetric, all of which encrypt same session key.
                     * Decrypt should try with each one, before failing.
                     */
                    px_debug("pgp_decrypt: using first of several keys");
                else
                {
                    got_key = 1;
                    res = parse_symenc_sesskey(ctx, pkt);
                }
                break;
            case PGP_PKT_SYMENCRYPTED_DATA:
                if (!got_key)
                    px_debug("pgp_decrypt: have data but no key");
                else if (got_data)
                    px_debug("pgp_decrypt: got second data packet");
                else
                {
                    got_data = 1;
                    ctx->disable_mdc = 1;
                    res = parse_symenc_data(ctx, pkt, mdst);
                }
                break;
            case PGP_PKT_SYMENCRYPTED_DATA_MDC:
                if (!got_key)
                    px_debug("pgp_decrypt: have data but no key");
                else if (got_data)
                    px_debug("pgp_decrypt: several data pkts not supported");
                else
                {
                    got_data = 1;
                    ctx->disable_mdc = 0;
                    res = parse_symenc_mdc_data(ctx, pkt, mdst);
                }
                break;
            default:
                px_debug("pgp_decrypt: unknown tag: 0x%02x", tag);
        }
        pullf_free(pkt);
        pkt = NULL;
    }

    if (pkt)
        pullf_free(pkt);

    if (src)
        pullf_free(src);

    if (res < 0)
        return res;

    if (!got_data || ctx->corrupt_prefix)
        res = PXE_PGP_CORRUPT_DATA;

    return res;
}

int pgp_expect_packet_end ( PullFilter pkt  ) 

Definition at line 1078 of file pgp-decrypt.c.

References pullf_read(), and px_debug().

Referenced by pgp_parse_pubenc_sesskey(), and process_secret_key().

{
    int         res = 1;
    uint8      *tmp;

    while (res > 0)
    {
        res = pullf_read(pkt, 32 * 1024, &tmp);
        if (res > 0)
        {
            px_debug("pgp_expect_packet_end: got data");
            return PXE_PGP_CORRUPT_DATA;
        }
    }
    return res < 0 ? res : 0;
}

int pgp_parse_pkt_hdr ( PullFilter src,
uint8 tag,
int *  len_p,
int  allow_ctx 
)

Definition at line 129 of file pgp-decrypt.c.

References parse_new_len(), parse_old_len(), PKT_CONTEXT, pullf_read(), and px_debug().

Referenced by internal_read_key(), pgp_decrypt(), pgp_get_keyid(), and process_data_packets().

{
    int         lentype;
    int         res;
    uint8      *p;

    /* EOF is normal here, thus we dont use GETBYTE */
    res = pullf_read(src, 1, &p);
    if (res < 0)
        return res;
    if (res == 0)
        return 0;

    if ((*p & 0x80) == 0)
    {
        px_debug("pgp_parse_pkt_hdr: not pkt hdr");
        return PXE_PGP_CORRUPT_DATA;
    }

    if (*p & 0x40)
    {
        *tag = *p & 0x3f;
        res = parse_new_len(src, len_p);
    }
    else
    {
        lentype = *p & 3;
        *tag = (*p >> 2) & 0x0F;
        if (lentype == 3)
            res = allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
        else
            res = parse_old_len(src, len_p, lentype);
    }
    return res;
}

int pgp_skip_packet ( PullFilter pkt  ) 

Definition at line 1064 of file pgp-decrypt.c.

References pullf_read().

Referenced by internal_read_key(), pgp_decrypt(), pgp_get_keyid(), read_pubenc_keyid(), and read_pubkey_keyid().

{
    int         res = 1;
    uint8      *tmp;

    while (res > 0)
        res = pullf_read(pkt, 32 * 1024, &tmp);
    return res < 0 ? res : 0;
}

static void pktreader_free ( void *  priv  )  [static]

Definition at line 209 of file pgp-decrypt.c.

References px_free.

{
    struct PktData *pkt = priv;

    memset(pkt, 0, sizeof(*pkt));
    px_free(pkt);
}

static int pktreader_pull ( void *  priv,
PullFilter src,
int  len,
uint8 **  data_p,
uint8 buf,
int  buflen 
) [static]

Definition at line 175 of file pgp-decrypt.c.

References PktData::len, parse_new_len(), PKT_CONTEXT, PKT_NORMAL, pullf_read(), and PktData::type.

{
    int         res;
    struct PktData *pkt = priv;

    /* PKT_CONTEXT means: whatever there is */
    if (pkt->type == PKT_CONTEXT)
        return pullf_read(src, len, data_p);

    if (pkt->len == 0)
    {
        /* this was last chunk in stream */
        if (pkt->type == PKT_NORMAL)
            return 0;

        /* next chunk in stream */
        res = parse_new_len(src, &pkt->len);
        if (res < 0)
            return res;
        pkt->type = res;
    }

    if (len > pkt->len)
        len = pkt->len;

    res = pullf_read(src, len, data_p);
    if (res > 0)
        pkt->len -= res;

    return res;
}

static int prefix_init ( void **  priv_p,
void *  arg,
PullFilter src 
) [static]

Definition at line 242 of file pgp-decrypt.c.

References buf, PGP_Context::cipher_algo, PGP_Context::corrupt_prefix, PktData::len, pgp_get_cipher_block_size(), PGP_MAX_BLOCK, pullf_read_max(), px_debug(), and tmpbuf.

{
    PGP_Context *ctx = arg;
    int         len;
    int         res;
    uint8      *buf;
    uint8       tmpbuf[PGP_MAX_BLOCK + 2];

    len = pgp_get_cipher_block_size(ctx->cipher_algo);
    if (len > sizeof(tmpbuf))
        return PXE_BUG;

    res = pullf_read_max(src, len + 2, &buf, tmpbuf);
    if (res < 0)
        return res;
    if (res != len + 2)
    {
        px_debug("prefix_init: short read");
        memset(tmpbuf, 0, sizeof(tmpbuf));
        return PXE_PGP_CORRUPT_DATA;
    }

    if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
    {
        px_debug("prefix_init: corrupt prefix");

        /*
         * The original purpose of the 2-byte check was to show user a
         * friendly "wrong key" message. This made following possible:
         *
         * "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge
         * Mister and Robert Zuccherato
         *
         * To avoid being 'oracle', we delay reporting, which basically means
         * we prefer to run into corrupt packet header.
         *
         * We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is
         * possibility of attack via timing, so we don't.
         */
        ctx->corrupt_prefix = 1;
    }
    memset(tmpbuf, 0, sizeof(tmpbuf));
    return 0;
}

static int process_data_packets ( PGP_Context ctx,
MBuf dst,
PullFilter src,
int  allow_compr,
int  need_mdc 
) [static]

Definition at line 871 of file pgp-decrypt.c.

References ALLOW_CTX_SIZE, PGP_Context::in_mdc_pkt, NO_MDC, parse_compressed_data(), parse_literal_data(), pgp_create_pkt_reader(), pgp_parse_pkt_hdr(), PGP_PKT_COMPRESSED_DATA, PGP_PKT_LITERAL_DATA, PGP_PKT_MDC, PKT_CONTEXT, pullf_create(), pullf_free(), pullf_read(), px_debug(), and PGP_Context::use_mdcbuf_filter.

Referenced by parse_compressed_data(), parse_symenc_data(), and parse_symenc_mdc_data().

{
    uint8       tag;
    int         len,
                res;
    int         got_data = 0;
    int         got_mdc = 0;
    PullFilter *pkt = NULL;
    uint8      *tmp;

    while (1)
    {
        res = pgp_parse_pkt_hdr(src, &tag, &len, ALLOW_CTX_SIZE);
        if (res <= 0)
            break;


        /* mdc packet should be last */
        if (got_mdc)
        {
            px_debug("process_data_packets: data after mdc");
            res = PXE_PGP_CORRUPT_DATA;
            break;
        }

        /* context length inside SYMENC_MDC needs special handling */
        if (need_mdc && res == PKT_CONTEXT)
            res = pullf_create(&pkt, &mdcbuf_filter, ctx, src);
        else
            res = pgp_create_pkt_reader(&pkt, src, len, res, ctx);
        if (res < 0)
            break;

        switch (tag)
        {
            case PGP_PKT_LITERAL_DATA:
                got_data = 1;
                res = parse_literal_data(ctx, dst, pkt);
                break;
            case PGP_PKT_COMPRESSED_DATA:
                if (allow_compr == 0)
                {
                    px_debug("process_data_packets: unexpected compression");
                    res = PXE_PGP_CORRUPT_DATA;
                }
                else if (got_data)
                {
                    /*
                     * compr data must be alone
                     */
                    px_debug("process_data_packets: only one cmpr pkt allowed");
                    res = PXE_PGP_CORRUPT_DATA;
                }
                else
                {
                    got_data = 1;
                    res = parse_compressed_data(ctx, dst, pkt);
                }
                break;
            case PGP_PKT_MDC:
                if (need_mdc == NO_MDC)
                {
                    px_debug("process_data_packets: unexpected MDC");
                    res = PXE_PGP_CORRUPT_DATA;
                    break;
                }

                /* notify mdc_filter */
                ctx->in_mdc_pkt = 1;

                res = pullf_read(pkt, 8192, &tmp);
                if (res > 0)
                    got_mdc = 1;
                break;
            default:
                px_debug("process_data_packets: unexpected pkt tag=%d", tag);
                res = PXE_PGP_CORRUPT_DATA;
        }

        pullf_free(pkt);
        pkt = NULL;

        if (res < 0)
            break;
    }

    if (pkt)
        pullf_free(pkt);

    if (res < 0)
        return res;

    if (!got_data)
    {
        px_debug("process_data_packets: no data");
        res = PXE_PGP_CORRUPT_DATA;
    }
    if (need_mdc && !got_mdc && !ctx->use_mdcbuf_filter)
    {
        px_debug("process_data_packets: got no mdc");
        res = PXE_PGP_CORRUPT_DATA;
    }
    return res;
}


Variable Documentation

struct PullFilterOps mdc_filter [static]
Initial value:
 {
    mdc_init, mdc_read, mdc_free
}

Definition at line 436 of file pgp-decrypt.c.

struct PullFilterOps mdcbuf_filter [static]
Initial value:
 {
    mdcbuf_init, mdcbuf_read, mdcbuf_free
}

Definition at line 600 of file pgp-decrypt.c.

Initial value:
 {
    decrypt_init, decrypt_read, NULL
}

Definition at line 324 of file pgp-decrypt.c.

Referenced by process_secret_key().

Initial value:
 {
    NULL, pktreader_pull, pktreader_free
}

Definition at line 217 of file pgp-decrypt.c.

struct PullFilterOps prefix_filter [static]
Initial value:
 {
    prefix_init, NULL, NULL
}

Definition at line 287 of file pgp-decrypt.c.