1use super::{Jwk, JwkError};
6
7impl Jwk {
8 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 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
75fn 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
89fn 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
116fn 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
147fn 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 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 assert_eq!(encode(&[0, 0, 0x80, 0x01], &[0, 1, 0, 1]), der);
184 let big = vec![0x7f; 300];
186 let der = encode(&big, &e);
187 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 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 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 assert_eq!(
223 malformed(&[&[0x30, 0x80], body].concat()),
224 "malformed RSAPublicKey: invalid length"
225 );
226 assert_eq!(
228 malformed(&[&[0x30, 0x89, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x80], body].concat()),
229 "malformed RSAPublicKey: invalid length"
230 );
231 #[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 assert_eq!(
239 malformed(&[0x30, 0x82, 0x01]),
240 "malformed RSAPublicKey: invalid length"
241 );
242 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 assert_eq!(
253 malformed(&[0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01]),
254 "malformed RSAPublicKey: empty INTEGER"
255 );
256 }
257}