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(), *other.as_const()) }
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) }
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) }.try_into().unwrap()
92 }
93
94 pub(crate) fn signature_size_bytes(&self) -> usize {
95 unsafe { EVP_PKEY_size(**self) }.try_into().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 { |evp_pkey| EVP_PKEY_get0_EC_KEY(**evp_pkey) })
101 .map_err(|()| KeyRejected::wrong_algorithm())
102 }
103
104 pub(crate) fn get_rsa(&self) -> Result<ConstPointer<'_, RSA>, KeyRejected> {
105 self.project_const_lifetime(unsafe { |evp_pkey| EVP_PKEY_get0_RSA(**evp_pkey) })
106 .map_err(|()| KeyRejected::wrong_algorithm())
107 }
108
109 pub(crate) fn marshal_rfc5280_public_key(&self) -> Result<Vec<u8>, Unspecified> {
110 let mut cbb = LcCBB::new(self.key_size_bytes() * 5);
114 if 1 != unsafe { EVP_marshal_public_key(cbb.as_mut_ptr(), **self) } {
115 return Err(Unspecified);
116 }
117 cbb.into_vec()
118 }
119
120 pub(crate) fn marshal_rfc5208_private_key(
121 &self,
122 version: Version,
123 ) -> Result<Vec<u8>, Unspecified> {
124 let key_size_bytes =
125 TryInto::<usize>::try_into(unsafe { EVP_PKEY_bits(**self) }).expect("fit in usize") / 8;
126 let mut cbb = LcCBB::new(key_size_bytes * 5);
127 match version {
128 Version::V1 => {
129 if 1 != unsafe { EVP_marshal_private_key(cbb.as_mut_ptr(), **self) } {
130 return Err(Unspecified);
131 }
132 }
133 Version::V2 => {
134 if 1 != unsafe { EVP_marshal_private_key_v2(cbb.as_mut_ptr(), **self) } {
135 return Err(Unspecified);
136 }
137 }
138 }
139 cbb.into_vec()
140 }
141
142 pub(crate) fn marshal_raw_private_key(&self) -> Result<Vec<u8>, Unspecified> {
143 let mut size = 0;
144 if 1 != unsafe { EVP_PKEY_get_raw_private_key(**self, null_mut(), &mut size) } {
145 return Err(Unspecified);
146 }
147 let mut buffer = vec![0u8; size];
148 let buffer_size = self.marshal_raw_private_to_buffer(&mut buffer)?;
149 debug_assert_eq!(buffer_size, size);
150 Ok(buffer)
151 }
152
153 pub(crate) fn marshal_raw_private_to_buffer(
154 &self,
155 buffer: &mut [u8],
156 ) -> Result<usize, Unspecified> {
157 let mut key_len = buffer.len();
158 if 1 == unsafe { EVP_PKEY_get_raw_private_key(**self, buffer.as_mut_ptr(), &mut key_len) } {
159 Ok(key_len)
160 } else {
161 Err(Unspecified)
162 }
163 }
164
165 #[allow(dead_code)]
166 pub(crate) fn marshal_raw_public_key(&self) -> Result<Vec<u8>, Unspecified> {
167 let mut size = 0;
168 if 1 != unsafe { EVP_PKEY_get_raw_public_key(**self, null_mut(), &mut size) } {
169 return Err(Unspecified);
170 }
171 let mut buffer = vec![0u8; size];
172 let buffer_size = self.marshal_raw_public_to_buffer(&mut buffer)?;
173 debug_assert_eq!(buffer_size, size);
174 Ok(buffer)
175 }
176
177 pub(crate) fn marshal_raw_public_to_buffer(
178 &self,
179 buffer: &mut [u8],
180 ) -> Result<usize, Unspecified> {
181 let mut key_len = buffer.len();
182 if 1 == unsafe {
183 EVP_PKEY_get_raw_public_key(**self, buffer.as_mut_ptr(), &mut key_len)
187 } {
188 Ok(key_len)
189 } else {
190 Err(Unspecified)
191 }
192 }
193}
194
195impl LcPtr<EVP_PKEY> {
196 pub(crate) fn parse_rfc5280_public_key(
197 bytes: &[u8],
198 evp_pkey_type: c_int,
199 ) -> Result<Self, KeyRejected> {
200 let mut cbs = cbs::build_CBS(bytes);
201 let evp_pkey = LcPtr::new(unsafe { EVP_parse_public_key(&mut cbs) })
203 .map_err(|()| KeyRejected::invalid_encoding())?;
204 evp_pkey
205 .as_const()
206 .id()
207 .eq(&evp_pkey_type)
208 .then_some(evp_pkey)
209 .ok_or(KeyRejected::wrong_algorithm())
210 }
211
212 pub(crate) fn parse_rfc5208_private_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_private_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 #[allow(non_snake_case)]
229 pub(crate) fn create_EVP_PKEY_CTX(&self) -> Result<LcPtr<EVP_PKEY_CTX>, ()> {
230 LcPtr::new(unsafe { EVP_PKEY_CTX_new(*self.as_mut_unsafe(), null_mut()) })
234 }
235
236 pub(crate) fn parse_raw_private_key(
237 bytes: &[u8],
238 evp_pkey_type: c_int,
239 ) -> Result<Self, KeyRejected> {
240 #[cfg(all(feature = "unstable", not(feature = "fips")))]
241 if evp_pkey_type == EVP_PKEY_PQDSA {
242 return match bytes.len() {
243 2560 => Self::new(unsafe {
244 EVP_PKEY_pqdsa_new_raw_private_key(NID_MLDSA44, bytes.as_ptr(), bytes.len())
245 }),
246 4032 => Self::new(unsafe {
247 EVP_PKEY_pqdsa_new_raw_private_key(NID_MLDSA65, bytes.as_ptr(), bytes.len())
248 }),
249 4896 => Self::new(unsafe {
250 EVP_PKEY_pqdsa_new_raw_private_key(NID_MLDSA87, bytes.as_ptr(), bytes.len())
251 }),
252 _ => Err(()),
253 }
254 .map_err(|()| KeyRejected::invalid_encoding());
255 }
256
257 Self::new(unsafe {
258 EVP_PKEY_new_raw_private_key(evp_pkey_type, null_mut(), bytes.as_ptr(), bytes.len())
259 })
260 .map_err(|()| KeyRejected::unspecified())
261 }
262
263 pub(crate) fn parse_raw_public_key(
264 bytes: &[u8],
265 evp_pkey_type: c_int,
266 ) -> Result<Self, KeyRejected> {
267 #[cfg(all(feature = "unstable", not(feature = "fips")))]
268 if evp_pkey_type == EVP_PKEY_PQDSA {
269 return match bytes.len() {
270 1312 => Self::new(unsafe {
271 EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA44, bytes.as_ptr(), bytes.len())
272 }),
273 1952 => Self::new(unsafe {
274 EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA65, bytes.as_ptr(), bytes.len())
275 }),
276 2592 => Self::new(unsafe {
277 EVP_PKEY_pqdsa_new_raw_public_key(NID_MLDSA87, bytes.as_ptr(), bytes.len())
278 }),
279 _ => Err(()),
280 }
281 .map_err(|()| KeyRejected::unspecified());
282 }
283
284 Self::new(unsafe {
285 EVP_PKEY_new_raw_public_key(evp_pkey_type, null_mut(), bytes.as_ptr(), bytes.len())
286 })
287 .map_err(|()| KeyRejected::invalid_encoding())
288 }
289
290 pub(crate) fn sign<F>(
291 &self,
292 message: &[u8],
293 digest: Option<&'static digest::Algorithm>,
294 padding_fn: Option<F>,
295 ) -> Result<Box<[u8]>, Unspecified>
296 where
297 F: EVP_PKEY_CTX_consumer,
298 {
299 let mut md_ctx = DigestContext::new_uninit();
300 let evp_md = if let Some(alg) = digest {
301 *digest::match_digest_type(&alg.id)
302 } else {
303 null()
304 };
305 let mut pctx = null_mut::<EVP_PKEY_CTX>();
306 if 1 != unsafe {
307 EVP_DigestSignInit(
311 md_ctx.as_mut_ptr(),
312 &mut pctx,
313 evp_md,
314 null_mut(),
315 *self.as_mut_unsafe(),
316 )
317 } {
318 return Err(Unspecified);
319 }
320
321 if let Some(pad_fn) = padding_fn {
322 pad_fn(pctx)?;
323 }
324
325 let mut sig_len = 0;
327 if 1 != unsafe {
328 EVP_DigestSign(
329 md_ctx.as_mut_ptr(),
330 null_mut(),
331 &mut sig_len,
332 message.as_ptr(),
333 message.len(),
334 )
335 } {
336 return Err(Unspecified);
337 }
338 if sig_len == 0 {
339 return Err(Unspecified);
340 }
341
342 let mut signature = vec![0u8; sig_len];
343 if 1 != indicator_check!(unsafe {
344 EVP_DigestSign(
345 md_ctx.as_mut_ptr(),
346 signature.as_mut_ptr(),
347 &mut sig_len,
348 message.as_ptr(),
349 message.len(),
350 )
351 }) {
352 return Err(Unspecified);
353 }
354 signature.truncate(sig_len);
355 Ok(signature.into_boxed_slice())
356 }
357
358 pub(crate) fn sign_digest<F>(
359 &self,
360 digest: &Digest,
361 padding_fn: Option<F>,
362 ) -> Result<Box<[u8]>, Unspecified>
363 where
364 F: EVP_PKEY_CTX_consumer,
365 {
366 let mut pctx = LcPtr::new(unsafe { EVP_PKEY_CTX_new(*self.as_mut_unsafe(), null_mut()) })?;
367
368 if 1 != unsafe { EVP_PKEY_sign_init(*pctx.as_mut()) } {
369 return Err(Unspecified);
370 }
371
372 if let Some(pad_fn) = padding_fn {
373 pad_fn(*pctx.as_mut())?;
374 }
375
376 let msg_digest = digest.as_ref();
377 let mut sig_len = 0;
378 if 1 != unsafe {
379 EVP_PKEY_sign(
380 *pctx.as_mut(),
381 null_mut(),
382 &mut sig_len,
383 msg_digest.as_ptr(),
384 msg_digest.len(),
385 )
386 } {
387 return Err(Unspecified);
388 }
389
390 let mut signature = vec![0u8; sig_len];
391 if 1 != indicator_check!(unsafe {
392 EVP_PKEY_sign(
393 *pctx.as_mut(),
394 signature.as_mut_ptr(),
395 &mut sig_len,
396 msg_digest.as_ptr(),
397 msg_digest.len(),
398 )
399 }) {
400 return Err(Unspecified);
401 }
402 signature.truncate(sig_len);
403
404 Ok(signature.into_boxed_slice())
405 }
406
407 pub(crate) fn verify<F>(
408 &self,
409 msg: &[u8],
410 digest: Option<&'static digest::Algorithm>,
411 padding_fn: Option<F>,
412 signature: &[u8],
413 ) -> Result<(), Unspecified>
414 where
415 F: EVP_PKEY_CTX_consumer,
416 {
417 let mut md_ctx = DigestContext::new_uninit();
418
419 let evp_md = if let Some(alg) = digest {
420 *digest::match_digest_type(&alg.id)
421 } else {
422 null()
423 };
424
425 let mut pctx = null_mut::<EVP_PKEY_CTX>();
426
427 if 1 != unsafe {
428 EVP_DigestVerifyInit(
429 md_ctx.as_mut_ptr(),
430 &mut pctx,
431 evp_md,
432 null_mut(),
433 *self.as_mut_unsafe(),
434 )
435 } {
436 return Err(Unspecified);
437 }
438 if let Some(pad_fn) = padding_fn {
439 pad_fn(pctx)?;
440 }
441
442 if 1 != indicator_check!(unsafe {
443 EVP_DigestVerify(
444 md_ctx.as_mut_ptr(),
445 signature.as_ptr(),
446 signature.len(),
447 msg.as_ptr(),
448 msg.len(),
449 )
450 }) {
451 return Err(Unspecified);
452 }
453
454 Ok(())
455 }
456
457 pub(crate) fn verify_digest_sig<F>(
458 &self,
459 digest: &Digest,
460 padding_fn: Option<F>,
461 signature: &[u8],
462 ) -> Result<(), Unspecified>
463 where
464 F: EVP_PKEY_CTX_consumer,
465 {
466 let mut pctx = LcPtr::new(unsafe { EVP_PKEY_CTX_new(*self.as_mut_unsafe(), null_mut()) })?;
467
468 if 1 != unsafe { EVP_PKEY_verify_init(*pctx.as_mut()) } {
469 return Err(Unspecified);
470 }
471
472 if let Some(pad_fn) = padding_fn {
473 pad_fn(*pctx.as_mut())?;
474 }
475
476 let msg_digest = digest.as_ref();
477
478 if 1 == unsafe {
479 indicator_check!(EVP_PKEY_verify(
480 *pctx.as_mut(),
481 signature.as_ptr(),
482 signature.len(),
483 msg_digest.as_ptr(),
484 msg_digest.len(),
485 ))
486 } {
487 Ok(())
488 } else {
489 Err(Unspecified)
490 }
491 }
492
493 pub(crate) fn agree(&self, peer_key: &Self) -> Result<Box<[u8]>, Unspecified> {
494 let mut pctx = self.create_EVP_PKEY_CTX()?;
495
496 if 1 != unsafe { EVP_PKEY_derive_init(*pctx.as_mut()) } {
497 return Err(Unspecified);
498 }
499
500 let mut secret_len = 0;
501 if 1 != unsafe { EVP_PKEY_derive_set_peer(*pctx.as_mut(), *peer_key.as_mut_unsafe()) } {
502 return Err(Unspecified);
503 }
504
505 if 1 != unsafe { EVP_PKEY_derive(*pctx.as_mut(), null_mut(), &mut secret_len) } {
506 return Err(Unspecified);
507 }
508
509 let mut secret = vec![0u8; secret_len];
510 if 1 != indicator_check!(unsafe {
511 EVP_PKEY_derive(*pctx.as_mut(), secret.as_mut_ptr(), &mut secret_len)
512 }) {
513 return Err(Unspecified);
514 }
515 secret.truncate(secret_len);
516
517 Ok(secret.into_boxed_slice())
518 }
519
520 pub(crate) fn generate<F>(pkey_type: c_int, params_fn: Option<F>) -> Result<Self, Unspecified>
521 where
522 F: EVP_PKEY_CTX_consumer,
523 {
524 let mut pkey_ctx = LcPtr::new(unsafe { EVP_PKEY_CTX_new_id(pkey_type, null_mut()) })?;
525
526 if 1 != unsafe { EVP_PKEY_keygen_init(*pkey_ctx.as_mut()) } {
527 return Err(Unspecified);
528 }
529
530 if let Some(pad_fn) = params_fn {
531 pad_fn(*pkey_ctx.as_mut())?;
532 }
533
534 let mut pkey = null_mut::<EVP_PKEY>();
535
536 if 1 != indicator_check!(unsafe { EVP_PKEY_keygen(*pkey_ctx.as_mut(), &mut pkey) }) {
537 return Err(Unspecified);
538 }
539
540 Ok(LcPtr::new(pkey)?)
541 }
542}
543
544impl Clone for LcPtr<EVP_PKEY> {
545 fn clone(&self) -> Self {
546 assert_eq!(
549 1,
550 unsafe { EVP_PKEY_up_ref(*self.as_mut_unsafe()) },
551 "infallible AWS-LC function"
552 );
553 Self::new(unsafe { *self.as_mut_unsafe() }).expect("non-null AWS-LC EVP_PKEY pointer")
554 }
555}