1use crate::aws_lc::{
5 EVP_DigestSign, EVP_DigestSignInit, EVP_DigestVerify, EVP_DigestVerifyInit, EVP_PKEY_CTX_new,
6 EVP_PKEY_CTX_new_id, EVP_PKEY_bits, EVP_PKEY_cmp, EVP_PKEY_derive, EVP_PKEY_derive_init,
7 EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY, EVP_PKEY_get0_RSA,
8 EVP_PKEY_get_raw_private_key, EVP_PKEY_get_raw_public_key, EVP_PKEY_id, EVP_PKEY_keygen,
9 EVP_PKEY_keygen_init, EVP_PKEY_new_raw_private_key, EVP_PKEY_new_raw_public_key,
10 EVP_PKEY_pqdsa_new_raw_private_key, EVP_PKEY_pqdsa_new_raw_public_key, EVP_PKEY_sign,
11 EVP_PKEY_sign_init, EVP_PKEY_size, EVP_PKEY_up_ref, EVP_PKEY_verify, EVP_PKEY_verify_init,
12 EVP_marshal_private_key, EVP_marshal_private_key_v2, EVP_marshal_public_key,
13 EVP_parse_private_key, EVP_parse_public_key, EC_KEY, EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_ED25519,
14 EVP_PKEY_PQDSA, NID_MLDSA44, NID_MLDSA65, NID_MLDSA87, RSA,
15};
16use crate::cbb::LcCBB;
17use crate::digest::digest_ctx::DigestContext;
18use crate::digest::Digest;
19use crate::error::{KeyRejected, Unspecified};
20use crate::fips::indicator_check;
21use crate::pkcs8::Version;
22use crate::ptr::{ConstPointer, LcPtr};
23use crate::{cbs, digest};
24use core::ffi::c_int;
25use std::ptr::{null, null_mut};
26use zeroize::Zeroizing;
27
28impl PartialEq<Self> for LcPtr<EVP_PKEY> {
29 fn eq(&self, other: &Self) -> bool {
31 1 == unsafe { EVP_PKEY_cmp(self.as_const_ptr(), other.as_const_ptr()) }
33 }
34}
35
36#[allow(non_camel_case_types)]
37pub(crate) trait EVP_PKEY_CTX_consumer: Fn(*mut EVP_PKEY_CTX) -> Result<(), ()> {}
38
39impl<T> EVP_PKEY_CTX_consumer for T where T: Fn(*mut EVP_PKEY_CTX) -> Result<(), ()> {}
40
41#[allow(non_upper_case_globals, clippy::type_complexity)]
42pub(crate) const No_EVP_PKEY_CTX_consumer: Option<fn(*mut EVP_PKEY_CTX) -> Result<(), ()>> = None;
43
44impl ConstPointer<'_, EVP_PKEY> {
45 pub(crate) fn validate_as_ed25519(&self) -> Result<(), KeyRejected> {
46 const ED25519_KEY_TYPE: c_int = EVP_PKEY_ED25519;
47 const ED25519_MIN_BITS: c_int = 253;
48 const ED25519_MAX_BITS: c_int = 256;
49
50 let key_type = self.id();
51 if key_type != ED25519_KEY_TYPE {
52 return Err(KeyRejected::wrong_algorithm());
53 }
54
55 let bits: c_int = self.key_size_bits().try_into().unwrap();
56 if bits < ED25519_MIN_BITS {
57 return Err(KeyRejected::too_small());
58 }
59
60 if bits > ED25519_MAX_BITS {
61 return Err(KeyRejected::too_large());
62 }
63 Ok(())
64 }
65
66 pub(crate) fn id(&self) -> i32 {
80 unsafe { EVP_PKEY_id(self.as_const_ptr()) }
81 }
82
83 pub(crate) fn key_size_bytes(&self) -> usize {
84 self.key_size_bits() / 8
85 }
86
87 pub(crate) fn key_size_bits(&self) -> usize {
88 unsafe { EVP_PKEY_bits(self.as_const_ptr()) }
89 .try_into()
90 .unwrap()
91 }
92
93 pub(crate) fn signature_size_bytes(&self) -> usize {
94 unsafe { EVP_PKEY_size(self.as_const_ptr()) }
95 .try_into()
96 .unwrap()
97 }
98
99 #[allow(dead_code)]
100 pub(crate) fn get_ec_key(&self) -> Result<ConstPointer<'_, EC_KEY>, KeyRejected> {
101 self.project_const_lifetime(unsafe {
102 |evp_pkey| EVP_PKEY_get0_EC_KEY(evp_pkey.as_const_ptr())
103 })
104 .map_err(|()| KeyRejected::wrong_algorithm())
105 }
106
107 pub(crate) fn get_rsa(&self) -> Result<ConstPointer<'_, RSA>, KeyRejected> {
108 self.project_const_lifetime(unsafe {
109 |evp_pkey| EVP_PKEY_get0_RSA(evp_pkey.as_const_ptr())
110 })
111 .map_err(|()| KeyRejected::wrong_algorithm())
112 }
113
114 pub(crate) fn marshal_rfc5280_public_key(&self) -> Result<Vec<u8>, Unspecified> {
115 let mut cbb = LcCBB::new(self.key_size_bytes() * 5);
119 if 1 != unsafe { EVP_marshal_public_key(cbb.as_mut_ptr(), self.as_const_ptr()) } {
120 return Err(Unspecified);
121 }
122 cbb.into_vec()
123 }
124
125 pub(crate) fn marshal_rfc5208_private_key(
126 &self,
127 version: Version,
128 ) -> Result<Vec<u8>, Unspecified> {
129 let key_size_bytes =
130 TryInto::<usize>::try_into(unsafe { EVP_PKEY_bits(self.as_const_ptr()) })
131 .expect("fit in usize")
132 / 8;
133 let mut cbb = LcCBB::new(key_size_bytes * 5);
134 match version {
135 Version::V1 => {
136 if 1 != unsafe { EVP_marshal_private_key(cbb.as_mut_ptr(), self.as_const_ptr()) } {
137 return Err(Unspecified);
138 }
139 }
140 Version::V2 => {
141 if 1 != unsafe { EVP_marshal_private_key_v2(cbb.as_mut_ptr(), self.as_const_ptr()) }
142 {
143 return Err(Unspecified);
144 }
145 }
146 }
147 cbb.into_vec()
148 }
149
150 pub(crate) fn marshal_raw_private_key(&self) -> Result<Vec<u8>, Unspecified> {
151 let mut size = 0;
152 if 1 != unsafe { EVP_PKEY_get_raw_private_key(self.as_const_ptr(), null_mut(), &mut size) }
153 {
154 return Err(Unspecified);
155 }
156 let mut buffer = vec![0u8; size];
157 let buffer_size = self.marshal_raw_private_to_buffer(&mut buffer)?;
158 debug_assert_eq!(buffer_size, size);
159 Ok(buffer)
160 }
161
162 pub(crate) fn marshal_raw_private_to_buffer(
163 &self,
164 buffer: &mut [u8],
165 ) -> Result<usize, Unspecified> {
166 let mut key_len = buffer.len();
167 if 1 == unsafe {
168 EVP_PKEY_get_raw_private_key(self.as_const_ptr(), buffer.as_mut_ptr(), &mut key_len)
169 } {
170 Ok(key_len)
171 } else {
172 Err(Unspecified)
173 }
174 }
175
176 #[allow(dead_code)]
177 pub(crate) fn marshal_raw_public_key(&self) -> Result<Vec<u8>, Unspecified> {
178 let mut size = 0;
179 if 1 != unsafe { EVP_PKEY_get_raw_public_key(self.as_const_ptr(), null_mut(), &mut size) } {
180 return Err(Unspecified);
181 }
182 let mut buffer = vec![0u8; size];
183 let buffer_size = self.marshal_raw_public_to_buffer(&mut buffer)?;
184 debug_assert_eq!(buffer_size, size);
185 Ok(buffer)
186 }
187
188 pub(crate) fn marshal_raw_public_to_buffer(
189 &self,
190 buffer: &mut [u8],
191 ) -> Result<usize, Unspecified> {
192 let mut key_len = buffer.len();
193 if 1 == unsafe {
194 EVP_PKEY_get_raw_public_key(self.as_const_ptr(), buffer.as_mut_ptr(), &mut key_len)
198 } {
199 Ok(key_len)
200 } else {
201 Err(Unspecified)
202 }
203 }
204}
205
206impl LcPtr<EVP_PKEY> {
207 #[inline]
208 pub unsafe fn as_mut_unsafe_ptr(&self) -> *mut EVP_PKEY {
209 self.as_const_ptr().cast_mut()
210 }
211
212 pub(crate) fn parse_rfc5280_public_key(
213 bytes: &[u8],
214 evp_pkey_type: c_int,
215 ) -> Result<Self, KeyRejected> {
216 let mut cbs = cbs::build_CBS(bytes);
217 let evp_pkey = LcPtr::new(unsafe { EVP_parse_public_key(&mut cbs) })
219 .map_err(|()| KeyRejected::invalid_encoding())?;
220 evp_pkey
221 .as_const()
222 .id()
223 .eq(&evp_pkey_type)
224 .then_some(evp_pkey)
225 .ok_or(KeyRejected::wrong_algorithm())
226 }
227
228 pub(crate) fn parse_rfc5208_private_key(
229 bytes: &[u8],
230 evp_pkey_type: c_int,
231 ) -> Result<Self, KeyRejected> {
232 let mut cbs = cbs::build_CBS(bytes);
233 let evp_pkey = LcPtr::new(unsafe { EVP_parse_private_key(&mut cbs) })
235 .map_err(|()| KeyRejected::invalid_encoding())?;
236 evp_pkey
237 .as_const()
238 .id()
239 .eq(&evp_pkey_type)
240 .then_some(evp_pkey)
241 .ok_or(KeyRejected::wrong_algorithm())
242 }
243
244 #[allow(non_snake_case)]
245 pub(crate) fn create_EVP_PKEY_CTX(&self) -> Result<LcPtr<EVP_PKEY_CTX>, ()> {
246 LcPtr::new(unsafe { EVP_PKEY_CTX_new(self.as_mut_unsafe_ptr(), null_mut()) })
254 }
255
256 pub(crate) fn parse_raw_private_key(
257 bytes: &[u8],
258 evp_pkey_type: c_int,
259 ) -> Result<Self, KeyRejected> {
260 if evp_pkey_type == EVP_PKEY_PQDSA {
261 return match bytes.len() {
262 2560 => Self::new(unsafe {
263 EVP_PKEY_pqdsa_new_raw_private_key(NID_MLDSA44, bytes.as_ptr(), bytes.len())
264 }),
265 4032 => Self::new(unsafe {
266 EVP_PKEY_pqdsa_new_raw_private_key(NID_MLDSA65, bytes.as_ptr(), bytes.len())
267 }),
268 4896 => Self::new(unsafe {
269 EVP_PKEY_pqdsa_new_raw_private_key(NID_MLDSA87, bytes.as_ptr(), bytes.len())
270 }),
271 _ => Err(()),
272 }
273 .map_err(|()| KeyRejected::invalid_encoding());
274 }
275
276 Self::new(unsafe {
277 EVP_PKEY_new_raw_private_key(evp_pkey_type, null_mut(), bytes.as_ptr(), bytes.len())
278 })
279 .map_err(|()| KeyRejected::unspecified())
280 }
281
282 pub(crate) fn parse_raw_public_key(
283 bytes: &[u8],
284 evp_pkey_type: c_int,
285 ) -> Result<Self, KeyRejected> {
286 if evp_pkey_type == EVP_PKEY_PQDSA {
287 return match bytes.len() {
288 1312 => Self::new(unsafe {
289 EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA44, bytes.as_ptr(), bytes.len())
290 }),
291 1952 => Self::new(unsafe {
292 EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, bytes.as_ptr(), bytes.len())
293 }),
294 2592 => Self::new(unsafe {
295 EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA87, bytes.as_ptr(), bytes.len())
296 }),
297 _ => Err(()),
298 }
299 .map_err(|()| KeyRejected::unspecified());
300 }
301
302 Self::new(unsafe {
303 EVP_PKEY_new_raw_public_key(evp_pkey_type, null_mut(), bytes.as_ptr(), bytes.len())
304 })
305 .map_err(|()| KeyRejected::invalid_encoding())
306 }
307
308 pub(crate) fn sign<F>(
309 &self,
310 message: &[u8],
311 digest: Option<&'static digest::Algorithm>,
312 padding_fn: Option<F>,
313 ) -> Result<Box<[u8]>, Unspecified>
314 where
315 F: EVP_PKEY_CTX_consumer,
316 {
317 let mut md_ctx = DigestContext::new_uninit();
318 let evp_md = if let Some(alg) = digest {
319 digest::match_digest_type(&alg.id).as_const_ptr()
320 } else {
321 null()
322 };
323 let mut pctx = null_mut::<EVP_PKEY_CTX>();
324 if 1 != unsafe {
325 EVP_DigestSignInit(
329 md_ctx.as_mut_ptr(),
330 &mut pctx,
331 evp_md,
332 null_mut(),
333 self.as_mut_unsafe_ptr(),
334 )
335 } {
336 return Err(Unspecified);
337 }
338
339 if let Some(pad_fn) = padding_fn {
340 pad_fn(pctx)?;
341 }
342
343 let mut sig_len = 0;
345 if 1 != unsafe {
346 EVP_DigestSign(
347 md_ctx.as_mut_ptr(),
348 null_mut(),
349 &mut sig_len,
350 message.as_ptr(),
351 message.len(),
352 )
353 } {
354 return Err(Unspecified);
355 }
356 if sig_len == 0 {
357 return Err(Unspecified);
358 }
359
360 let mut signature = vec![0u8; sig_len];
361 if 1 != indicator_check!(unsafe {
362 EVP_DigestSign(
363 md_ctx.as_mut_ptr(),
364 signature.as_mut_ptr(),
365 &mut sig_len,
366 message.as_ptr(),
367 message.len(),
368 )
369 }) {
370 return Err(Unspecified);
371 }
372 signature.truncate(sig_len);
373 Ok(signature.into_boxed_slice())
374 }
375
376 pub(crate) fn sign_digest<F>(
377 &self,
378 digest: &Digest,
379 padding_fn: Option<F>,
380 ) -> Result<Box<[u8]>, Unspecified>
381 where
382 F: EVP_PKEY_CTX_consumer,
383 {
384 let mut pctx = self.create_EVP_PKEY_CTX()?;
385
386 if 1 != unsafe { EVP_PKEY_sign_init(pctx.as_mut_ptr()) } {
387 return Err(Unspecified);
388 }
389
390 if let Some(pad_fn) = padding_fn {
391 pad_fn(pctx.as_mut_ptr())?;
392 }
393
394 let msg_digest = digest.as_ref();
395 let mut sig_len = 0;
396 if 1 != unsafe {
397 EVP_PKEY_sign(
398 pctx.as_mut_ptr(),
399 null_mut(),
400 &mut sig_len,
401 msg_digest.as_ptr(),
402 msg_digest.len(),
403 )
404 } {
405 return Err(Unspecified);
406 }
407
408 let mut signature = vec![0u8; sig_len];
409 if 1 != indicator_check!(unsafe {
410 EVP_PKEY_sign(
411 pctx.as_mut_ptr(),
412 signature.as_mut_ptr(),
413 &mut sig_len,
414 msg_digest.as_ptr(),
415 msg_digest.len(),
416 )
417 }) {
418 return Err(Unspecified);
419 }
420 signature.truncate(sig_len);
421
422 Ok(signature.into_boxed_slice())
423 }
424
425 pub(crate) fn verify<F>(
426 &self,
427 msg: &[u8],
428 digest: Option<&'static digest::Algorithm>,
429 padding_fn: Option<F>,
430 signature: &[u8],
431 ) -> Result<(), Unspecified>
432 where
433 F: EVP_PKEY_CTX_consumer,
434 {
435 let mut md_ctx = DigestContext::new_uninit();
436
437 let evp_md = if let Some(alg) = digest {
438 digest::match_digest_type(&alg.id).as_const_ptr()
439 } else {
440 null()
441 };
442
443 let mut pctx = null_mut::<EVP_PKEY_CTX>();
444
445 if 1 != unsafe {
446 EVP_DigestVerifyInit(
447 md_ctx.as_mut_ptr(),
448 &mut pctx,
449 evp_md,
450 null_mut(),
451 self.as_mut_unsafe_ptr(),
452 )
453 } {
454 return Err(Unspecified);
455 }
456 if let Some(pad_fn) = padding_fn {
457 pad_fn(pctx)?;
458 }
459
460 if 1 != indicator_check!(unsafe {
461 EVP_DigestVerify(
462 md_ctx.as_mut_ptr(),
463 signature.as_ptr(),
464 signature.len(),
465 msg.as_ptr(),
466 msg.len(),
467 )
468 }) {
469 return Err(Unspecified);
470 }
471
472 Ok(())
473 }
474
475 pub(crate) fn verify_digest_sig<F>(
476 &self,
477 digest: &Digest,
478 padding_fn: Option<F>,
479 signature: &[u8],
480 ) -> Result<(), Unspecified>
481 where
482 F: EVP_PKEY_CTX_consumer,
483 {
484 let mut pctx = self.create_EVP_PKEY_CTX()?;
485
486 if 1 != unsafe { EVP_PKEY_verify_init(pctx.as_mut_ptr()) } {
487 return Err(Unspecified);
488 }
489
490 if let Some(pad_fn) = padding_fn {
491 pad_fn(pctx.as_mut_ptr())?;
492 }
493
494 let msg_digest = digest.as_ref();
495
496 if 1 == unsafe {
497 indicator_check!(EVP_PKEY_verify(
498 pctx.as_mut_ptr(),
499 signature.as_ptr(),
500 signature.len(),
501 msg_digest.as_ptr(),
502 msg_digest.len(),
503 ))
504 } {
505 Ok(())
506 } else {
507 Err(Unspecified)
508 }
509 }
510
511 pub(crate) fn agree(&self, peer_key: &mut Self) -> Result<Zeroizing<Vec<u8>>, Unspecified> {
512 let mut pctx = self.create_EVP_PKEY_CTX()?;
513
514 if 1 != unsafe { EVP_PKEY_derive_init(pctx.as_mut_ptr()) } {
515 return Err(Unspecified);
516 }
517
518 let mut secret_len = 0;
519 if 1 != unsafe { EVP_PKEY_derive_set_peer(pctx.as_mut_ptr(), peer_key.as_mut_ptr()) } {
520 return Err(Unspecified);
521 }
522
523 if 1 != unsafe { EVP_PKEY_derive(pctx.as_mut_ptr(), null_mut(), &mut secret_len) } {
524 return Err(Unspecified);
525 }
526
527 let mut secret = Zeroizing::new(vec![0u8; secret_len]);
529 if 1 != indicator_check!(unsafe {
530 EVP_PKEY_derive(pctx.as_mut_ptr(), secret.as_mut_ptr(), &mut secret_len)
531 }) {
532 return Err(Unspecified);
533 }
534 secret.truncate(secret_len);
536
537 Ok(secret)
538 }
539
540 pub(crate) fn generate<F>(pkey_type: c_int, params_fn: Option<F>) -> Result<Self, Unspecified>
541 where
542 F: EVP_PKEY_CTX_consumer,
543 {
544 let mut pkey_ctx = LcPtr::new(unsafe { EVP_PKEY_CTX_new_id(pkey_type, null_mut()) })?;
545
546 if 1 != unsafe { EVP_PKEY_keygen_init(pkey_ctx.as_mut_ptr()) } {
547 return Err(Unspecified);
548 }
549
550 if let Some(pad_fn) = params_fn {
551 pad_fn(pkey_ctx.as_mut_ptr())?;
552 }
553
554 let mut pkey = null_mut::<EVP_PKEY>();
555
556 if 1 != indicator_check!(unsafe { EVP_PKEY_keygen(pkey_ctx.as_mut_ptr(), &mut pkey) }) {
557 return Err(Unspecified);
558 }
559
560 Ok(LcPtr::new(pkey)?)
561 }
562}
563
564impl Clone for LcPtr<EVP_PKEY> {
565 fn clone(&self) -> Self {
566 assert_eq!(
573 1,
574 unsafe { EVP_PKEY_up_ref(self.as_mut_unsafe_ptr()) },
575 "infallible AWS-LC function"
576 );
577 Self::new(unsafe { self.as_mut_unsafe_ptr() }).expect("non-null AWS-LC EVP_PKEY pointer")
578 }
579}
580
581#[cfg(test)]
582mod tests {
583 use super::*;
584 use crate::aws_lc::EVP_PKEY_X25519;
585
586 fn generate_ed25519() -> LcPtr<EVP_PKEY> {
587 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_ED25519, No_EVP_PKEY_CTX_consumer)
588 .expect("ed25519 keygen")
589 }
590
591 fn generate_x25519() -> LcPtr<EVP_PKEY> {
592 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_X25519, No_EVP_PKEY_CTX_consumer)
593 .expect("x25519 keygen")
594 }
595
596 #[test]
597 fn agree_computes_matching_shared_secret_from_both_sides() {
598 let mut key_a = generate_x25519();
599 let mut key_b = generate_x25519();
600
601 let secret_ab = key_a.agree(&mut key_b).expect("agree a->b");
602 let secret_ba = key_b.agree(&mut key_a).expect("agree b->a");
603
604 assert!(!secret_ab.is_empty());
605 assert_eq!(secret_ab.as_slice(), secret_ba.as_slice());
606 }
607
608 #[test]
609 fn agree_rejects_mismatched_key_types() {
610 let x25519_key = generate_x25519();
611 let mut ed25519_key = generate_ed25519();
612
613 assert!(x25519_key.agree(&mut ed25519_key).is_err());
614 }
615}