Skip to main content

structured_pkix/key/
rsa.rs

1//! The RSA public key a certificate carries, read in place.
2//!
3//! RFC 8017 A.1.1 defines `RSAPublicKey ::= SEQUENCE { modulus INTEGER,
4//! publicExponent INTEGER }`; RFC 4055 §1.2 carries the same structure for
5//! `rsaEncryption` and `id-RSASSA-PSS` keys. [`read`] returns the original
6//! magnitudes and where they were written. Key size, exponent policy and every
7//! arithmetic check belong to the provider that verifies with the key.
8//! <https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1.1>
9
10use super::{PublicKeyInfo, same_oid};
11use crate::error::{Error, ErrorCode, Located, Result};
12use structured_asn1::memory::Work;
13use structured_asn1::{Element, ScopedReader, Tag, universal};
14
15const FIELD: &str = "subjectPublicKey.rsa";
16
17/// A positive integer as its big-endian magnitude, without the sign octet.
18#[derive(Debug, Clone, Copy)]
19pub struct Magnitude<'a> {
20    bytes: &'a [u8],
21    offset: u64,
22}
23
24impl<'a> Magnitude<'a> {
25    /// Big-endian magnitude; the first octet is never zero.
26    #[must_use]
27    pub fn as_bytes(self) -> &'a [u8] {
28        self.bytes
29    }
30
31    /// Where the first magnitude octet sits in the whole document.
32    #[must_use]
33    pub fn offset(self) -> u64 {
34        self.offset
35    }
36
37    /// The exact number of significant bits. A 256-octet modulus whose first
38    /// octet is `0x01` has 2041 bits, not 2048.
39    #[must_use]
40    pub fn bits(self) -> u64 {
41        // Nonempty with a nonzero first octet by construction.
42        (self.bytes.len() as u64 - 1) * 8 + u64::from(8 - self.bytes[0].leading_zeros())
43    }
44}
45
46/// The two components of an RSA public key, as the certificate wrote them.
47#[derive(Debug, Clone, Copy)]
48pub struct PublicKey<'a> {
49    element: Element<'a>,
50    modulus: Magnitude<'a>,
51    exponent: Magnitude<'a>,
52}
53
54impl<'a> PublicKey<'a> {
55    /// The whole original `RSAPublicKey` SEQUENCE inside the key bits.
56    #[must_use]
57    pub fn element(self) -> Element<'a> {
58        self.element
59    }
60
61    /// The modulus `n`.
62    #[must_use]
63    pub fn modulus(self) -> Magnitude<'a> {
64        self.modulus
65    }
66
67    /// The public exponent `e`.
68    #[must_use]
69    pub fn exponent(self) -> Magnitude<'a> {
70        self.exponent
71    }
72}
73
74/// Reads the RSA key carried by `key` under the current `execution`.
75///
76/// The key's algorithm must be `rsaEncryption` or `id-RSASSA-PSS`. The key
77/// bits are decoded with their original parser session, offsets, encoding and
78/// depth; `execution` pays for every step and the source ceilings still apply.
79/// Key bytes and components remain borrowed; nested-reader metadata uses
80/// the existing accounted scratch path.
81///
82/// # Errors
83///
84/// `UnexpectedField` for another algorithm, `MalformedValue` for padded key
85/// bits or a non-positive component, `TrailingData` for anything after the
86/// structure or its two fields, and the located encoding or resource error
87/// otherwise. A resource refusal happens before the work it would fund.
88///
89/// # Examples
90///
91/// ```
92/// use std::sync::Arc;
93/// use structured_asn1::{Parser, memory::{Memory, MemoryAccount}};
94/// use structured_pkix::{PublicKeyInfo, key::rsa};
95/// let memory = Memory::new(Arc::new(MemoryAccount::new(4096, 4096)));
96/// let parser = Parser::der(memory.clone());
97/// // rsaEncryption, NULL; RSAPublicKey { 0x00c3 (195), 65537 }
98/// let spki = b"\x30\x1d\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\
99///              \x03\x0c\x00\x30\x09\x02\x02\x00\xc3\x02\x03\x01\x00\x01";
100/// let mut reader = parser.read(spki, 0).unwrap();
101/// let element = reader.next_element().unwrap().unwrap();
102/// let key = PublicKeyInfo::read_element(&reader, &element, "subjectPublicKeyInfo")?;
103/// let rsa = rsa::read(key, &memory)?;
104/// assert_eq!(rsa.modulus().as_bytes(), [0xc3]);
105/// assert_eq!(rsa.modulus().bits(), 8);
106/// assert_eq!(rsa.modulus().offset(), 25);
107/// assert_eq!(rsa.exponent().as_bytes(), [1, 0, 1]);
108/// # Ok::<(), structured_pkix::Error>(())
109/// ```
110pub fn read<'a, W: Work>(key: PublicKeyInfo<'a>, execution: &W) -> Result<PublicKey<'a>> {
111    let identifier = key.algorithm();
112    let at = identifier.offset();
113    let algorithm = identifier.algorithm();
114    // Deferred OID decisions share the source ceiling with the nested key
115    // decoder; a separately funded operation must not reset that ceiling.
116    let query = identifier.query_in(execution);
117    if !same_oid(algorithm, crate::oid::RSA_ENCRYPTION, &query, FIELD, at)?
118        && !same_oid(algorithm, crate::oid::RSASSA_PSS, &query, FIELD, at)?
119    {
120        return Err(Error::new(ErrorCode::UnexpectedField, FIELD, at));
121    }
122    let octets = key.whole_octets(FIELD)?;
123    let (reader, element) = identifier
124        .nested(octets, key.key_offset())
125        .open(execution, FIELD)?;
126    if element.tag() != Tag::constructed(universal::SEQUENCE) {
127        return Err(Error::new(
128            ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
129            FIELD,
130            element.span().start,
131        ));
132    }
133    let mut fields = reader.enter(&element).field(FIELD)?;
134    let modulus = magnitude(&mut fields)?;
135    let exponent = magnitude(&mut fields)?;
136    if !fields.is_empty() {
137        return Err(Error::new(ErrorCode::TrailingData, FIELD, fields.offset()));
138    }
139    Ok(PublicKey {
140        element,
141        modulus,
142        exponent,
143    })
144}
145
146fn magnitude<'a>(fields: &mut ScopedReader<'a, '_>) -> Result<Magnitude<'a>> {
147    let element = fields
148        .expect(Tag::primitive(universal::INTEGER))
149        .field(FIELD)?;
150    let integer = fields.integer(&element).field(FIELD)?;
151    // X.690 §8.3.2 leaves at most one leading zero octet, the sign of a
152    // positive value whose top bit is set. Zero and negative values are not
153    // RSA components (RFC 8017 §3.1).
154    let start = element.contents_span().start;
155    let (bytes, offset) = match integer.as_bytes() {
156        [0x00, rest @ ..] => (rest, start + 1),
157        all => (all, start),
158    };
159    if integer.is_negative() || bytes.is_empty() {
160        return Err(Error::new(
161            ErrorCode::MalformedValue,
162            FIELD,
163            element.span().start,
164        ));
165    }
166    Ok(Magnitude { bytes, offset })
167}