Skip to main content

yacme_key/
ecdsa.rs

1//! Yacme's cryptographic primatives for ECDSA signatures
2
3use const_oid::AssociatedOid;
4use elliptic_curve::sec1::ToEncodedPoint;
5use signature::rand_core::OsRng;
6
7use crate::{PublicKeyAlgorithm, Signature};
8
9/// Named elliptic curves supported by Yacme
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum EcdsaAlgorithm {
12    /// The NIST P-256 (a.k.a. secp256r1, prime256v1) elliptic curve.
13    P256,
14}
15
16impl EcdsaAlgorithm {
17    pub(crate) fn random(&self) -> EcdsaSigningKey {
18        match self {
19            EcdsaAlgorithm::P256 => {
20                EcdsaSigningKey::P256(::elliptic_curve::SecretKey::random(&mut OsRng))
21            }
22        }
23    }
24}
25
26/// Implements the ECDSA signature scheme across
27/// varying elliptic curve cryptography algorithms
28pub(crate) enum EcdsaSigningKey {
29    P256(::elliptic_curve::SecretKey<p256::NistP256>),
30}
31
32impl signature::Signer<Signature> for EcdsaSigningKey {
33    fn try_sign(&self, msg: &[u8]) -> Result<Signature, ::ecdsa::Error> {
34        match self {
35            EcdsaSigningKey::P256(key) => {
36                let signature = <::ecdsa::SigningKey<p256::NistP256> as signature::Signer<
37                    ::ecdsa::Signature<p256::NistP256>,
38                >>::sign(&key.into(), msg);
39                let bytes = signature.to_vec();
40                Ok(Signature(bytes))
41            }
42        }
43    }
44}
45
46impl pkcs8::EncodePrivateKey for EcdsaSigningKey {
47    fn to_pkcs8_der(&self) -> pkcs8::Result<der::SecretDocument> {
48        match self {
49            EcdsaSigningKey::P256(key) => key.to_pkcs8_der(),
50        }
51    }
52}
53
54impl crate::SigningKeyAlgorithm for EcdsaSigningKey {
55    fn as_jwk(&self) -> crate::jwk::Jwk {
56        match self {
57            EcdsaSigningKey::P256(key) => key.public_key().to_jwk().into(),
58        }
59    }
60
61    fn public_key(&self) -> crate::PublicKey {
62        match self {
63            EcdsaSigningKey::P256(key) => Box::new(EcdsaPublicKey::from(key.public_key())).into(),
64        }
65    }
66
67    fn try_sign_digest(&self, digest: sha2::Sha256) -> Result<Signature, ecdsa::Error> {
68        match self {
69            EcdsaSigningKey::P256(key) => {
70                let signature = <::ecdsa::SigningKey<p256::NistP256> as signature::DigestSigner<
71                    sha2::Sha256,
72                    ::ecdsa::Signature<p256::NistP256>,
73                >>::try_sign_digest(&key.into(), digest)?;
74                let bytes = signature.to_vec();
75                Ok(Signature(bytes))
76            }
77        }
78    }
79
80    fn algorithm(&self) -> pkcs8::AlgorithmIdentifier {
81        match self {
82            EcdsaSigningKey::P256(_) => pkcs8::AlgorithmIdentifier {
83                oid: const_oid::db::rfc5912::ECDSA_WITH_SHA_256,
84                parameters: None,
85            },
86        }
87    }
88
89    fn kind(&self) -> crate::SignatureKind {
90        match self {
91            EcdsaSigningKey::P256(_) => crate::SignatureKind::Ecdsa(crate::EcdsaAlgorithm::P256),
92        }
93    }
94}
95
96impl EcdsaSigningKey {
97    pub(crate) fn from_pkcs8_pem(
98        data: &str,
99        algorithm: EcdsaAlgorithm,
100    ) -> Result<Self, pkcs8::Error> {
101        use pkcs8::DecodePrivateKey;
102        match algorithm {
103            EcdsaAlgorithm::P256 => Ok(EcdsaSigningKey::P256(
104                ::elliptic_curve::SecretKey::from_pkcs8_pem(data)?,
105            )),
106        }
107    }
108}
109
110enum EcdsaPublicKey {
111    P256(elliptic_curve::PublicKey<p256::NistP256>),
112}
113
114impl From<elliptic_curve::PublicKey<p256::NistP256>> for EcdsaPublicKey {
115    fn from(value: elliptic_curve::PublicKey<p256::NistP256>) -> Self {
116        EcdsaPublicKey::P256(value)
117    }
118}
119
120impl PublicKeyAlgorithm for EcdsaPublicKey {
121    fn as_jwk(&self) -> crate::jwk::Jwk {
122        match self {
123            EcdsaPublicKey::P256(key) => key.to_jwk().into(),
124        }
125    }
126
127    fn algorithm(&self) -> pkcs8::AlgorithmIdentifier {
128        match self {
129            EcdsaPublicKey::P256(_) => pkcs8::AlgorithmIdentifier {
130                oid: const_oid::db::rfc5912::ID_EC_PUBLIC_KEY,
131                parameters: Some((&p256::NistP256::OID).into()),
132            },
133        }
134    }
135
136    fn as_bytes(&self) -> Vec<u8> {
137        match self {
138            EcdsaPublicKey::P256(key) => key.to_encoded_point(false).as_ref().into(),
139        }
140    }
141}