Skip to main content

jwt_simple/algorithms/
es256k.rs

1use std::convert::{TryFrom, TryInto};
2
3use ct_codecs::{Base64UrlSafeNoPadding, Encoder};
4use k256::ecdsa::{self, signature::DigestVerifier as _, signature::RandomizedDigestSigner as _};
5use k256::elliptic_curve::Generate as _;
6use k256::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey};
7use serde::{de::DeserializeOwned, Serialize};
8
9use crate::algorithms::jwk::{
10    decode_secret, ec_export, ec_point, ec_point_matches, ec_thumbprint, Jwk, JwkDescriptor,
11    KeyRole, KeyType,
12};
13use crate::claims::*;
14use crate::common::*;
15#[cfg(feature = "cwt")]
16use crate::cwt_token::*;
17use crate::error::*;
18use crate::jwt_header::*;
19use crate::token::*;
20
21const ES256K_PUBLIC_JWK: JwkDescriptor = JwkDescriptor::new(
22    KeyType::Ec,
23    Some("secp256k1"),
24    "ES256K",
25    KeyRole::SignaturePublic,
26);
27const ES256K_PRIVATE_JWK: JwkDescriptor = ES256K_PUBLIC_JWK.with_role(KeyRole::SignaturePrivate);
28
29#[doc(hidden)]
30#[derive(Debug, Clone)]
31pub struct K256PublicKey(ecdsa::VerifyingKey);
32
33impl AsRef<ecdsa::VerifyingKey> for K256PublicKey {
34    fn as_ref(&self) -> &ecdsa::VerifyingKey {
35        &self.0
36    }
37}
38
39impl K256PublicKey {
40    pub(crate) fn from_jwk(jwk: &str) -> Result<(Self, Option<String>), Error> {
41        let jwk = Jwk::parse(jwk, &ES256K_PUBLIC_JWK)?;
42        let point = ec_point(&jwk, 32).ok_or(JWTError::InvalidPublicKey)?;
43        let pk = Self::from_bytes(&point)?;
44        Ok((pk, jwk.kid().map(Into::into)))
45    }
46
47    pub(crate) fn to_jwk(&self, key_id: Option<&str>) -> String {
48        ec_export(
49            &ES256K_PUBLIC_JWK,
50            &self.to_bytes_uncompressed(),
51            None,
52            key_id,
53        )
54    }
55
56    pub(crate) fn jwk_thumbprint(&self) -> String {
57        ec_thumbprint("secp256k1", &self.to_bytes_uncompressed())
58    }
59
60    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
61        let k256_pk =
62            ecdsa::VerifyingKey::from_sec1_bytes(raw).map_err(|_| JWTError::InvalidPublicKey)?;
63        Ok(K256PublicKey(k256_pk))
64    }
65
66    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
67        let k256_pk = ecdsa::VerifyingKey::from_public_key_der(der)
68            .map_err(|_| JWTError::InvalidPublicKey)?;
69        Ok(K256PublicKey(k256_pk))
70    }
71
72    pub fn from_pem(pem: &str) -> Result<Self, Error> {
73        let k256_pk = ecdsa::VerifyingKey::from_public_key_pem(pem)
74            .map_err(|_| JWTError::InvalidPublicKey)?;
75        Ok(K256PublicKey(k256_pk))
76    }
77
78    pub fn to_bytes(&self) -> Vec<u8> {
79        self.0.to_sec1_point(false).as_bytes().to_vec()
80    }
81
82    pub fn to_bytes_uncompressed(&self) -> Vec<u8> {
83        self.0.to_sec1_point(false).as_bytes().to_vec()
84    }
85
86    pub fn to_der(&self) -> Result<Vec<u8>, Error> {
87        let k256_pk = k256::PublicKey::from(self.0);
88        Ok(k256_pk
89            .to_public_key_der()
90            .map_err(|_| JWTError::InvalidPublicKey)?
91            .as_ref()
92            .to_vec())
93    }
94
95    pub fn to_pem(&self) -> Result<String, Error> {
96        let k256_pk = k256::PublicKey::from(self.0);
97        Ok(k256_pk
98            .to_public_key_pem(Default::default())
99            .map_err(|_| JWTError::InvalidPublicKey)?)
100    }
101}
102
103#[doc(hidden)]
104pub struct K256KeyPair {
105    k256_sk: ecdsa::SigningKey,
106    metadata: Option<KeyMetadata>,
107}
108
109impl std::fmt::Debug for K256KeyPair {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        write!(f, "EcKey")
112    }
113}
114
115impl AsRef<ecdsa::SigningKey> for K256KeyPair {
116    fn as_ref(&self) -> &ecdsa::SigningKey {
117        &self.k256_sk
118    }
119}
120
121impl K256KeyPair {
122    pub(crate) fn from_jwk(jwk: &str) -> Result<(Self, Option<String>), Error> {
123        let jwk = Jwk::parse(jwk, &ES256K_PRIVATE_JWK)?;
124        let d = decode_secret(jwk.d(), 32).ok_or(JWTError::InvalidKeyPair)?;
125        let key_pair = Self::from_bytes(&d)?;
126        ensure!(
127            ec_point_matches(&jwk, &key_pair.public_key().to_bytes_uncompressed()),
128            JWTError::InvalidKeyPair
129        );
130        Ok((key_pair, jwk.kid().map(Into::into)))
131    }
132
133    pub(crate) fn to_jwk(&self, key_id: Option<&str>) -> String {
134        let point = self.public_key().to_bytes_uncompressed();
135        let d = zeroize::Zeroizing::new(self.k256_sk.to_bytes().to_vec());
136        ec_export(&ES256K_PRIVATE_JWK, &point, Some(&d), key_id)
137    }
138
139    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
140        let raw: &k256::FieldBytes = raw.try_into().map_err(|_| JWTError::InvalidKeyPair)?;
141        let k256_sk = ecdsa::SigningKey::from_bytes(raw).map_err(|_| JWTError::InvalidKeyPair)?;
142        Ok(K256KeyPair {
143            k256_sk,
144            metadata: None,
145        })
146    }
147
148    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
149        let k256_sk =
150            ecdsa::SigningKey::from_pkcs8_der(der).map_err(|_| JWTError::InvalidKeyPair)?;
151        Ok(K256KeyPair {
152            k256_sk,
153            metadata: None,
154        })
155    }
156
157    pub fn from_pem(pem: &str) -> Result<Self, Error> {
158        let k256_sk =
159            ecdsa::SigningKey::from_pkcs8_pem(pem).map_err(|_| JWTError::InvalidKeyPair)?;
160        Ok(K256KeyPair {
161            k256_sk,
162            metadata: None,
163        })
164    }
165
166    pub fn to_bytes(&self) -> Vec<u8> {
167        self.k256_sk.to_bytes().to_vec()
168    }
169
170    pub fn to_der(&self) -> Result<Vec<u8>, Error> {
171        let k256_sk = k256::SecretKey::from(&self.k256_sk);
172        Ok(k256_sk
173            .to_pkcs8_der()
174            .map_err(|_| JWTError::InvalidKeyPair)?
175            .as_bytes()
176            .to_vec())
177    }
178
179    pub fn to_pem(&self) -> Result<String, Error> {
180        let k256_sk = k256::SecretKey::from(&self.k256_sk);
181        Ok(k256_sk
182            .to_pkcs8_pem(Default::default())
183            .map_err(|_| JWTError::InvalidKeyPair)?
184            .to_string())
185    }
186
187    pub fn public_key(&self) -> K256PublicKey {
188        let k256_pk = self.k256_sk.verifying_key();
189        K256PublicKey(*k256_pk)
190    }
191
192    pub fn generate() -> Self {
193        let mut rng = rand::rng();
194        let k256_sk = ecdsa::SigningKey::generate_from_rng(&mut rng);
195        K256KeyPair {
196            k256_sk,
197            metadata: None,
198        }
199    }
200}
201
202pub trait ECDSAP256kKeyPairLike {
203    fn jwt_alg_name() -> &'static str;
204    fn key_pair(&self) -> &K256KeyPair;
205    fn key_id(&self) -> &Option<String>;
206    fn metadata(&self) -> &Option<KeyMetadata>;
207    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error>;
208
209    fn sign<CustomClaims: Serialize>(
210        &self,
211        claims: JWTClaims<CustomClaims>,
212    ) -> Result<String, Error> {
213        self.sign_with_options(claims, &Default::default())
214    }
215
216    fn sign_with_options<CustomClaims: Serialize>(
217        &self,
218        claims: JWTClaims<CustomClaims>,
219        opts: &HeaderOptions,
220    ) -> Result<String, Error> {
221        let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
222            .with_key_metadata(self.metadata())
223            .with_options(opts);
224        Token::build(&jwt_header, claims, |authenticated| {
225            let mut rng = rand::rng();
226            let signature: ecdsa::Signature = self
227                .key_pair()
228                .as_ref()
229                .sign_digest_with_rng(&mut rng, |digest: &mut hmac_sha256::Hash| {
230                    digest.update(authenticated.as_bytes())
231                });
232            Ok(signature.to_vec())
233        })
234    }
235}
236
237pub trait ECDSAP256kPublicKeyLike {
238    fn jwt_alg_name() -> &'static str;
239    fn public_key(&self) -> &K256PublicKey;
240    fn key_id(&self) -> &Option<String>;
241    fn set_key_id(&mut self, key_id: String);
242
243    fn verify_token<CustomClaims: DeserializeOwned>(
244        &self,
245        token: &str,
246        options: Option<VerificationOptions>,
247    ) -> Result<JWTClaims<CustomClaims>, Error> {
248        Token::verify(
249            Self::jwt_alg_name(),
250            token,
251            options,
252            |authenticated, signature| {
253                let ecdsa_signature = ecdsa::Signature::try_from(signature)
254                    .map_err(|_| JWTError::InvalidSignature)?;
255                self.public_key()
256                    .as_ref()
257                    .verify_digest(
258                        |digest: &mut hmac_sha256::Hash| {
259                            digest.update(authenticated.as_bytes());
260                            Ok(())
261                        },
262                        &ecdsa_signature,
263                    )
264                    .map_err(|_| JWTError::InvalidSignature)?;
265                Ok(())
266            },
267            |_salt: Option<&[u8]>| Ok(()),
268        )
269    }
270
271    #[cfg(feature = "cwt")]
272    fn verify_cwt_token<CustomClaims: DeserializeOwned>(
273        &self,
274        token: &[u8],
275        options: Option<VerificationOptions>,
276    ) -> Result<JWTClaims<NoCustomClaims>, Error> {
277        CWTToken::verify(
278            Self::jwt_alg_name(),
279            token,
280            options,
281            |authenticated, signature| {
282                let ecdsa_signature = ecdsa::Signature::try_from(signature)
283                    .map_err(|_| JWTError::InvalidSignature)?;
284                self.public_key()
285                    .as_ref()
286                    .verify_digest(
287                        |digest: &mut hmac_sha256::Hash| {
288                            digest.update(authenticated.as_bytes());
289                            Ok(())
290                        },
291                        &ecdsa_signature,
292                    )
293                    .map_err(|_| JWTError::InvalidSignature)?;
294                Ok(())
295            },
296        )
297    }
298
299    /// Decode CWT token metadata that can be useful prior to signature/tag verification
300    #[cfg(feature = "cwt")]
301    fn decode_cwt_metadata(&self, token: impl AsRef<[u8]>) -> Result<TokenMetadata, Error> {
302        CWTToken::decode_metadata(token)
303    }
304
305    fn create_key_id(&mut self) -> &str {
306        self.set_key_id(
307            Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
308                &self.public_key().to_bytes(),
309            ))
310            .unwrap(),
311        );
312        self.key_id().as_ref().map(|x| x.as_str()).unwrap()
313    }
314}
315
316pub struct ES256kKeyPair {
317    key_pair: K256KeyPair,
318    key_id: Option<String>,
319}
320
321impl std::fmt::Debug for ES256kKeyPair {
322    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
323        write!(f, "EcKey")
324    }
325}
326
327#[derive(Debug, Clone)]
328pub struct ES256kPublicKey {
329    pk: K256PublicKey,
330    key_id: Option<String>,
331}
332
333impl ECDSAP256kKeyPairLike for ES256kKeyPair {
334    fn jwt_alg_name() -> &'static str {
335        "ES256K"
336    }
337
338    fn key_pair(&self) -> &K256KeyPair {
339        &self.key_pair
340    }
341
342    fn key_id(&self) -> &Option<String> {
343        &self.key_id
344    }
345
346    fn metadata(&self) -> &Option<KeyMetadata> {
347        &self.key_pair.metadata
348    }
349
350    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
351        self.key_pair.metadata = Some(metadata);
352        Ok(())
353    }
354}
355
356impl ES256kKeyPair {
357    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
358        Ok(ES256kKeyPair {
359            key_pair: K256KeyPair::from_bytes(raw)?,
360            key_id: None,
361        })
362    }
363
364    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
365        Ok(ES256kKeyPair {
366            key_pair: K256KeyPair::from_der(der)?,
367            key_id: None,
368        })
369    }
370
371    pub fn from_pem(pem: &str) -> Result<Self, Error> {
372        Ok(ES256kKeyPair {
373            key_pair: K256KeyPair::from_pem(pem)?,
374            key_id: None,
375        })
376    }
377
378    pub fn to_bytes(&self) -> Vec<u8> {
379        self.key_pair.to_bytes()
380    }
381
382    pub fn to_der(&self) -> Result<Vec<u8>, Error> {
383        self.key_pair.to_der()
384    }
385
386    pub fn to_pem(&self) -> Result<String, Error> {
387        self.key_pair.to_pem()
388    }
389
390    pub fn public_key(&self) -> ES256kPublicKey {
391        ES256kPublicKey {
392            pk: self.key_pair.public_key(),
393            key_id: self.key_id.clone(),
394        }
395    }
396
397    pub fn generate() -> Self {
398        ES256kKeyPair {
399            key_pair: K256KeyPair::generate(),
400            key_id: None,
401        }
402    }
403
404    pub fn with_key_id(mut self, key_id: &str) -> Self {
405        self.key_id = Some(key_id.to_string());
406        self
407    }
408
409    /// Import a key pair from a private JWK (`kty: EC`, `crv: secp256k1`).
410    ///
411    /// See [strict JWK validation](crate#strict-jwk-validation) for the rules.
412    pub fn from_jwk(jwk: &str) -> Result<Self, Error> {
413        let (key_pair, key_id) = K256KeyPair::from_jwk(jwk)?;
414        Ok(ES256kKeyPair { key_pair, key_id })
415    }
416
417    /// Export the key pair as a JWK, private key included.
418    ///
419    /// Use `public_key().to_jwk()` to share the public key.
420    pub fn to_jwk(&self) -> String {
421        self.key_pair.to_jwk(self.key_id.as_deref())
422    }
423
424    /// The JWK thumbprint of the public key.
425    pub fn jwk_thumbprint(&self) -> String {
426        self.key_pair.public_key().jwk_thumbprint()
427    }
428}
429
430impl ECDSAP256kPublicKeyLike for ES256kPublicKey {
431    fn jwt_alg_name() -> &'static str {
432        "ES256K"
433    }
434
435    fn public_key(&self) -> &K256PublicKey {
436        &self.pk
437    }
438
439    fn key_id(&self) -> &Option<String> {
440        &self.key_id
441    }
442
443    fn set_key_id(&mut self, key_id: String) {
444        self.key_id = Some(key_id);
445    }
446}
447
448impl ES256kPublicKey {
449    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
450        Ok(ES256kPublicKey {
451            pk: K256PublicKey::from_bytes(raw)?,
452            key_id: None,
453        })
454    }
455
456    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
457        Ok(ES256kPublicKey {
458            pk: K256PublicKey::from_der(der)?,
459            key_id: None,
460        })
461    }
462
463    pub fn from_pem(pem: &str) -> Result<Self, Error> {
464        Ok(ES256kPublicKey {
465            pk: K256PublicKey::from_pem(pem)?,
466            key_id: None,
467        })
468    }
469
470    pub fn to_bytes(&self) -> Vec<u8> {
471        self.pk.to_bytes()
472    }
473
474    pub fn to_der(&self) -> Result<Vec<u8>, Error> {
475        self.pk.to_der()
476    }
477
478    pub fn to_pem(&self) -> Result<String, Error> {
479        self.pk.to_pem()
480    }
481
482    pub fn with_key_id(mut self, key_id: &str) -> Self {
483        self.key_id = Some(key_id.to_string());
484        self
485    }
486
487    /// Import a public key from a JWK (`kty: EC`, `crv: secp256k1`).
488    ///
489    /// See [strict JWK validation](crate#strict-jwk-validation) for the rules.
490    pub fn from_jwk(jwk: &str) -> Result<Self, Error> {
491        let (pk, key_id) = K256PublicKey::from_jwk(jwk)?;
492        Ok(ES256kPublicKey { pk, key_id })
493    }
494
495    /// Export the public key as a JWK, with `alg: ES256K` and `use: sig`.
496    pub fn to_jwk(&self) -> String {
497        self.pk.to_jwk(self.key_id.as_deref())
498    }
499
500    /// The JWK thumbprint of the key.
501    pub fn jwk_thumbprint(&self) -> String {
502        self.pk.jwk_thumbprint()
503    }
504}