jwt_compact_frame/alg/
p256.rs

1//! `ES256` algorithm implementation using the `p256` crate.
2
3use p256::ecdsa::{
4	signature::{DigestSigner, DigestVerifier},
5	Signature, SigningKey, VerifyingKey,
6};
7use sha2::{Digest, Sha256};
8
9use core::num::NonZeroUsize;
10
11use crate::{
12	alg::{self, SecretBytes},
13	alloc::Cow,
14	jwk::{JsonWebKey, JwkError, KeyType},
15	Algorithm, AlgorithmSignature,
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 Signature = Signature;
38	type SigningKey = SigningKey;
39	type VerifyingKey = VerifyingKey;
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		let mut digest = Sha256::default();
47		digest.update(message);
48		signing_key.sign_digest(digest)
49	}
50
51	fn verify_signature(
52		&self,
53		signature: &Self::Signature,
54		verifying_key: &Self::VerifyingKey,
55		message: &[u8],
56	) -> bool {
57		let mut digest = Sha256::default();
58		digest.update(message);
59
60		verifying_key.verify_digest(digest, signature).is_ok()
61	}
62}
63
64impl alg::SigningKey<Es256> for SigningKey {
65	fn from_slice(raw: &[u8]) -> anyhow::Result<Self> {
66		Self::from_slice(raw).map_err(|err| anyhow::anyhow!(err))
67	}
68
69	fn to_verifying_key(&self) -> VerifyingKey {
70		*self.verifying_key()
71	}
72
73	fn as_bytes(&self) -> SecretBytes<'_> {
74		SecretBytes::owned(self.to_bytes().to_vec())
75	}
76}
77
78impl alg::VerifyingKey<Es256> for VerifyingKey {
79	fn from_slice(raw: &[u8]) -> anyhow::Result<Self> {
80		Self::from_sec1_bytes(raw).map_err(|err| anyhow::anyhow!(err))
81	}
82
83	/// Serializes the key as a 33-byte compressed form.
84	fn as_bytes(&self) -> Cow<'_, [u8]> {
85		let bytes = self.to_encoded_point(true).as_bytes().to_vec();
86		Cow::Owned(bytes)
87	}
88}
89
90fn create_jwk<'a>(pk: &VerifyingKey, sk: Option<&'a SigningKey>) -> JsonWebKey<'a> {
91	let uncompressed = pk.to_encoded_point(false);
92	JsonWebKey::EllipticCurve {
93		curve: "P-256".into(),
94		x: Cow::Owned(uncompressed.x().expect("x coord").to_vec()),
95		y: Cow::Owned(uncompressed.y().expect("y coord").to_vec()),
96		secret: sk.map(|sk| SecretBytes::owned(sk.to_bytes().to_vec())),
97	}
98}
99
100impl<'a> From<&'a VerifyingKey> for JsonWebKey<'a> {
101	fn from(key: &'a VerifyingKey) -> JsonWebKey<'a> {
102		create_jwk(key, None)
103	}
104}
105
106impl TryFrom<&JsonWebKey<'_>> for VerifyingKey {
107	type Error = JwkError;
108
109	fn try_from(jwk: &JsonWebKey<'_>) -> Result<Self, Self::Error> {
110		const COORDINATE_SIZE: usize = 32;
111
112		let JsonWebKey::EllipticCurve { curve, x, y, .. } = jwk else {
113			return Err(JwkError::key_type(jwk, KeyType::EllipticCurve));
114		};
115		JsonWebKey::ensure_curve(curve, "P-256")?;
116		JsonWebKey::ensure_len("x", x, COORDINATE_SIZE)?;
117		JsonWebKey::ensure_len("y", y, COORDINATE_SIZE)?;
118
119		let mut key_bytes = [0_u8; 2 * COORDINATE_SIZE + 1];
120		key_bytes[0] = 4; // uncompressed key marker
121		key_bytes[1..=COORDINATE_SIZE].copy_from_slice(x);
122		key_bytes[(1 + COORDINATE_SIZE)..].copy_from_slice(y);
123		VerifyingKey::from_sec1_bytes(&key_bytes[..]).map_err(|err| JwkError::custom(anyhow::anyhow!(err)))
124	}
125}
126
127impl<'a> From<&'a SigningKey> for JsonWebKey<'a> {
128	fn from(key: &'a SigningKey) -> JsonWebKey<'a> {
129		create_jwk(key.verifying_key(), Some(key))
130	}
131}
132
133impl TryFrom<&JsonWebKey<'_>> for SigningKey {
134	type Error = JwkError;
135
136	fn try_from(jwk: &JsonWebKey<'_>) -> Result<Self, Self::Error> {
137		let JsonWebKey::EllipticCurve { secret, .. } = jwk else {
138			return Err(JwkError::key_type(jwk, KeyType::EllipticCurve));
139		};
140		let sk_bytes = secret.as_deref();
141		let sk_bytes = sk_bytes.ok_or_else(|| JwkError::NoField("d".into()))?;
142		JsonWebKey::ensure_len("d", sk_bytes, 32)?;
143
144		let sk = Self::from_slice(sk_bytes).map_err(|err| JwkError::custom(anyhow::anyhow!(err)))?;
145		jwk.ensure_key_match(sk)
146	}
147}