1use serde::{Deserialize, Serialize};
19use x509_cert::Certificate;
20use x509_cert::der::asn1::UintRef;
21use x509_cert::der::oid::db::fips204::{ID_ML_DSA_44, ID_ML_DSA_65, ID_ML_DSA_87};
22use x509_cert::der::oid::db::rfc5912::{
23 ID_EC_PUBLIC_KEY, RSA_ENCRYPTION, SECP_256_R_1, SECP_384_R_1,
24};
25use x509_cert::der::oid::db::rfc8410::ID_ED_25519;
26use x509_cert::der::{Decode, Encode, Reader, SliceReader};
27use x509_cert::spki::SubjectPublicKeyInfoRef;
28
29use crate::backend::BackendError;
30use crate::types::KeyAlgorithm;
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(try_from = "Vec<u8>", into = "Vec<u8>")]
38pub struct PublicKeyDer(Vec<u8>);
39
40impl PublicKeyDer {
41 pub fn new(der: Vec<u8>) -> Result<Self, BackendError> {
52 SubjectPublicKeyInfoRef::from_der(&der).map_err(|e| {
53 BackendError::InvalidKeyFormat(format!("not a SubjectPublicKeyInfo: {e}"))
54 })?;
55 Ok(Self(der))
56 }
57
58 pub fn from_key_material(bytes: &[u8]) -> Result<Self, BackendError> {
74 if let Ok((label, der)) = x509_cert::der::pem::decode_vec(bytes) {
78 return match label {
79 "PUBLIC KEY" => Self::new(der),
80 "CERTIFICATE" => certificate_public_key(&der),
81 other => Err(BackendError::InvalidKeyFormat(format!(
82 "PEM block is labelled '{other}', expected 'PUBLIC KEY' or 'CERTIFICATE'"
83 ))),
84 };
85 }
86
87 if let Ok(key) = Self::new(bytes.to_vec()) {
89 return Ok(key);
90 }
91 certificate_public_key(bytes).map_err(|e| {
95 BackendError::InvalidKeyFormat(format!(
96 "not a public key or certificate, in DER or PEM ({e})"
97 ))
98 })
99 }
100
101 #[must_use]
103 pub fn as_bytes(&self) -> &[u8] {
104 &self.0
105 }
106
107 pub fn algorithm(&self) -> Result<KeyAlgorithm, BackendError> {
120 let spki = SubjectPublicKeyInfoRef::from_der(&self.0)
124 .map_err(|e| BackendError::InvalidKeyFormat(format!("SPKI is unreadable: {e}")))?;
125
126 match spki.algorithm.oid {
127 RSA_ENCRYPTION => {
128 let key = spki.subject_public_key.as_bytes().ok_or_else(|| {
129 BackendError::InvalidKeyFormat(
130 "RSA public key is not a whole number of bytes".to_string(),
131 )
132 })?;
133 rsa_algorithm(key)
134 }
135 ID_EC_PUBLIC_KEY => match spki.algorithm.parameters_oid() {
136 Ok(SECP_256_R_1) => Ok(KeyAlgorithm::EcdsaP256),
137 Ok(SECP_384_R_1) => Ok(KeyAlgorithm::EcdsaP384),
138 Ok(curve) => Err(BackendError::UnsupportedAlgorithm(format!(
139 "EC curve {curve} is not supported (expected P-256 or P-384)"
140 ))),
141 Err(e) => Err(BackendError::InvalidKeyFormat(format!(
142 "EC key does not name a curve: {e}"
143 ))),
144 },
145 ID_ED_25519 => Ok(KeyAlgorithm::Ed25519),
146 ID_ML_DSA_44 => Ok(KeyAlgorithm::MlDsa44),
147 ID_ML_DSA_65 => Ok(KeyAlgorithm::MlDsa65),
148 ID_ML_DSA_87 => Ok(KeyAlgorithm::MlDsa87),
149 oid => Err(BackendError::UnsupportedAlgorithm(format!(
150 "public key algorithm {oid} is not supported"
151 ))),
152 }
153 }
154}
155
156impl From<PublicKeyDer> for Vec<u8> {
157 fn from(key: PublicKeyDer) -> Self {
158 key.0
159 }
160}
161
162impl TryFrom<Vec<u8>> for PublicKeyDer {
163 type Error = BackendError;
164
165 fn try_from(der: Vec<u8>) -> Result<Self, Self::Error> {
166 Self::new(der)
167 }
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172#[serde(try_from = "Vec<u8>", into = "Vec<u8>")]
173pub struct CertificateDer(Vec<u8>);
174
175impl CertificateDer {
176 pub fn new(der: Vec<u8>) -> Result<Self, BackendError> {
183 Certificate::from_der(&der).map_err(|e| {
184 BackendError::InvalidKeyFormat(format!("not an X.509 certificate: {e}"))
185 })?;
186 Ok(Self(der))
187 }
188
189 pub fn from_key_material(bytes: &[u8]) -> Result<Self, BackendError> {
203 if let Ok((label, der)) = x509_cert::der::pem::decode_vec(bytes) {
204 return match label {
205 "CERTIFICATE" => Self::new(der),
206 other => Err(BackendError::InvalidKeyFormat(format!(
207 "PEM block is labelled '{other}', expected 'CERTIFICATE'"
208 ))),
209 };
210 }
211 Self::new(bytes.to_vec())
212 }
213
214 #[must_use]
216 pub fn as_bytes(&self) -> &[u8] {
217 &self.0
218 }
219
220 pub fn public_key(&self) -> Result<PublicKeyDer, BackendError> {
232 certificate_public_key(&self.0)
233 }
234}
235
236fn certificate_public_key(der: &[u8]) -> Result<PublicKeyDer, BackendError> {
242 let certificate = Certificate::from_der(der)
243 .map_err(|e| BackendError::InvalidKeyFormat(format!("not an X.509 certificate: {e}")))?;
244 let spki = certificate
245 .tbs_certificate()
246 .subject_public_key_info()
247 .to_der()
248 .map_err(|e| {
249 BackendError::InvalidKeyFormat(format!(
250 "certificate's public key cannot be encoded: {e}"
251 ))
252 })?;
253 PublicKeyDer::new(spki)
254}
255
256impl From<CertificateDer> for Vec<u8> {
257 fn from(certificate: CertificateDer) -> Self {
258 certificate.0
259 }
260}
261
262impl TryFrom<Vec<u8>> for CertificateDer {
263 type Error = BackendError;
264
265 fn try_from(der: Vec<u8>) -> Result<Self, Self::Error> {
266 Self::new(der)
267 }
268}
269
270fn rsa_algorithm(key: &[u8]) -> Result<KeyAlgorithm, BackendError> {
275 let mut reader = SliceReader::new(key).map_err(|e| {
276 BackendError::InvalidKeyFormat(format!("RSA public key is unreadable: {e}"))
277 })?;
278 let modulus_bits = reader
279 .sequence(|body| {
280 let modulus: UintRef<'_> = body.decode()?;
281 Ok::<_, x509_cert::der::Error>(bit_length(modulus.as_bytes()))
282 })
283 .map_err(|e| BackendError::InvalidKeyFormat(format!("RSA modulus cannot be read: {e}")))?;
284
285 match modulus_bits {
286 2048 => Ok(KeyAlgorithm::Rsa2048),
287 4096 => Ok(KeyAlgorithm::Rsa4096),
288 bits => Err(BackendError::UnsupportedAlgorithm(format!(
289 "RSA key size {bits} bits not supported (expected 2048 or 4096)"
290 ))),
291 }
292}
293
294fn bit_length(magnitude: &[u8]) -> u32 {
299 let Some((&top, rest)) = magnitude.split_first() else {
300 return 0;
301 };
302
303 u32::try_from(rest.len())
304 .unwrap_or(u32::MAX)
305 .saturating_mul(8)
306 .saturating_add(u8::BITS.saturating_sub(top.leading_zeros()))
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312
313 mod vectors {
320 pub const RSA_2048: &[u8] = include_bytes!("../tests/vectors/rsa2048.spki.der");
321 pub const RSA_4096: &[u8] = include_bytes!("../tests/vectors/rsa4096.spki.der");
322 pub const P256: &[u8] = include_bytes!("../tests/vectors/p256.spki.der");
323 pub const P384: &[u8] = include_bytes!("../tests/vectors/p384.spki.der");
324 pub const ED25519: &[u8] = include_bytes!("../tests/vectors/ed25519.spki.der");
325 pub const ML_DSA_44: &[u8] = include_bytes!("../tests/vectors/mldsa44.spki.der");
326 pub const ML_DSA_65: &[u8] = include_bytes!("../tests/vectors/mldsa65.spki.der");
327 pub const ML_DSA_87: &[u8] = include_bytes!("../tests/vectors/mldsa87.spki.der");
328 pub const CERTIFICATE: &[u8] = include_bytes!("../tests/vectors/p256.cert.der");
329 }
330
331 #[test]
332 fn reads_the_algorithm_out_of_each_key_type() {
333 let cases = [
334 (vectors::RSA_2048, KeyAlgorithm::Rsa2048),
335 (vectors::RSA_4096, KeyAlgorithm::Rsa4096),
336 (vectors::P256, KeyAlgorithm::EcdsaP256),
337 (vectors::P384, KeyAlgorithm::EcdsaP384),
338 (vectors::ED25519, KeyAlgorithm::Ed25519),
339 (vectors::ML_DSA_44, KeyAlgorithm::MlDsa44),
340 (vectors::ML_DSA_65, KeyAlgorithm::MlDsa65),
341 (vectors::ML_DSA_87, KeyAlgorithm::MlDsa87),
342 ];
343
344 for (der, expected) in cases {
345 let key = PublicKeyDer::new(der.to_vec()).expect("vector is valid SPKI");
346 assert_eq!(key.algorithm().unwrap(), expected);
347 }
348 }
349
350 #[test]
353 fn rejects_a_certificate_offered_as_a_public_key() {
354 let err = PublicKeyDer::new(vectors::CERTIFICATE.to_vec()).unwrap_err();
355 assert!(
356 err.to_string().contains("not a SubjectPublicKeyInfo"),
357 "{err}"
358 );
359 }
360
361 #[test]
362 fn reads_the_public_key_out_of_a_certificate() {
363 let certificate =
364 CertificateDer::new(vectors::CERTIFICATE.to_vec()).expect("vector is a certificate");
365 let key = certificate.public_key().unwrap();
366 assert_eq!(key.algorithm().unwrap(), KeyAlgorithm::EcdsaP256);
367 assert_eq!(key.as_bytes(), vectors::P256);
368 }
369
370 #[test]
371 fn rejects_a_public_key_offered_as_a_certificate() {
372 assert!(CertificateDer::new(vectors::P256.to_vec()).is_err());
373 }
374
375 #[test]
377 fn rejects_trailing_data() {
378 let mut der = vectors::P256.to_vec();
379 der.push(0);
380 assert!(PublicKeyDer::new(der).is_err());
381 }
382
383 #[test]
384 fn rejects_empty_and_truncated_input() {
385 assert!(PublicKeyDer::new(Vec::new()).is_err());
386 let truncated = vectors::P256
387 .get(..10)
388 .expect("vector is longer than 10 bytes");
389 assert!(PublicKeyDer::new(truncated.to_vec()).is_err());
390 }
391
392 #[test]
394 fn deserializing_rejects_bytes_that_are_not_a_key() {
395 let key = PublicKeyDer::new(vectors::P256.to_vec()).unwrap();
396 let json = serde_json::to_string(&key).unwrap();
397 assert_eq!(serde_json::from_str::<PublicKeyDer>(&json).unwrap(), key);
398
399 let certificate_json = serde_json::to_string(vectors::CERTIFICATE).unwrap();
400 assert!(serde_json::from_str::<PublicKeyDer>(&certificate_json).is_err());
401 }
402
403 fn armour(label: &str, der: &[u8]) -> Vec<u8> {
405 x509_cert::der::pem::encode_string(label, x509_cert::der::pem::LineEnding::LF, der)
406 .expect("armouring is infallible for a valid label")
407 .into_bytes()
408 }
409
410 #[test]
412 fn reads_a_key_from_der_and_pem_and_certificates() {
413 let expected = PublicKeyDer::new(vectors::P256.to_vec()).unwrap();
414
415 let sources = [
416 vectors::P256.to_vec(),
417 armour("PUBLIC KEY", vectors::P256),
418 vectors::CERTIFICATE.to_vec(),
419 armour("CERTIFICATE", vectors::CERTIFICATE),
420 ];
421
422 for source in sources {
423 assert_eq!(PublicKeyDer::from_key_material(&source).unwrap(), expected);
424 }
425 }
426
427 #[test]
430 fn refuses_a_pem_block_that_is_not_a_key_or_certificate() {
431 let private = armour("PRIVATE KEY", vectors::P256);
432 let err = PublicKeyDer::from_key_material(&private).unwrap_err();
433 assert!(err.to_string().contains("PRIVATE KEY"), "{err}");
434 }
435
436 #[test]
437 fn refuses_key_material_that_is_neither() {
438 let err = PublicKeyDer::from_key_material(b"just some bytes").unwrap_err();
439 assert!(
440 err.to_string().contains("public key or certificate"),
441 "{err}"
442 );
443 }
444
445 #[test]
447 fn reads_a_certificate_from_der_and_pem() {
448 let expected = CertificateDer::new(vectors::CERTIFICATE.to_vec()).unwrap();
449
450 for source in [
451 vectors::CERTIFICATE.to_vec(),
452 armour("CERTIFICATE", vectors::CERTIFICATE),
453 ] {
454 assert_eq!(
455 CertificateDer::from_key_material(&source).unwrap(),
456 expected
457 );
458 }
459 }
460
461 #[test]
462 fn refuses_a_pem_block_that_is_not_a_certificate() {
463 let key = armour("PUBLIC KEY", vectors::P256);
464 let err = CertificateDer::from_key_material(&key).unwrap_err();
465 assert!(err.to_string().contains("PUBLIC KEY"), "{err}");
466 }
467
468 #[test]
469 fn bit_length_counts_from_the_top_set_bit() {
470 assert_eq!(bit_length(&[]), 0);
471 assert_eq!(bit_length(&[0x01]), 1);
472 assert_eq!(bit_length(&[0x80]), 8);
473 assert_eq!(bit_length(&[0x80, 0x00]), 16);
474 assert_eq!(bit_length(&[0x0f, 0xff]), 12);
475 }
476}