jwt_compact/alg/
p256.rs

1//! `ES256` algorithm implementation using the `p256` crate.
2
3use core::num::NonZeroUsize;
4
5use p256::ecdsa::{
6    Signature, SigningKey, VerifyingKey,
7    signature::{DigestSigner, DigestVerifier},
8};
9use sha2::{Digest, Sha256};
10
11use crate::{
12    Algorithm, AlgorithmSignature,
13    alg::{self, SecretBytes},
14    alloc::Cow,
15    jwk::{JsonWebKey, JwkError, KeyType},
16};
17
18impl AlgorithmSignature for Signature {
19    const LENGTH: Option<NonZeroUsize> = NonZeroUsize::new(64);
20
21    fn try_from_slice(slice: &[u8]) -> anyhow::Result<Self> {
22        Signature::try_from(slice).map_err(|err| anyhow::anyhow!(err))
23    }
24
25    fn as_bytes(&self) -> Cow<'_, [u8]> {
26        Cow::Owned(self.to_bytes().to_vec())
27    }
28}
29
30/// `ES256` signing algorithm. Implements elliptic curve digital signatures (ECDSA)
31/// on the secp256r1 curve (aka P-256).
32#[derive(Debug, Default)]
33#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
34pub struct Es256;
35
36impl Algorithm for Es256 {
37    type SigningKey = SigningKey;
38    type VerifyingKey = VerifyingKey;
39    type Signature = Signature;
40
41    fn name(&self) -> Cow<'static, str> {
42        Cow::Borrowed("ES256")
43    }
44
45    fn sign(&self, signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
46        signing_key.sign_digest(|digest: &mut Sha256| {
47            digest.update(message);
48        })
49    }
50
51    fn verify_signature(
52        &self,
53        signature: &Self::Signature,
54        verifying_key: &Self::VerifyingKey,
55        message: &[u8],
56    ) -> bool {
57        verifying_key
58            .verify_digest(
59                |digest: &mut Sha256| {
60                    digest.update(message);
61                    Ok(())
62                },
63                signature,
64            )
65            .is_ok()
66    }
67}
68
69impl alg::SigningKey<Es256> for SigningKey {
70    fn from_slice(raw: &[u8]) -> anyhow::Result<Self> {
71        Self::from_slice(raw).map_err(|err| anyhow::anyhow!(err))
72    }
73
74    fn to_verifying_key(&self) -> VerifyingKey {
75        *self.verifying_key()
76    }
77
78    fn as_bytes(&self) -> SecretBytes<'_> {
79        SecretBytes::owned(self.to_bytes().to_vec())
80    }
81}
82
83impl alg::VerifyingKey<Es256> for VerifyingKey {
84    fn from_slice(raw: &[u8]) -> anyhow::Result<Self> {
85        Self::from_sec1_bytes(raw).map_err(|err| anyhow::anyhow!(err))
86    }
87
88    /// Serializes the key as a 33-byte compressed form.
89    fn as_bytes(&self) -> Cow<'_, [u8]> {
90        let bytes = self.to_encoded_point(true).as_bytes().to_vec();
91        Cow::Owned(bytes)
92    }
93}
94
95fn create_jwk<'a>(pk: &VerifyingKey, sk: Option<&'a SigningKey>) -> JsonWebKey<'a> {
96    let uncompressed = pk.to_encoded_point(false);
97    JsonWebKey::EllipticCurve {
98        curve: "P-256".into(),
99        x: Cow::Owned(uncompressed.x().expect("x coord").to_vec()),
100        y: Cow::Owned(uncompressed.y().expect("y coord").to_vec()),
101        secret: sk.map(|sk| SecretBytes::owned(sk.to_bytes().to_vec())),
102    }
103}
104
105impl<'a> From<&'a VerifyingKey> for JsonWebKey<'a> {
106    fn from(key: &'a VerifyingKey) -> JsonWebKey<'a> {
107        create_jwk(key, None)
108    }
109}
110
111impl TryFrom<&JsonWebKey<'_>> for VerifyingKey {
112    type Error = JwkError;
113
114    fn try_from(jwk: &JsonWebKey<'_>) -> Result<Self, Self::Error> {
115        const COORDINATE_SIZE: usize = 32;
116
117        let JsonWebKey::EllipticCurve { curve, x, y, .. } = jwk else {
118            return Err(JwkError::key_type(jwk, KeyType::EllipticCurve));
119        };
120        JsonWebKey::ensure_curve(curve, "P-256")?;
121        JsonWebKey::ensure_len("x", x, COORDINATE_SIZE)?;
122        JsonWebKey::ensure_len("y", y, COORDINATE_SIZE)?;
123
124        let mut key_bytes = [0_u8; 2 * COORDINATE_SIZE + 1];
125        key_bytes[0] = 4; // uncompressed key marker
126        key_bytes[1..=COORDINATE_SIZE].copy_from_slice(x);
127        key_bytes[(1 + COORDINATE_SIZE)..].copy_from_slice(y);
128        VerifyingKey::from_sec1_bytes(&key_bytes[..])
129            .map_err(|err| JwkError::custom(anyhow::anyhow!(err)))
130    }
131}
132
133impl<'a> From<&'a SigningKey> for JsonWebKey<'a> {
134    fn from(key: &'a SigningKey) -> JsonWebKey<'a> {
135        create_jwk(key.verifying_key(), Some(key))
136    }
137}
138
139impl TryFrom<&JsonWebKey<'_>> for SigningKey {
140    type Error = JwkError;
141
142    fn try_from(jwk: &JsonWebKey<'_>) -> Result<Self, Self::Error> {
143        let JsonWebKey::EllipticCurve { secret, .. } = jwk else {
144            return Err(JwkError::key_type(jwk, KeyType::EllipticCurve));
145        };
146        let sk_bytes = secret.as_deref();
147        let sk_bytes = sk_bytes.ok_or_else(|| JwkError::NoField("d".into()))?;
148        JsonWebKey::ensure_len("d", sk_bytes, 32)?;
149
150        let sk =
151            Self::from_slice(sk_bytes).map_err(|err| JwkError::custom(anyhow::anyhow!(err)))?;
152        jwk.ensure_key_match(sk)
153    }
154}