Skip to content

Commit

Permalink
RSA OAEP Support
Browse files Browse the repository at this point in the history
  • Loading branch information
skmcgrail committed Feb 12, 2024
1 parent cc9f7ee commit 14c8552
Show file tree
Hide file tree
Showing 16 changed files with 983 additions and 309 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ jobs:

- name: Run coverage
working-directory: ./aws-lc-rs
run: cargo llvm-cov --workspace --features unstable --no-fail-fast --ignore-filename-regex "aws-lc-(fips-)?sys/.*" --lcov --output-path ${{ runner.temp }}/lcov.info
run: cargo llvm-cov --workspace --features unstable,ring-sig-verify,ring-io --no-fail-fast --ignore-filename-regex "aws-lc-(fips-)?sys/.*" --lcov --output-path ${{ runner.temp }}/lcov.info
- name: Run FIPS coverage
working-directory: ./aws-lc-rs
run: cargo llvm-cov --workspace --features unstable,fips --no-fail-fast --ignore-filename-regex "aws-lc-(fips-)?sys/.*" --lcov --output-path ${{ runner.temp }}/lcov-fips.info
run: cargo llvm-cov --workspace --features unstable,ring-sig-verify,ring-io,fips --no-fail-fast --ignore-filename-regex "aws-lc-(fips-)?sys/.*" --lcov --output-path ${{ runner.temp }}/lcov-fips.info
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
Expand Down
9 changes: 7 additions & 2 deletions aws-lc-rs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ include ../Makefile

UNAME_S := $(shell uname -s)

AWS_LC_RS_COVERAGE_FEATURES := unstable,ring-sig-verify,ring-io

asan:
# TODO: This build target produces linker error on Mac.
# Run specific tests:
Expand All @@ -21,7 +23,10 @@ asan-fips:
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

coverage:
cargo llvm-cov --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc-sys/*" --lcov --output-path lcov.info
cargo llvm-cov --features "${AWS_LC_RS_COVERAGE_FEATURES}" --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc(-fips|)-sys/*" --lcov --output-path lcov.info

coverage-fips:
cargo llvm-cov --features "${AWS_LC_RS_COVERAGE_FEATURES},fips" --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc(-fips|)-sys/*" --lcov --output-path lcov.info

test:
cargo test --all-targets --features unstable
Expand All @@ -44,4 +49,4 @@ clippy:

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

.PHONY: asan asan-fips asan-release ci clippy coverage test msrv clippy
.PHONY: asan asan-fips asan-release ci clippy coverage coverage-fips test msrv clippy
10 changes: 1 addition & 9 deletions aws-lc-rs/src/bn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 OR ISC

use crate::ptr::{ConstPointer, DetachableLcPtr, LcPtr};
use aws_lc::{BN_bin2bn, BN_bn2bin, BN_cmp, BN_new, BN_num_bits, BN_num_bytes, BN_set_u64, BIGNUM};
use aws_lc::{BN_bin2bn, BN_bn2bin, BN_new, BN_num_bits, BN_num_bytes, BN_set_u64, BIGNUM};
use mirai_annotations::unrecoverable;
use std::cmp::Ordering;
use std::ptr::null_mut;

impl TryFrom<&[u8]> for LcPtr<BIGNUM> {
Expand Down Expand Up @@ -65,13 +64,6 @@ impl ConstPointer<BIGNUM> {
}
}

pub(crate) fn compare(&self, other: &ConstPointer<BIGNUM>) -> Ordering {
unsafe {
let result = BN_cmp(**self, **other);
result.cmp(&0)
}
}

pub(crate) fn num_bits(&self) -> u32 {
unsafe { BN_num_bits(**self) }
}
Expand Down
6 changes: 3 additions & 3 deletions aws-lc-rs/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl KeyPair for Ed25519KeyPair {
}
}

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

if 1 != unsafe { EVP_PKEY_keygen_init(*pkey_ctx) } {
Expand Down Expand Up @@ -191,7 +191,7 @@ impl Ed25519KeyPair {
/// # Errors
/// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error.
pub fn generate_pkcs8(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
let evp_pkey = unsafe { generate_key()? };
let evp_pkey = generate_key()?;
evp_pkey.marshall_private_key(Version::V2)
}

Expand Down Expand Up @@ -228,7 +228,7 @@ impl Ed25519KeyPair {
/// # Errors
/// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error.
pub fn generate_pkcs8v1(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
let evp_pkey = unsafe { generate_key()? };
let evp_pkey = generate_key()?;
evp_pkey.marshall_private_key(Version::V1)
}

Expand Down
6 changes: 6 additions & 0 deletions aws-lc-rs/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ macro_rules! generated_encodings {
f.debug_struct(stringify!($name)).finish()
}
}

impl<'a> From<Buffer<'a, buffer_type::[<$name Type>]>> for $name<'a> {
fn from(value: Buffer<'a, buffer_type::[<$name Type>]>) -> Self {
Self(value)
}
}
)*
}}
}
Expand Down
27 changes: 7 additions & 20 deletions aws-lc-rs/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,14 @@ impl KeyRejected {
KeyRejected("InconsistentComponents")
}

//pub(crate) fn invalid_component() -> Self {
// KeyRejected("InvalidComponent")
//}

#[inline]
pub(crate) fn invalid_encoding() -> Self {
KeyRejected("InvalidEncoding")
}

// XXX: See the comment at the call site.
//pub(crate) fn rng_failed() -> Self {
// KeyRejected("RNG failed")
//}

//pub(crate) fn public_key_is_missing() -> Self {
// KeyRejected("PublicKeyIsMissing")
//}
pub(crate) fn unsupported_size() -> Self {
KeyRejected("UnsupportedSize")
}

pub(crate) fn too_small() -> Self {
KeyRejected("TooSmall")
Expand All @@ -152,21 +143,17 @@ impl KeyRejected {
KeyRejected("TooLarge")
}

//pub(crate) fn version_not_supported() -> Self {
// KeyRejected("VersionNotSupported")
//}

pub(crate) fn wrong_algorithm() -> Self {
KeyRejected("WrongAlgorithm")
}

pub(crate) fn private_modulus_len_not_multiple_of_512_bits() -> Self {
KeyRejected("PrivateModulusLenNotMultipleOf512Bits")
}

pub(crate) fn unexpected_error() -> Self {
KeyRejected("UnexpectedError")
}

pub(crate) fn unspecified() -> Self {
KeyRejected("Unspecified")
}
}

impl std::error::Error for KeyRejected {
Expand Down
2 changes: 1 addition & 1 deletion aws-lc-rs/src/pkcs8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl AsRef<[u8]> for Document {

impl Drop for Document {
fn drop(&mut self) {
self.bytes.zeroize();
self.bytes.as_mut().zeroize();
}
}

Expand Down
1 change: 1 addition & 0 deletions aws-lc-rs/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ impl<P: Pointer> DetachablePointer<P> {
}

impl<P: Pointer> DetachablePointer<P> {
#[allow(dead_code)]
#[inline]
pub fn as_const(&self) -> ConstPointer<P::T> {
match &self.pointer {
Expand Down
9 changes: 8 additions & 1 deletion aws-lc-rs/src/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@
// components.

mod encoding;
mod encryption;
pub(crate) mod key;
pub(crate) mod signature;

pub use self::key::{KeyPair, KeySize, PublicKey, PublicKeyComponents};
#[allow(clippy::module_name_repetitions)]
pub use self::signature::RsaParameters;
pub use self::{
encryption::{
EncryptionAlgorithm, EncryptionAlgorithmId, PrivateDecryptingKey, PublicEncryptingKey,
OAEP_SHA1_MGF1SHA1, OAEP_SHA256_MGF1SHA256, OAEP_SHA384_MGF1SHA384, OAEP_SHA512_MGF1SHA512,
},
key::{KeyPair, KeySize, PublicKey, PublicKeyComponents},
};

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

Expand Down
102 changes: 102 additions & 0 deletions aws-lc-rs/src/rsa/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,105 @@ pub(in super::super) mod pkcs8 {
LcPtr::try_from(pkcs8)
}
}

/// [RFC 8017](https://www.rfc-editor.org/rfc/rfc8017.html)
///
/// PKCS #1: RSA Cryptography Specifications Version 2.2
pub(in super::super) mod rfc8017 {
use crate::{
cbs,
error::Unspecified,
ptr::{DetachableLcPtr, LcPtr},
};
use aws_lc::{
EVP_PKEY_assign_RSA, EVP_PKEY_new, RSA_parse_private_key, RSA_parse_public_key,
RSA_public_key_to_bytes, EVP_PKEY,
};
use std::ptr::null_mut;

/// DER encode a RSA public key to `RSAPublicKey` structure.
pub(in super::super) unsafe fn encode_public_key_der(
pubkey: &LcPtr<EVP_PKEY>,
) -> Result<Box<[u8]>, ()> {
let mut pubkey_bytes = null_mut::<u8>();
let mut outlen: usize = 0;
if 1 != RSA_public_key_to_bytes(
&mut pubkey_bytes,
&mut outlen,
*pubkey.get_rsa().map_err(|_| Unspecified)?.as_const(),
) {
return Err(());
}
let pubkey_bytes = LcPtr::new(pubkey_bytes)?;
let pubkey_slice = pubkey_bytes.as_slice(outlen);
let pubkey_vec = Vec::from(pubkey_slice);
Ok(pubkey_vec.into_boxed_slice())
}

/// Decode a DER encoded `RSAPublicKey` structure.
#[inline]
pub(in super::super) fn decode_public_key_der(
public_key: &[u8],
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
let mut cbs = unsafe { cbs::build_CBS(public_key) };

let rsa = DetachableLcPtr::new(unsafe { RSA_parse_public_key(&mut cbs) })?;

let pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;

if 1 != unsafe { EVP_PKEY_assign_RSA(*pkey, *rsa) } {
return Err(Unspecified);
}

rsa.detach();

Ok(pkey)
}

/// Decodes a DER encoded `RSAPrivateKey` structure.
#[inline]
pub(in super::super) fn decode_private_key_der(
private_key: &[u8],
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
let mut cbs = unsafe { cbs::build_CBS(private_key) };

let rsa = DetachableLcPtr::new(unsafe { RSA_parse_private_key(&mut cbs) })?;

let pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;

if 1 != unsafe { EVP_PKEY_assign_RSA(*pkey, *rsa) } {
return Err(Unspecified);
}

rsa.detach();

Ok(pkey)
}
}

/// [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280.html)
///
/// Encodings that use the `SubjectPublicKeyInfo` structure.
pub(in super::super) mod rfc5280 {
use crate::{cbb::LcCBB, cbs, encoding::PublicKeyX509Der, error::Unspecified, ptr::LcPtr};
use aws_lc::{EVP_marshal_public_key, EVP_parse_public_key, EVP_PKEY};

pub(in super::super) fn encode_public_key_der(
key: &LcPtr<EVP_PKEY>,
) -> Result<PublicKeyX509Der<'static>, Unspecified> {
let mut der = LcCBB::new(1024);

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

Ok(PublicKeyX509Der::from(der.into_buffer()?))
}

pub(in super::super) fn decode_public_key_der(
value: &[u8],
) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
let mut der = unsafe { cbs::build_CBS(value) };
Ok(LcPtr::new(unsafe { EVP_parse_public_key(&mut der) })?)
}
}
Loading

0 comments on commit 14c8552

Please sign in to comment.