use super::{PublicKeyInfo, same_oid};
use crate::error::{Error, ErrorCode, Located, Result};
use structured_asn1::memory::Work;
use structured_asn1::{Element, ScopedReader, Tag, universal};
const FIELD: &str = "subjectPublicKey.rsa";
#[derive(Debug, Clone, Copy)]
pub struct Magnitude<'a> {
bytes: &'a [u8],
offset: u64,
}
impl<'a> Magnitude<'a> {
#[must_use]
pub fn as_bytes(self) -> &'a [u8] {
self.bytes
}
#[must_use]
pub fn offset(self) -> u64 {
self.offset
}
#[must_use]
pub fn bits(self) -> u64 {
(self.bytes.len() as u64 - 1) * 8 + u64::from(8 - self.bytes[0].leading_zeros())
}
}
#[derive(Debug, Clone, Copy)]
pub struct PublicKey<'a> {
element: Element<'a>,
modulus: Magnitude<'a>,
exponent: Magnitude<'a>,
}
impl<'a> PublicKey<'a> {
#[must_use]
pub fn element(self) -> Element<'a> {
self.element
}
#[must_use]
pub fn modulus(self) -> Magnitude<'a> {
self.modulus
}
#[must_use]
pub fn exponent(self) -> Magnitude<'a> {
self.exponent
}
}
pub fn read<'a, W: Work>(key: PublicKeyInfo<'a>, execution: &W) -> Result<PublicKey<'a>> {
let identifier = key.algorithm();
let at = identifier.offset();
let algorithm = identifier.algorithm();
if !same_oid(algorithm, crate::oid::RSA_ENCRYPTION, execution, FIELD, at)?
&& !same_oid(algorithm, crate::oid::RSASSA_PSS, execution, FIELD, at)?
{
return Err(Error::new(ErrorCode::UnexpectedField, FIELD, at));
}
let octets = key.whole_octets(FIELD)?;
let (reader, element) = identifier
.nested(octets, key.key_offset())
.open(execution, FIELD)?;
if element.tag() != Tag::constructed(universal::SEQUENCE) {
return Err(Error::new(
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
FIELD,
element.span().start,
));
}
let mut fields = reader.enter(&element).field(FIELD)?;
let modulus = magnitude(&mut fields)?;
let exponent = magnitude(&mut fields)?;
if !fields.is_empty() {
return Err(Error::new(ErrorCode::TrailingData, FIELD, fields.offset()));
}
Ok(PublicKey {
element,
modulus,
exponent,
})
}
fn magnitude<'a>(fields: &mut ScopedReader<'a, '_>) -> Result<Magnitude<'a>> {
let element = fields
.expect(Tag::primitive(universal::INTEGER))
.field(FIELD)?;
let integer = fields.integer(&element).field(FIELD)?;
let start = element.contents_span().start;
let (bytes, offset) = match integer.as_bytes() {
[0x00, rest @ ..] => (rest, start + 1),
all => (all, start),
};
if integer.is_negative() || bytes.is_empty() {
return Err(Error::new(
ErrorCode::MalformedValue,
FIELD,
element.span().start,
));
}
Ok(Magnitude { bytes, offset })
}