Skip to content

Commit

Permalink
EVP_PKEY refactoring for keygen/sign/verify; Start of ML-DSA impl (#689)
Browse files Browse the repository at this point in the history
* Generation/Serialization for ML-DSA

* Support sign/verify for EVP_PKEY

* Consolidate EVP_DigestSign/EVP_DigestVerify usage

* Consolidate EVP_PKEY_keygen usage

* Satisfy clippy
  • Loading branch information
justsmth authored Feb 12, 2025
1 parent 5af71cc commit 33614e2
Show file tree
Hide file tree
Showing 15 changed files with 431 additions and 440 deletions.
22 changes: 4 additions & 18 deletions aws-lc-rs/src/agreement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ use crate::ptr::ConstPointer;
pub use ephemeral::{agree_ephemeral, EphemeralPrivateKey};

use crate::aws_lc::{
EVP_PKEY_CTX_new_id, EVP_PKEY_derive, EVP_PKEY_derive_init, EVP_PKEY_derive_set_peer,
EVP_PKEY_get0_EC_KEY, EVP_PKEY_keygen, EVP_PKEY_keygen_init, NID_X9_62_prime256v1,
NID_secp384r1, NID_secp521r1, EVP_PKEY, EVP_PKEY_X25519, NID_X25519,
EVP_PKEY_derive, EVP_PKEY_derive_init, EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY,
NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, EVP_PKEY, EVP_PKEY_X25519, NID_X25519,
};

use crate::buffer::Buffer;
Expand All @@ -74,6 +73,7 @@ use crate::encoding::{
AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, PublicKeyX509Der,
};
use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
use crate::fips::indicator_check;
use crate::ptr::LcPtr;
use core::fmt;
Expand Down Expand Up @@ -482,21 +482,7 @@ impl AsBigEndian<Curve25519SeedBin<'static>> for PrivateKey {
}

pub(crate) fn generate_x25519() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
let mut pkey_ctx = LcPtr::new(unsafe { EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, null_mut()) })?;

if 1 != unsafe { EVP_PKEY_keygen_init(*pkey_ctx.as_mut()) } {
return Err(Unspecified);
}

let mut pkey: *mut EVP_PKEY = null_mut();

if 1 != indicator_check!(unsafe { EVP_PKEY_keygen(*pkey_ctx.as_mut(), &mut pkey) }) {
return Err(Unspecified);
}

let pkey = LcPtr::new(pkey)?;

Ok(pkey)
LcPtr::<EVP_PKEY>::generate(EVP_PKEY_X25519, No_EVP_PKEY_CTX_consumer)
}

const MAX_PUBLIC_KEY_LEN: usize = ec::PUBLIC_KEY_MAX_LEN;
Expand Down
6 changes: 1 addition & 5 deletions aws-lc-rs/src/bn.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

use crate::aws_lc::{BN_bin2bn, BN_bn2bin, BN_new, BN_num_bits, BN_num_bytes, BN_set_u64, BIGNUM};
use crate::aws_lc::{BN_bin2bn, BN_bn2bin, BN_new, BN_num_bytes, BN_set_u64, BIGNUM};
use crate::ptr::{ConstPointer, DetachableLcPtr, LcPtr};
use core::ptr::null_mut;

Expand Down Expand Up @@ -60,8 +60,4 @@ impl ConstPointer<BIGNUM> {
byte_vec
}
}

pub(crate) fn num_bits(&self) -> u32 {
unsafe { BN_num_bits(**self) }
}
}
36 changes: 12 additions & 24 deletions aws-lc-rs/src/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// SPDX-License-Identifier: Apache-2.0 OR ISC

use crate::ec::signature::AlgorithmID;
use core::ptr::null_mut;
// TODO: Uncomment when MSRV >= 1.64
use std::os::raw::c_int;

Expand All @@ -15,12 +14,12 @@ use crate::aws_lc::EC_KEY_check_key;
use crate::aws_lc::{
ECDSA_SIG_from_bytes, ECDSA_SIG_get0_r, ECDSA_SIG_get0_s, EC_GROUP_get_curve_name,
EC_KEY_get0_group, EC_group_p224, EC_group_p256, EC_group_p384, EC_group_p521,
EC_group_secp256k1, EVP_PKEY_CTX_new_id, EVP_PKEY_CTX_set_ec_paramgen_curve_nid,
EVP_PKEY_get0_EC_KEY, EVP_PKEY_keygen, EVP_PKEY_keygen_init, NID_X9_62_prime256v1,
NID_secp224r1, NID_secp256k1, NID_secp384r1, NID_secp521r1, EC_GROUP, EC_KEY, EVP_PKEY,
EVP_PKEY_EC,
EC_group_secp256k1, EVP_PKEY_CTX_set_ec_paramgen_curve_nid, EVP_PKEY_get0_EC_KEY,
NID_X9_62_prime256v1, NID_secp224r1, NID_secp256k1, NID_secp384r1, NID_secp521r1, EC_GROUP,
EC_KEY, EVP_PKEY, EVP_PKEY_EC,
};
use crate::error::{KeyRejected, Unspecified};
#[cfg(feature = "fips")]
use crate::fips::indicator_check;
use crate::ptr::{ConstPointer, LcPtr};
use crate::signature::Signature;
Expand Down Expand Up @@ -85,25 +84,14 @@ pub(crate) fn validate_evp_key(

#[inline]
pub(crate) fn evp_key_generate(nid: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
let mut pkey_ctx = LcPtr::new(unsafe { EVP_PKEY_CTX_new_id(EVP_PKEY_EC, null_mut()) })?;

if 1 != unsafe { EVP_PKEY_keygen_init(*pkey_ctx.as_mut()) } {
return Err(Unspecified);
}

if 1 != unsafe { EVP_PKEY_CTX_set_ec_paramgen_curve_nid(*pkey_ctx.as_mut(), nid) } {
return Err(Unspecified);
}

let mut pkey = null_mut::<EVP_PKEY>();

if 1 != indicator_check!(unsafe { EVP_PKEY_keygen(*pkey_ctx.as_mut(), &mut pkey) }) {
return Err(Unspecified);
}

let pkey = LcPtr::new(pkey)?;

Ok(pkey)
let params_fn = |ctx| {
if 1 == unsafe { EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) } {
Ok(())
} else {
Err(())
}
};
LcPtr::<EVP_PKEY>::generate(EVP_PKEY_EC, Some(params_fn))
}

#[inline]
Expand Down
83 changes: 10 additions & 73 deletions aws-lc-rs/src/ec/key_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,29 @@
// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

use crate::aws_lc::{EVP_DigestSign, EVP_DigestSignInit, EVP_PKEY, EVP_PKEY_EC};
use crate::aws_lc::{EVP_PKEY, EVP_PKEY_EC};
use core::fmt;
use core::fmt::{Debug, Formatter};
use core::mem::MaybeUninit;
use core::ptr::{null, null_mut};

use crate::digest::digest_ctx::DigestContext;
use crate::ec::evp_key_generate;
use crate::ec::signature::{EcdsaSignatureFormat, EcdsaSigningAlgorithm, PublicKey};
#[cfg(feature = "fips")]
use crate::ec::validate_evp_key;
#[cfg(not(feature = "fips"))]
use crate::ec::verify_evp_key_nid;

use crate::ec;
use crate::ec::encoding::rfc5915::{marshal_rfc5915_private_key, parse_rfc5915_private_key};
use crate::ec::encoding::sec1::{
marshal_sec1_private_key, parse_sec1_private_bn, parse_sec1_public_point,
};
use crate::encoding::{AsBigEndian, AsDer, EcPrivateKeyBin, EcPrivateKeyRfc5915Der};
use crate::error::{KeyRejected, Unspecified};
use crate::fips::indicator_check;
use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
use crate::pkcs8::{Document, Version};
use crate::ptr::LcPtr;
use crate::rand::SecureRandom;
use crate::signature::{KeyPair, Signature};
use crate::{digest, ec};

/// An ECDSA key pair, used for signing.
#[allow(clippy::module_name_repetitions)]
Expand Down Expand Up @@ -212,82 +209,22 @@ impl EcdsaKeyPair {
// * Digest Algorithms: SHA256, SHA384, SHA512
#[inline]
pub fn sign(&self, _rng: &dyn SecureRandom, message: &[u8]) -> Result<Signature, Unspecified> {
let mut md_ctx = DigestContext::new_uninit();

let digest = digest::match_digest_type(&self.algorithm.digest.id);

if 1 != unsafe {
// EVP_DigestSignInit does not mutate |pkey| for thread-safety purposes and may be
// used concurrently with other non-mutating functions on |pkey|.
// https://github.com/aws/aws-lc/blob/9b4b5a15a97618b5b826d742419ccd54c819fa42/include/openssl/evp.h#L297-L313
EVP_DigestSignInit(
md_ctx.as_mut_ptr(),
null_mut(),
*digest,
null_mut(),
*self.evp_pkey.as_mut_unsafe(),
)
} {
return Err(Unspecified);
}

let mut out_sig = vec![0u8; get_signature_length(&mut md_ctx)?];

let out_sig = compute_ecdsa_signature(&mut md_ctx, message, out_sig.as_mut_slice())?;
let out_sig = self.evp_pkey.sign(
message,
Some(self.algorithm.digest),
No_EVP_PKEY_CTX_consumer,
)?;

Ok(match self.algorithm.sig_format {
EcdsaSignatureFormat::ASN1 => Signature::new(|slice| {
slice[..out_sig.len()].copy_from_slice(out_sig);
slice[..out_sig.len()].copy_from_slice(&out_sig);
out_sig.len()
}),
EcdsaSignatureFormat::Fixed => ec::ecdsa_asn1_to_fixed(self.algorithm.id, out_sig)?,
EcdsaSignatureFormat::Fixed => ec::ecdsa_asn1_to_fixed(self.algorithm.id, &out_sig)?,
})
}
}

#[inline]
fn get_signature_length(ctx: &mut DigestContext) -> Result<usize, Unspecified> {
let mut out_sig_len = MaybeUninit::<usize>::uninit();

// determine signature size
if 1 != unsafe {
EVP_DigestSign(
ctx.as_mut_ptr(),
null_mut(),
out_sig_len.as_mut_ptr(),
null(),
0,
)
} {
return Err(Unspecified);
}

Ok(unsafe { out_sig_len.assume_init() })
}

#[inline]
fn compute_ecdsa_signature<'a>(
ctx: &mut DigestContext,
message: &[u8],
signature: &'a mut [u8],
) -> Result<&'a mut [u8], Unspecified> {
let mut out_sig_len = signature.len();

if 1 != indicator_check!(unsafe {
EVP_DigestSign(
ctx.as_mut_ptr(),
signature.as_mut_ptr(),
&mut out_sig_len,
message.as_ptr(),
message.len(),
)
}) {
return Err(Unspecified);
}

Ok(&mut signature[0..out_sig_len])
}

/// Elliptic curve private key.
pub struct PrivateKey<'a>(&'a EcdsaKeyPair);

Expand Down
40 changes: 5 additions & 35 deletions aws-lc-rs/src/ec/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
// SPDX-License-Identifier: Apache-2.0 OR ISC

use crate::aws_lc::{
ECDSA_SIG_new, ECDSA_SIG_set0, ECDSA_SIG_to_bytes, EVP_DigestVerify, EVP_DigestVerifyInit,
NID_X9_62_prime256v1, NID_secp256k1, NID_secp384r1, NID_secp521r1, BIGNUM, ECDSA_SIG, EVP_PKEY,
ECDSA_SIG_new, ECDSA_SIG_set0, ECDSA_SIG_to_bytes, NID_X9_62_prime256v1, NID_secp256k1,
NID_secp384r1, NID_secp521r1, BIGNUM, ECDSA_SIG, EVP_PKEY,
};

use crate::digest::digest_ctx::DigestContext;
use crate::ec::compressed_public_key_size_bytes;
use crate::ec::encoding::parse_ec_public_key;
use crate::ec::encoding::sec1::marshal_sec1_public_point;
use crate::encoding::{
AsBigEndian, AsDer, EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, PublicKeyX509Der,
};
use crate::error::Unspecified;
use crate::fips::indicator_check;
use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
use crate::ptr::{DetachableLcPtr, LcPtr};
use crate::signature::VerificationAlgorithm;
use crate::{digest, sealed};
Expand Down Expand Up @@ -232,37 +231,8 @@ fn verify_asn1_signature(
msg: &[u8],
signature: &[u8],
) -> Result<(), Unspecified> {
let mut pkey = parse_ec_public_key(public_key, alg.nid())?;

let mut md_ctx = DigestContext::new_uninit();

let digest = digest::match_digest_type(&digest.id);

if 1 != unsafe {
EVP_DigestVerifyInit(
md_ctx.as_mut_ptr(),
null_mut(),
*digest,
null_mut(),
*pkey.as_mut(),
)
} {
return Err(Unspecified);
}

if 1 != indicator_check!(unsafe {
EVP_DigestVerify(
md_ctx.as_mut_ptr(),
signature.as_ptr(),
signature.len(),
msg.as_ptr(),
msg.len(),
)
}) {
return Err(Unspecified);
}

Ok(())
let evp_pkey = parse_ec_public_key(public_key, alg.nid())?;
evp_pkey.verify(msg, Some(digest), No_EVP_PKEY_CTX_consumer, signature)
}

#[inline]
Expand Down
Loading

0 comments on commit 33614e2

Please sign in to comment.