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