Skip to main content

jwt_simple/algorithms/
es256.rs

1use std::convert::{TryFrom, TryInto};
2
3use ct_codecs::{Base64UrlSafeNoPadding, Encoder};
4use p256::ecdsa::{self, signature::DigestVerifier as _, signature::RandomizedDigestSigner as _};
5use p256::elliptic_curve::Generate as _;
6use p256::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey};
7use p256::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 ES256_PUBLIC_JWK: JwkDescriptor = JwkDescriptor::new(
23    KeyType::Ec,
24    Some("P-256"),
25    "ES256",
26    KeyRole::SignaturePublic,
27);
28const ES256_PRIVATE_JWK: JwkDescriptor = ES256_PUBLIC_JWK.with_role(KeyRole::SignaturePrivate);
29
30#[doc(hidden)]
31#[derive(Debug, Clone)]
32pub struct P256PublicKey(ecdsa::VerifyingKey);
33
34impl AsRef<ecdsa::VerifyingKey> for P256PublicKey {
35    fn as_ref(&self) -> &ecdsa::VerifyingKey {
36        &self.0
37    }
38}
39
40impl P256PublicKey {
41    pub(crate) fn from_jwk(jwk: &str) -> Result<(Self, Option<String>), Error> {
42        let jwk = Jwk::parse(jwk, &ES256_PUBLIC_JWK)?;
43        let point = ec_point(&jwk, 32).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            &ES256_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-256", &self.to_bytes_uncompressed())
59    }
60
61    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
62        let p256_pk =
63            ecdsa::VerifyingKey::from_sec1_bytes(raw).map_err(|_| JWTError::InvalidPublicKey)?;
64        Ok(P256PublicKey(p256_pk))
65    }
66
67    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
68        let p256_pk = ecdsa::VerifyingKey::from_public_key_der(der)
69            .map_err(|_| JWTError::InvalidPublicKey)?;
70        Ok(P256PublicKey(p256_pk))
71    }
72
73    pub fn from_pem(pem: &str) -> Result<Self, Error> {
74        let p256_pk = ecdsa::VerifyingKey::from_public_key_pem(pem)
75            .map_err(|_| JWTError::InvalidPublicKey)?;
76        Ok(P256PublicKey(p256_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 p256_pk = p256::PublicKey::from(self.0);
89        Ok(p256_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 p256_pk = p256::PublicKey::from(self.0);
98        Ok(p256_pk
99            .to_public_key_pem(Default::default())
100            .map_err(|_| JWTError::InvalidPublicKey)?)
101    }
102}
103
104#[doc(hidden)]
105pub struct P256KeyPair {
106    p256_sk: ecdsa::SigningKey,
107    metadata: Option<KeyMetadata>,
108}
109
110impl std::fmt::Debug for P256KeyPair {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        write!(f, "EcKey")
113    }
114}
115
116impl AsRef<ecdsa::SigningKey> for P256KeyPair {
117    fn as_ref(&self) -> &ecdsa::SigningKey {
118        &self.p256_sk
119    }
120}
121
122impl P256KeyPair {
123    pub(crate) fn from_jwk(jwk: &str) -> Result<(Self, Option<String>), Error> {
124        let jwk = Jwk::parse(jwk, &ES256_PRIVATE_JWK)?;
125        let d = decode_secret(jwk.d(), 32).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.p256_sk.to_bytes().to_vec());
137        ec_export(&ES256_PRIVATE_JWK, &point, Some(&d), key_id)
138    }
139
140    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
141        let raw: &p256::FieldBytes = raw.try_into().map_err(|_| JWTError::InvalidKeyPair)?;
142        let p256_sk = ecdsa::SigningKey::from_bytes(raw).map_err(|_| JWTError::InvalidKeyPair)?;
143        Ok(P256KeyPair {
144            p256_sk,
145            metadata: None,
146        })
147    }
148
149    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
150        let p256_sk =
151            ecdsa::SigningKey::from_pkcs8_der(der).map_err(|_| JWTError::InvalidKeyPair)?;
152        Ok(P256KeyPair {
153            p256_sk,
154            metadata: None,
155        })
156    }
157
158    pub fn from_pem(pem: &str) -> Result<Self, Error> {
159        let p256_sk =
160            ecdsa::SigningKey::from_pkcs8_pem(pem).map_err(|_| JWTError::InvalidKeyPair)?;
161        Ok(P256KeyPair {
162            p256_sk,
163            metadata: None,
164        })
165    }
166
167    pub fn to_bytes(&self) -> Vec<u8> {
168        self.p256_sk.to_bytes().to_vec()
169    }
170
171    pub fn to_der(&self) -> Result<Vec<u8>, Error> {
172        let scalar = NonZeroScalar::from_repr(self.p256_sk.to_bytes());
173        if bool::from(scalar.is_none()) {
174            return Err(JWTError::InvalidKeyPair.into());
175        }
176        let p256_sk =
177            p256::SecretKey::from(NonZeroScalar::from_repr(scalar.unwrap().into()).unwrap());
178        Ok(p256_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.p256_sk.to_bytes());
187        if bool::from(scalar.is_none()) {
188            return Err(JWTError::InvalidKeyPair.into());
189        }
190        let p256_sk =
191            p256::SecretKey::from(NonZeroScalar::from_repr(scalar.unwrap().into()).unwrap());
192        Ok(p256_sk
193            .to_pkcs8_pem(Default::default())
194            .map_err(|_| JWTError::InvalidKeyPair)?
195            .to_string())
196    }
197
198    pub fn public_key(&self) -> P256PublicKey {
199        let p256_pk = self.p256_sk.verifying_key();
200        P256PublicKey(*p256_pk)
201    }
202
203    pub fn generate() -> Self {
204        let mut rng = rand::rng();
205        let p256_sk = ecdsa::SigningKey::generate_from_rng(&mut rng);
206        P256KeyPair {
207            p256_sk,
208            metadata: None,
209        }
210    }
211}
212
213pub trait ECDSAP256KeyPairLike {
214    fn jwt_alg_name() -> &'static str;
215    fn key_pair(&self) -> &P256KeyPair;
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_sha256::Hash| {
241                    digest.update(authenticated.as_bytes())
242                });
243            Ok(signature.to_vec())
244        })
245    }
246}
247
248pub trait ECDSAP256PublicKeyLike {
249    fn jwt_alg_name() -> &'static str;
250    fn public_key(&self) -> &P256PublicKey;
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_sha256::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_sha256::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 ES256KeyPair {
328    key_pair: P256KeyPair,
329    key_id: Option<String>,
330}
331
332impl std::fmt::Debug for ES256KeyPair {
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 ES256PublicKey {
340    pk: P256PublicKey,
341    key_id: Option<String>,
342}
343
344impl ECDSAP256KeyPairLike for ES256KeyPair {
345    fn jwt_alg_name() -> &'static str {
346        "ES256"
347    }
348
349    fn key_pair(&self) -> &P256KeyPair {
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 ES256KeyPair {
368    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
369        Ok(ES256KeyPair {
370            key_pair: P256KeyPair::from_bytes(raw)?,
371            key_id: None,
372        })
373    }
374
375    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
376        Ok(ES256KeyPair {
377            key_pair: P256KeyPair::from_der(der)?,
378            key_id: None,
379        })
380    }
381
382    pub fn from_pem(pem: &str) -> Result<Self, Error> {
383        Ok(ES256KeyPair {
384            key_pair: P256KeyPair::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) -> ES256PublicKey {
402        ES256PublicKey {
403            pk: self.key_pair.public_key(),
404            key_id: self.key_id.clone(),
405        }
406    }
407
408    pub fn generate() -> Self {
409        ES256KeyPair {
410            key_pair: P256KeyPair::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-256`).
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) = P256KeyPair::from_jwk(jwk)?;
425        Ok(ES256KeyPair { 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 ECDSAP256PublicKeyLike for ES256PublicKey {
442    fn jwt_alg_name() -> &'static str {
443        "ES256"
444    }
445
446    fn public_key(&self) -> &P256PublicKey {
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 ES256PublicKey {
460    pub fn from_bytes(raw: &[u8]) -> Result<Self, Error> {
461        Ok(ES256PublicKey {
462            pk: P256PublicKey::from_bytes(raw)?,
463            key_id: None,
464        })
465    }
466
467    pub fn from_der(der: &[u8]) -> Result<Self, Error> {
468        Ok(ES256PublicKey {
469            pk: P256PublicKey::from_der(der)?,
470            key_id: None,
471        })
472    }
473
474    pub fn from_pem(pem: &str) -> Result<Self, Error> {
475        Ok(ES256PublicKey {
476            pk: P256PublicKey::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-256`).
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) = P256PublicKey::from_jwk(jwk)?;
503        Ok(ES256PublicKey { pk, key_id })
504    }
505
506    /// Export the public key as a JWK, with `alg: ES256` 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}
516
517#[cfg(test)]
518mod jwk_tests {
519    use crate::algorithms::jwk_test_vectors;
520    use crate::algorithms::test_util::{b64, error_of, json, member_bytes, unb64, with, without};
521    use crate::prelude::*;
522    use crate::JWTError;
523
524    // Thumbprints computed with jwcrypto 1.5.6.
525    const P256: &str = r#"{"kty":"EC","crv":"P-256",
526        "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
527        "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
528        "d":"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"}"#;
529    const P256_THUMBPRINT: &str = "cn-I_WNMClehiVp51i_0VpOENW1upEerA8sEam5hn-s";
530    const P384: &str = r#"{"kty":"EC","crv":"P-384",
531        "x":"LUwGxVN6rAonzPWy9u0PjghkPwE4CHit0QJ5kGzDqg8oGYav-Ln8veWuBTIz0h-e",
532        "y":"U-AWY87B3rceQqi6QYg8-RYj4LZsejs1NdqTD3ueSanvFGtPpBVpURzfFFhNstIt",
533        "d":"t8OYG13e1MHzM_oUKHTPZtgc0Z8WHi95AB2XVcF3N27UelbAVnqKxERaNbsir7ec"}"#;
534    const P384_THUMBPRINT: &str = "X87vqkTYo4hKc59UwU-zy0NKzDsrgMRum4flPbRwXVs";
535    const K256: &str = r#"{"kty":"EC","crv":"secp256k1",
536        "x":"EyvzgldJCeQIOPfRJ9oZO3rVVzS8ZlFtgToMR2OWSuE",
537        "y":"JlvzSwhNHfvBwDiRfgsJuT1zjRSTDzZpASPlUSmi8tA",
538        "d":"hwiWAz2LjbQMp9MEzs9YzNvmcPkvJt5i-fc7kgceObk"}"#;
539    const K256_THUMBPRINT: &str = "sCqxz4FJp22HsNYDd_gawjMoBLsFAaQixbb8JSoXRrA";
540
541    #[test]
542    fn independent_thumbprints() {
543        let key_pair = ES256KeyPair::from_jwk(P256).unwrap();
544        assert_eq!(key_pair.jwk_thumbprint(), P256_THUMBPRINT);
545        let public = ES256PublicKey::from_jwk(&without(P256, &["d"])).unwrap();
546        assert_eq!(public.jwk_thumbprint(), P256_THUMBPRINT);
547
548        let key_pair = ES384KeyPair::from_jwk(P384).unwrap();
549        assert_eq!(key_pair.jwk_thumbprint(), P384_THUMBPRINT);
550        assert_eq!(key_pair.public_key().jwk_thumbprint(), P384_THUMBPRINT);
551
552        let key_pair = ES256kKeyPair::from_jwk(K256).unwrap();
553        assert_eq!(key_pair.jwk_thumbprint(), K256_THUMBPRINT);
554        assert_eq!(key_pair.public_key().jwk_thumbprint(), K256_THUMBPRINT);
555    }
556
557    macro_rules! round_trip {
558        ($key_pair:ident, $public_key:ident, $crv:expr, $alg:expr, $size:expr) => {{
559            let key_pair = $key_pair::generate().with_key_id("k1");
560            let private_jwk = key_pair.to_jwk();
561            let public_jwk = key_pair.public_key().to_jwk();
562            let exported = json(&public_jwk);
563            assert_eq!(exported["kty"], "EC");
564            assert_eq!(exported["crv"], $crv);
565            assert_eq!(exported["alg"], $alg);
566            assert_eq!(exported["use"], "sig");
567            assert_eq!(exported["kid"], "k1");
568            assert!(exported.get("d").is_none());
569            assert_eq!(member_bytes(&public_jwk, "x").len(), $size);
570            assert_eq!(member_bytes(&public_jwk, "y").len(), $size);
571            assert_eq!(member_bytes(&private_jwk, "d").len(), $size);
572
573            let restored = $key_pair::from_jwk(&private_jwk).unwrap();
574            let public_key = $public_key::from_jwk(&public_jwk).unwrap();
575            assert_eq!(restored.to_bytes(), key_pair.to_bytes());
576            assert_eq!(restored.to_jwk(), private_jwk);
577            assert_eq!(public_key.to_jwk(), public_jwk);
578            assert_eq!(restored.jwk_thumbprint(), public_key.jwk_thumbprint());
579
580            let token = restored
581                .sign(Claims::create(Duration::from_hours(1)))
582                .unwrap();
583            let options = VerificationOptions {
584                required_key_id: Some("k1".into()),
585                ..Default::default()
586            };
587            public_key
588                .verify_token::<NoCustomClaims>(&token, Some(options))
589                .unwrap();
590        }};
591    }
592
593    #[test]
594    fn round_trips() {
595        round_trip!(ES256KeyPair, ES256PublicKey, "P-256", "ES256", 32);
596        round_trip!(ES384KeyPair, ES384PublicKey, "P-384", "ES384", 48);
597        round_trip!(ES256kKeyPair, ES256kPublicKey, "secp256k1", "ES256K", 32);
598    }
599
600    #[test]
601    fn coordinates_are_full_size_and_checked_one_by_one() {
602        let key_pair = (0..10_000)
603            .map(|_| ES256KeyPair::generate())
604            .find(|kp| kp.public_key().public_key().to_bytes_uncompressed()[1] == 0)
605            .unwrap();
606        let public_jwk = key_pair.public_key().to_jwk();
607        let x = member_bytes(&public_jwk, "x");
608        assert_eq!(x.len(), 32);
609        assert_eq!(x[0], 0);
610        ES256PublicKey::from_jwk(&public_jwk).unwrap();
611        ES256KeyPair::from_jwk(&key_pair.to_jwk()).unwrap();
612
613        let short = with(&public_jwk, "x", b64(&x[1..]).into());
614        assert!(matches!(
615            error_of(ES256PublicKey::from_jwk(&short)),
616            JWTError::InvalidPublicKey
617        ));
618
619        let public_jwk = without(P256, &["d"]);
620        let x = member_bytes(P256, "x");
621        let y = member_bytes(P256, "y");
622        let xy = [&x[..], &y[..]].concat();
623        // A valid point must still have two full-length coordinates.
624        for split in [31, 33] {
625            let jwk = with(&public_jwk, "x", b64(&xy[..split]).into());
626            let jwk = with(&jwk, "y", b64(&xy[split..]).into());
627            assert!(
628                matches!(
629                    error_of(ES256PublicKey::from_jwk(&jwk)),
630                    JWTError::InvalidPublicKey
631                ),
632                "{}",
633                split
634            );
635        }
636        let mut off_curve = y.clone();
637        off_curve[31] ^= 1;
638        let jwk = with(&public_jwk, "y", b64(&off_curve).into());
639        assert!(ES256PublicKey::from_jwk(&jwk).is_err());
640        assert!(ES256PublicKey::from_jwk(&without(&public_jwk, &["y"])).is_err());
641    }
642
643    #[test]
644    fn private_scalar_must_be_valid_and_match() {
645        let order = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVE";
646        assert_eq!(unb64(order).len(), 32);
647        let other = json(&ES256KeyPair::generate().to_jwk());
648        for (case, d) in [
649            ("zero", b64(&[0u8; 32])),
650            ("group order", order.to_string()),
651            ("other key", other["d"].as_str().unwrap().to_string()),
652            ("short", b64(&member_bytes(P256, "d")[1..])),
653        ] {
654            let jwk = with(P256, "d", d.into());
655            assert!(
656                matches!(
657                    error_of(ES256KeyPair::from_jwk(&jwk)),
658                    JWTError::InvalidKeyPair
659                ),
660                "{}",
661                case
662            );
663        }
664        assert!(ES256KeyPair::from_jwk(&without(P256, &["y"])).is_err());
665    }
666
667    #[test]
668    fn keys_only_load_into_their_own_type() {
669        let p256_public = without(P256, &["d"]);
670        assert!(ES384PublicKey::from_jwk(&p256_public).is_err());
671        assert!(ES256kPublicKey::from_jwk(&p256_public).is_err());
672        assert!(ES256KeyPair::from_jwk(&without(P384, &["d"])).is_err());
673
674        ES256PublicKey::from_jwk(&with(&p256_public, "alg", "ES256".into())).unwrap();
675        let mut rejected = vec![
676            with(&p256_public, "crv", "secp256k1".into()),
677            with(&p256_public, "use", "enc".into()),
678            with(&p256_public, "key_ops", serde_json::json!(["deriveBits"])),
679        ];
680        for alg in [
681            "ES384",
682            "ES256K",
683            "ECDH-ES+A256KW",
684            "ECDH",
685            "EdDSA",
686            "RS256",
687        ] {
688            rejected.push(with(&p256_public, "alg", alg.into()));
689        }
690        for jwk in rejected {
691            assert!(ES256PublicKey::from_jwk(&jwk).is_err(), "{}", jwk);
692        }
693    }
694
695    #[test]
696    fn webcrypto_exports() {
697        for export in jwk_test_vectors::ALL {
698            let export = json(export);
699            let entry = &export["keys"]["ES256"];
700            let key_pair = ES256KeyPair::from_jwk(&entry["private"].to_string()).unwrap();
701            let public_key = ES256PublicKey::from_jwk(&entry["public"].to_string()).unwrap();
702            assert_eq!(key_pair.jwk_thumbprint(), public_key.jwk_thumbprint());
703            public_key
704                .verify_token::<NoCustomClaims>(entry["jwt"].as_str().unwrap(), None)
705                .unwrap();
706
707            let entry = &export["keys"]["ES384"];
708            let key_pair = ES384KeyPair::from_jwk(&entry["private"].to_string()).unwrap();
709            let public_key = ES384PublicKey::from_jwk(&entry["public"].to_string()).unwrap();
710            assert_eq!(key_pair.jwk_thumbprint(), public_key.jwk_thumbprint());
711            public_key
712                .verify_token::<NoCustomClaims>(entry["jwt"].as_str().unwrap(), None)
713                .unwrap();
714
715            // Without usage information, ECDH public keys look like signing keys.
716            let ecdh = &export["keys"]["ECDH-P256"];
717            let labeled = ecdh["public"].get("alg").is_some();
718            assert_eq!(
719                ES256PublicKey::from_jwk(&ecdh["public"].to_string()).is_err(),
720                labeled
721            );
722            assert!(ES256KeyPair::from_jwk(&ecdh["private"].to_string()).is_err());
723        }
724    }
725}