1use {
8 crate::{
9 rfc3447::DigestInfo,
10 rfc5280::{AlgorithmIdentifier, AlgorithmParameter},
11 X509CertificateError as Error,
12 },
13 bcder::{encode::Values, ConstOid, OctetString, Oid},
14 ring::{digest, signature},
15 spki::ObjectIdentifier,
16 std::fmt::{Display, Formatter},
17};
18
19const OID_SHA1: ConstOid = Oid(&[43, 14, 3, 2, 26]);
23
24const OID_SHA256: ConstOid = Oid(&[96, 134, 72, 1, 101, 3, 4, 2, 1]);
28
29const OID_SHA384: ConstOid = Oid(&[96, 134, 72, 1, 101, 3, 4, 2, 2]);
33
34const OID_SHA512: ConstOid = Oid(&[96, 134, 72, 1, 101, 3, 4, 2, 3]);
38
39const OID_SHA1_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 5]);
43
44const OID_SHA256_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 11]);
48
49const OID_SHA384_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 12]);
53
54const OID_SHA512_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 13]);
58
59const OID_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 1]);
63
64pub(crate) const OID_ECDSA_SHA256: ConstOid = Oid(&[42, 134, 72, 206, 61, 4, 3, 2]);
68
69pub(crate) const OID_ECDSA_SHA384: ConstOid = Oid(&[42, 134, 72, 206, 61, 4, 3, 3]);
73
74pub(crate) const OID_EC_PUBLIC_KEY: ConstOid = Oid(&[42, 134, 72, 206, 61, 2, 1]);
78
79const OID_ED25519_KEY_AGREEMENT: ConstOid = Oid(&[43, 101, 110]);
83
84const OID_ED25519_SIGNATURE_ALGORITHM: ConstOid = Oid(&[43, 101, 112]);
88
89pub(crate) const OID_EC_SECP256R1: ConstOid = Oid(&[42, 134, 72, 206, 61, 3, 1, 7]);
93
94pub(crate) const OID_EC_SECP384R1: ConstOid = Oid(&[43, 129, 4, 0, 34]);
98
99pub(crate) const OID_NO_SIGNATURE_ALGORITHM: ConstOid = Oid(&[43, 6, 1, 5, 5, 7, 6, 2]);
103
104#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
115pub enum DigestAlgorithm {
116 Sha1,
120
121 Sha256,
125
126 Sha384,
130
131 Sha512,
135}
136
137impl Display for DigestAlgorithm {
138 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
139 match self {
140 DigestAlgorithm::Sha1 => f.write_str("SHA-1"),
141 DigestAlgorithm::Sha256 => f.write_str("SHA-256"),
142 DigestAlgorithm::Sha384 => f.write_str("SHA-384"),
143 DigestAlgorithm::Sha512 => f.write_str("SHA-512"),
144 }
145 }
146}
147
148impl From<DigestAlgorithm> for Oid {
149 fn from(alg: DigestAlgorithm) -> Self {
150 Oid(match alg {
151 DigestAlgorithm::Sha1 => OID_SHA1.as_ref(),
152 DigestAlgorithm::Sha256 => OID_SHA256.as_ref(),
153 DigestAlgorithm::Sha384 => OID_SHA384.as_ref(),
154 DigestAlgorithm::Sha512 => OID_SHA512.as_ref(),
155 }
156 .into())
157 }
158}
159
160impl TryFrom<&Oid> for DigestAlgorithm {
161 type Error = Error;
162
163 fn try_from(v: &Oid) -> Result<Self, Self::Error> {
164 if v == &OID_SHA1 {
165 Ok(Self::Sha1)
166 } else if v == &OID_SHA256 {
167 Ok(Self::Sha256)
168 } else if v == &OID_SHA384 {
169 Ok(Self::Sha384)
170 } else if v == &OID_SHA512 {
171 Ok(Self::Sha512)
172 } else {
173 Err(Error::UnknownDigestAlgorithm(format!("{}", v)))
174 }
175 }
176}
177
178impl TryFrom<&AlgorithmIdentifier> for DigestAlgorithm {
179 type Error = Error;
180
181 fn try_from(v: &AlgorithmIdentifier) -> Result<Self, Self::Error> {
182 Self::try_from(&v.algorithm)
183 }
184}
185
186impl From<DigestAlgorithm> for AlgorithmIdentifier {
187 fn from(alg: DigestAlgorithm) -> Self {
188 Self {
189 algorithm: alg.into(),
190 parameters: None,
191 }
192 }
193}
194
195impl From<DigestAlgorithm> for digest::Context {
196 fn from(alg: DigestAlgorithm) -> Self {
197 digest::Context::new(match alg {
198 DigestAlgorithm::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY,
199 DigestAlgorithm::Sha256 => &digest::SHA256,
200 DigestAlgorithm::Sha384 => &digest::SHA384,
201 DigestAlgorithm::Sha512 => &digest::SHA512,
202 })
203 }
204}
205
206impl DigestAlgorithm {
207 pub fn digester(&self) -> digest::Context {
209 digest::Context::from(*self)
210 }
211
212 pub fn digest_data(&self, data: &[u8]) -> Vec<u8> {
214 let mut h = self.digester();
215 h.update(data);
216 h.finish().as_ref().to_vec()
217 }
218
219 pub fn digest_reader<R: std::io::Read>(&self, fh: &mut R) -> Result<Vec<u8>, std::io::Error> {
221 let mut h = self.digester();
222
223 loop {
224 let mut buffer = [0u8; 16384];
225 let count = fh.read(&mut buffer)?;
226
227 h.update(&buffer[0..count]);
228
229 if count < buffer.len() {
230 break;
231 }
232 }
233
234 Ok(h.finish().as_ref().to_vec())
235 }
236
237 pub fn digest_path(&self, path: &std::path::Path) -> Result<Vec<u8>, std::io::Error> {
239 self.digest_reader(&mut std::fs::File::open(path)?)
240 }
241
242 pub fn rsa_pkcs1_encode(
251 &self,
252 message: &[u8],
253 target_length_in_bytes: usize,
254 ) -> Result<Vec<u8>, Error> {
255 let digest = self.digest_data(message);
256
257 let digest_info = DigestInfo {
258 algorithm: (*self).into(),
259 digest: OctetString::new(digest.into()),
260 };
261 let mut digest_info_der = vec![];
262 digest_info.write_encoded(bcder::Mode::Der, &mut digest_info_der)?;
263
264 let encoded_digest_len = digest_info_der.len();
265
266 if encoded_digest_len + 11 > target_length_in_bytes {
270 return Err(Error::PkcsEncodeTooShort);
271 }
272
273 let pad_len = target_length_in_bytes - encoded_digest_len - 3;
274
275 let mut res = vec![0xff; target_length_in_bytes];
276 res[0] = 0x00;
278 res[1] = 0x01;
280 res[2 + pad_len] = 0x00;
283
284 let digest_destination = &mut res[3 + pad_len..];
285 digest_destination.copy_from_slice(&digest_info_der);
286
287 Ok(res)
288 }
289}
290
291#[derive(Copy, Clone, Debug, Eq, PartialEq)]
302pub enum SignatureAlgorithm {
303 RsaSha1,
307
308 RsaSha256,
312
313 RsaSha384,
317
318 RsaSha512,
322
323 EcdsaSha256,
327
328 EcdsaSha384,
332
333 Ed25519,
337
338 NoSignature(DigestAlgorithm)
342}
343
344impl SignatureAlgorithm {
345 pub fn from_oid_and_digest_algorithm(
358 oid: &Oid,
359 digest_algorithm: DigestAlgorithm,
360 ) -> Result<Self, Error> {
361 if let Ok(alg) = Self::try_from(oid) {
362 Ok(alg)
363 } else if let Ok(key_alg) = KeyAlgorithm::try_from(oid) {
364 match key_alg {
365 KeyAlgorithm::Rsa => match digest_algorithm {
366 DigestAlgorithm::Sha1 => Ok(Self::RsaSha1),
367 DigestAlgorithm::Sha256 => Ok(Self::RsaSha256),
368 DigestAlgorithm::Sha384 => Ok(Self::RsaSha384),
369 DigestAlgorithm::Sha512 => Ok(Self::RsaSha512),
370 },
371 KeyAlgorithm::Ed25519 => Ok(Self::Ed25519),
372 KeyAlgorithm::Ecdsa(_) => match digest_algorithm {
373 DigestAlgorithm::Sha256 => Ok(Self::EcdsaSha256),
374 DigestAlgorithm::Sha384 => Ok(Self::EcdsaSha384),
375 DigestAlgorithm::Sha1 | DigestAlgorithm::Sha512 => {
376 Err(Error::UnknownSignatureAlgorithm(format!(
377 "cannot use digest {:?} with ECDSA",
378 digest_algorithm
379 )))
380 }
381 },
382 }
383 } else if oid == &OID_NO_SIGNATURE_ALGORITHM {
384 Ok(Self::NoSignature(digest_algorithm))
385 } else {
386 Err(Error::UnknownSignatureAlgorithm(format!(
387 "do not know how to resolve {} to a signature algorithm",
388 oid
389 )))
390 }
391 }
392
393 pub fn from_digest_algorithm(
395 digest_algorithm: DigestAlgorithm,
396 ) -> Self {
397 Self::NoSignature(digest_algorithm)
398 }
399
400 pub fn resolve_verification_algorithm(
405 &self,
406 key_algorithm: KeyAlgorithm,
407 ) -> Result<&'static dyn signature::VerificationAlgorithm, Error> {
408 match key_algorithm {
409 KeyAlgorithm::Rsa => match self {
410 Self::RsaSha1 => Ok(&signature::RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY),
411 Self::RsaSha256 => Ok(&signature::RSA_PKCS1_2048_8192_SHA256),
412 Self::RsaSha384 => Ok(&signature::RSA_PKCS1_2048_8192_SHA384),
413 Self::RsaSha512 => Ok(&signature::RSA_PKCS1_2048_8192_SHA512),
414 alg => Err(Error::UnsupportedSignatureVerification(key_algorithm, *alg)),
415 },
416 KeyAlgorithm::Ed25519 => match self {
417 Self::Ed25519 => Ok(&signature::ED25519),
418 alg => Err(Error::UnsupportedSignatureVerification(key_algorithm, *alg)),
419 },
420 KeyAlgorithm::Ecdsa(curve) => match curve {
421 EcdsaCurve::Secp256r1 => match self {
422 Self::EcdsaSha256 => Ok(&signature::ECDSA_P256_SHA256_ASN1),
423 Self::EcdsaSha384 => Ok(&signature::ECDSA_P256_SHA384_ASN1),
424 alg => Err(Error::UnsupportedSignatureVerification(key_algorithm, *alg)),
425 },
426 EcdsaCurve::Secp384r1 => match self {
427 Self::EcdsaSha256 => Ok(&signature::ECDSA_P384_SHA256_ASN1),
428 Self::EcdsaSha384 => Ok(&signature::ECDSA_P384_SHA384_ASN1),
429 alg => Err(Error::UnsupportedSignatureVerification(key_algorithm, *alg)),
430 },
431 },
432 }
433 }
434
435 pub fn digest_algorithm(&self) -> Option<DigestAlgorithm> {
437 match self {
438 SignatureAlgorithm::RsaSha1 => Some(DigestAlgorithm::Sha1),
439 SignatureAlgorithm::RsaSha256 => Some(DigestAlgorithm::Sha256),
440 SignatureAlgorithm::RsaSha384 => Some(DigestAlgorithm::Sha384),
441 SignatureAlgorithm::RsaSha512 => Some(DigestAlgorithm::Sha512),
442 SignatureAlgorithm::EcdsaSha256 => Some(DigestAlgorithm::Sha256),
443 SignatureAlgorithm::EcdsaSha384 => Some(DigestAlgorithm::Sha384),
444 SignatureAlgorithm::Ed25519 => None,
446 SignatureAlgorithm::NoSignature(digest_algorithm) => Some(*digest_algorithm),
447 }
448 }
449}
450
451impl Display for SignatureAlgorithm {
452 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
453 match self {
454 SignatureAlgorithm::RsaSha1 => f.write_str("SHA-1 with RSA encryption"),
455 SignatureAlgorithm::RsaSha256 => f.write_str("SHA-256 with RSA encryption"),
456 SignatureAlgorithm::RsaSha384 => f.write_str("SHA-384 with RSA encryption"),
457 SignatureAlgorithm::RsaSha512 => f.write_str("SHA-512 with RSA encryption"),
458 SignatureAlgorithm::EcdsaSha256 => f.write_str("ECDSA with SHA-256"),
459 SignatureAlgorithm::EcdsaSha384 => f.write_str("ECDSA with SHA-384"),
460 SignatureAlgorithm::Ed25519 => f.write_str("ED25519"),
461 SignatureAlgorithm::NoSignature(digest_algorithm) => f.write_fmt(format_args!("No signature with {}", digest_algorithm)),
462 }
463 }
464}
465
466impl From<SignatureAlgorithm> for Oid {
467 fn from(alg: SignatureAlgorithm) -> Self {
468 Oid(match alg {
469 SignatureAlgorithm::RsaSha1 => OID_SHA1_RSA.as_ref(),
470 SignatureAlgorithm::RsaSha256 => OID_SHA256_RSA.as_ref(),
471 SignatureAlgorithm::RsaSha384 => OID_SHA384_RSA.as_ref(),
472 SignatureAlgorithm::RsaSha512 => OID_SHA512_RSA.as_ref(),
473 SignatureAlgorithm::EcdsaSha256 => OID_ECDSA_SHA256.as_ref(),
474 SignatureAlgorithm::EcdsaSha384 => OID_ECDSA_SHA384.as_ref(),
475 SignatureAlgorithm::Ed25519 => OID_ED25519_SIGNATURE_ALGORITHM.as_ref(),
476 SignatureAlgorithm::NoSignature(_) => OID_NO_SIGNATURE_ALGORITHM.as_ref(),
477 }
478 .into())
479 }
480}
481
482impl TryFrom<&Oid> for SignatureAlgorithm {
483 type Error = Error;
484
485 fn try_from(v: &Oid) -> Result<Self, Self::Error> {
486 if v == &OID_SHA1_RSA {
487 Ok(Self::RsaSha1)
488 } else if v == &OID_SHA256_RSA {
489 Ok(Self::RsaSha256)
490 } else if v == &OID_SHA384_RSA {
491 Ok(Self::RsaSha384)
492 } else if v == &OID_SHA512_RSA {
493 Ok(Self::RsaSha512)
494 } else if v == &OID_ECDSA_SHA256 {
495 Ok(Self::EcdsaSha256)
496 } else if v == &OID_ECDSA_SHA384 {
497 Ok(Self::EcdsaSha384)
498 } else if v == &OID_ED25519_SIGNATURE_ALGORITHM {
499 Ok(Self::Ed25519)
500 } else {
501 Err(Error::UnknownSignatureAlgorithm(format!("{}", v)))
502 }
503 }
504}
505
506impl TryFrom<&AlgorithmIdentifier> for SignatureAlgorithm {
507 type Error = Error;
508
509 fn try_from(v: &AlgorithmIdentifier) -> Result<Self, Self::Error> {
510 Self::try_from(&v.algorithm)
511 }
512}
513
514impl From<SignatureAlgorithm> for AlgorithmIdentifier {
515 fn from(alg: SignatureAlgorithm) -> Self {
516 Self {
517 algorithm: alg.into(),
518 parameters: None,
519 }
520 }
521}
522
523#[derive(Copy, Clone, Debug, Eq, PartialEq)]
525pub enum EcdsaCurve {
526 Secp256r1,
527 Secp384r1,
528}
529
530impl EcdsaCurve {
531 pub fn all() -> &'static [Self] {
533 &[Self::Secp256r1, Self::Secp384r1]
534 }
535
536 pub fn as_signature_oid(&self) -> Oid {
538 Oid(match self {
539 Self::Secp256r1 => OID_EC_SECP256R1.as_ref().into(),
540 Self::Secp384r1 => OID_EC_SECP384R1.as_ref().into(),
541 })
542 }
543}
544
545impl TryFrom<&Oid> for EcdsaCurve {
546 type Error = Error;
547
548 fn try_from(v: &Oid) -> Result<Self, Self::Error> {
549 if v == &OID_EC_SECP256R1 {
550 Ok(Self::Secp256r1)
551 } else if v == &OID_EC_SECP384R1 {
552 Ok(Self::Secp384r1)
553 } else {
554 Err(Error::UnknownEllipticCurve(format!("{}", v)))
555 }
556 }
557}
558
559impl From<EcdsaCurve> for &'static signature::EcdsaSigningAlgorithm {
560 fn from(curve: EcdsaCurve) -> Self {
561 match curve {
562 EcdsaCurve::Secp256r1 => &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
563 EcdsaCurve::Secp384r1 => &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
564 }
565 }
566}
567
568#[derive(Copy, Clone, Debug, Eq, PartialEq)]
573pub enum KeyAlgorithm {
574 Rsa,
578
579 Ecdsa(EcdsaCurve),
583
584 Ed25519,
586}
587
588impl Display for KeyAlgorithm {
589 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
590 match self {
591 Self::Rsa => f.write_str("RSA"),
592 Self::Ecdsa(_) => f.write_str("ECDSA"),
593 Self::Ed25519 => f.write_str("ED25519"),
594 }
595 }
596}
597
598impl TryFrom<&Oid> for KeyAlgorithm {
599 type Error = Error;
600
601 fn try_from(v: &Oid) -> Result<Self, Self::Error> {
602 if v == &OID_RSA {
603 Ok(Self::Rsa)
604 } else if v == &OID_EC_PUBLIC_KEY {
605 Ok(Self::Ecdsa(EcdsaCurve::Secp384r1))
607 } else if v == &OID_ED25519_KEY_AGREEMENT || v == &OID_ED25519_SIGNATURE_ALGORITHM {
610 Ok(Self::Ed25519)
611 } else {
612 Err(Error::UnknownKeyAlgorithm(format!("{}", v)))
613 }
614 }
615}
616
617impl TryFrom<&ObjectIdentifier> for KeyAlgorithm {
618 type Error = Error;
619
620 fn try_from(v: &ObjectIdentifier) -> Result<Self, Self::Error> {
621 match v.as_bytes() {
623 x if x == OID_RSA.as_ref() => Ok(Self::Rsa),
624 x if x == OID_EC_PUBLIC_KEY.as_ref() => Ok(Self::Ecdsa(EcdsaCurve::Secp384r1)),
625 x if x == OID_ED25519_KEY_AGREEMENT.as_ref()
626 || x == OID_ED25519_SIGNATURE_ALGORITHM.as_ref() =>
627 {
628 Ok(Self::Ed25519)
629 }
630 _ => Err(Error::UnknownKeyAlgorithm(v.to_string())),
631 }
632 }
633}
634
635impl From<KeyAlgorithm> for Oid {
636 fn from(alg: KeyAlgorithm) -> Self {
637 Oid(match alg {
638 KeyAlgorithm::Rsa => OID_RSA.as_ref(),
639 KeyAlgorithm::Ecdsa(_) => OID_EC_PUBLIC_KEY.as_ref(),
640 KeyAlgorithm::Ed25519 => OID_ED25519_KEY_AGREEMENT.as_ref(),
641 }
642 .into())
643 }
644}
645
646impl From<KeyAlgorithm> for ObjectIdentifier {
647 fn from(alg: KeyAlgorithm) -> Self {
648 let bytes = match alg {
649 KeyAlgorithm::Rsa => OID_RSA.as_ref(),
650 KeyAlgorithm::Ecdsa(_) => OID_EC_PUBLIC_KEY.as_ref(),
651 KeyAlgorithm::Ed25519 => OID_ED25519_KEY_AGREEMENT.as_ref(),
652 };
653
654 ObjectIdentifier::from_bytes(bytes).expect("OID bytes should be valid")
655 }
656}
657
658impl TryFrom<&AlgorithmIdentifier> for KeyAlgorithm {
659 type Error = Error;
660
661 fn try_from(v: &AlgorithmIdentifier) -> Result<Self, Self::Error> {
662 let ka = Self::try_from(&v.algorithm)?;
665
666 let ka = if let Some(params) = &v.parameters {
667 match ka {
668 Self::Ecdsa(_) => {
669 let curve_oid = params.decode_oid()?;
670 let curve = EcdsaCurve::try_from(&curve_oid)?;
671
672 Ok(Self::Ecdsa(curve))
673 }
674 Self::Ed25519 => {
675 if params.as_slice() == [0x05, 0x00] {
677 Ok(ka)
678 } else {
679 Err(Error::UnhandledKeyAlgorithmParameters("on ED25519"))
680 }
681 }
682 Self::Rsa => {
683 if params.as_slice() == [0x05, 0x00] {
685 Ok(ka)
686 } else {
687 Err(Error::UnhandledKeyAlgorithmParameters("on RSA"))
688 }
689 }
690 }?
691 } else {
692 ka
693 };
694
695 Ok(ka)
696 }
697}
698
699impl From<KeyAlgorithm> for AlgorithmIdentifier {
700 fn from(alg: KeyAlgorithm) -> Self {
701 let parameters = match alg {
702 KeyAlgorithm::Ed25519 => None,
703 KeyAlgorithm::Rsa => None,
704 KeyAlgorithm::Ecdsa(curve) => {
705 Some(AlgorithmParameter::from_oid(curve.as_signature_oid()))
706 }
707 };
708
709 Self {
710 algorithm: alg.into(),
711 parameters,
712 }
713 }
714}
715
716#[cfg(test)]
717mod test {
718 use super::*;
719
720 #[test]
721 fn digest_pkcs1() -> Result<(), Error> {
722 let message = b"deadbeef";
723 let raw_digest = DigestAlgorithm::Sha256.digest_data(message);
724
725 let encoded = DigestAlgorithm::Sha256.rsa_pkcs1_encode(message, 128)?;
727 assert_eq!(&encoded[0..3], &[0x00, 0x01, 0xff]);
728 assert_eq!(&encoded[96..], &raw_digest);
729
730 Ok(())
731 }
732
733 #[test]
734 fn key_algorithm_oids() -> Result<(), Error> {
735 let oid = ObjectIdentifier::from(KeyAlgorithm::Rsa);
736 assert_eq!(oid.to_string(), "1.2.840.113549.1.1.1");
737 let oid = ObjectIdentifier::new("1.2.840.113549.1.1.1").unwrap();
738 assert_eq!(KeyAlgorithm::try_from(&oid)?, KeyAlgorithm::Rsa);
739
740 let oid = ObjectIdentifier::from(KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1));
741 assert_eq!(oid.to_string(), "1.2.840.10045.2.1");
742 let oid = ObjectIdentifier::new("1.2.840.10045.2.1").unwrap();
743 assert_eq!(
744 KeyAlgorithm::try_from(&oid)?,
745 KeyAlgorithm::Ecdsa(EcdsaCurve::Secp384r1)
746 );
747
748 let oid = ObjectIdentifier::from(KeyAlgorithm::Ed25519);
749 assert_eq!(oid.to_string(), "1.3.101.110");
750 let oid = ObjectIdentifier::new("1.3.101.110").unwrap();
751 assert_eq!(KeyAlgorithm::try_from(&oid)?, KeyAlgorithm::Ed25519);
752
753 Ok(())
754 }
755}