1pub(crate) mod public_key;
2
3use crate::{Error, OidNames};
4use pkcs1::der::Decode;
5use x509_parser::{asn1_rs::ToDer, x509::AlgorithmIdentifier};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize))]
10#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
11#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
12#[non_exhaustive]
13pub enum ParameterStatus {
14 Absent,
16 Decoded,
18 Unparsed,
20 DecodeError,
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
30#[non_exhaustive]
31pub struct PssParameters {
32 pub hash_oid: String,
34 pub mask_gen_oid: String,
36 pub mask_gen_hash_oid: Option<String>,
38 pub salt_length: u32,
40 pub trailer_field: u32,
42}
43
44#[derive(Clone, Debug, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize))]
47#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
48#[non_exhaustive]
49pub struct AlgorithmInfo {
50 pub oid: String,
52 pub name: Option<String>,
54 pub parameters_der: Option<Vec<u8>>,
56 pub parameter_status: ParameterStatus,
58 pub pss: Option<PssParameters>,
60}
61
62pub(crate) fn inspect(
63 alg: &AlgorithmIdentifier<'_>,
64 signature: bool,
65 names: &OidNames,
66) -> Result<AlgorithmInfo, Error> {
67 let oid = alg.algorithm.to_id_string();
68 let name = names.get(&oid).map(str::to_owned);
69 let parameters_der = alg
70 .parameters
71 .as_ref()
72 .map(|p| p.to_der_vec().map_err(|_| Error::InvalidCertificate))
73 .transpose()?;
74 let mut parameter_status = if parameters_der.is_some() {
75 ParameterStatus::Unparsed
76 } else {
77 ParameterStatus::Absent
78 };
79 let mut pss = None;
80 if oid == "1.2.840.113549.1.1.10" {
81 if let Some(bytes) = parameters_der.as_deref() {
82 match pkcs1::RsaPssParams::from_der(bytes) {
83 Ok(p) => {
84 let mask_gen_oid = p.mask_gen.oid.to_string();
85 let mask_gen_hash_oid = if mask_gen_oid == "1.2.840.113549.1.1.8" {
86 p.mask_gen.parameters.as_ref().map(|a| a.oid.to_string())
87 } else {
88 None
89 };
90 parameter_status = ParameterStatus::Decoded;
91 pss = Some(PssParameters {
92 hash_oid: p.hash.oid.to_string(),
93 mask_gen_oid,
94 mask_gen_hash_oid,
95 salt_length: u32::from(p.salt_len),
96 trailer_field: p.trailer_field as u32,
97 });
98 }
99 Err(_) => parameter_status = ParameterStatus::DecodeError,
100 }
101 } else if signature {
102 parameter_status = ParameterStatus::DecodeError;
104 }
105 } else if matches!(
106 oid.as_str(),
107 "1.3.101.110" | "1.3.101.111" | "1.3.101.112" | "1.3.101.113"
108 ) && parameters_der.is_some()
109 {
110 parameter_status = ParameterStatus::DecodeError;
111 }
112 if oid == "1.2.840.10045.2.1" {
113 parameter_status = match alg.parameters.as_ref() {
114 Some(p)
115 if p.class() == x509_parser::asn1_rs::Class::Universal && p.as_oid().is_ok() =>
116 {
117 ParameterStatus::Decoded
118 }
119 Some(_) => ParameterStatus::Unparsed, None => ParameterStatus::DecodeError,
121 };
122 }
123 Ok(AlgorithmInfo {
124 oid,
125 name,
126 parameters_der,
127 parameter_status,
128 pss,
129 })
130}
131
132pub(crate) fn rsa_bits(bytes: &[u8]) -> Option<usize> {
133 let key = pkcs1::RsaPublicKey::from_der(bytes).ok()?;
134 let modulus = key.modulus.as_bytes();
135 let Some(first) = modulus.iter().position(|b| *b != 0) else {
136 return Some(0);
137 };
138 Some((modulus.len() - first) * 8 - modulus[first].leading_zeros() as usize)
139}
140
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143#[cfg_attr(feature = "serde", derive(serde::Serialize))]
144#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
145#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
146#[non_exhaustive]
147pub enum KeyDataStatus {
148 Unparsed,
150 Decoded,
152 DecodeError,
154}
155
156pub(crate) fn key_details(
157 oid: &str,
158 curve: Option<&str>,
159 bytes: &[u8],
160 unused: u8,
161) -> (Option<usize>, KeyDataStatus) {
162 let decoded = |bits| (Some(bits), KeyDataStatus::Decoded);
163 let failed = (None, KeyDataStatus::DecodeError);
164 match oid {
165 "1.2.840.113549.1.1.1" | "1.2.840.113549.1.1.10" => {
166 if unused != 0 {
167 return failed;
168 }
169 rsa_bits(bytes).map(decoded).unwrap_or(failed)
170 }
171 "1.3.101.110" | "1.3.101.112" => {
172 if bytes.len() == 32 && unused == 0 {
173 decoded(255)
174 } else {
175 failed
176 }
177 }
178 "1.3.101.111" | "1.3.101.113" => {
179 let encoded_length = if oid == "1.3.101.111" { 56 } else { 57 };
180 if bytes.len() == encoded_length && unused == 0 {
181 decoded(448)
182 } else {
183 failed
184 }
185 }
186 "1.2.840.10045.2.1" => {
187 let bits: usize = match curve {
188 Some(
189 "1.2.840.10045.3.1.7"
190 | "1.3.132.0.10"
191 | "1.2.156.10197.1.301"
192 | "1.3.36.3.3.2.8.1.1.7",
193 ) => 256,
194 Some("1.2.840.10045.3.1.1") => 192,
195 Some("1.3.132.0.33") => 224,
196 Some("1.3.36.3.3.2.8.1.1.13") => 512,
197 Some("1.3.132.0.34" | "1.3.36.3.3.2.8.1.1.11") => 384,
198 Some("1.3.132.0.35") => 521,
199 _ => return (None, KeyDataStatus::Unparsed),
200 };
201 let width = bits.div_ceil(8);
202 let expected = match bytes.first() {
204 Some(2 | 3) => 1 + width,
205 Some(4) => 1 + 2 * width,
206 _ => return failed,
207 };
208 if bytes.len() == expected && unused == 0 {
209 decoded(bits)
210 } else {
211 failed
212 }
213 }
214 _ => (None, KeyDataStatus::Unparsed),
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use x509_parser::asn1_rs::{Any, FromDer, Oid};
222
223 fn pss(params: Option<&[u8]>, signature: bool) -> AlgorithmInfo {
224 let oid = Oid::from(&[1, 2, 840, 113549, 1, 1, 10]).unwrap();
225 let params = params.map(|p| Any::from_der(p).unwrap().1);
226 inspect(
227 &AlgorithmIdentifier::new(oid, params),
228 signature,
229 &OidNames::default(),
230 )
231 .unwrap()
232 }
233
234 #[test]
235 fn pss_defaults_absent_restrictions_and_decode_failures_are_distinct() {
236 let default = pss(Some(&[0x30, 0]), true);
237 assert_eq!(default.parameter_status, ParameterStatus::Decoded);
238 let p = default.pss.unwrap();
239 assert_eq!(p.hash_oid, "1.3.14.3.2.26");
240 assert_eq!(p.mask_gen_hash_oid.as_deref(), Some("1.3.14.3.2.26"));
241 assert_eq!(p.salt_length, 20);
242 assert_eq!(pss(None, false).parameter_status, ParameterStatus::Absent);
243 assert_eq!(
244 pss(None, true).parameter_status,
245 ParameterStatus::DecodeError
246 );
247 for bytes in [
248 &[5, 0][..],
249 &[0x30, 3, 0xa2, 1, 0],
250 &[0x30, 6, 0xa2, 4, 2, 2, 1, 0], &[0x30, 2, 5, 0], ] {
253 let info = pss(Some(bytes), true);
254 assert_eq!(info.parameter_status, ParameterStatus::DecodeError);
255 assert_eq!(info.parameters_der.as_deref(), Some(bytes));
256 assert_eq!(info.pss, None);
257 }
258 }
259
260 #[test]
261 fn montgomery_and_additional_prime_curves_use_their_actual_encodings() {
262 assert_eq!(
263 key_details("1.3.101.110", None, &[0; 32], 0),
264 (Some(255), KeyDataStatus::Decoded)
265 );
266 assert_eq!(
267 key_details("1.3.101.111", None, &[0; 56], 0),
268 (Some(448), KeyDataStatus::Decoded)
269 );
270 assert_eq!(
271 key_details("1.3.101.111", None, &[0; 57], 0),
272 (None, KeyDataStatus::DecodeError)
273 );
274 for (oid, bits) in [
275 ("1.2.840.10045.3.1.1", 192usize),
276 ("1.3.132.0.33", 224),
277 ("1.3.36.3.3.2.8.1.1.7", 256),
278 ("1.3.36.3.3.2.8.1.1.11", 384),
279 ("1.3.36.3.3.2.8.1.1.13", 512),
280 ] {
281 let bytes = vec![2; 1 + bits.div_ceil(8)];
282 assert_eq!(
283 key_details("1.2.840.10045.2.1", Some(oid), &bytes, 0),
284 (Some(bits), KeyDataStatus::Decoded)
285 );
286 }
287 assert_eq!(
289 key_details("2.16.840.1.101.3.4.3.17", None, &[0; 32], 0),
290 (None, KeyDataStatus::Unparsed)
291 );
292 }
293
294 #[test]
295 fn key_encoding_failures_do_not_become_unknown_algorithms_or_fake_sizes() {
296 assert_eq!(
297 key_details("1.3.101.112", None, &[0; 31], 0),
298 (None, KeyDataStatus::DecodeError)
299 );
300 assert_eq!(
301 key_details("1.3.101.113", None, &[0; 57], 1),
302 (None, KeyDataStatus::DecodeError)
303 );
304 assert_eq!(
305 key_details("1.2.3.4", None, &[0; 32], 0),
306 (None, KeyDataStatus::Unparsed)
307 );
308 assert_eq!(
309 key_details("1.2.840.10045.2.1", Some("1.2.3.4"), &[4; 65], 0),
310 (None, KeyDataStatus::Unparsed)
311 );
312 assert_eq!(
313 key_details(
314 "1.2.840.10045.2.1",
315 Some("1.2.840.10045.3.1.7"),
316 &[4; 64],
317 0
318 ),
319 (None, KeyDataStatus::DecodeError)
320 );
321 assert_eq!(
322 key_details("1.2.840.113549.1.1.1", None, &[0x30, 0], 0),
323 (None, KeyDataStatus::DecodeError)
324 );
325 }
326}