use super::PublicKeyInfo;
use crate::error::{Error, ErrorCode, Result};
use structured_asn1::memory::Work;
const FIELD: &str = "subjectPublicKey.rfc8410";
const PARAMETERS: &str = "subjectPublicKeyInfo.algorithm.parameters";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Algorithm {
X25519,
X448,
Ed25519,
Ed448,
}
impl Algorithm {
#[must_use]
pub const fn public_key_len(self) -> usize {
match self {
Self::X25519 | Self::Ed25519 => 32,
Self::X448 => 56,
Self::Ed448 => 57,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PublicKey<'a> {
algorithm: Algorithm,
bytes: &'a [u8],
offset: u64,
}
impl<'a> PublicKey<'a> {
#[must_use]
pub fn algorithm(&self) -> Algorithm {
self.algorithm
}
#[must_use]
pub fn as_bytes(&self) -> &'a [u8] {
self.bytes
}
#[must_use]
pub fn offset(&self) -> u64 {
self.offset
}
}
pub fn read<'a, W: Work>(key: PublicKeyInfo<'a>, execution: &W) -> Result<PublicKey<'a>> {
let identifier = key.algorithm();
let work = identifier.query_in(execution);
let at = identifier.offset();
let charge = |amount| {
work.charge_work(amount)
.map_err(|reason| Error::resource(reason, FIELD, at))
};
charge(1)?;
let oid = identifier.algorithm();
let bytes = oid.as_bytes();
if bytes.len() != 3 {
return Err(Error::new(ErrorCode::UnexpectedField, FIELD, at));
}
charge(3)?;
let algorithm = match bytes {
[0x2b, 0x65, 0x6e] => Algorithm::X25519,
[0x2b, 0x65, 0x6f] => Algorithm::X448,
[0x2b, 0x65, 0x70] => Algorithm::Ed25519,
[0x2b, 0x65, 0x71] => Algorithm::Ed448,
_ => return Err(Error::new(ErrorCode::UnexpectedField, FIELD, at)),
};
if let Some(parameters) = identifier.parameters_nested() {
return Err(Error::new(
ErrorCode::MalformedValue,
PARAMETERS,
parameters.offset(),
));
}
let bytes = key.whole_octets(FIELD)?;
let offset = key.key_offset();
if bytes.len() != algorithm.public_key_len() {
return Err(Error::new(ErrorCode::MalformedValue, FIELD, offset));
}
Ok(PublicKey {
algorithm,
bytes,
offset,
})
}