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