use std::io::BufRead;
use log::debug;
use crate::pgp::{
crypto::public_key::PublicKeyAlgorithm,
errors::{ensure, unsupported_err, Result},
parsing_reader::BufReadParsing,
types::{KeyVersion, PublicParams, Timestamp},
};
fn public_key_parser_v4_v6<B: BufRead>(
key_ver: &KeyVersion,
mut i: B,
) -> Result<(
KeyVersion,
PublicKeyAlgorithm,
Timestamp,
Option<u16>,
PublicParams,
)> {
let created_at = i.read_timestamp()?;
let alg = i.read_u8().map(PublicKeyAlgorithm::from)?;
let pub_len = if *key_ver == KeyVersion::V6 {
let len = i.read_be_u32()?;
ensure!(len > 0, "key length must not be 0");
Some(len as usize)
} else {
None
};
let params = if let Some(pub_len) = pub_len {
PublicParams::try_from_reader(alg, Some(pub_len), i.read_take(pub_len))?
} else {
PublicParams::try_from_reader(alg, None, &mut i)?
};
Ok((*key_ver, alg, created_at, None, params))
}
fn public_key_parser_v2_v3<B: BufRead>(
key_ver: &KeyVersion,
mut i: B,
) -> Result<(
KeyVersion,
PublicKeyAlgorithm,
Timestamp,
Option<u16>,
PublicParams,
)> {
let created_at = i.read_timestamp()?;
let exp = i.read_be_u16()?;
let alg = i.read_u8().map(PublicKeyAlgorithm::from)?;
let params = PublicParams::try_from_reader(alg, None, &mut i)?;
Ok((*key_ver, alg, created_at, Some(exp), params))
}
#[allow(clippy::type_complexity)]
pub(crate) fn parse<B: BufRead>(
mut i: B,
) -> Result<(
KeyVersion,
PublicKeyAlgorithm,
Timestamp,
Option<u16>,
PublicParams,
)> {
let key_ver = i.read_u8().map(KeyVersion::from)?;
debug!("public params for key version {key_ver:?}");
let key = match key_ver {
KeyVersion::V2 | KeyVersion::V3 => public_key_parser_v2_v3(&key_ver, i)?,
KeyVersion::V4 | KeyVersion::V6 => public_key_parser_v4_v6(&key_ver, i)?,
KeyVersion::V5 | KeyVersion::Other(_) => {
unsupported_err!("key version {:?}", key_ver);
}
};
Ok(key)
}