Skip to main content

jwt_simple/algorithms/
es384.rs

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