Skip to content

Commit ab1ab3d

Browse files
authored
Common traits for ParsedPublicKey (#879)
* Traits for signature::ParsedPublicKey * Traits for agreement::ParsedPublicKey * Also Clone * More Clone tests * Document thread-safety
1 parent 520bb36 commit ab1ab3d

File tree

6 files changed

+105
-26
lines changed

6 files changed

+105
-26
lines changed

aws-lc-rs/src/agreement.rs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,14 @@ impl KeyInner {
220220
}
221221
}
222222

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

233233
impl Debug for PrivateKey {
@@ -536,6 +536,13 @@ impl PublicKey {
536536
}
537537
}
538538

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

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

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

@@ -730,35 +745,40 @@ impl ParsedPublicKey {
730745
impl ParsedPublicKey {
731746
#[allow(non_upper_case_globals)]
732747
pub(crate) fn new(bytes: impl AsRef<[u8]>, nid: i32) -> Result<Self, KeyRejected> {
733-
let key_bytes = bytes.as_ref();
734-
if key_bytes.is_empty() {
748+
let bytes = bytes.as_ref().to_vec().into_boxed_slice();
749+
if bytes.is_empty() {
735750
return Err(KeyRejected::unspecified());
736751
}
737752
match nid {
738753
NID_X25519 => {
739754
let format: ParsedPublicKeyFormat;
740755
let key = if let Ok(evp_pkey) =
741-
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_X25519)
756+
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_X25519)
742757
{
743758
format = ParsedPublicKeyFormat::X509;
744759
evp_pkey
745760
} else {
746761
format = ParsedPublicKeyFormat::Raw;
747-
try_parse_x25519_public_key_raw_bytes(key_bytes)?
762+
try_parse_x25519_public_key_raw_bytes(&bytes)?
748763
};
749764

750-
Ok(ParsedPublicKey { format, nid, key })
765+
Ok(ParsedPublicKey {
766+
format,
767+
nid,
768+
key,
769+
bytes,
770+
})
751771
}
752772
NID_X9_62_prime256v1 | NID_secp384r1 | NID_secp521r1 => {
753773
let format: ParsedPublicKeyFormat;
754774
let key = if let Ok(evp_pkey) =
755-
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_EC)
775+
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&bytes, EVP_PKEY_EC)
756776
{
757777
validate_ec_evp_key(&evp_pkey.as_const(), nid)?;
758778
format = ParsedPublicKeyFormat::X509;
759779
evp_pkey
760-
} else if let Ok(evp_pkey) = parse_sec1_public_point(key_bytes, nid) {
761-
format = match key_bytes[0] {
780+
} else if let Ok(evp_pkey) = parse_sec1_public_point(&bytes, nid) {
781+
format = match bytes[0] {
762782
0x02 | 0x03 => ParsedPublicKeyFormat::Compressed,
763783
0x04 => ParsedPublicKeyFormat::Uncompressed,
764784
0x06 | 0x07 => ParsedPublicKeyFormat::Hybrid,
@@ -769,13 +789,25 @@ impl ParsedPublicKey {
769789
return Err(KeyRejected::invalid_encoding());
770790
};
771791

772-
Ok(ParsedPublicKey { format, nid, key })
792+
Ok(ParsedPublicKey {
793+
format,
794+
nid,
795+
key,
796+
bytes,
797+
})
773798
}
774799
_ => Err(KeyRejected::unspecified()),
775800
}
776801
}
777802
}
778803

804+
impl AsRef<[u8]> for ParsedPublicKey {
805+
/// Returns the original bytes from which this key was parsed.
806+
fn as_ref(&self) -> &[u8] {
807+
&self.bytes
808+
}
809+
}
810+
779811
impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
780812
#[allow(dead_code)]
781813
fn parse(&self) -> Result<ParsedPublicKey, KeyRejected> {

aws-lc-rs/src/agreement/parsed_public_key_tests.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,25 @@ use crate::agreement::{
88
use crate::encoding::{AsBigEndian, AsDer, EcPublicKeyCompressedBin, PublicKeyX509Der};
99
use crate::test;
1010

11+
#[test]
12+
fn test_types() {
13+
test::compile_time_assert_send::<UnparsedPublicKey<&[u8]>>();
14+
test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
15+
test::compile_time_assert_send::<UnparsedPublicKey<Vec<u8>>>();
16+
test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
17+
test::compile_time_assert_clone::<UnparsedPublicKey<&[u8]>>();
18+
test::compile_time_assert_clone::<UnparsedPublicKey<Vec<u8>>>();
19+
test::compile_time_assert_send::<ParsedPublicKey>();
20+
test::compile_time_assert_sync::<ParsedPublicKey>();
21+
test::compile_time_assert_clone::<ParsedPublicKey>();
22+
}
23+
1124
#[test]
1225
fn test_parsed_public_key_x25519_raw() {
1326
let raw_key =
1427
test::from_dirty_hex("e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c");
1528
let parsed = ParsedPublicKey::new(&raw_key, X25519.id.nid()).unwrap();
29+
assert_eq!(&raw_key, parsed.as_ref());
1630

1731
assert_eq!(parsed.format(), ParsedPublicKeyFormat::Raw);
1832
assert_eq!(parsed.alg(), &X25519);

aws-lc-rs/src/signature.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,24 @@ pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
397397
/// parsing the key on each verification.
398398
///
399399
/// See the [`crate::signature`] module-level documentation for examples.
400+
#[derive(Clone)]
400401
pub struct ParsedPublicKey {
401402
algorithm: &'static dyn VerificationAlgorithm,
402403
parsed_algorithm: &'static dyn ParsedVerificationAlgorithm,
403404
key: LcPtr<EVP_PKEY>,
405+
bytes: Box<[u8]>,
404406
}
405407

408+
// See EVP_PKEY documentation here:
409+
// https://github.com/aws/aws-lc/blob/125af14c57451565b875fbf1282a38a6ecf83782/include/openssl/evp.h#L83-L89
410+
// An |EVP_PKEY| object represents a public or private key. A given object may
411+
// be used concurrently on multiple threads by non-mutating functions, provided
412+
// no other thread is concurrently calling a mutating function. Unless otherwise
413+
// documented, functions which take a |const| pointer are non-mutating and
414+
// functions which take a non-|const| pointer are mutating.
415+
unsafe impl Send for ParsedPublicKey {}
416+
unsafe impl Sync for ParsedPublicKey {}
417+
406418
impl ParsedPublicKey {
407419
/// Creates a new `ParsedPublicKey` directly from public key bytes.
408420
///
@@ -497,11 +509,19 @@ impl ParsedPublicKey {
497509
}
498510
}
499511

512+
/// Provides the original bytes from which this key was parsed
513+
impl AsRef<[u8]> for ParsedPublicKey {
514+
fn as_ref(&self) -> &[u8] {
515+
&self.bytes
516+
}
517+
}
518+
500519
impl Debug for ParsedPublicKey {
501520
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
502521
f.write_str(&format!(
503-
"ParsedPublicKey {{ algorithm: {:?}, }}",
522+
"ParsedPublicKey {{ algorithm: {:?}, bytes: \"{}\" }}",
504523
self.algorithm,
524+
hex::encode(self.bytes.as_ref())
505525
))
506526
}
507527
}
@@ -633,10 +653,12 @@ pub(crate) fn parse_public_key(
633653
unreachable!()
634654
};
635655

656+
let bytes = bytes.to_vec().into_boxed_slice();
636657
Ok(ParsedPublicKey {
637658
algorithm,
638659
parsed_algorithm,
639660
key,
661+
bytes,
640662
})
641663
}
642664

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

10561078
#[cfg(test)]
10571079
mod tests {
1058-
use regex::Regex;
1059-
10601080
use crate::rand::{generate, SystemRandom};
1061-
use crate::signature::{UnparsedPublicKey, ED25519};
1081+
use crate::signature::{ParsedPublicKey, UnparsedPublicKey, ED25519};
1082+
use crate::test;
1083+
use regex::Regex;
10621084

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

10801102
assert!(pubkey_re.is_match(&unparsed_pubkey_debug));
10811103
}
1104+
#[test]
1105+
fn test_types() {
1106+
test::compile_time_assert_send::<UnparsedPublicKey<&[u8]>>();
1107+
test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
1108+
test::compile_time_assert_send::<UnparsedPublicKey<Vec<u8>>>();
1109+
test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
1110+
test::compile_time_assert_clone::<UnparsedPublicKey<&[u8]>>();
1111+
test::compile_time_assert_clone::<UnparsedPublicKey<Vec<u8>>>();
1112+
test::compile_time_assert_send::<ParsedPublicKey>();
1113+
test::compile_time_assert_sync::<ParsedPublicKey>();
1114+
test::compile_time_assert_clone::<ParsedPublicKey>();
1115+
}
10821116
}

aws-lc-rs/tests/ecdsa_tests.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ fn ecdsa_traits() {
1919
test::compile_time_assert_sync::<EcdsaKeyPair>();
2020
test::compile_time_assert_send::<Signature>();
2121
test::compile_time_assert_sync::<Signature>();
22-
test::compile_time_assert_send::<UnparsedPublicKey<&[u8]>>();
23-
test::compile_time_assert_sync::<UnparsedPublicKey<&[u8]>>();
24-
test::compile_time_assert_send::<UnparsedPublicKey<Vec<u8>>>();
25-
test::compile_time_assert_sync::<UnparsedPublicKey<Vec<u8>>>();
2622
}
2723

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

207203
{
208204
let ppk = ParsedPublicKey::new(alg, &public_key).unwrap();
205+
assert_eq!(ppk.as_ref(), public_key.as_slice());
209206
let actual_result = ppk.verify_sig(&msg, &sig);
210207
assert_eq!(actual_result.is_ok(), is_valid);
211208

aws-lc-rs/tests/ed25519_tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,11 @@ fn test_signature_verification(
107107
sig: &[u8],
108108
expected_result: Result<(), error::Unspecified>,
109109
) {
110-
assert_eq!(
111-
expected_result,
112-
signature::UnparsedPublicKey::new(&ED25519, public_key).verify(msg, sig)
113-
);
110+
let upk = signature::UnparsedPublicKey::new(&ED25519, public_key);
111+
assert_eq!(public_key, upk.as_ref());
112+
assert_eq!(expected_result, upk.verify(msg, sig));
114113
let ppk = ParsedPublicKey::new(&ED25519, public_key).unwrap();
114+
assert_eq!(public_key, ppk.as_ref());
115115
assert_eq!(expected_result, ppk.verify_sig(msg, sig));
116116
}
117117

aws-lc-rs/tests/rsa_test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ fn test_signature_rsa_pkcs1_sign() {
9999
let public_key = key_pair.public_key();
100100
{
101101
let upk = UnparsedPublicKey::new(verification_alg, public_key.as_ref());
102+
assert_eq!(public_key.as_ref(), upk.as_ref());
102103

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

116117
{
117118
let ppk = ParsedPublicKey::new(verification_alg, public_key.as_ref()).unwrap();
119+
assert_eq!(public_key.as_ref(), ppk.as_ref());
118120

119121
let mut actual = vec![0u8; key_pair.public_modulus_len()];
120122
key_pair

0 commit comments

Comments
 (0)