Skip to main content

identity_kit/jose/
pkcs1.rs

1//! PKCS #1 `RSAPublicKey ::= SEQUENCE { modulus INTEGER, publicExponent INTEGER }` (RFC 8017
2//! Appendix A.1.1) in DER: the form in which some vaults and HSMs return an RSA public key, and
3//! the raw key of an `rsa-pub` Multikey.
4
5use super::{Jwk, JwkError};
6
7impl Jwk {
8    /// An `RSA` key from a DER-encoded PKCS #1 `RSAPublicKey`
9    /// (`SEQUENCE { modulus INTEGER, publicExponent INTEGER }`, RFC 8017 Appendix A.1.1).
10    ///
11    /// This is for key store backends whose vault returns an RSA public key as PKCS #1 rather
12    /// than as a `SubjectPublicKeyInfo` (for that, see [`Jwk::from_spki_der`]). The parser is
13    /// strict DER: definite lengths in the fewest octets, non-negative minimally encoded
14    /// INTEGERs, nothing after the `SEQUENCE`. It needs no Cargo feature.
15    ///
16    /// Unlike [`Jwk::from_spki_der`], it takes no [`KeyType`](super::KeyType) and does not check
17    /// the modulus size, as [`Jwk::from_rsa_public`] and [`Jwk::from_multikey`] do not: PKCS #1
18    /// carries no algorithm identifier for a hint to select a parser by, and
19    /// [`DefaultVerifier`](super::DefaultVerifier) rejects an unusable modulus, or one shorter
20    /// than 2048 bits, when the key is used.
21    ///
22    /// # Errors
23    ///
24    /// [`JwkError::InvalidKey`] with `key: "RSA"` when `der` is not a DER `RSAPublicKey`.
25    ///
26    /// # Examples
27    ///
28    /// ```
29    /// use identity_kit::jose::Jwk;
30    ///
31    /// // `SEQUENCE { INTEGER 0x00c5, INTEGER 65537 }`: the leading zero keeps the modulus positive.
32    /// let der = [0x30, 0x09, 0x02, 0x02, 0x00, 0xc5, 0x02, 0x03, 0x01, 0x00, 0x01];
33    /// let jwk = Jwk::from_pkcs1_der(&der)?;
34    /// assert_eq!(jwk.rsa_public_components()?, (vec![0xc5], vec![0x01, 0x00, 0x01]));
35    /// assert_eq!(jwk.to_pkcs1_der()?, der);
36    /// # Ok::<(), identity_kit::jose::JwkError>(())
37    /// ```
38    pub fn from_pkcs1_der(der: &[u8]) -> Result<Self, JwkError> {
39        let (n, e) = decode(der)?;
40        Self::from_rsa_public(&n, &e)
41    }
42
43    /// This `RSA` key's public parameters as a DER-encoded PKCS #1 `RSAPublicKey`
44    /// (RFC 8017 Appendix A.1.1), for key store backends whose vault takes that form.
45    ///
46    /// The encoding is DER, so it is the same for every JWK of the same key.
47    ///
48    /// # Errors
49    ///
50    /// The errors of [`Jwk::rsa_public_components`]: [`JwkError::UnexpectedKeyType`] for any
51    /// other key, [`JwkError::MissingMember`] or [`JwkError::InvalidBase64Url`] for a broken `n`
52    /// or `e`; [`JwkError::InvalidKey`] when `n` or `e` is zero, which no `RSAPublicKey` that
53    /// [`Jwk::from_pkcs1_der`] reads can hold.
54    pub fn to_pkcs1_der(&self) -> Result<Vec<u8>, JwkError> {
55        let (n, e) = self.rsa_public_components()?;
56        if [&n, &e].iter().any(|value| value.iter().all(|&b| b == 0)) {
57            return Err(JwkError::InvalidKey {
58                key: "RSA",
59                reason: "modulus and exponent must not be zero".to_owned(),
60            });
61        }
62        Ok(encode(&n, &e))
63    }
64}
65
66const SEQUENCE: u8 = 0x30;
67const INTEGER: u8 = 0x02;
68
69fn encode(n: &[u8], e: &[u8]) -> Vec<u8> {
70    let mut body = integer(n);
71    body.extend(integer(e));
72    tlv(SEQUENCE, &body)
73}
74
75/// The big-endian `n` and `e` of `der`, without leading zero octets.
76fn decode(der: &[u8]) -> Result<(Vec<u8>, Vec<u8>), JwkError> {
77    let (body, rest) = read_tlv(der, SEQUENCE)?;
78    if !rest.is_empty() {
79        return Err(invalid("trailing bytes after RSAPublicKey"));
80    }
81    let (n, body) = read_tlv(body, INTEGER)?;
82    let (e, body) = read_tlv(body, INTEGER)?;
83    if !body.is_empty() {
84        return Err(invalid("trailing bytes inside RSAPublicKey"));
85    }
86    Ok((unsigned(n)?.to_vec(), unsigned(e)?.to_vec()))
87}
88
89/// A DER INTEGER holding the unsigned big-endian `value`.
90fn integer(value: &[u8]) -> Vec<u8> {
91    let first = value.iter().position(|&b| b != 0).unwrap_or(value.len());
92    let trimmed = &value[first..];
93    let mut body = Vec::with_capacity(trimmed.len() + 1);
94    if trimmed.first().is_none_or(|&b| b & 0x80 != 0) {
95        body.push(0);
96    }
97    body.extend_from_slice(trimmed);
98    tlv(INTEGER, &body)
99}
100
101fn tlv(tag: u8, body: &[u8]) -> Vec<u8> {
102    let mut out = vec![tag];
103    let len = body.len();
104    if len < 0x80 {
105        out.push(len as u8);
106    } else {
107        let be = len.to_be_bytes();
108        let first = be.iter().position(|&b| b != 0).unwrap_or(be.len() - 1);
109        out.push(0x80 | (be.len() - first) as u8);
110        out.extend_from_slice(&be[first..]);
111    }
112    out.extend_from_slice(body);
113    out
114}
115
116/// The body of the TLV at the start of `der`, which must have tag `tag`, and what follows.
117fn read_tlv(der: &[u8], tag: u8) -> Result<(&[u8], &[u8]), JwkError> {
118    let (&found, rest) = der.split_first().ok_or_else(|| invalid("unexpected end"))?;
119    if found != tag {
120        return Err(invalid("unexpected ASN.1 tag"));
121    }
122    let (&first, rest) = rest
123        .split_first()
124        .ok_or_else(|| invalid("unexpected end"))?;
125    let (len, rest) = if first < 0x80 {
126        (usize::from(first), rest)
127    } else {
128        let count = usize::from(first & 0x7f);
129        if count == 0 || count > size_of::<usize>() || rest.len() < count {
130            return Err(invalid("invalid length"));
131        }
132        let (len_bytes, rest) = rest.split_at(count);
133        if len_bytes[0] == 0 || (count == 1 && len_bytes[0] < 0x80) {
134            return Err(invalid("length is not minimally encoded"));
135        }
136        let len = len_bytes
137            .iter()
138            .fold(0usize, |acc, &b| (acc << 8) | usize::from(b));
139        (len, rest)
140    };
141    if rest.len() < len {
142        return Err(invalid("length exceeds input"));
143    }
144    Ok(rest.split_at(len))
145}
146
147/// The magnitude of a non-negative, minimally encoded INTEGER body.
148fn unsigned(body: &[u8]) -> Result<&[u8], JwkError> {
149    match body {
150        [] => Err(invalid("empty INTEGER")),
151        [first, ..] if first & 0x80 != 0 => Err(invalid("negative INTEGER")),
152        [0, second, ..] if second & 0x80 == 0 => Err(invalid("INTEGER has a leading zero")),
153        [0, rest @ ..] => Ok(rest),
154        _ => Ok(body),
155    }
156}
157
158fn invalid(reason: &str) -> JwkError {
159    JwkError::InvalidKey {
160        key: "RSA",
161        reason: format!("malformed RSAPublicKey: {reason}"),
162    }
163}
164
165#[cfg(test)]
166mod tests {
167    use super::*;
168
169    #[test]
170    fn pkcs1_round_trips_and_is_minimal() {
171        // RFC 8017: INTEGERs are two's complement, so a high bit needs a leading zero.
172        let n = [0x80, 0x01];
173        let e = [0x01, 0x00, 0x01];
174        let der = encode(&n, &e);
175        assert_eq!(
176            der,
177            [
178                0x30, 0x0a, 0x02, 0x03, 0x00, 0x80, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01
179            ]
180        );
181        assert_eq!(decode(&der).unwrap(), (n.to_vec(), e.to_vec()));
182        // Leading zeros of the input are dropped.
183        assert_eq!(encode(&[0, 0, 0x80, 0x01], &[0, 1, 0, 1]), der);
184        // Long-form lengths.
185        let big = vec![0x7f; 300];
186        let der = encode(&big, &e);
187        // 1 + 3 + 300 bytes of modulus INTEGER plus 5 of exponent: 309 = 0x135.
188        assert_eq!(&der[..4], [0x30, 0x82, 0x01, 0x35]);
189        assert_eq!(decode(&der).unwrap().0, big);
190        for broken in [
191            &[0x30, 0x00][..],
192            &[0x30, 0x04, 0x02, 0x01, 0xff, 0x02][..],
193            &[0x30, 0x06, 0x02, 0x01, 0x80, 0x02, 0x01, 0x01][..],
194            &[0x30, 0x07, 0x02, 0x02, 0x00, 0x01, 0x02, 0x01, 0x01][..],
195            &[0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x00][..],
196            &[0x30, 0x81, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01][..],
197        ] {
198            assert!(decode(broken).is_err(), "{broken:02x?}");
199        }
200    }
201
202    /// Why `der` is not an `RSAPublicKey`.
203    fn malformed(der: &[u8]) -> String {
204        match decode(der) {
205            Err(JwkError::InvalidKey { key: "RSA", reason }) => reason,
206            other => panic!("{der:02x?}: {other:?}"),
207        }
208    }
209
210    #[test]
211    fn pkcs1_lengths_are_strict_der() {
212        // X.690 §10.1: definite lengths in the fewest octets, the long form from 128 on. A body of
213        // exactly 128 bytes: 2 + 121 bytes of modulus INTEGER plus 5 of exponent.
214        let n = vec![0x7f; 121];
215        let e = [0x01, 0x00, 0x01];
216        let der = encode(&n, &e);
217        assert_eq!(&der[..3], [0x30, 0x81, 0x80]);
218        assert_eq!(decode(&der).unwrap(), (n, e.to_vec()));
219        let body = &der[3..];
220
221        // `0x80` is the indefinite length of BER, which DER does not allow.
222        assert_eq!(
223            malformed(&[&[0x30, 0x80], body].concat()),
224            "malformed RSAPublicKey: invalid length"
225        );
226        // Nine length octets, more than a `usize` holds, although their value is 128.
227        assert_eq!(
228            malformed(&[&[0x30, 0x89, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x80], body].concat()),
229            "malformed RSAPublicKey: invalid length"
230        );
231        // Eight length octets fit a 64-bit `usize`; 2^56 bytes are not there.
232        #[cfg(target_pointer_width = "64")]
233        assert_eq!(
234            malformed(&[0x30, 0x88, 0x01, 0, 0, 0, 0, 0, 0, 0]),
235            "malformed RSAPublicKey: length exceeds input"
236        );
237        // Fewer length octets than announced.
238        assert_eq!(
239            malformed(&[0x30, 0x82, 0x01]),
240            "malformed RSAPublicKey: invalid length"
241        );
242        // The length octets, but no body.
243        assert_eq!(
244            malformed(&[0x30, 0x81, 0x80]),
245            "malformed RSAPublicKey: length exceeds input"
246        );
247    }
248
249    #[test]
250    fn pkcs1_rejects_an_empty_integer() {
251        // X.690 §8.3.1: the contents of an INTEGER are one or more octets.
252        assert_eq!(
253            malformed(&[0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01]),
254            "malformed RSAPublicKey: empty INTEGER"
255        );
256    }
257}