int
pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
			   const uint8 *key, int key_len, int pubtype)
{
	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)
{
	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;
}
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;
}
Exemple #4
0
/*
 * 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;
}