Skip to main content

simoom_tls/
keys.rs

1//! Public / private key types and parsing: SubjectPublicKeyInfo, PKCS#8,
2//! SEC1 (`EC PRIVATE KEY`) and PKCS#1 (`RSA PRIVATE KEY`).
3
4use crate::asn1::{self, Der, DerError, DerResult, TAG_OID, TAG_SEQUENCE};
5#[cfg(feature = "p384")]
6use crate::crypto::ec::p384;
7use crate::crypto::p256;
8#[cfg(feature = "rsa")]
9use crate::crypto::rsa::{RsaPrivateKey, RsaPublicKey};
10use crate::crypto::sha2::HashAlg;
11use crate::pem;
12
13/// A supported NIST curve.
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum EcCurve {
16    P256,
17    #[cfg(feature = "p384")]
18    P384,
19}
20
21impl EcCurve {
22    /// Scalar and coordinate size in bytes.
23    pub fn byte_len(self) -> usize {
24        match self {
25            EcCurve::P256 => 32,
26            #[cfg(feature = "p384")]
27            EcCurve::P384 => 48,
28        }
29    }
30    /// The hash paired with this curve in TLS 1.3 signature schemes.
31    pub fn hash(self) -> HashAlg {
32        match self {
33            EcCurve::P256 => HashAlg::Sha256,
34            #[cfg(feature = "p384")]
35            EcCurve::P384 => HashAlg::Sha384,
36        }
37    }
38    pub fn generate_private(self) -> Vec<u8> {
39        match self {
40            EcCurve::P256 => p256::generate_private().to_vec(),
41            #[cfg(feature = "p384")]
42            EcCurve::P384 => p384::generate_private(),
43        }
44    }
45    pub fn public_key(self, private: &[u8]) -> Option<Vec<u8>> {
46        match self {
47            EcCurve::P256 => p256::public_key(private).map(|p| p.to_vec()),
48            #[cfg(feature = "p384")]
49            EcCurve::P384 => p384::public_key(private),
50        }
51    }
52    /// [`EcCurve::public_key`] for a key being loaded: P-256 skips building its base-point
53    /// table (start-up time and memory), which the first signature builds instead.
54    pub fn public_key_for_load(self, private: &[u8]) -> Option<Vec<u8>> {
55        match self {
56            EcCurve::P256 => p256::public_key_untabled(private).map(|p| p.to_vec()),
57            #[cfg(feature = "p384")]
58            EcCurve::P384 => p384::public_key(private),
59        }
60    }
61    /// ECDSA over a digest; (r, s) big-endian, curve-sized.
62    pub fn sign(self, private: &[u8], digest: &[u8], hash: HashAlg) -> Option<(Vec<u8>, Vec<u8>)> {
63        match self {
64            EcCurve::P256 => p256::sign(private, digest, hash).map(|(r, s)| (r.to_vec(), s.to_vec())),
65            #[cfg(feature = "p384")]
66            EcCurve::P384 => p384::sign(private, digest, hash),
67        }
68    }
69    pub fn verify(self, public: &[u8], digest: &[u8], r: &[u8], s: &[u8]) -> bool {
70        match self {
71            EcCurve::P256 => p256::verify(public, digest, r, s),
72            #[cfg(feature = "p384")]
73            EcCurve::P384 => p384::verify(public, digest, r, s),
74        }
75    }
76    pub fn validate_point(self, public: &[u8]) -> bool {
77        match self {
78            EcCurve::P256 => p256::validate_point(public),
79            #[cfg(feature = "p384")]
80            EcCurve::P384 => p384::validate_point(public),
81        }
82    }
83}
84
85pub const OID_RSA_ENCRYPTION: &str = "1.2.840.113549.1.1.1";
86pub const OID_RSASSA_PSS: &str = "1.2.840.113549.1.1.10";
87pub const OID_EC_PUBLIC_KEY: &str = "1.2.840.10045.2.1";
88pub const OID_P256: &str = "1.2.840.10045.3.1.7";
89pub const OID_P384: &str = "1.3.132.0.34";
90pub const OID_ED25519: &str = "1.3.101.112";
91
92fn derr<T>(m: &'static str) -> DerResult<T> {
93    Err(DerError(m.into()))
94}
95
96pub fn curve_from_oid(oid: &str) -> Option<EcCurve> {
97    match oid {
98        OID_P256 => Some(EcCurve::P256),
99        #[cfg(feature = "p384")]
100        OID_P384 => Some(EcCurve::P384),
101        _ => None,
102    }
103}
104
105pub fn curve_oid(c: EcCurve) -> &'static str {
106    match c {
107        EcCurve::P256 => OID_P256,
108        #[cfg(feature = "p384")]
109        EcCurve::P384 => OID_P384,
110    }
111}
112
113/// A public key usable for signature verification.
114#[derive(Clone, Debug)]
115pub enum PublicKey {
116    Ec { curve: EcCurve, point: Vec<u8> },
117    #[cfg(feature = "rsa")]
118    Rsa(RsaPublicKey),
119    #[cfg(feature = "ed25519")]
120    Ed25519([u8; 32]),
121}
122
123impl PublicKey {
124    /// Parses a DER SubjectPublicKeyInfo.
125    pub fn from_spki(spki: &[u8]) -> DerResult<PublicKey> {
126        let mut outer = Der::new(spki);
127        let mut s = outer.sequence()?;
128        let mut alg = s.sequence()?;
129        let oid = alg.oid()?;
130        let key = s.bit_string()?;
131        match oid.as_str() {
132            #[cfg(feature = "rsa")]
133            OID_RSA_ENCRYPTION | OID_RSASSA_PSS => {
134                let mut k = Der::new(key).sequence()?;
135                let n = k.uint()?;
136                let e = k.uint()?;
137                RsaPublicKey::new(n, e).map(PublicKey::Rsa).ok_or(DerError("unsupported RSA key".into()))
138            }
139            OID_EC_PUBLIC_KEY => {
140                let params = alg.read()?;
141                if params.tag != TAG_OID {
142                    return derr("explicit EC parameters not supported");
143                }
144                let curve = curve_from_oid(&asn1::decode_oid(params.value)?).ok_or(DerError("unsupported curve".into()))?;
145                if !curve.validate_point(key) {
146                    return derr("invalid EC point");
147                }
148                Ok(PublicKey::Ec { curve, point: key.to_vec() })
149            }
150            #[cfg(feature = "ed25519")]
151            OID_ED25519 => {
152                let k: [u8; 32] = key.try_into().map_err(|_| DerError("bad Ed25519 public key length".into()))?;
153                Ok(PublicKey::Ed25519(k))
154            }
155            _ => derr("unsupported public key algorithm"),
156        }
157    }
158
159    pub fn describe(&self) -> String {
160        match self {
161            PublicKey::Ec { curve, .. } => format!("ECDSA {:?}", curve),
162            #[cfg(feature = "rsa")]
163            PublicKey::Rsa(r) => format!("RSA {}", r.modulus_bits()),
164            #[cfg(feature = "ed25519")]
165            PublicKey::Ed25519(_) => "Ed25519".to_string(),
166        }
167    }
168
169    /// Encodes the key as a DER SubjectPublicKeyInfo.
170    pub fn to_spki(&self) -> Vec<u8> {
171        match self {
172            PublicKey::Ec { curve, point } => {
173                asn1::seq(&[asn1::seq(&[asn1::oid(OID_EC_PUBLIC_KEY), asn1::oid(curve_oid(*curve))]), asn1::bit_string(point)])
174            }
175            #[cfg(feature = "rsa")]
176            PublicKey::Rsa(r) => {
177                let (n, e) = r.components();
178                let key = asn1::seq(&[asn1::uint(&n), asn1::uint(&e)]);
179                asn1::seq(&[asn1::seq(&[asn1::oid(OID_RSA_ENCRYPTION), asn1::tlv(asn1::TAG_NULL, &[])]), asn1::bit_string(&key)])
180            }
181            #[cfg(feature = "ed25519")]
182            PublicKey::Ed25519(k) => asn1::seq(&[asn1::seq(&[asn1::oid(OID_ED25519)]), asn1::bit_string(k)]),
183        }
184    }
185
186    /// Whether two keys are the same.
187    pub fn same_as(&self, other: &PublicKey) -> bool {
188        self.to_spki() == other.to_spki()
189    }
190}
191
192/// A private signing key (server certificates).
193#[derive(Clone, Debug)]
194#[allow(clippy::large_enum_variant)] // one per connection or key; boxing would add an indirection on the hot path
195pub enum PrivateKey {
196    Ec { curve: EcCurve, d: Vec<u8>, public: Vec<u8> },
197    #[cfg(feature = "rsa")]
198    Rsa(RsaPrivateKey),
199    #[cfg(feature = "ed25519")]
200    Ed25519 { seed: [u8; 32], public: [u8; 32] },
201}
202
203impl PrivateKey {
204    /// Parses the first private key found in PEM text (PKCS#8, SEC1 or PKCS#1). Encrypted
205    /// keys are not supported.
206    pub fn from_pem(data: &[u8]) -> Result<PrivateKey, String> {
207        let blocks = pem::parse_pem(data)?;
208        for b in blocks {
209            let r = match b.label.as_str() {
210                "PRIVATE KEY" => PrivateKey::from_pkcs8(&b.der),
211                "EC PRIVATE KEY" => PrivateKey::from_sec1(&b.der, None),
212                #[cfg(feature = "rsa")]
213                "RSA PRIVATE KEY" => PrivateKey::from_pkcs1(&b.der),
214                "ENCRYPTED PRIVATE KEY" => return Err("encrypted private keys are not supported".into()),
215                _ => continue,
216            };
217            return r.map_err(|e| e.to_string());
218        }
219        Err("no private key found in PEM input".into())
220    }
221
222    /// Parses DER in any supported format (tries PKCS#8, then SEC1, then PKCS#1).
223    pub fn from_der(der: &[u8]) -> Result<PrivateKey, String> {
224        let r = PrivateKey::from_pkcs8(der).or_else(|_| PrivateKey::from_sec1(der, None));
225        #[cfg(feature = "rsa")]
226        let r = r.or_else(|_| PrivateKey::from_pkcs1(der));
227        r.map_err(|e| format!("unrecognised private key: {e}"))
228    }
229
230    pub fn from_pkcs8(der: &[u8]) -> DerResult<PrivateKey> {
231        let mut s = Der::new(der).sequence()?;
232        let version = s.small_uint()?;
233        if version > 1 {
234            return derr("unsupported PKCS#8 version");
235        }
236        let mut alg = s.sequence()?;
237        let oid = alg.oid()?;
238        let key = s.octet_string()?;
239        match oid.as_str() {
240            #[cfg(feature = "rsa")]
241            OID_RSA_ENCRYPTION => PrivateKey::from_pkcs1(key),
242            OID_EC_PUBLIC_KEY => {
243                let p = alg.expect(TAG_OID)?;
244                let curve = curve_from_oid(&asn1::decode_oid(p.value)?).ok_or(DerError("unsupported curve".into()))?;
245                PrivateKey::from_sec1(key, Some(curve))
246            }
247            #[cfg(feature = "ed25519")]
248            OID_ED25519 => {
249                let seed = Der::new(key).octet_string()?;
250                let seed: [u8; 32] = seed.try_into().map_err(|_| DerError("bad Ed25519 private key length".into()))?;
251                Ok(PrivateKey::ed25519_from_seed(seed))
252            }
253            _ => derr("unsupported private key algorithm"),
254        }
255    }
256
257    #[cfg(feature = "ed25519")]
258    /// An Ed25519 key from its 32-byte seed.
259    pub fn ed25519_from_seed(seed: [u8; 32]) -> PrivateKey {
260        PrivateKey::Ed25519 { seed, public: crate::crypto::ed25519::public_key(&seed) }
261    }
262
263    #[cfg(feature = "ed25519")]
264    /// A fresh random Ed25519 key.
265    pub fn generate_ed25519() -> PrivateKey {
266        PrivateKey::ed25519_from_seed(crate::crypto::rng::array::<32>())
267    }
268
269    /// A fresh random ECDSA key.
270    pub fn generate_ec(curve: EcCurve) -> PrivateKey {
271        let d = curve.generate_private();
272        let public = curve.public_key(&d).expect("valid scalar");
273        PrivateKey::Ec { curve, d, public }
274    }
275
276    pub fn from_sec1(der: &[u8], curve: Option<EcCurve>) -> DerResult<PrivateKey> {
277        let mut s = Der::new(der).sequence()?;
278        if s.small_uint()? != 1 {
279            return derr("unsupported SEC1 version");
280        }
281        let d = s.octet_string()?;
282        let mut curve = curve;
283        if let Some(params) = s.optional(0xa0)? {
284            let c = curve_from_oid(&params.reader().oid()?).ok_or(DerError("unsupported curve".into()))?;
285            if curve.is_some() && curve != Some(c) {
286                return derr("curve mismatch");
287            }
288            curve = Some(c);
289        }
290        let curve = curve.ok_or(DerError("EC key without curve".into()))?;
291        let mut dv = d.to_vec();
292        while dv.len() < curve.byte_len() {
293            dv.insert(0, 0);
294        }
295        if dv.len() != curve.byte_len() {
296            return derr("bad EC private key length");
297        }
298        let public = curve.public_key_for_load(&dv).ok_or(DerError("invalid EC private scalar".into()))?;
299        Ok(PrivateKey::Ec { curve, d: dv, public })
300    }
301
302    #[cfg(feature = "rsa")]
303    pub fn from_pkcs1(der: &[u8]) -> DerResult<PrivateKey> {
304        let mut s = Der::new(der).sequence()?;
305        if s.small_uint()? != 0 {
306            return derr("multi-prime RSA keys not supported");
307        }
308        let n = s.uint()?;
309        let e = s.uint()?;
310        let d = s.uint()?;
311        let mut k = RsaPrivateKey::new(n, e, d).ok_or(DerError("invalid RSA private key".into()))?;
312        if let (Ok(p), Ok(q), Ok(dp), Ok(dq), Ok(qinv)) = (s.uint(), s.uint(), s.uint(), s.uint(), s.uint()) {
313            k.set_crt(p, q, dp, dq, qinv);
314        }
315        k.pkcs1 = Some(der.to_vec());
316        Ok(PrivateKey::Rsa(k))
317    }
318
319    pub fn public_key(&self) -> PublicKey {
320        match self {
321            PrivateKey::Ec { curve, public, .. } => PublicKey::Ec { curve: *curve, point: public.clone() },
322            #[cfg(feature = "rsa")]
323            PrivateKey::Rsa(r) => PublicKey::Rsa(r.public.clone()),
324            #[cfg(feature = "ed25519")]
325            PrivateKey::Ed25519 { public, .. } => PublicKey::Ed25519(*public),
326        }
327    }
328
329    /// Encodes the key as PKCS#8 DER (RSA keys need their original PKCS#1 encoding).
330    pub fn to_pkcs8(&self) -> Vec<u8> {
331        match self {
332            #[cfg(feature = "rsa")]
333            PrivateKey::Rsa(r) => {
334                let pkcs1 = r.pkcs1_der().unwrap_or_default();
335                asn1::seq(&[
336                    asn1::uint(&[0]),
337                    asn1::seq(&[asn1::oid(OID_RSA_ENCRYPTION), asn1::tlv(asn1::TAG_NULL, &[])]),
338                    asn1::octet_string(pkcs1),
339                ])
340            }
341            _ => self.to_pkcs8_der().expect("EC / Ed25519 key"),
342        }
343    }
344
345    /// Encodes an EC or Ed25519 key as PKCS#8 DER (used by the self-signed generator).
346    pub fn to_pkcs8_der(&self) -> Option<Vec<u8>> {
347        match self {
348            PrivateKey::Ec { curve, d, public } => {
349                let sec1 = asn1::seq(&[asn1::uint(&[1]), asn1::octet_string(d), asn1::explicit(1, &asn1::bit_string(public))]);
350                Some(asn1::seq(&[
351                    asn1::uint(&[0]),
352                    asn1::seq(&[asn1::oid(OID_EC_PUBLIC_KEY), asn1::oid(curve_oid(*curve))]),
353                    asn1::octet_string(&sec1),
354                ]))
355            }
356            #[cfg(feature = "ed25519")]
357            PrivateKey::Ed25519 { seed, .. } => Some(asn1::seq(&[
358                asn1::uint(&[0]),
359                asn1::seq(&[asn1::oid(OID_ED25519)]),
360                asn1::octet_string(&asn1::octet_string(seed)),
361            ])),
362            #[cfg(feature = "rsa")]
363            PrivateKey::Rsa(_) => None,
364        }
365    }
366}
367
368/// Encodes an ECDSA (r, s) pair as a DER `Ecdsa-Sig-Value`.
369pub fn ecdsa_sig_to_der(r: &[u8], s: &[u8]) -> Vec<u8> {
370    asn1::seq(&[asn1::uint(r), asn1::uint(s)])
371}
372
373/// Decodes a DER `Ecdsa-Sig-Value` into (r, s).
374pub fn ecdsa_sig_from_der(sig: &[u8]) -> Option<(Vec<u8>, Vec<u8>)> {
375    let mut outer = Der::new(sig);
376    let mut s = outer.sequence().ok()?;
377    if !outer.is_empty() {
378        return None;
379    }
380    let r = s.uint().ok()?.to_vec();
381    let sv = s.uint().ok()?.to_vec();
382    if !s.is_empty() {
383        return None;
384    }
385    Some((r, sv))
386}
387
388/// Signature algorithm identifiers as they appear in certificates.
389#[derive(Clone, Debug, PartialEq, Eq)]
390pub enum SignatureAlgorithm {
391    RsaPkcs1(HashAlg),
392    RsaPss { hash: HashAlg, salt_len: usize },
393    Ecdsa(HashAlg),
394    Ed25519,
395    /// sha1WithRSAEncryption: legacy certificates, CRLs and OCSP responses (feature `sha1`).
396    #[cfg(feature = "sha1")]
397    RsaPkcs1Sha1,
398    /// ecdsa-with-SHA1 (feature `sha1`).
399    #[cfg(feature = "sha1")]
400    EcdsaSha1,
401    Unknown(String),
402}
403
404fn hash_from_oid(oid: &str) -> Option<HashAlg> {
405    match oid {
406        "2.16.840.1.101.3.4.2.1" => Some(HashAlg::Sha256),
407        "2.16.840.1.101.3.4.2.2" => Some(HashAlg::Sha384),
408        "2.16.840.1.101.3.4.2.3" => Some(HashAlg::Sha512),
409        _ => None,
410    }
411}
412
413impl SignatureAlgorithm {
414    /// Parses an AlgorithmIdentifier (the reader is positioned inside the SEQUENCE).
415    pub fn parse(alg: &mut Der) -> DerResult<SignatureAlgorithm> {
416        let oid = alg.oid()?;
417        Ok(match oid.as_str() {
418            "1.2.840.113549.1.1.11" => SignatureAlgorithm::RsaPkcs1(HashAlg::Sha256),
419            "1.2.840.113549.1.1.12" => SignatureAlgorithm::RsaPkcs1(HashAlg::Sha384),
420            "1.2.840.113549.1.1.13" => SignatureAlgorithm::RsaPkcs1(HashAlg::Sha512),
421            "1.2.840.10045.4.3.2" => SignatureAlgorithm::Ecdsa(HashAlg::Sha256),
422            "1.2.840.10045.4.3.3" => SignatureAlgorithm::Ecdsa(HashAlg::Sha384),
423            "1.2.840.10045.4.3.4" => SignatureAlgorithm::Ecdsa(HashAlg::Sha512),
424            #[cfg(feature = "sha1")]
425            "1.2.840.113549.1.1.5" => SignatureAlgorithm::RsaPkcs1Sha1,
426            #[cfg(feature = "sha1")]
427            "1.2.840.10045.4.1" => SignatureAlgorithm::EcdsaSha1,
428            #[cfg(feature = "ed25519")]
429            OID_ED25519 => SignatureAlgorithm::Ed25519,
430            OID_RSASSA_PSS => {
431                // The defaults (SHA-1, salt 20) are not supported: parameters must be explicit.
432                let mut hash = None;
433                let mut mgf_hash = None;
434                let mut salt_len = 20usize;
435                if let Some(params) = alg.optional(TAG_SEQUENCE)? {
436                    let mut p = params.reader();
437                    while !p.is_empty() {
438                        let t = p.read()?;
439                        let mut inner = t.reader();
440                        match t.tag {
441                            0xa0 => {
442                                let mut a = inner.sequence()?;
443                                hash = Some(hash_from_oid(&a.oid()?).ok_or(DerError("unsupported PSS hash".into()))?);
444                            }
445                            0xa1 => {
446                                let mut a = inner.sequence()?;
447                                if a.oid()? != "1.2.840.113549.1.1.8" {
448                                    return derr("unsupported PSS mask generation function");
449                                }
450                                let mut h = a.sequence()?;
451                                mgf_hash = Some(hash_from_oid(&h.oid()?).ok_or(DerError("unsupported MGF hash".into()))?);
452                            }
453                            0xa2 => salt_len = inner.small_uint()? as usize,
454                            0xa3 => {
455                                if inner.small_uint()? != 1 {
456                                    return derr("unsupported PSS trailer");
457                                }
458                            }
459                            _ => return derr("unexpected PSS parameter"),
460                        }
461                    }
462                }
463                match (hash, mgf_hash) {
464                    (Some(hash), Some(m)) if hash == m => SignatureAlgorithm::RsaPss { hash, salt_len },
465                    _ => return derr("RSA-PSS parameters not supported (SHA-1 or differing MGF hash)"),
466                }
467            }
468            other => SignatureAlgorithm::Unknown(other.to_string()),
469        })
470    }
471
472    /// Verifies `sig` over `message` with `key`.
473    pub fn verify(&self, key: &PublicKey, message: &[u8], sig: &[u8]) -> bool {
474        match (self, key) {
475            #[cfg(feature = "rsa")]
476            (SignatureAlgorithm::RsaPkcs1(h), PublicKey::Rsa(k)) => k.verify_pkcs1(*h, &h.hash(message), sig),
477            #[cfg(feature = "rsa")]
478            (SignatureAlgorithm::RsaPss { hash, salt_len }, PublicKey::Rsa(k)) => {
479                k.verify_pss(*hash, &hash.hash(message), sig, Some(*salt_len))
480            }
481            (SignatureAlgorithm::Ecdsa(h), PublicKey::Ec { curve, point }) => match ecdsa_sig_from_der(sig) {
482                Some((r, s)) => curve.verify(point, &h.hash(message), &r, &s),
483                None => false,
484            },
485            #[cfg(feature = "ed25519")]
486            (SignatureAlgorithm::Ed25519, PublicKey::Ed25519(k)) => crate::crypto::ed25519::verify(k, message, sig),
487            #[cfg(all(feature = "sha1", feature = "rsa"))]
488            (SignatureAlgorithm::RsaPkcs1Sha1, PublicKey::Rsa(k)) => k.verify_pkcs1_sha1(&crate::crypto::sha1::Sha1::digest(message), sig),
489            #[cfg(feature = "sha1")]
490            (SignatureAlgorithm::EcdsaSha1, PublicKey::Ec { curve, point }) => match ecdsa_sig_from_der(sig) {
491                Some((r, s)) => curve.verify(point, &crate::crypto::sha1::Sha1::digest(message), &r, &s),
492                None => false,
493            },
494            _ => false,
495        }
496    }
497}
498
499#[cfg(all(test, feature = "rsa", feature = "p384", feature = "ed25519"))]
500mod tests {
501    use super::*;
502
503    const RSA_PKCS8: &str = include_str!("../testdata/rsa2048.pkcs8.pem");
504    const RSA_PKCS1: &str = include_str!("../testdata/rsa2048.pkcs1.pem");
505    const EC_SEC1: &str = include_str!("../testdata/ec256.sec1.pem");
506    const EC_PKCS8: &str = include_str!("../testdata/ec256.pkcs8.pem");
507    const EC384_SEC1: &str = include_str!("../testdata/ec384.sec1.pem");
508    const MSG: &[u8] = include_bytes!("../testdata/msg.txt");
509    const SIG_PKCS1: &[u8] = include_bytes!("../testdata/rsa_pkcs1_sha256.sig");
510    const SIG_PSS: &[u8] = include_bytes!("../testdata/rsa_pss_sha384.sig");
511
512    #[test]
513    fn parse_all_key_formats() {
514        let a = PrivateKey::from_pem(RSA_PKCS8.as_bytes()).unwrap();
515        let b = PrivateKey::from_pem(RSA_PKCS1.as_bytes()).unwrap();
516        assert!(matches!(a, PrivateKey::Rsa(_)));
517        assert!(matches!(b, PrivateKey::Rsa(_)));
518        let c = PrivateKey::from_pem(EC_SEC1.as_bytes()).unwrap();
519        let d = PrivateKey::from_pem(EC_PKCS8.as_bytes()).unwrap();
520        match (&c, &d) {
521            (PrivateKey::Ec { d: d1, public: p1, .. }, PrivateKey::Ec { d: d2, public: p2, .. }) => {
522                assert_eq!(d1, d2);
523                assert_eq!(p1, p2);
524            }
525            _ => panic!("expected EC keys"),
526        }
527        let e = PrivateKey::from_pem(EC384_SEC1.as_bytes()).unwrap();
528        assert!(matches!(e, PrivateKey::Ec { curve: EcCurve::P384, .. }));
529        // PKCS#8 export re-parses
530        let der = c.to_pkcs8_der().unwrap();
531        assert!(matches!(PrivateKey::from_der(&der).unwrap(), PrivateKey::Ec { .. }));
532    }
533
534    #[test]
535    fn rsa_against_openssl_vectors() {
536        let key = match PrivateKey::from_pem(RSA_PKCS8.as_bytes()).unwrap() {
537            #[cfg(feature = "rsa")]
538            PrivateKey::Rsa(r) => r,
539            _ => unreachable!(),
540        };
541        let h256 = HashAlg::Sha256.hash(MSG);
542        // PKCS#1 v1.5 is deterministic: our signature must equal OpenSSL's byte for byte.
543        assert!(key.public.verify_pkcs1(HashAlg::Sha256, &h256, SIG_PKCS1));
544        assert_eq!(key.sign_pkcs1(HashAlg::Sha256, &h256).unwrap(), SIG_PKCS1);
545        let mut bad = SIG_PKCS1.to_vec();
546        bad[10] ^= 1;
547        assert!(!key.public.verify_pkcs1(HashAlg::Sha256, &h256, &bad));
548        // PSS signature made by OpenSSL (SHA-384, salt 48)
549        let h384 = HashAlg::Sha384.hash(MSG);
550        assert!(key.public.verify_pss(HashAlg::Sha384, &h384, SIG_PSS, Some(48)));
551        assert!(!key.public.verify_pss(HashAlg::Sha384, &h384, SIG_PSS, Some(32)));
552        assert!(!key.public.verify_pss(HashAlg::Sha384, &HashAlg::Sha384.hash(b"x"), SIG_PSS, None));
553        // our PSS signatures verify
554        let s = key.sign_pss(HashAlg::Sha256, &h256).unwrap();
555        assert!(key.public.verify_pss(HashAlg::Sha256, &h256, &s, Some(32)));
556    }
557
558    #[test]
559    fn rsa_crt_and_blinding_match_plain_exponentiation() {
560        let key = match PrivateKey::from_pem(RSA_PKCS1.as_bytes()).unwrap() {
561            #[cfg(feature = "rsa")]
562            PrivateKey::Rsa(r) => r,
563            _ => unreachable!(),
564        };
565        assert!(key.has_crt());
566        let (n, e) = key.public.components();
567        // the same key without CRT parameters: d from the PKCS#1 structure
568        let der = key.pkcs1_der().unwrap().to_vec();
569        let mut sq = Der::new(&der).sequence().unwrap();
570        sq.small_uint().unwrap();
571        sq.uint().unwrap();
572        sq.uint().unwrap();
573        let d = sq.uint().unwrap().to_vec();
574        let plain = RsaPrivateKey::new(&n, &e, &d).unwrap();
575        assert!(!plain.has_crt());
576        let h256 = HashAlg::Sha256.hash(MSG);
577        for _ in 0..3 {
578            // blinding factors change between calls; results must not
579            assert_eq!(key.sign_pkcs1(HashAlg::Sha256, &h256).unwrap(), SIG_PKCS1);
580            assert_eq!(plain.sign_pkcs1(HashAlg::Sha256, &h256).unwrap(), SIG_PKCS1);
581        }
582        // inconsistent CRT parameters are refused
583        let mut k2 = plain.clone();
584        assert!(!k2.set_crt(&[7], &[11], &[1], &[1], &[1]));
585        assert!(!k2.has_crt());
586    }
587
588    #[test]
589    fn ecdsa_der_roundtrip() {
590        let sig = ecdsa_sig_to_der(&[0x80, 1], &[0, 0, 5]);
591        assert_eq!(ecdsa_sig_from_der(&sig).unwrap(), (vec![0x80, 1], vec![5]));
592    }
593}