Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 46 additions & 14 deletions aws-lc-rs/src/agreement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,14 @@ impl KeyInner {
}
}

unsafe impl Send for PrivateKey {}

// https://github.com/awslabs/aws-lc/blob/main/include/openssl/ec_key.h#L88
// An |EC_KEY| object represents a public or private EC key. A given object may
// See EVP_PKEY documentation here:
// https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89
// An |EVP_PKEY| object represents a public or private key. A given object may
// be used concurrently on multiple threads by non-mutating functions, provided
// no other thread is concurrently calling a mutating function. Unless otherwise
// documented, functions which take a |const| pointer are non-mutating and
// functions which take a non-|const| pointer are mutating.
unsafe impl Send for PrivateKey {}
unsafe impl Sync for PrivateKey {}

impl Debug for PrivateKey {
Expand Down Expand Up @@ -536,6 +536,13 @@ impl PublicKey {
}
}

// See EVP_PKEY documentation here:
// https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89
// An |EVP_PKEY| object represents a public or private key. A given object may
// be used concurrently on multiple threads by non-mutating functions, provided
// no other thread is concurrently calling a mutating function. Unless otherwise
// documented, functions which take a |const| pointer are non-mutating and
// functions which take a non-|const| pointer are mutating.
unsafe impl Send for PublicKey {}
unsafe impl Sync for PublicKey {}

Expand Down Expand Up @@ -666,13 +673,21 @@ impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
/// This represents a public key that has been successfully parsed and validated
/// from its encoded form. The key can be used with the `agree` function to
/// perform key agreement operations.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ParsedPublicKey {
format: ParsedPublicKeyFormat,
nid: i32,
key: LcPtr<EVP_PKEY>,
bytes: Box<[u8]>,
}

// See EVP_PKEY documentation here:
// https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89
// An |EVP_PKEY| object represents a public or private key. A given object may
// be used concurrently on multiple threads by non-mutating functions, provided
// no other thread is concurrently calling a mutating function. Unless otherwise
// documented, functions which take a |const| pointer are non-mutating and
// functions which take a non-|const| pointer are mutating.
unsafe impl Send for ParsedPublicKey {}
unsafe impl Sync for ParsedPublicKey {}

Expand Down Expand Up @@ -730,35 +745,40 @@ impl ParsedPublicKey {
impl ParsedPublicKey {
#[allow(non_upper_case_globals)]
pub(crate) fn new(bytes: impl AsRef<[u8]>, nid: i32) -> Result<Self, KeyRejected> {
let key_bytes = bytes.as_ref();
if key_bytes.is_empty() {
let bytes = bytes.as_ref().to_vec().into_boxed_slice();
if bytes.is_empty() {
return Err(KeyRejected::unspecified());
}
match nid {
NID_X25519 => {
let format: ParsedPublicKeyFormat;
let key = if let Ok(evp_pkey) =
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_X25519)
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_X25519)
{
format = ParsedPublicKeyFormat::X509;
evp_pkey
} else {
format = ParsedPublicKeyFormat::Raw;
try_parse_x25519_public_key_raw_bytes(key_bytes)?
try_parse_x25519_public_key_raw_bytes(&bytes)?
};

Ok(ParsedPublicKey { format, nid, key })
Ok(ParsedPublicKey {
format,
nid,
key,
bytes,
})
}
NID_X9_62_prime256v1 | NID_secp384r1 | NID_secp521r1 => {
let format: ParsedPublicKeyFormat;
let key = if let Ok(evp_pkey) =
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_EC)
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_EC)
{
validate_ec_evp_key(&evp_pkey.as_const(), nid)?;
format = ParsedPublicKeyFormat::X509;
evp_pkey
} else if let Ok(evp_pkey) = parse_sec1_public_point(key_bytes, nid) {
format = match key_bytes[0] {
} else if let Ok(evp_pkey) = parse_sec1_public_point(&bytes, nid) {
format = match bytes[0] {
0x02 | 0x03 => ParsedPublicKeyFormat::Compressed,
0x04 => ParsedPublicKeyFormat::Uncompressed,
0x06 | 0x07 => ParsedPublicKeyFormat::Hybrid,
Expand All @@ -769,13 +789,25 @@ impl ParsedPublicKey {
return Err(KeyRejected::invalid_encoding());
};

Ok(ParsedPublicKey { format, nid, key })
Ok(ParsedPublicKey {
format,
nid,
key,
bytes,
})
}
_ => Err(KeyRejected::unspecified()),
}
}
}

impl AsRef<[u8]> for ParsedPublicKey {
/// Returns the original bytes from which this key was parsed.
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}

impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
#[allow(dead_code)]
fn parse(&self) -> Result<ParsedPublicKey, KeyRejected> {
Expand Down
14 changes: 14 additions & 0 deletions aws-lc-rs/src/agreement/parsed_public_key_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,25 @@ use crate::agreement::{
use crate::encoding::{AsBigEndian, AsDer, EcPublicKeyCompressedBin, PublicKeyX509Der};
use crate::test;

#[test]
fn test_types() {
test::compile_time_assert_send::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_send::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_clone::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_clone::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_send::<ParsedPublicKey>();
test::compile_time_assert_sync::<ParsedPublicKey>();
test::compile_time_assert_clone::<ParsedPublicKey>();
}

#[test]
fn test_parsed_public_key_x25519_raw() {
let raw_key =
test::from_dirty_hex("e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c");
let parsed = ParsedPublicKey::new(&raw_key, X25519.id.nid()).unwrap();
assert_eq!(&raw_key, parsed.as_ref());

assert_eq!(parsed.format(), ParsedPublicKeyFormat::Raw);
assert_eq!(parsed.alg(), &X25519);
Expand Down
42 changes: 38 additions & 4 deletions aws-lc-rs/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,12 +397,24 @@ pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
/// parsing the key on each verification.
///
/// See the [`crate::signature`] module-level documentation for examples.
#[derive(Clone)]
pub struct ParsedPublicKey {
algorithm: &'static dyn VerificationAlgorithm,
parsed_algorithm: &'static dyn ParsedVerificationAlgorithm,
key: LcPtr<EVP_PKEY>,
bytes: Box<[u8]>,
}

// See EVP_PKEY documentation here:
// https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89
// An |EVP_PKEY| object represents a public or private key. A given object may
// be used concurrently on multiple threads by non-mutating functions, provided
// no other thread is concurrently calling a mutating function. Unless otherwise
// documented, functions which take a |const| pointer are non-mutating and
// functions which take a non-|const| pointer are mutating.
unsafe impl Send for ParsedPublicKey {}
unsafe impl Sync for ParsedPublicKey {}

impl ParsedPublicKey {
/// Creates a new `ParsedPublicKey` directly from public key bytes.
///
Expand Down Expand Up @@ -497,11 +509,19 @@ impl ParsedPublicKey {
}
}

/// Provides the original bytes from which this key was parsed
impl AsRef<[u8]> for ParsedPublicKey {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}

impl Debug for ParsedPublicKey {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str(&format!(
"ParsedPublicKey {{ algorithm: {:?}, }}",
"ParsedPublicKey {{ algorithm: {:?}, bytes: \"{}\" }}",
self.algorithm,
hex::encode(self.bytes.as_ref())
))
}
}
Expand Down Expand Up @@ -633,10 +653,12 @@ pub(crate) fn parse_public_key(
unreachable!()
};

let bytes = bytes.to_vec().into_boxed_slice();
Ok(ParsedPublicKey {
algorithm,
parsed_algorithm,
key,
bytes,
})
}

Expand Down Expand Up @@ -1055,10 +1077,10 @@ pub static ED25519: EdDSAParameters = EdDSAParameters {};

#[cfg(test)]
mod tests {
use regex::Regex;

use crate::rand::{generate, SystemRandom};
use crate::signature::{UnparsedPublicKey, ED25519};
use crate::signature::{ParsedPublicKey, UnparsedPublicKey, ED25519};
use crate::test;
use regex::Regex;

#[cfg(feature = "fips")]
mod fips;
Expand All @@ -1079,4 +1101,16 @@ mod tests {

assert!(pubkey_re.is_match(&unparsed_pubkey_debug));
}
#[test]
fn test_types() {
test::compile_time_assert_send::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_send::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_clone::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_clone::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_send::<ParsedPublicKey>();
test::compile_time_assert_sync::<ParsedPublicKey>();
test::compile_time_assert_clone::<ParsedPublicKey>();
}
}
5 changes: 1 addition & 4 deletions aws-lc-rs/tests/ecdsa_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ fn ecdsa_traits() {
test::compile_time_assert_sync::<EcdsaKeyPair>();
test::compile_time_assert_send::<Signature>();
test::compile_time_assert_sync::<Signature>();
test::compile_time_assert_send::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
test::compile_time_assert_send::<UnparsedPublicKey<Vec<u8>>>();
test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
}

#[test]
Expand Down Expand Up @@ -206,6 +202,7 @@ fn test_signature_ecdsa_verify_asn1(data_file: test::File) {

{
let ppk = ParsedPublicKey::new(alg, &public_key).unwrap();
assert_eq!(ppk.as_ref(), public_key.as_slice());
let actual_result = ppk.verify_sig(&msg, &sig);
assert_eq!(actual_result.is_ok(), is_valid);

Expand Down
8 changes: 4 additions & 4 deletions aws-lc-rs/tests/ed25519_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ fn test_signature_verification(
sig: &[u8],
expected_result: Result<(), error::Unspecified>,
) {
assert_eq!(
expected_result,
signature::UnparsedPublicKey::new(&ED25519, public_key).verify(msg, sig)
);
let upk = signature::UnparsedPublicKey::new(&ED25519, public_key);
assert_eq!(public_key, upk.as_ref());
assert_eq!(expected_result, upk.verify(msg, sig));
let ppk = ParsedPublicKey::new(&ED25519, public_key).unwrap();
assert_eq!(public_key, ppk.as_ref());
assert_eq!(expected_result, ppk.verify_sig(msg, sig));
}

Expand Down
2 changes: 2 additions & 0 deletions aws-lc-rs/tests/rsa_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ fn test_signature_rsa_pkcs1_sign() {
let public_key = key_pair.public_key();
{
let upk = UnparsedPublicKey::new(verification_alg, public_key.as_ref());
assert_eq!(public_key.as_ref(), upk.as_ref());

let mut actual = vec![0u8; key_pair.public_modulus_len()];
key_pair
Expand All @@ -115,6 +116,7 @@ fn test_signature_rsa_pkcs1_sign() {

{
let ppk = ParsedPublicKey::new(verification_alg, public_key.as_ref()).unwrap();
assert_eq!(public_key.as_ref(), ppk.as_ref());

let mut actual = vec![0u8; key_pair.public_modulus_len()];
key_pair
Expand Down
Loading