Skip to content

Commit

Permalink
Remove dups of EVP_marshal_public_key/EVP_parse_public_key
Browse files Browse the repository at this point in the history
  • Loading branch information
justsmth committed Jan 22, 2025
1 parent 809a292 commit 6f4b871
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 97 deletions.
1 change: 1 addition & 0 deletions aws-lc-rs/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fn main() {
println!("cargo:warning=### Slow tests are enabled: {disable}! ###");
}
}
println!("cargo:rerun-if-env-changed=AWS_LC_RS_DISABLE_SLOW_TESTS");

// This appears asymmetric, but it reflects the `cfg` statements in lib.rs that
// require `aws-lc-sys` to be present when "fips" is not enabled.
Expand Down
45 changes: 9 additions & 36 deletions aws-lc-rs/src/agreement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,27 @@ mod ephemeral;

pub use ephemeral::{agree_ephemeral, EphemeralPrivateKey};

use crate::cbb::LcCBB;
use crate::ec::{ec_group_from_nid, evp_key_generate};
use crate::error::{KeyRejected, Unspecified};
use crate::fips::indicator_check;
use crate::ptr::{ConstPointer, LcPtr};
use crate::{ec, hex};
use aws_lc::{
CBS_init, EVP_PKEY_CTX_new_id, EVP_PKEY_bits, EVP_PKEY_derive, EVP_PKEY_derive_init,
EVP_PKEY_derive_set_peer, EVP_PKEY_get0_EC_KEY, EVP_PKEY_get_raw_private_key,
EVP_PKEY_get_raw_public_key, EVP_PKEY_id, EVP_PKEY_keygen, EVP_PKEY_keygen_init,
EVP_PKEY_new_raw_private_key, EVP_PKEY_new_raw_public_key, EVP_marshal_public_key,
EVP_parse_public_key, NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, BIGNUM, CBS,
EVP_PKEY_CTX_new_id, EVP_PKEY_derive, EVP_PKEY_derive_init, EVP_PKEY_derive_set_peer,
EVP_PKEY_get0_EC_KEY, EVP_PKEY_get_raw_private_key, EVP_PKEY_get_raw_public_key,
EVP_PKEY_keygen, EVP_PKEY_keygen_init, EVP_PKEY_new_raw_private_key,
EVP_PKEY_new_raw_public_key, NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, BIGNUM,
EVP_PKEY, EVP_PKEY_X25519, NID_X25519,
};

use crate::buffer::Buffer;
use crate::encoding::{
AsBigEndian, AsDer, Curve25519SeedBin, EcPrivateKeyBin, EcPrivateKeyRfc5915Der,
EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, PublicKeyX509Der,
};
use core::fmt;
use core::fmt::{Debug, Formatter};
use core::ptr::null_mut;
use std::mem::MaybeUninit;

#[allow(non_camel_case_types)]
#[derive(PartialEq, Eq)]
Expand Down Expand Up @@ -616,15 +614,8 @@ impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
| KeyInner::ECDH_P384(evp_pkey)
| KeyInner::ECDH_P521(evp_pkey)
| KeyInner::X25519(evp_pkey) => {
let key_size_bytes =
TryInto::<usize>::try_into(unsafe { EVP_PKEY_bits(*evp_pkey.as_const()) })
.expect("fit in usize")
* 8;
let mut der = LcCBB::new(key_size_bytes * 5);
if 1 != unsafe { EVP_marshal_public_key(der.as_mut_ptr(), *evp_pkey.as_const()) } {
return Err(Unspecified);
};
Ok(PublicKeyX509Der::from(der.into_buffer()?))
let der = evp_pkey.marshall_rfc5280_public_key()?;
Ok(PublicKeyX509Der::from(Buffer::new(der)))
}
}
}
Expand Down Expand Up @@ -788,7 +779,7 @@ fn ec_key_ecdh<'a>(
peer_pub_key_bytes: &[u8],
nid: i32,
) -> Result<&'a [u8], ()> {
let mut pub_key = ec::try_parse_public_key_bytes(peer_pub_key_bytes, nid)?;
let mut pub_key = ec::try_parse_public_key_bytes(peer_pub_key_bytes, nid).map_err(|_| ())?;

let mut pkey_ctx = priv_key.create_EVP_PKEY_CTX()?;

Expand Down Expand Up @@ -849,7 +840,7 @@ fn x25519_diffie_hellman<'a>(
pub(crate) fn try_parse_x25519_public_key_bytes(
key_bytes: &[u8],
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
try_parse_x25519_subject_public_key_info_bytes(key_bytes)
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_X25519)
.or(try_parse_x25519_public_key_raw_bytes(key_bytes))
}

Expand All @@ -869,24 +860,6 @@ fn try_parse_x25519_public_key_raw_bytes(key_bytes: &[u8]) -> Result<LcPtr<EVP_P
})?)
}

fn try_parse_x25519_subject_public_key_info_bytes(
key_bytes: &[u8],
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
// Try to parse as SubjectPublicKeyInfo first
let mut cbs = {
let mut cbs = MaybeUninit::<CBS>::uninit();
unsafe {
CBS_init(cbs.as_mut_ptr(), key_bytes.as_ptr(), key_bytes.len());
cbs.assume_init()
}
};
let evp_pkey = LcPtr::new(unsafe { EVP_parse_public_key(&mut cbs) })?;
if EVP_PKEY_X25519 != unsafe { EVP_PKEY_id(*evp_pkey.as_const()) } {
return Err(Unspecified);
}
Ok(evp_pkey)
}

#[cfg(test)]
mod tests {
use crate::agreement::{
Expand Down
23 changes: 4 additions & 19 deletions aws-lc-rs/src/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
// SPDX-License-Identifier: Apache-2.0 OR ISC

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

#[cfg(feature = "fips")]
Expand All @@ -22,8 +20,8 @@ use aws_lc::{
EC_KEY_new, EC_KEY_set_group, EC_KEY_set_private_key, EC_KEY_set_public_key, EC_POINT_mul,
EC_POINT_new, EC_POINT_oct2point, EC_POINT_point2oct, EVP_PKEY_CTX_new_id,
EVP_PKEY_CTX_set_ec_paramgen_curve_nid, EVP_PKEY_assign_EC_KEY, EVP_PKEY_get0_EC_KEY,
EVP_PKEY_keygen, EVP_PKEY_keygen_init, EVP_PKEY_new, EVP_parse_public_key, BIGNUM, CBS,
EC_GROUP, EC_KEY, EC_POINT, EVP_PKEY, EVP_PKEY_EC,
EVP_PKEY_keygen, EVP_PKEY_keygen_init, EVP_PKEY_new, BIGNUM, CBS, EC_GROUP, EC_KEY, EC_POINT,
EVP_PKEY, EVP_PKEY_EC,
};

use crate::error::{KeyRejected, Unspecified};
Expand Down Expand Up @@ -164,7 +162,8 @@ pub(crate) fn try_parse_public_key_bytes(
key_bytes: &[u8],
expected_curve_nid: i32,
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
try_parse_subject_public_key_info_bytes(key_bytes)
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_EC)
.map_err(|_| Unspecified)
.and_then(|key| {
validate_evp_key(&key.as_const(), expected_curve_nid)
.map(|()| key)
Expand All @@ -176,20 +175,6 @@ pub(crate) fn try_parse_public_key_bytes(
))
}

fn try_parse_subject_public_key_info_bytes(
key_bytes: &[u8],
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
// Try to parse as SubjectPublicKeyInfo first
let mut cbs = {
let mut cbs = MaybeUninit::<CBS>::uninit();
unsafe {
CBS_init(cbs.as_mut_ptr(), key_bytes.as_ptr(), key_bytes.len());
cbs.assume_init()
}
};
Ok(LcPtr::new(unsafe { EVP_parse_public_key(&mut cbs) })?)
}

fn try_parse_public_key_raw_bytes(
key_bytes: &[u8],
expected_curve_nid: i32,
Expand Down
26 changes: 6 additions & 20 deletions aws-lc-rs/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ use aws_lc::{
CBS_init, EVP_DigestSign, EVP_DigestSignInit, EVP_DigestVerify, EVP_DigestVerifyInit,
EVP_PKEY_CTX_new_id, EVP_PKEY_get_raw_private_key, EVP_PKEY_get_raw_public_key, EVP_PKEY_id,
EVP_PKEY_keygen, EVP_PKEY_keygen_init, EVP_PKEY_new_raw_private_key,
EVP_PKEY_new_raw_public_key, EVP_marshal_public_key, EVP_parse_public_key, CBS, EVP_PKEY,
EVP_PKEY_ED25519,
EVP_PKEY_new_raw_public_key, CBS, EVP_PKEY, EVP_PKEY_ED25519,
};

use crate::cbb::LcCBB;
use crate::buffer::Buffer;
use crate::digest::digest_ctx::DigestContext;
use crate::encoding::{
AsBigEndian, AsDer, Curve25519SeedBin, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der,
Expand Down Expand Up @@ -113,18 +112,8 @@ fn try_ed25519_public_key_from_bytes(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>
})?);
}
// Otherwise we support X.509 SubjectPublicKeyInfo formatted keys which are inherently larger
let mut cbs = {
let mut cbs = MaybeUninit::<CBS>::uninit();
unsafe {
CBS_init(cbs.as_mut_ptr(), key_bytes.as_ptr(), key_bytes.len());
cbs.assume_init()
}
};
let evp_pkey = LcPtr::new(unsafe { EVP_parse_public_key(&mut cbs) })?;
if EVP_PKEY_ED25519 != unsafe { EVP_PKEY_id(*evp_pkey.as_const()) } {
return Err(Unspecified);
}
Ok(evp_pkey)
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_ED25519)
.map_err(|_| Unspecified)
}

/// An Ed25519 key pair, for signing.
Expand Down Expand Up @@ -206,11 +195,8 @@ impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
// 2:d=1 hl=2 l= 5 cons: SEQUENCE
// 4:d=2 hl=2 l= 3 prim: OBJECT :ED25519
// 9:d=1 hl=2 l= 33 prim: BIT STRING
let mut cbb = LcCBB::new(44);
if 1 != unsafe { EVP_marshal_public_key(cbb.as_mut_ptr(), *self.evp_pkey.as_const()) } {
return Err(Unspecified);
}
Ok(PublicKeyX509Der::from(cbb.into_buffer()?))
let der = self.evp_pkey.marshall_rfc5280_public_key()?;
Ok(PublicKeyX509Der::from(Buffer::new(der)))
}
}

Expand Down
26 changes: 26 additions & 0 deletions aws-lc-rs/src/evp_pkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,32 @@ impl LcPtr<EVP_PKEY> {
}
}

pub(crate) fn marshall_rfc5280_public_key(&self) -> Result<Vec<u8>, Unspecified> {
let key_size_bytes: usize = unsafe { EVP_PKEY_bits(*self.as_const()) / 8 }.try_into()?;
// Data shows that the SubjectPublicKeyInfo is roughly 356% to 375% increase in size compared to the RSA key
// size in bytes for keys ranging from 2048-bit to 4096-bit. So size the initial capacity to be roughly
// 500% as a conservative estimate to avoid needing to reallocate for any key in that range.
let mut cbb = LcCBB::new(key_size_bytes * 5);
if 1 != unsafe { EVP_marshal_public_key(cbb.as_mut_ptr(), *self.as_const()) } {
return Err(Unspecified);
};
cbb.into_vec()
}

pub(crate) fn parse_rfc5280_public_key(
bytes: &[u8],
evp_pkey_type: c_int,
) -> Result<Self, KeyRejected> {
let mut cbs = cbs::build_CBS(bytes);
// Also checks the validity of the key
let evp_pkey = LcPtr::new(unsafe { EVP_parse_public_key(&mut cbs) })
.map_err(|()| KeyRejected::invalid_encoding())?;
Ok(unsafe { EVP_PKEY_id(*evp_pkey.as_const()) }
.eq(&evp_pkey_type)
.then_some(evp_pkey)
.ok_or(KeyRejected::wrong_algorithm())?)
}

pub(crate) fn marshall_rfc5208_private_key(
&self,
version: Version,
Expand Down
29 changes: 7 additions & 22 deletions aws-lc-rs/src/rsa/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,42 +82,27 @@ pub(in crate::rsa) mod rfc8017 {
///
/// Encodings that use the `SubjectPublicKeyInfo` structure.
pub(in crate::rsa) mod rfc5280 {
use crate::aws_lc::EVP_PKEY_RSA;
use crate::buffer::Buffer;
use crate::{
cbb::LcCBB,
cbs,
encoding::PublicKeyX509Der,
error::{KeyRejected, Unspecified},
ptr::LcPtr,
rsa::key::{is_rsa_key, key_size_bytes},
rsa::key::is_rsa_key,
};
use aws_lc::{EVP_marshal_public_key, EVP_parse_public_key, EVP_PKEY};
use aws_lc::EVP_PKEY;

pub(in crate::rsa) fn encode_public_key_der(
key: &LcPtr<EVP_PKEY>,
) -> Result<PublicKeyX509Der<'static>, Unspecified> {
// Data shows that the SubjectPublicKeyInfo is roughly 356% to 375% increase in size compared to the RSA key
// size in bytes for keys ranging from 2048-bit to 4096-bit. So size the initial capacity to be roughly
// 400% as a conservative estimate to avoid needing to reallocate for any key in that range.
let key_size_bytes = key_size_bytes(key);

// key_size_bytes * 5 == key_size_bytes * (1 + 400%)
let mut der = LcCBB::new(key_size_bytes * 5);

if 1 != unsafe { EVP_marshal_public_key(der.as_mut_ptr(), *key.as_const()) } {
return Err(Unspecified);
};

Ok(PublicKeyX509Der::from(der.into_buffer()?))
let der = key.marshall_rfc5280_public_key()?;
Ok(PublicKeyX509Der::from(Buffer::new(der)))
}

pub(in crate::rsa) fn decode_public_key_der(
value: &[u8],
) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
let mut der = cbs::build_CBS(value);
let key = LcPtr::new(unsafe { EVP_parse_public_key(&mut der) })?;
if !is_rsa_key(&key) {
return Err(KeyRejected::unspecified());
}
Ok(key)
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(value, EVP_PKEY_RSA)
}
}

0 comments on commit 6f4b871

Please sign in to comment.