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 #[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 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 pub fn to_jwk(&self) -> String {
432 self.key_pair.to_jwk(self.key_id.as_deref())
433 }
434
435 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 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 pub fn to_jwk(&self) -> String {
508 self.pk.to_jwk(self.key_id.as_deref())
509 }
510
511 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 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 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 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}