x509_certificate/
algorithm.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Cryptographic algorithms commonly encountered in X.509 certificates.
6
7use {
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
19/// SHA-1 digest algorithm.
20///
21/// 1.3.14.3.2.26
22const OID_SHA1: ConstOid = Oid(&[43, 14, 3, 2, 26]);
23
24/// SHA-256 digest algorithm.
25///
26/// 2.16.840.1.101.3.4.2.1
27const OID_SHA256: ConstOid = Oid(&[96, 134, 72, 1, 101, 3, 4, 2, 1]);
28
29/// SHA-512 digest algorithm.
30///
31/// 2.16.840.1.101.3.4.2.2
32const OID_SHA384: ConstOid = Oid(&[96, 134, 72, 1, 101, 3, 4, 2, 2]);
33
34/// SHA-512 digest algorithm.
35///
36/// 2.16.840.1.101.3.4.2.3
37const OID_SHA512: ConstOid = Oid(&[96, 134, 72, 1, 101, 3, 4, 2, 3]);
38
39/// RSA+SHA-1 encryption.
40///
41/// 1.2.840.113549.1.1.5
42const OID_SHA1_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 5]);
43
44/// RSA+SHA-256 encryption.
45///
46/// 1.2.840.113549.1.1.11
47const OID_SHA256_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 11]);
48
49/// RSA+SHA-384 encryption.
50///
51/// 1.2.840.113549.1.1.12
52const OID_SHA384_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 12]);
53
54/// RSA+SHA-512 encryption.
55///
56/// 1.2.840.113549.1.1.13
57const OID_SHA512_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 13]);
58
59/// RSA encryption.
60///
61/// 1.2.840.113549.1.1.1
62const OID_RSA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 1, 1]);
63
64/// ECDSA with SHA-256.
65///
66/// 1.2.840.10045.4.3.2
67pub(crate) const OID_ECDSA_SHA256: ConstOid = Oid(&[42, 134, 72, 206, 61, 4, 3, 2]);
68
69/// ECDSA with SHA-384.
70///
71/// 1.2.840.10045.4.3.2
72pub(crate) const OID_ECDSA_SHA384: ConstOid = Oid(&[42, 134, 72, 206, 61, 4, 3, 3]);
73
74/// Elliptic curve public key cryptography.
75///
76/// 1.2.840.10045.2.1
77pub(crate) const OID_EC_PUBLIC_KEY: ConstOid = Oid(&[42, 134, 72, 206, 61, 2, 1]);
78
79/// ED25519 key agreement.
80///
81/// 1.3.101.110
82const OID_ED25519_KEY_AGREEMENT: ConstOid = Oid(&[43, 101, 110]);
83
84/// Edwards curve digital signature algorithm.
85///
86/// 1.3.101.112
87const OID_ED25519_SIGNATURE_ALGORITHM: ConstOid = Oid(&[43, 101, 112]);
88
89/// Elliptic curve identifier for secp256r1.
90///
91/// 1.2.840.10045.3.1.7
92pub(crate) const OID_EC_SECP256R1: ConstOid = Oid(&[42, 134, 72, 206, 61, 3, 1, 7]);
93
94/// Elliptic curve identifier for secp384r1.
95///
96/// 1.3.132.0.34
97pub(crate) const OID_EC_SECP384R1: ConstOid = Oid(&[43, 129, 4, 0, 34]);
98
99/// No signature identifier
100/// 
101/// 1.3.6.1.5.5.7.6.2
102pub(crate) const OID_NO_SIGNATURE_ALGORITHM: ConstOid = Oid(&[43, 6, 1, 5, 5, 7, 6, 2]);
103
104/// A hashing algorithm used for digesting data.
105///
106/// Instances can be converted to and from [Oid] via `From`/`Into`
107/// implementations.
108///
109/// They can also be converted to and from The ASN.1 [AlgorithmIdentifier],
110/// which is commonly used to represent them in X.509 certificates.
111///
112/// Instances can be converted into a [digest::Context] capable of computing
113/// digests via `From`/`Into`.
114#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
115pub enum DigestAlgorithm {
116    /// SHA-1.
117    ///
118    /// Corresponds to OID 1.3.14.3.2.26.
119    Sha1,
120
121    /// SHA-256.
122    ///
123    /// Corresponds to OID 2.16.840.1.101.3.4.2.1.
124    Sha256,
125
126    /// SHA-384.
127    ///
128    /// Corresponds to OID 2.16.840.1.101.3.4.2.2.
129    Sha384,
130
131    /// SHA-512.
132    ///
133    /// Corresponds to OID 2.16.840.1.101.3.4.2.3.
134    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    /// Obtain an object that can be used to digest content using this algorithm.
208    pub fn digester(&self) -> digest::Context {
209        digest::Context::from(*self)
210    }
211
212    /// Digest a slice of data.
213    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    /// Digest content from a reader.
220    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    /// Digest the content of a path.
238    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    /// EMSA-PKCS1-v1_5 padding procedure.
243    ///
244    /// As defined by https://tools.ietf.org/html/rfc3447#section-9.2.
245    ///
246    /// `message` is the message to digest and encode.
247    ///
248    /// `target_length_in_bytes` is the target length of the padding. This should match the RSA
249    /// key length. e.g. 2048 bit keys are length 256.
250    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        // At least 8 bytes of padding are required. And there's a 2 byte header plus NULL
267        // termination of the padding. So the target length must be 11+ bytes longer than
268        // the encoded digest.
269        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        // Constant header.
277        res[0] = 0x00;
278        // Private key block type.
279        res[1] = 0x01;
280        // Padding bytes are already filled in.
281        // NULL terminate padding.
282        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/// An algorithm used to digitally sign content.
292///
293/// Instances can be converted to/from [Oid] via `From`/`Into`.
294///
295/// Similarly, instances can be converted to/from an ASN.1
296/// [AlgorithmIdentifier].
297///
298/// It is also possible to obtain a [signature::VerificationAlgorithm] from
299/// an instance. This type can perform actual cryptographic verification
300/// that was signed with this algorithm.
301#[derive(Copy, Clone, Debug, Eq, PartialEq)]
302pub enum SignatureAlgorithm {
303    /// SHA-1 with RSA encryption.
304    ///
305    /// Corresponds to OID 1.2.840.113549.1.1.5.
306    RsaSha1,
307
308    /// SHA-256 with RSA encryption.
309    ///
310    /// Corresponds to OID 1.2.840.113549.1.1.11.
311    RsaSha256,
312
313    /// SHA-384 with RSA encryption.
314    ///
315    /// Corresponds to OID 1.2.840.113549.1.1.12.
316    RsaSha384,
317
318    /// SHA-512 with RSA encryption.
319    ///
320    /// Corresponds to OID 1.2.840.113549.1.1.13.
321    RsaSha512,
322
323    /// ECDSA with SHA-256.
324    ///
325    /// Corresponds to OID 1.2.840.10045.4.3.2.
326    EcdsaSha256,
327
328    /// ECDSA with SHA-384.
329    ///
330    /// Corresponds to OID 1.2.840.10045.4.3.3.
331    EcdsaSha384,
332
333    /// ED25519
334    ///
335    /// Corresponds to OID 1.3.101.112.
336    Ed25519,
337
338    /// No signature with digest algorithm
339    /// 
340    /// Corresponds to OID 1.3.6.1.5.5.7.6.2
341    NoSignature(DigestAlgorithm)
342}
343
344impl SignatureAlgorithm {
345    /// Attempt to resolve an instance from an OID, known [KeyAlgorithm], and optional [DigestAlgorithm].
346    ///
347    /// Signature algorithm OIDs in the wild are typically either:
348    ///
349    /// a) an OID that denotes the key algorithm and corresponding digest format (what this
350    ///    enumeration represents)
351    /// b) an OID that denotes just the key algorithm.
352    ///
353    /// What this function does is attempt to construct an instance from any OID.
354    /// If the OID defines a key + digest algorithm, we get a [SignatureAlgorithm]
355    /// from that. If we get a key algorithm we combine with the provided [DigestAlgorithm]
356    /// to resolve an appropriate [SignatureAlgorithm].
357    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    /// Creates an instance with the noSignature mechanism and [DigestAlgorithm]
394    pub fn from_digest_algorithm(
395        digest_algorithm: DigestAlgorithm,
396    ) -> Self {
397        Self::NoSignature(digest_algorithm)
398    }
399
400    /// Attempt to resolve the verification algorithm using info about the signing key algorithm.
401    ///
402    /// Only specific combinations of methods are supported. e.g. you can only use
403    /// RSA verification with RSA signing keys. Same for ECDSA and ED25519.
404    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    /// Resolve the [DigestAlgorithm] for this signature algorithm.
436    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            // TODO there's got to be a digest algorithm, right?
445            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/// Represents a known curve used with ECDSA.
524#[derive(Copy, Clone, Debug, Eq, PartialEq)]
525pub enum EcdsaCurve {
526    Secp256r1,
527    Secp384r1,
528}
529
530impl EcdsaCurve {
531    /// Obtain all variants of this type.
532    pub fn all() -> &'static [Self] {
533        &[Self::Secp256r1, Self::Secp384r1]
534    }
535
536    /// Obtain the OID representing this elliptic curve.
537    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/// Cryptographic algorithm used by a private key.
569///
570/// Instances can be converted to/from the underlying ASN.1 type and
571/// OIDs.
572#[derive(Copy, Clone, Debug, Eq, PartialEq)]
573pub enum KeyAlgorithm {
574    /// RSA
575    ///
576    /// Corresponds to OID 1.2.840.113549.1.1.1.
577    Rsa,
578
579    /// Corresponds to OID 1.2.840.10045.2.1
580    ///
581    /// The inner OID tracks the curve / parameter in use.
582    Ecdsa(EcdsaCurve),
583
584    /// Corresponds to OID 1.3.101.110
585    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            // Default to an arbitrary elliptic curve when just the OID is given to us.
606            Ok(Self::Ecdsa(EcdsaCurve::Secp384r1))
607        // ED25519 appears to use the signature algorithm OID for private key
608        // identification, so we need to accept both.
609        } 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        // Similar implementation as above.
622        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        // This will obtain a generic instance with defaults for configurable
663        // parameters. So check for and apply parameters.
664        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                    // NULL is meaningless. Just a placeholder. Allow it through.
676                    if params.as_slice() == [0x05, 0x00] {
677                        Ok(ka)
678                    } else {
679                        Err(Error::UnhandledKeyAlgorithmParameters("on ED25519"))
680                    }
681                }
682                Self::Rsa => {
683                    // NULL is meaningless. Just a placeholder. Allow it through.
684                    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        // RSA 1024.
726        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}