Header And Logo

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

Defines | Functions

pgp-pubkey.c File Reference

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

Go to the source code of this file.

Defines

#define HIDE_CLEAR   0
#define HIDE_CKSUM   255
#define HIDE_SHA1   254

Functions

int pgp_key_alloc (PGP_PubKey **pk_p)
void pgp_key_free (PGP_PubKey *pk)
static int calc_key_id (PGP_PubKey *pk)
int _pgp_read_public_key (PullFilter *pkt, PGP_PubKey **pk_p)
static int check_key_sha1 (PullFilter *src, PGP_PubKey *pk)
static int check_key_cksum (PullFilter *src, PGP_PubKey *pk)
static int process_secret_key (PullFilter *pkt, PGP_PubKey **pk_p, const uint8 *key, int key_len)
static int internal_read_key (PullFilter *src, PGP_PubKey **pk_p, const uint8 *psw, int psw_len, int pubtype)
int pgp_set_pubkey (PGP_Context *ctx, MBuf *keypkt, const uint8 *key, int key_len, int pubtype)

Define Documentation

#define HIDE_CKSUM   255

Definition at line 250 of file pgp-pubkey.c.

Referenced by process_secret_key().

#define HIDE_CLEAR   0

Definition at line 249 of file pgp-pubkey.c.

Referenced by process_secret_key().

#define HIDE_SHA1   254

Definition at line 251 of file pgp-pubkey.c.

Referenced by process_secret_key().


Function Documentation

int _pgp_read_public_key ( PullFilter pkt,
PGP_PubKey **  pk_p 
)

Definition at line 159 of file pgp-pubkey.c.

References PGP_PubKey::algo, calc_key_id(), PGP_PubKey::can_encrypt, PGP_PubKey::dsa, PGP_PubKey::elg, GETBYTE, pgp_key_alloc(), pgp_key_free(), pgp_mpi_read(), PGP_PUB_DSA_SIGN, PGP_PUB_ELG_ENCRYPT, PGP_PUB_RSA_ENCRYPT, PGP_PUB_RSA_ENCRYPT_SIGN, PGP_PUB_RSA_SIGN, PGP_PubKey::pub, pullf_read_fixed(), px_debug(), PGP_PubKey::rsa, PGP_PubKey::time, and PGP_PubKey::ver.

Referenced by internal_read_key(), process_secret_key(), and read_pubkey_keyid().

{
    int         res;
    PGP_PubKey *pk;

    res = pgp_key_alloc(&pk);
    if (res < 0)
        return res;

    /* get version */
    GETBYTE(pkt, pk->ver);
    if (pk->ver != 4)
    {
        res = PXE_PGP_NOT_V4_KEYPKT;
        goto out;
    }

    /* read time */
    res = pullf_read_fixed(pkt, 4, pk->time);
    if (res < 0)
        goto out;

    /* pubkey algorithm */
    GETBYTE(pkt, pk->algo);

    switch (pk->algo)
    {
        case PGP_PUB_DSA_SIGN:
            res = pgp_mpi_read(pkt, &pk->pub.dsa.p);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->pub.dsa.q);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->pub.dsa.g);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->pub.dsa.y);
            if (res < 0)
                break;

            res = calc_key_id(pk);
            break;

        case PGP_PUB_RSA_SIGN:
        case PGP_PUB_RSA_ENCRYPT:
        case PGP_PUB_RSA_ENCRYPT_SIGN:
            res = pgp_mpi_read(pkt, &pk->pub.rsa.n);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->pub.rsa.e);
            if (res < 0)
                break;

            res = calc_key_id(pk);

            if (pk->algo != PGP_PUB_RSA_SIGN)
                pk->can_encrypt = 1;
            break;

        case PGP_PUB_ELG_ENCRYPT:
            res = pgp_mpi_read(pkt, &pk->pub.elg.p);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->pub.elg.g);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->pub.elg.y);
            if (res < 0)
                break;

            res = calc_key_id(pk);

            pk->can_encrypt = 1;
            break;

        default:
            px_debug("unknown public algo: %d", pk->algo);
            res = PXE_PGP_UNKNOWN_PUBALGO;
    }

out:
    if (res < 0)
        pgp_key_free(pk);
    else
        *pk_p = pk;

    return res;
}

static int calc_key_id ( PGP_PubKey pk  )  [static]

Definition at line 85 of file pgp-pubkey.c.

References PGP_PubKey::algo, PGP_PubKey::dsa, PGP_PubKey::elg, hash(), PGP_PubKey::key_id, PGP_DIGEST_SHA1, pgp_load_digest(), pgp_mpi_hash(), PGP_PUB_DSA_SIGN, PGP_PUB_ELG_ENCRYPT, PGP_PUB_RSA_ENCRYPT, PGP_PUB_RSA_ENCRYPT_SIGN, PGP_PUB_RSA_SIGN, PGP_PubKey::pub, px_md_finish, px_md_free, px_md_update, PGP_PubKey::rsa, PGP_PubKey::time, and PGP_PubKey::ver.

Referenced by _pgp_read_public_key().

{
    int         res;
    PX_MD      *md;
    int         len;
    uint8       hdr[3];
    uint8       hash[20];

    res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
    if (res < 0)
        return res;

    len = 1 + 4 + 1;
    switch (pk->algo)
    {
        case PGP_PUB_ELG_ENCRYPT:
            len += 2 + pk->pub.elg.p->bytes;
            len += 2 + pk->pub.elg.g->bytes;
            len += 2 + pk->pub.elg.y->bytes;
            break;
        case PGP_PUB_RSA_SIGN:
        case PGP_PUB_RSA_ENCRYPT:
        case PGP_PUB_RSA_ENCRYPT_SIGN:
            len += 2 + pk->pub.rsa.n->bytes;
            len += 2 + pk->pub.rsa.e->bytes;
            break;
        case PGP_PUB_DSA_SIGN:
            len += 2 + pk->pub.dsa.p->bytes;
            len += 2 + pk->pub.dsa.q->bytes;
            len += 2 + pk->pub.dsa.g->bytes;
            len += 2 + pk->pub.dsa.y->bytes;
            break;
    }

    hdr[0] = 0x99;
    hdr[1] = len >> 8;
    hdr[2] = len & 0xFF;
    px_md_update(md, hdr, 3);

    px_md_update(md, &pk->ver, 1);
    px_md_update(md, pk->time, 4);
    px_md_update(md, &pk->algo, 1);

    switch (pk->algo)
    {
        case PGP_PUB_ELG_ENCRYPT:
            pgp_mpi_hash(md, pk->pub.elg.p);
            pgp_mpi_hash(md, pk->pub.elg.g);
            pgp_mpi_hash(md, pk->pub.elg.y);
            break;
        case PGP_PUB_RSA_SIGN:
        case PGP_PUB_RSA_ENCRYPT:
        case PGP_PUB_RSA_ENCRYPT_SIGN:
            pgp_mpi_hash(md, pk->pub.rsa.n);
            pgp_mpi_hash(md, pk->pub.rsa.e);
            break;
        case PGP_PUB_DSA_SIGN:
            pgp_mpi_hash(md, pk->pub.dsa.p);
            pgp_mpi_hash(md, pk->pub.dsa.q);
            pgp_mpi_hash(md, pk->pub.dsa.g);
            pgp_mpi_hash(md, pk->pub.dsa.y);
            break;
    }

    px_md_finish(md, hash);
    px_md_free(md);

    memcpy(pk->key_id, hash + 12, 8);
    memset(hash, 0, 20);

    return 0;
}

static int check_key_cksum ( PullFilter src,
PGP_PubKey pk 
) [static]

Definition at line 300 of file pgp-pubkey.c.

References PGP_PubKey::algo, buf, PGP_PubKey::dsa, PGP_PubKey::elg, pgp_mpi_cksum(), PGP_PUB_DSA_SIGN, PGP_PUB_ELG_ENCRYPT, PGP_PUB_RSA_ENCRYPT, PGP_PUB_RSA_ENCRYPT_SIGN, PGP_PUB_RSA_SIGN, pullf_read_fixed(), px_debug(), PGP_PubKey::rsa, and PGP_PubKey::sec.

Referenced by process_secret_key().

{
    int         res;
    unsigned    got_cksum,
                my_cksum = 0;
    uint8       buf[2];

    res = pullf_read_fixed(src, 2, buf);
    if (res < 0)
        return res;

    got_cksum = ((unsigned) buf[0] << 8) + buf[1];
    switch (pk->algo)
    {
        case PGP_PUB_ELG_ENCRYPT:
            my_cksum = pgp_mpi_cksum(0, pk->sec.elg.x);
            break;
        case PGP_PUB_RSA_SIGN:
        case PGP_PUB_RSA_ENCRYPT:
        case PGP_PUB_RSA_ENCRYPT_SIGN:
            my_cksum = pgp_mpi_cksum(0, pk->sec.rsa.d);
            my_cksum = pgp_mpi_cksum(my_cksum, pk->sec.rsa.p);
            my_cksum = pgp_mpi_cksum(my_cksum, pk->sec.rsa.q);
            my_cksum = pgp_mpi_cksum(my_cksum, pk->sec.rsa.u);
            break;
        case PGP_PUB_DSA_SIGN:
            my_cksum = pgp_mpi_cksum(0, pk->sec.dsa.x);
            break;
    }
    if (my_cksum != got_cksum)
    {
        px_debug("key cksum check failed");
        return PXE_PGP_KEYPKT_CORRUPT;
    }
    return 0;
}

static int check_key_sha1 ( PullFilter src,
PGP_PubKey pk 
) [static]

Definition at line 254 of file pgp-pubkey.c.

References PGP_PubKey::algo, PGP_PubKey::dsa, PGP_PubKey::elg, memcmp(), PGP_DIGEST_SHA1, pgp_load_digest(), pgp_mpi_hash(), PGP_PUB_DSA_SIGN, PGP_PUB_ELG_ENCRYPT, PGP_PUB_RSA_ENCRYPT, PGP_PUB_RSA_ENCRYPT_SIGN, PGP_PUB_RSA_SIGN, pullf_read_fixed(), px_debug(), px_md_finish, px_md_free, PGP_PubKey::rsa, and PGP_PubKey::sec.

Referenced by process_secret_key().

{
    int         res;
    uint8       got_sha1[20];
    uint8       my_sha1[20];
    PX_MD      *md;

    res = pullf_read_fixed(src, 20, got_sha1);
    if (res < 0)
        return res;

    res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
    if (res < 0)
        goto err;
    switch (pk->algo)
    {
        case PGP_PUB_ELG_ENCRYPT:
            pgp_mpi_hash(md, pk->sec.elg.x);
            break;
        case PGP_PUB_RSA_SIGN:
        case PGP_PUB_RSA_ENCRYPT:
        case PGP_PUB_RSA_ENCRYPT_SIGN:
            pgp_mpi_hash(md, pk->sec.rsa.d);
            pgp_mpi_hash(md, pk->sec.rsa.p);
            pgp_mpi_hash(md, pk->sec.rsa.q);
            pgp_mpi_hash(md, pk->sec.rsa.u);
            break;
        case PGP_PUB_DSA_SIGN:
            pgp_mpi_hash(md, pk->sec.dsa.x);
            break;
    }
    px_md_finish(md, my_sha1);
    px_md_free(md);

    if (memcmp(my_sha1, got_sha1, 20) != 0)
    {
        px_debug("key sha1 check failed");
        res = PXE_PGP_KEYPKT_CORRUPT;
    }
err:
    memset(got_sha1, 0, 20);
    memset(my_sha1, 0, 20);
    return res;
}

static int internal_read_key ( PullFilter src,
PGP_PubKey **  pk_p,
const uint8 psw,
int  psw_len,
int  pubtype 
) [static]

Definition at line 459 of file pgp-pubkey.c.

References _pgp_read_public_key(), PGP_PubKey::can_encrypt, NULL, pgp_create_pkt_reader(), pgp_key_free(), pgp_parse_pkt_hdr(), PGP_PKT_MARKER, PGP_PKT_PRIV_61, PGP_PKT_PUBLIC_KEY, PGP_PKT_PUBLIC_SUBKEY, PGP_PKT_SECRET_KEY, PGP_PKT_SECRET_SUBKEY, PGP_PKT_SIGNATURE, PGP_PKT_TRUST, PGP_PKT_USER_ATTR, PGP_PKT_USER_ID, pgp_skip_packet(), process_secret_key(), pullf_free(), and px_debug().

Referenced by pgp_set_pubkey().

{
    PullFilter *pkt = NULL;
    int         res;
    uint8       tag;
    int         len;
    PGP_PubKey *enc_key = NULL;
    PGP_PubKey *pk = NULL;
    int         got_main_key = 0;

    /*
     * Search for encryption key.
     *
     * Error out on anything fancy.
     */
    while (1)
    {
        res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
        if (res <= 0)
            break;
        res = pgp_create_pkt_reader(&pkt, src, len, res, NULL);
        if (res < 0)
            break;

        switch (tag)
        {
            case PGP_PKT_PUBLIC_KEY:
            case PGP_PKT_SECRET_KEY:
                if (got_main_key)
                {
                    res = PXE_PGP_MULTIPLE_KEYS;
                    break;
                }
                got_main_key = 1;
                res = pgp_skip_packet(pkt);
                break;

            case PGP_PKT_PUBLIC_SUBKEY:
                if (pubtype != 0)
                    res = PXE_PGP_EXPECT_SECRET_KEY;
                else
                    res = _pgp_read_public_key(pkt, &pk);
                break;

            case PGP_PKT_SECRET_SUBKEY:
                if (pubtype != 1)
                    res = PXE_PGP_EXPECT_PUBLIC_KEY;
                else
                    res = process_secret_key(pkt, &pk, psw, psw_len);
                break;

            case PGP_PKT_SIGNATURE:
            case PGP_PKT_MARKER:
            case PGP_PKT_TRUST:
            case PGP_PKT_USER_ID:
            case PGP_PKT_USER_ATTR:
            case PGP_PKT_PRIV_61:
                res = pgp_skip_packet(pkt);
                break;
            default:
                px_debug("unknown/unexpected packet: %d", tag);
                res = PXE_PGP_UNEXPECTED_PKT;
        }
        pullf_free(pkt);
        pkt = NULL;

        if (pk != NULL)
        {
            if (res >= 0 && pk->can_encrypt)
            {
                if (enc_key == NULL)
                {
                    enc_key = pk;
                    pk = NULL;
                }
                else
                    res = PXE_PGP_MULTIPLE_SUBKEYS;
            }

            if (pk)
                pgp_key_free(pk);
            pk = NULL;
        }

        if (res < 0)
            break;
    }

    if (pkt)
        pullf_free(pkt);

    if (res < 0)
    {
        if (enc_key)
            pgp_key_free(enc_key);
        return res;
    }

    if (!enc_key)
        res = PXE_PGP_NO_USABLE_KEY;
    else
        *pk_p = enc_key;
    return res;
}

int pgp_key_alloc ( PGP_PubKey **  pk_p  ) 

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

References px_alloc.

Referenced by _pgp_read_public_key().

{
    PGP_PubKey *pk;

    pk = px_alloc(sizeof(*pk));
    memset(pk, 0, sizeof(*pk));
    *pk_p = pk;
    return 0;
}

void pgp_key_free ( PGP_PubKey pk  ) 
int pgp_set_pubkey ( PGP_Context ctx,
MBuf keypkt,
const uint8 key,
int  key_len,
int  pubtype 
)

Definition at line 566 of file pgp-pubkey.c.

References internal_read_key(), PGP_Context::pub_key, pullf_create_mbuf_reader(), and pullf_free().

Referenced by decrypt_internal(), and encrypt_internal().

{
    int         res;
    PullFilter *src;
    PGP_PubKey *pk = NULL;

    res = pullf_create_mbuf_reader(&src, keypkt);
    if (res < 0)
        return res;

    res = internal_read_key(src, &pk, key, key_len, pubtype);
    pullf_free(src);

    if (res >= 0)
        ctx->pub_key = pk;

    return res < 0 ? res : 0;
}

static int process_secret_key ( PullFilter pkt,
PGP_PubKey **  pk_p,
const uint8 key,
int  key_len 
) [static]

Definition at line 338 of file pgp-pubkey.c.

References _pgp_read_public_key(), PGP_PubKey::algo, check_key_cksum(), check_key_sha1(), debug_expect::cipher_algo, PGP_PubKey::dsa, PGP_PubKey::elg, GETBYTE, HIDE_CKSUM, HIDE_CLEAR, HIDE_SHA1, PGP_S2K::key, PGP_S2K::key_len, NULL, pgp_cfb_create(), pgp_cfb_free(), pgp_decrypt_filter, pgp_expect_packet_end(), pgp_get_cipher_block_size(), pgp_key_free(), pgp_mpi_read(), PGP_PUB_DSA_SIGN, PGP_PUB_ELG_ENCRYPT, PGP_PUB_RSA_ENCRYPT, PGP_PUB_RSA_ENCRYPT_SIGN, PGP_PUB_RSA_SIGN, pgp_s2k_process(), pgp_s2k_read(), pullf_create(), pullf_free(), pullf_read_fixed(), px_debug(), PGP_PubKey::rsa, and PGP_PubKey::sec.

Referenced by internal_read_key().

{
    int         res;
    int         hide_type;
    int         cipher_algo;
    int         bs;
    uint8       iv[512];
    PullFilter *pf_decrypt = NULL,
               *pf_key;
    PGP_CFB    *cfb = NULL;
    PGP_S2K     s2k;
    PGP_PubKey *pk;

    /* first read public key part */
    res = _pgp_read_public_key(pkt, &pk);
    if (res < 0)
        return res;

    /*
     * is secret key encrypted?
     */
    GETBYTE(pkt, hide_type);
    if (hide_type == HIDE_SHA1 || hide_type == HIDE_CKSUM)
    {
        if (key == NULL)
            return PXE_PGP_NEED_SECRET_PSW;
        GETBYTE(pkt, cipher_algo);
        res = pgp_s2k_read(pkt, &s2k);
        if (res < 0)
            return res;

        res = pgp_s2k_process(&s2k, cipher_algo, key, key_len);
        if (res < 0)
            return res;

        bs = pgp_get_cipher_block_size(cipher_algo);
        if (bs == 0)
        {
            px_debug("unknown cipher algo=%d", cipher_algo);
            return PXE_PGP_UNSUPPORTED_CIPHER;
        }
        res = pullf_read_fixed(pkt, bs, iv);
        if (res < 0)
            return res;

        /*
         * create decrypt filter
         */
        res = pgp_cfb_create(&cfb, cipher_algo, s2k.key, s2k.key_len, 0, iv);
        if (res < 0)
            return res;
        res = pullf_create(&pf_decrypt, &pgp_decrypt_filter, cfb, pkt);
        if (res < 0)
            return res;
        pf_key = pf_decrypt;
    }
    else if (hide_type == HIDE_CLEAR)
    {
        pf_key = pkt;
    }
    else
    {
        px_debug("unknown hide type");
        return PXE_PGP_KEYPKT_CORRUPT;
    }

    /* read secret key */
    switch (pk->algo)
    {
        case PGP_PUB_RSA_SIGN:
        case PGP_PUB_RSA_ENCRYPT:
        case PGP_PUB_RSA_ENCRYPT_SIGN:
            res = pgp_mpi_read(pkt, &pk->sec.rsa.d);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->sec.rsa.p);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->sec.rsa.q);
            if (res < 0)
                break;
            res = pgp_mpi_read(pkt, &pk->sec.rsa.u);
            if (res < 0)
                break;
            break;
        case PGP_PUB_ELG_ENCRYPT:
            res = pgp_mpi_read(pf_key, &pk->sec.elg.x);
            break;
        case PGP_PUB_DSA_SIGN:
            res = pgp_mpi_read(pf_key, &pk->sec.dsa.x);
            break;
        default:
            px_debug("unknown public algo: %d", pk->algo);
            res = PXE_PGP_KEYPKT_CORRUPT;
    }
    /* read checksum / sha1 */
    if (res >= 0)
    {
        if (hide_type == HIDE_SHA1)
            res = check_key_sha1(pf_key, pk);
        else
            res = check_key_cksum(pf_key, pk);
    }
    if (res >= 0)
        res = pgp_expect_packet_end(pf_key);

    if (pf_decrypt)
        pullf_free(pf_decrypt);
    if (cfb)
        pgp_cfb_free(cfb);

    if (res < 0)
        pgp_key_free(pk);
    else
        *pk_p = pk;

    return res;
}