static int decompress_init(void **priv_p, void *arg, PullFilter *src) { PGP_Context *ctx = arg; struct DecomprData *dec; int res; if (ctx->compress_algo != PGP_COMPR_ZLIB && ctx->compress_algo != PGP_COMPR_ZIP) return PXE_PGP_UNSUPPORTED_COMPR; dec = px_alloc(sizeof(*dec)); memset(dec, 0, sizeof(*dec)); dec->buf_len = ZIP_OUT_BUF; *priv_p = dec; dec->stream.zalloc = z_alloc; dec->stream.zfree = z_free; if (ctx->compress_algo == PGP_COMPR_ZIP) res = inflateInit2(&dec->stream, -15); else res = inflateInit(&dec->stream); if (res != Z_OK) { px_free(dec); px_debug("decompress_init: inflateInit error"); return PXE_PGP_COMPRESSION_ERROR; } return 0; }
static int decompress_read(void *priv, PullFilter *src, int len, uint8 **data_p, uint8 *buf, int buflen) { int res; int flush; struct DecomprData *dec = priv; restart: if (dec->buf_data > 0) { if (len > dec->buf_data) len = dec->buf_data; *data_p = dec->pos; dec->pos += len; dec->buf_data -= len; return len; } if (dec->eof) return 0; if (dec->stream.avail_in == 0) { uint8 *tmp; res = pullf_read(src, 8192, &tmp); if (res < 0) return res; dec->stream.next_in = tmp; dec->stream.avail_in = res; } dec->stream.next_out = dec->buf; dec->stream.avail_out = dec->buf_len; dec->pos = dec->buf; /* * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do * it anyway (Z_NO_FLUSH), but seems to reserve the right not to. So lets * follow the API. */ flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH; res = inflate(&dec->stream, flush); if (res != Z_OK && res != Z_STREAM_END) { px_debug("decompress_read: inflate error: %d", res); return PXE_PGP_CORRUPT_DATA; } dec->buf_data = dec->buf_len - dec->stream.avail_out; if (res == Z_STREAM_END) dec->eof = 1; goto restart; }
static BIGNUM * mpi_to_bn(PGP_MPI * n) { BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL); if (!bn) return NULL; if (BN_num_bits(bn) != n->bits) { px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d", n->bits, BN_num_bits(bn)); BN_clear_free(bn); return NULL; } return bn; }
int mbuf_append(MBuf *dst, const uint8 *buf, int len) { if (dst->no_write) { px_debug("mbuf_append: no_write"); return PXE_BUG; } prepare_room(dst, len); memcpy(dst->data_end, buf, len); dst->data_end += len; return 0; }
static int check_key_sha1(PullFilter *src, PGP_PubKey *pk) { 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; }
int pgp_mpi_alloc(int bits, PGP_MPI ** mpi) { PGP_MPI *n; int len = (bits + 7) / 8; if (bits < 0 || bits > 0xFFFF) { px_debug("pgp_mpi_alloc: unreasonable request: bits=%d", bits); return PXE_PGP_CORRUPT_DATA; } n = px_alloc(sizeof(*n) + len); n->bits = bits; n->bytes = len; n->data = (uint8 *) (n) + sizeof(*n); *mpi = n; return 0; }
/* * caller wants exatly len bytes and dont bother with references */ int pullf_read_fixed(PullFilter *src, int len, uint8 *dst) { int res; uint8 *p; res = pullf_read_max(src, len, &p, dst); if (res < 0) return res; if (res != len) { px_debug("pullf_read_fixed: need=%d got=%d", len, res); return PXE_MBUF_SHORT_READ; } if (p != dst) memcpy(dst, p, len); return 0; }
static PGP_MPI * bn_to_mpi(BIGNUM *bn) { int res; PGP_MPI *n; res = pgp_mpi_alloc(BN_num_bits(bn), &n); if (res < 0) return NULL; if (BN_num_bytes(bn) != n->bytes) { px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d", BN_num_bytes(bn), n->bytes); pgp_mpi_free(n); return NULL; } BN_bn2bin(bn, n->data); return n; }
/* * secret message: 1 byte algo, sesskey, 2 byte cksum * ignore algo in cksum */ static int control_cksum(uint8 *msg, int msglen) { int i; unsigned my_cksum, got_cksum; if (msglen < 3) return PXE_PGP_WRONG_KEY; my_cksum = 0; for (i = 1; i < msglen - 2; i++) my_cksum += msg[i]; my_cksum &= 0xFFFF; got_cksum = ((unsigned) (msg[msglen - 2]) << 8) + msg[msglen - 1]; if (my_cksum != got_cksum) { px_debug("pubenc cksum failed"); return PXE_PGP_WRONG_KEY; } return 0; }
static int check_key_cksum(PullFilter *src, PGP_PubKey *pk) { 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 internal_read_key(PullFilter *src, PGP_PubKey **pk_p, const uint8 *psw, int psw_len, int pubtype) { 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; }
static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p, const uint8 *key, int key_len) { 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; }
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p) { 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; }
int pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt) { int ver; int algo; int res; uint8 key_id[8]; PGP_PubKey *pk; uint8 *msg; int msglen; PGP_MPI *m; pk = ctx->pub_key; if (pk == NULL) { px_debug("no pubkey?"); return PXE_BUG; } GETBYTE(pkt, ver); if (ver != 3) { px_debug("unknown pubenc_sesskey pkt ver=%d", ver); return PXE_PGP_CORRUPT_DATA; } /* * check if keyid's match - user-friendly msg */ res = pullf_read_fixed(pkt, 8, key_id); if (res < 0) return res; if (memcmp(key_id, any_key, 8) != 0 && memcmp(key_id, pk->key_id, 8) != 0) { px_debug("key_id's does not match"); return PXE_PGP_WRONG_KEY; } /* * Decrypt */ GETBYTE(pkt, algo); switch (algo) { case PGP_PUB_ELG_ENCRYPT: res = decrypt_elgamal(pk, pkt, &m); break; case PGP_PUB_RSA_ENCRYPT: case PGP_PUB_RSA_ENCRYPT_SIGN: res = decrypt_rsa(pk, pkt, &m); break; default: res = PXE_PGP_UNKNOWN_PUBALGO; } if (res < 0) return res; /* * extract message */ msg = check_eme_pkcs1_v15(m->data, m->bytes); if (msg == NULL) { px_debug("check_eme_pkcs1_v15 failed"); res = PXE_PGP_WRONG_KEY; goto out; } msglen = m->bytes - (msg - m->data); res = control_cksum(msg, msglen); if (res < 0) goto out; /* * got sesskey */ ctx->cipher_algo = *msg; ctx->sess_key_len = msglen - 3; memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len); out: pgp_mpi_free(m); if (res < 0) return res; return pgp_expect_packet_end(pkt); }