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; }
/* * dst should have room for 17 bytes */ int pgp_get_keyid(MBuf *pgp_data, char *dst) { int res; PullFilter *src; PullFilter *pkt = NULL; int len; uint8 tag; int got_pub_key = 0, got_symenc_key = 0, got_pubenc_key = 0; int got_data = 0; uint8 keyid_buf[8]; int got_main_key = 0; res = pullf_create_mbuf_reader(&src, pgp_data); if (res < 0) return res; 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_SECRET_KEY: case PGP_PKT_PUBLIC_KEY: /* main key is for signing, so ignore it */ if (!got_main_key) { got_main_key = 1; res = pgp_skip_packet(pkt); } else res = PXE_PGP_MULTIPLE_KEYS; break; case PGP_PKT_SECRET_SUBKEY: case PGP_PKT_PUBLIC_SUBKEY: res = read_pubkey_keyid(pkt, keyid_buf); if (res < 0) break; if (res > 0) got_pub_key++; break; case PGP_PKT_PUBENCRYPTED_SESSKEY: got_pubenc_key++; res = read_pubenc_keyid(pkt, keyid_buf); break; case PGP_PKT_SYMENCRYPTED_DATA: case PGP_PKT_SYMENCRYPTED_DATA_MDC: /* don't skip it, just stop */ got_data = 1; break; case PGP_PKT_SYMENCRYPTED_SESSKEY: got_symenc_key++; /* fallthru */ 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: res = PXE_PGP_CORRUPT_DATA; } if (pkt) pullf_free(pkt); pkt = NULL; if (res < 0 || got_data) break; } pullf_free(src); if (pkt) pullf_free(pkt); if (res < 0) return res; /* now check sanity */ if (got_pub_key && got_pubenc_key) res = PXE_PGP_CORRUPT_DATA; if (got_pub_key > 1) res = PXE_PGP_MULTIPLE_KEYS; if (got_pubenc_key > 1) res = PXE_PGP_MULTIPLE_KEYS; /* * if still ok, look what we got */ if (res >= 0) { if (got_pubenc_key || got_pub_key) { if (memcmp(keyid_buf, any_key, 8) == 0) { memcpy(dst, "ANYKEY", 7); res = 6; } else res = print_key(keyid_buf, dst); } else if (got_symenc_key) { memcpy(dst, "SYMKEY", 7); res = 6; } else res = PXE_PGP_NO_USABLE_KEY; } return res; }