1use core::convert::TryFrom;
4
5use p256::{
6 ecdsa::{
7 signature::{
8 hazmat::{PrehashSigner, PrehashVerifier},
9 Signer, Verifier,
10 },
11 Signature, SigningKey, VerifyingKey,
12 },
13 elliptic_curve::{
14 self,
15 ecdh::diffie_hellman,
16 sec1::{Coordinates, FromEncodedPoint, ToEncodedPoint},
17 },
18 EncodedPoint, PublicKey, SecretKey,
19};
20use subtle::ConstantTimeEq;
21
22use super::{ec_common, EcCurves, HasKeyAlg, HasKeyBackend, KeyAlg};
23use crate::{
24 buffer::{ArrayKey, WriteBuffer},
25 error::Error,
26 generic_array::typenum::{U32, U33, U65},
27 jwk::{FromJwk, JwkEncoder, JwkParts, ToJwk},
28 kdf::KeyExchange,
29 random::KeyMaterial,
30 repr::{KeyGen, KeyMeta, KeyPublicBytes, KeySecretBytes, KeypairBytes, KeypairMeta},
31 sign::{KeySigVerify, KeySign, SignatureType},
32};
33
34pub const ES256_SIGNATURE_LENGTH: usize = 64;
44
45pub const PUBLIC_KEY_LENGTH: usize = 33;
47pub const SECRET_KEY_LENGTH: usize = 32;
49pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH;
51
52pub const JWK_KEY_TYPE: &str = "EC";
54pub const JWK_CURVE: &str = "P-256";
56
57type FieldSize = elliptic_curve::FieldBytesSize<p256::NistP256>;
58
59#[derive(Clone, Debug)]
61pub struct P256KeyPair {
62 secret: Option<SecretKey>,
64 public: PublicKey,
65}
66
67impl P256KeyPair {
68 #[inline]
69 pub(crate) fn from_secret_key(sk: SecretKey) -> Self {
70 let pk = sk.public_key();
71 Self {
72 secret: Some(sk),
73 public: pk,
74 }
75 }
76
77 pub(crate) fn check_public_bytes(&self, pk: &[u8]) -> Result<(), Error> {
78 if self.with_public_bytes(|slf| slf.ct_eq(pk)).into() {
79 Ok(())
80 } else {
81 Err(err_msg!(InvalidKeyData, "invalid p256 keypair"))
82 }
83 }
84
85 pub(crate) fn to_signing_key(&self) -> Option<SigningKey> {
86 self.secret.clone().map(SigningKey::from)
87 }
88
89 pub fn sign(&self, message: &[u8]) -> Option<[u8; ES256_SIGNATURE_LENGTH]> {
91 if let Some(skey) = self.to_signing_key() {
92 let sig: Signature = skey.sign(message);
93 let sigb: [u8; 64] = sig.to_bytes().into();
94 Some(sigb)
95 } else {
96 None
97 }
98 }
99
100 pub fn sign_prehashed(&self, hashed_message: &[u8]) -> Option<[u8; ES256_SIGNATURE_LENGTH]> {
102 if let Some(skey) = self.to_signing_key() {
103 if let Ok(sig) = PrehashSigner::<Signature>::sign_prehash(&skey, hashed_message) {
104 let sigb: [u8; 64] = sig.to_bytes().into();
105 return Some(sigb);
106 }
107 }
108 None
109 }
110
111 pub fn verify_signature(&self, message: &[u8], signature: &[u8]) -> bool {
113 if let Ok(sig) = Signature::try_from(signature) {
114 let vk = VerifyingKey::from(&self.public);
115 vk.verify(message, &sig).is_ok()
116 } else {
117 false
118 }
119 }
120
121 pub fn verify_signature_prehashed(&self, hashed_message: &[u8], signature: &[u8]) -> bool {
123 if let Ok(sig) = Signature::try_from(signature) {
124 let vk = VerifyingKey::from(&self.public);
125 vk.verify_prehash(hashed_message, &sig).is_ok()
126 } else {
127 false
128 }
129 }
130}
131
132impl HasKeyBackend for P256KeyPair {}
133
134impl HasKeyAlg for P256KeyPair {
135 fn algorithm(&self) -> KeyAlg {
136 KeyAlg::EcCurve(EcCurves::Secp256r1)
137 }
138}
139
140impl KeyMeta for P256KeyPair {
141 type KeySize = U32;
142}
143
144impl KeyGen for P256KeyPair {
145 fn generate(mut rng: impl KeyMaterial) -> Result<Self, Error> {
146 ArrayKey::<FieldSize>::temp(|buf| loop {
147 rng.read_okm(buf);
148 if let Ok(key) = SecretKey::from_bytes(buf) {
149 return Ok(Self::from_secret_key(key));
150 }
151 })
152 }
153}
154
155impl KeySecretBytes for P256KeyPair {
156 fn from_secret_bytes(key: &[u8]) -> Result<Self, Error> {
157 if key.len() == SECRET_KEY_LENGTH {
158 if let Ok(sk) = SecretKey::from_bytes(key.into()) {
159 return Ok(Self::from_secret_key(sk));
160 }
161 }
162 Err(err_msg!(InvalidKeyData))
163 }
164
165 fn with_secret_bytes<O>(&self, f: impl FnOnce(Option<&[u8]>) -> O) -> O {
166 if let Some(sk) = self.secret.as_ref() {
167 ArrayKey::<FieldSize>::temp(|arr| {
168 ec_common::write_sk(sk, &mut arr[..]);
169 f(Some(arr))
170 })
171 } else {
172 f(None)
173 }
174 }
175}
176
177impl KeypairMeta for P256KeyPair {
178 type PublicKeySize = U33;
179 type KeypairSize = U65;
180}
181
182impl KeypairBytes for P256KeyPair {
183 fn from_keypair_bytes(kp: &[u8]) -> Result<Self, Error> {
184 if kp.len() != KEYPAIR_LENGTH {
185 return Err(err_msg!(InvalidKeyData));
186 }
187 let result = P256KeyPair::from_secret_bytes(&kp[..SECRET_KEY_LENGTH])
188 .map_err(|_| err_msg!(InvalidKeyData))?;
189 result.check_public_bytes(&kp[SECRET_KEY_LENGTH..])?;
190 Ok(result)
191 }
192
193 fn with_keypair_bytes<O>(&self, f: impl FnOnce(Option<&[u8]>) -> O) -> O {
194 if let Some(sk) = self.secret.as_ref() {
195 ArrayKey::<<Self as KeypairMeta>::KeypairSize>::temp(|arr| {
196 ec_common::write_sk(sk, &mut arr[..SECRET_KEY_LENGTH]);
197 let pk_enc = self.public.to_encoded_point(true);
198 arr[SECRET_KEY_LENGTH..].copy_from_slice(pk_enc.as_bytes());
199 f(Some(&*arr))
200 })
201 } else {
202 f(None)
203 }
204 }
205}
206
207impl KeyPublicBytes for P256KeyPair {
208 fn from_public_bytes(key: &[u8]) -> Result<Self, Error> {
209 let pk = PublicKey::from_sec1_bytes(key).map_err(|_| err_msg!(InvalidKeyData))?;
210 Ok(Self {
211 secret: None,
212 public: pk,
213 })
214 }
215
216 fn with_public_bytes<O>(&self, f: impl FnOnce(&[u8]) -> O) -> O {
217 f(self.public.to_encoded_point(true).as_bytes())
218 }
219}
220
221impl KeySign for P256KeyPair {
222 fn write_signature(
223 &self,
224 message: &[u8],
225 sig_type: Option<SignatureType>,
226 out: &mut dyn WriteBuffer,
227 ) -> Result<(), Error> {
228 match sig_type {
229 None | Some(SignatureType::ES256) => {
230 if let Some(sig) = self.sign(message) {
231 out.buffer_write(&sig[..])?;
232 Ok(())
233 } else {
234 Err(err_msg!(Unsupported, "Undefined secret key"))
235 }
236 }
237 Some(SignatureType::ES256ph) => {
238 if let Some(sig) = self.sign_prehashed(message) {
239 out.buffer_write(&sig[..])?;
240 Ok(())
241 } else {
242 Err(err_msg!(Unsupported, "Signing operation not supported"))
243 }
244 }
245 #[allow(unreachable_patterns)]
246 _ => Err(err_msg!(Unsupported, "Unsupported signature type")),
247 }
248 }
249}
250
251impl KeySigVerify for P256KeyPair {
252 fn verify_signature(
253 &self,
254 message: &[u8],
255 signature: &[u8],
256 sig_type: Option<SignatureType>,
257 ) -> Result<bool, Error> {
258 match sig_type {
259 None | Some(SignatureType::ES256) => Ok(self.verify_signature(message, signature)),
260 Some(SignatureType::ES256ph) => Ok(self.verify_signature_prehashed(message, signature)),
261 #[allow(unreachable_patterns)]
262 _ => Err(err_msg!(Unsupported, "Unsupported signature type")),
263 }
264 }
265}
266
267impl ToJwk for P256KeyPair {
268 fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error> {
269 let pk_enc = self.public.to_encoded_point(false);
270 let (x, y) = match pk_enc.coordinates() {
271 Coordinates::Identity => {
272 return Err(err_msg!(
273 Unsupported,
274 "Cannot convert identity point to JWK"
275 ))
276 }
277 Coordinates::Uncompressed { x, y } => (x, y),
278 Coordinates::Compressed { .. } | Coordinates::Compact { .. } => unreachable!(),
279 };
280
281 enc.add_str("crv", JWK_CURVE)?;
282 enc.add_str("kty", JWK_KEY_TYPE)?;
283 enc.add_as_base64("x", &x[..])?;
284 enc.add_as_base64("y", &y[..])?;
285 if enc.is_secret() {
286 self.with_secret_bytes(|buf| {
287 if let Some(sk) = buf {
288 enc.add_as_base64("d", sk)
289 } else {
290 Ok(())
291 }
292 })?;
293 }
294 Ok(())
295 }
296}
297
298impl FromJwk for P256KeyPair {
299 fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
300 if jwk.kty != JWK_KEY_TYPE {
301 return Err(err_msg!(InvalidKeyData, "Unsupported key type"));
302 }
303 if jwk.crv != JWK_CURVE {
304 return Err(err_msg!(InvalidKeyData, "Unsupported key algorithm"));
305 }
306 let pk_x = ArrayKey::<FieldSize>::try_new_with(|arr| {
307 if jwk.x.decode_base64(arr)? != arr.len() {
308 Err(err_msg!(InvalidKeyData))
309 } else {
310 Ok(())
311 }
312 })?;
313 let pk_y = ArrayKey::<FieldSize>::try_new_with(|arr| {
314 if jwk.y.decode_base64(arr)? != arr.len() {
315 Err(err_msg!(InvalidKeyData))
316 } else {
317 Ok(())
318 }
319 })?;
320 let pk = Option::from(PublicKey::from_encoded_point(
321 &EncodedPoint::from_affine_coordinates(pk_x.as_ref(), pk_y.as_ref(), false),
322 ))
323 .ok_or_else(|| err_msg!(InvalidKeyData))?;
324 if jwk.d.is_some() {
325 ArrayKey::<FieldSize>::temp(|arr| {
326 if jwk.d.decode_base64(arr)? != arr.len() {
327 Err(err_msg!(InvalidKeyData))
328 } else {
329 let kp = P256KeyPair::from_secret_bytes(arr)?;
330 if kp.public != pk {
331 Err(err_msg!(InvalidKeyData))
332 } else {
333 Ok(kp)
334 }
335 }
336 })
337 } else {
338 Ok(Self {
339 secret: None,
340 public: pk,
341 })
342 }
343 }
344}
345
346impl KeyExchange for P256KeyPair {
347 fn write_key_exchange(&self, other: &Self, out: &mut dyn WriteBuffer) -> Result<(), Error> {
348 match self.secret.as_ref() {
349 Some(sk) => {
350 let xk = diffie_hellman(sk.to_nonzero_scalar(), other.public.as_affine());
351 out.buffer_write(xk.raw_secret_bytes().as_ref())?;
352 Ok(())
353 }
354 None => Err(err_msg!(MissingSecretKey)),
355 }
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use base64::Engine;
362 use sha2::Digest;
363
364 use super::*;
365 use crate::repr::ToPublicBytes;
366
367 #[test]
368 fn jwk_expected() {
369 let test_pvt_b64 = "jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI";
377 let test_pub_b64 = (
378 "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
379 "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
380 );
381 let test_pvt = base64::engine::general_purpose::URL_SAFE_NO_PAD
382 .decode(test_pvt_b64)
383 .unwrap();
384 let sk = P256KeyPair::from_secret_bytes(&test_pvt).expect("Error creating signing key");
385
386 let jwk = sk.to_jwk_public(None).expect("Error converting key to JWK");
387 let jwk = JwkParts::try_from_str(&jwk).expect("Error parsing JWK");
388 assert_eq!(jwk.kty, JWK_KEY_TYPE);
389 assert_eq!(jwk.crv, JWK_CURVE);
390 assert_eq!(jwk.x, test_pub_b64.0);
391 assert_eq!(jwk.y, test_pub_b64.1);
392 assert_eq!(jwk.d, None);
393 let pk_load = P256KeyPair::from_jwk_parts(jwk).unwrap();
394 assert_eq!(sk.to_public_bytes(), pk_load.to_public_bytes());
395
396 let jwk = sk.to_jwk_secret(None).expect("Error converting key to JWK");
397 let jwk = JwkParts::from_slice(&jwk).expect("Error parsing JWK");
398 assert_eq!(jwk.kty, JWK_KEY_TYPE);
399 assert_eq!(jwk.crv, JWK_CURVE);
400 assert_eq!(jwk.x, test_pub_b64.0);
401 assert_eq!(jwk.y, test_pub_b64.1);
402 assert_eq!(jwk.d, test_pvt_b64);
403 let sk_load = P256KeyPair::from_jwk_parts(jwk).unwrap();
404 assert_eq!(
405 sk.to_keypair_bytes().unwrap(),
406 sk_load.to_keypair_bytes().unwrap()
407 );
408 }
409
410 #[test]
411 fn jwk_thumbprint() {
412 let pk = P256KeyPair::from_jwk(
413 r#"{
414 "kty": "EC",
415 "crv": "P-256",
416 "x": "tDeeYABgKEAbWicYPCEEI8sP4SRIhHKcHDW7VqrB4LA",
417 "y": "J08HOoIZ0rX2Me3bNFZUltfxIk1Hrc8FsLu8VaSxsMI"
418 }"#,
419 )
420 .unwrap();
421 assert_eq!(
422 pk.to_jwk_thumbprint(None).unwrap(),
423 "8fm8079s3nu4FLV_7dVJoJ69A8XCXn7Za2mtaWCnxR4"
424 );
425 }
426
427 #[test]
428 fn sign_verify_expected() {
429 let test_msg = b"This is a dummy message for use with tests";
430 let test_sig = &hex!(
431 "241f765f19d4e6148452f2249d2fa69882244a6ad6e70aadb8848a6409d20712
432 4e85faf9587100247de7bdace13a3073b47ec8a531ca91c1375b2b6134344413"
433 );
434 let test_pvt = base64::engine::general_purpose::URL_SAFE_NO_PAD
435 .decode("jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI")
436 .unwrap();
437 let kp = P256KeyPair::from_secret_bytes(&test_pvt).unwrap();
438 let sig = kp.sign(&test_msg[..]).unwrap();
439 assert_eq!(sig, &test_sig[..]);
440 assert!(kp.verify_signature(&test_msg[..], &sig[..]));
441 assert!(!kp.verify_signature(b"Not the message", &sig[..]));
442 assert!(!kp.verify_signature(&test_msg[..], &[0u8; 64]));
443 }
444
445 #[test]
446 fn sign_verify_expected_prehash() {
447 let test_msg = sha2::Sha384::digest(b"This is a dummy message for use with tests");
448 let test_sig = &hex!(
449 "a3c0cbc5614ee2c5c1b0cb7302eb9f8d2ab4296ad0e699aa13ec7dc8ff1aca06
450 9075df4336f072547fec3beea6003f3d55bef11c0ee5dba1da091606dfc796f9"
451 );
452 let test_pvt = base64::engine::general_purpose::URL_SAFE_NO_PAD
453 .decode("jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI")
454 .unwrap();
455 let kp = P256KeyPair::from_secret_bytes(&test_pvt).unwrap();
456 let sig = kp.sign_prehashed(&test_msg[..]).unwrap();
457 assert_eq!(sig, &test_sig[..]);
458 assert!(kp.verify_signature_prehashed(&test_msg[..], &sig[..]));
459 assert!(!kp.verify_signature_prehashed(b"Not the message", &sig[..]));
460 assert!(!kp.verify_signature_prehashed(&test_msg[..], &[0u8; 64]));
461 }
462
463 #[test]
464 fn key_exchange_random() {
465 let kp1 = P256KeyPair::random().unwrap();
466 let kp2 = P256KeyPair::random().unwrap();
467 assert_ne!(
468 kp1.to_keypair_bytes().unwrap(),
469 kp2.to_keypair_bytes().unwrap()
470 );
471
472 let xch1 = kp1.key_exchange_bytes(&kp2).unwrap();
473 let xch2 = kp2.key_exchange_bytes(&kp1).unwrap();
474 assert_eq!(xch1.len(), 32);
475 assert_eq!(xch1, xch2);
476 }
477
478 #[test]
479 fn round_trip_bytes() {
480 let kp = P256KeyPair::random().unwrap();
481 let cmp = P256KeyPair::from_keypair_bytes(&kp.to_keypair_bytes().unwrap()).unwrap();
482 assert_eq!(
483 kp.to_keypair_bytes().unwrap(),
484 cmp.to_keypair_bytes().unwrap()
485 );
486 }
487}