Skip to content

Commit 34283fa

Browse files
authored
RSA OAEP Support (#303)
1 parent 564b3c7 commit 34283fa

21 files changed

+1508
-334
lines changed

aws-lc-rs/Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ include ../Makefile
22

33
UNAME_S := $(shell uname -s)
44

5+
AWS_LC_RS_COV_EXTRA_FEATURES := unstable
6+
57
asan:
68
# TODO: This build target produces linker error on Mac.
79
# Run specific tests:
@@ -21,7 +23,10 @@ asan-fips:
2123
RUST_BACKTRACE=1 ASAN_OPTIONS=detect_leaks=1 RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address cargo +nightly test --lib --bins --tests --examples --target `rustc -vV | sed -n 's|host: ||p'` --no-default-features --features fips,asan
2224

2325
coverage:
24-
cargo llvm-cov --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc-sys/*" --lcov --output-path lcov.info
26+
cargo llvm-cov --features "${AWS_LC_RS_COV_EXTRA_FEATURES}" --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc(-fips|)-sys/*" --lcov --output-path lcov.info
27+
28+
coverage-fips:
29+
cargo llvm-cov --features "${AWS_LC_RS_COV_EXTRA_FEATURES},fips" --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc(-fips|)-sys/*" --lcov --output-path lcov.info
2530

2631
test:
2732
cargo test --all-targets --features unstable
@@ -44,4 +49,4 @@ clippy:
4449

4550
ci: format clippy msrv test coverage api-diff-pub
4651

47-
.PHONY: asan asan-fips asan-release ci clippy coverage test msrv clippy
52+
.PHONY: asan asan-fips asan-release ci clippy coverage coverage-fips test msrv clippy

aws-lc-rs/src/bn.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 OR ISC
33

44
use crate::ptr::{ConstPointer, DetachableLcPtr, LcPtr};
5-
use aws_lc::{BN_bin2bn, BN_bn2bin, BN_cmp, BN_new, BN_num_bits, BN_num_bytes, BN_set_u64, BIGNUM};
6-
use core::cmp::Ordering;
5+
use aws_lc::{BN_bin2bn, BN_bn2bin, BN_new, BN_num_bits, BN_num_bytes, BN_set_u64, BIGNUM};
76
use core::ptr::null_mut;
87
use mirai_annotations::unrecoverable;
98

@@ -65,13 +64,6 @@ impl ConstPointer<BIGNUM> {
6564
}
6665
}
6766

68-
pub(crate) fn compare(&self, other: &ConstPointer<BIGNUM>) -> Ordering {
69-
unsafe {
70-
let result = BN_cmp(**self, **other);
71-
result.cmp(&0)
72-
}
73-
}
74-
7567
pub(crate) fn num_bits(&self) -> u32 {
7668
unsafe { BN_num_bits(**self) }
7769
}

aws-lc-rs/src/encoding.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ macro_rules! generated_encodings {
4545
f.debug_struct(stringify!($name)).finish()
4646
}
4747
}
48+
49+
impl<'a> From<Buffer<'a, buffer_type::[<$name Type>]>> for $name<'a> {
50+
fn from(value: Buffer<'a, buffer_type::[<$name Type>]>) -> Self {
51+
Self(value)
52+
}
53+
}
4854
)*
4955
}}
5056
}

aws-lc-rs/src/error.rs

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -128,24 +128,11 @@ impl KeyRejected {
128128
KeyRejected("InconsistentComponents")
129129
}
130130

131-
//pub(crate) fn invalid_component() -> Self {
132-
// KeyRejected("InvalidComponent")
133-
//}
134-
135131
#[inline]
136132
pub(crate) fn invalid_encoding() -> Self {
137133
KeyRejected("InvalidEncoding")
138134
}
139135

140-
// XXX: See the comment at the call site.
141-
//pub(crate) fn rng_failed() -> Self {
142-
// KeyRejected("RNG failed")
143-
//}
144-
145-
//pub(crate) fn public_key_is_missing() -> Self {
146-
// KeyRejected("PublicKeyIsMissing")
147-
//}
148-
149136
pub(crate) fn too_small() -> Self {
150137
KeyRejected("TooSmall")
151138
}
@@ -154,21 +141,17 @@ impl KeyRejected {
154141
KeyRejected("TooLarge")
155142
}
156143

157-
//pub(crate) fn version_not_supported() -> Self {
158-
// KeyRejected("VersionNotSupported")
159-
//}
160-
161144
pub(crate) fn wrong_algorithm() -> Self {
162145
KeyRejected("WrongAlgorithm")
163146
}
164147

165-
pub(crate) fn private_modulus_len_not_multiple_of_512_bits() -> Self {
166-
KeyRejected("PrivateModulusLenNotMultipleOf512Bits")
167-
}
168-
169148
pub(crate) fn unexpected_error() -> Self {
170149
KeyRejected("UnexpectedError")
171150
}
151+
152+
pub(crate) fn unspecified() -> Self {
153+
KeyRejected("Unspecified")
154+
}
172155
}
173156

174157
impl Error for KeyRejected {
@@ -239,6 +222,12 @@ impl From<TryFromIntError> for KeyRejected {
239222
}
240223
}
241224

225+
impl From<Unspecified> for KeyRejected {
226+
fn from(_: Unspecified) -> Self {
227+
Self::unspecified()
228+
}
229+
}
230+
242231
#[allow(deprecated, unused_imports)]
243232
#[cfg(test)]
244233
mod tests {

aws-lc-rs/src/evp_pkey.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use crate::error::{KeyRejected, Unspecified};
88
use crate::pkcs8::{Document, Version};
99
use crate::ptr::LcPtr;
1010
use aws_lc::{
11-
EVP_PKEY_bits, EVP_PKEY_get1_EC_KEY, EVP_PKEY_get1_RSA, EVP_PKEY_id, EVP_marshal_private_key,
12-
EVP_marshal_private_key_v2, EVP_parse_private_key, EC_KEY, EVP_PKEY, RSA,
11+
EVP_PKEY_bits, EVP_PKEY_get1_EC_KEY, EVP_PKEY_get1_RSA, EVP_PKEY_id, EVP_PKEY_up_ref,
12+
EVP_marshal_private_key, EVP_marshal_private_key_v2, EVP_parse_private_key, EC_KEY, EVP_PKEY,
13+
RSA,
1314
};
1415
// TODO: Uncomment when MSRV >= 1.64
1516
// use core::ffi::c_int;
@@ -112,3 +113,14 @@ impl LcPtr<EVP_PKEY> {
112113
Ok(Document::new(buffer.into_boxed_slice()))
113114
}
114115
}
116+
117+
impl Clone for LcPtr<EVP_PKEY> {
118+
fn clone(&self) -> Self {
119+
assert_eq!(
120+
1,
121+
unsafe { EVP_PKEY_up_ref(**self) },
122+
"infallible AWS-LC function"
123+
);
124+
Self::new(**self).expect("non-null AWS-LC EVP_PKEY pointer")
125+
}
126+
}

aws-lc-rs/src/fips.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ pub(crate) fn set_fips_service_status_unapproved() {
2222
indicator::set_unapproved();
2323
}
2424

25+
#[allow(dead_code)]
26+
#[cfg(all(feature = "fips", debug_assertions))]
27+
#[inline]
28+
pub(crate) fn clear_fips_service_status() {
29+
indicator::clear();
30+
}
31+
2532
#[cfg(all(feature = "fips", debug_assertions))]
2633
pub(crate) mod indicator {
2734
use core::cell::Cell;
@@ -47,6 +54,10 @@ pub(crate) mod indicator {
4754
pub fn set_unapproved() {
4855
STATUS_INDICATOR.with(|v| v.set(Some(false)));
4956
}
57+
58+
pub fn clear() {
59+
STATUS_INDICATOR.with(|v| v.set(None));
60+
}
5061
}
5162

5263
#[cfg(all(feature = "fips", debug_assertions))]
@@ -125,8 +136,12 @@ pub(crate) use indicator_check;
125136
#[cfg(all(feature = "fips", debug_assertions))]
126137
macro_rules! check_fips_service_status {
127138
($function:expr) => {{
128-
use $crate::fips::get_fips_service_status;
139+
// Clear the current indicator status first by retrieving it
140+
use $crate::fips::{clear_fips_service_status, get_fips_service_status};
141+
clear_fips_service_status();
142+
// do the expression
129143
let result = $function;
144+
// Check indicator after expression
130145
get_fips_service_status().map(|()| result)
131146
}};
132147
}

aws-lc-rs/src/ptr.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,6 @@ impl<P: Pointer> DetachablePointer<P> {
101101
}
102102
}
103103

104-
impl<P: Pointer> DetachablePointer<P> {
105-
#[inline]
106-
pub fn as_const(&self) -> ConstPointer<P::T> {
107-
match &self.pointer {
108-
Some(pointer) => ConstPointer {
109-
ptr: pointer.as_const_ptr(),
110-
},
111-
None => {
112-
// Safety: pointer is only None when DetachableLcPtr is detached or dropped
113-
verify_unreachable!()
114-
}
115-
}
116-
}
117-
}
118-
119104
impl<P: Pointer> From<DetachablePointer<P>> for ManagedPointer<P> {
120105
#[inline]
121106
fn from(mut dptr: DetachablePointer<P>) -> Self {
@@ -225,7 +210,7 @@ create_pointer!(EVP_AEAD_CTX, EVP_AEAD_CTX_free);
225210

226211
#[cfg(test)]
227212
mod tests {
228-
use crate::ptr::{ConstPointer, DetachablePointer, ManagedPointer};
213+
use crate::ptr::{DetachablePointer, ManagedPointer};
229214
use aws_lc::BIGNUM;
230215

231216
#[test]
@@ -236,10 +221,6 @@ mod tests {
236221
let debug = format!("{detachable_ptr:?}");
237222
assert!(debug.contains("DetachablePointer { pointer: Some("));
238223

239-
let const_ptr: ConstPointer<BIGNUM> = detachable_ptr.as_const();
240-
let debug = format!("{const_ptr:?}");
241-
assert!(debug.contains("ConstPointer { ptr:"));
242-
243224
let lc_ptr = ManagedPointer::new(detachable_ptr.detach()).unwrap();
244225
let debug = format!("{lc_ptr:?}");
245226
assert!(debug.contains("ManagedPointer { pointer:"));

aws-lc-rs/src/rsa.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,90 @@
44
// SPDX-License-Identifier: Apache-2.0 OR ISC
55

66
//! RSA Signature and Encryption Support.
7+
//!
8+
//! # OAEP Encryption / Decryption
9+
//!
10+
//! ```rust
11+
//! # use std::error::Error;
12+
//! # fn main() -> Result<(), Box<dyn Error>> {
13+
//! use aws_lc_rs::{
14+
//! encoding::{AsDer, Pkcs8V1Der, PublicKeyX509Der},
15+
//! rsa::{KeySize, OAEP_SHA256_MGF1SHA256, OaepPublicEncryptingKey, OaepPrivateDecryptingKey, PublicEncryptingKey, PrivateDecryptingKey}
16+
//! };
17+
//!
18+
//! // Generate a RSA 2048-bit key.
19+
//! let private_key = PrivateDecryptingKey::generate(KeySize::Rsa2048)?;
20+
//!
21+
//! // Serialize the RSA private key to DER encoded PKCS#8 format for later usage.
22+
//! let private_key_der = AsDer::<Pkcs8V1Der>::as_der(&private_key)?;
23+
//! let private_key_der_bytes = private_key_der.as_ref();
24+
//!
25+
//! // Load a RSA private key from DER encoded PKCS#8 document.
26+
//! let private_key = PrivateDecryptingKey::from_pkcs8(private_key_der_bytes)?;
27+
//!
28+
//! // Retrieve the RSA public key
29+
//! let public_key = private_key.public_key();
30+
//!
31+
//! // Serialize the RSA public key to DER encoded X.509 SubjectPublicKeyInfo for later usage.
32+
//! let public_key_der = AsDer::<PublicKeyX509Der>::as_der(&public_key)?;
33+
//! let public_key_der_bytes = public_key_der.as_ref();
34+
//!
35+
//! // Load a RSA public key from DER encoded X.509 SubjectPublicKeyInfo.
36+
//! let public_key = PublicEncryptingKey::from_der(public_key_der_bytes)?;
37+
//!
38+
//! // Construct a RSA-OAEP public encrypting key
39+
//! let public_key = OaepPublicEncryptingKey::new(public_key)?;
40+
//!
41+
//! // The maximum size plaintext can be determined by calling `OaepPublicEncryptingKey::max_plaintext_size`
42+
//! let message = b"hello world";
43+
//! let mut ciphertext = vec![0u8; public_key.ciphertext_size()]; // Output will be the size of the RSA key length in bytes rounded up.
44+
//!
45+
//! // Encrypt a message with the public key without the optional label provided.
46+
//! let ciphertext = public_key.encrypt(&OAEP_SHA256_MGF1SHA256, message, &mut ciphertext, None)?;
47+
//!
48+
//! assert_ne!(message, ciphertext);
49+
//!
50+
//! // Construct a RSA-OAEP private decrypting key
51+
//! let private_key = OaepPrivateDecryptingKey::new(private_key)?;
52+
//!
53+
//! // Decrypt a message with the private key.
54+
//! let mut plaintext = vec![0u8; private_key.min_output_size()];
55+
//! let plaintext = private_key.decrypt(&OAEP_SHA256_MGF1SHA256, ciphertext, &mut plaintext, None)?;
56+
//!
57+
//! assert_eq!(message, plaintext);
58+
//!
59+
//! # Ok(())
60+
//! # }
61+
//! ```
762
863
// *R* and *r* in Montgomery math refer to different things, so we always use
964
// `R` to refer to *R* to avoid confusion, even when that's against the normal
1065
// naming conventions. Also the standard camelCase names are used for `KeyPair`
1166
// components.
1267

1368
mod encoding;
69+
mod encryption;
1470
pub(crate) mod key;
1571
pub(crate) mod signature;
1672

17-
pub use self::key::{KeyPair, KeySize, PublicKey, PublicKeyComponents};
1873
#[allow(clippy::module_name_repetitions)]
1974
pub use self::signature::RsaParameters;
75+
pub use self::{
76+
encryption::{
77+
EncryptionAlgorithmId, OaepAlgorithm, OaepPrivateDecryptingKey, OaepPublicEncryptingKey,
78+
PrivateDecryptingKey, PublicEncryptingKey, OAEP_SHA1_MGF1SHA1, OAEP_SHA256_MGF1SHA256,
79+
OAEP_SHA384_MGF1SHA384, OAEP_SHA512_MGF1SHA512,
80+
},
81+
key::{KeyPair, KeySize, PublicKey, PublicKeyComponents},
82+
};
2083

2184
pub(crate) use self::signature::RsaVerificationAlgorithmId;
2285

2386
#[cfg(test)]
2487
mod tests {
88+
#[cfg(feature = "fips")]
89+
mod fips;
90+
2591
#[cfg(feature = "ring-io")]
2692
#[test]
2793
fn test_rsa() {

0 commit comments

Comments
 (0)