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