Skip to content

Commit

Permalink
Add feature based on aws-lc-rs cryptographic library instead of ring
Browse files Browse the repository at this point in the history
  • Loading branch information
Kiril Nikolov committed Mar 15, 2024
1 parent 193eb8d commit 6126206
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ jobs:
- name: Run tests no features
run: cargo test --no-default-features

- name: Run tests no features
run: cargo test --features fips

wasm:
name: Run tests in wasm
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ base64 = "0.21.0"
# For PEM decoding
pem = { version = "3", optional = true }
simple_asn1 = { version = "0.6", optional = true }
aws-lc-rs = { version = "1.6.2", optional = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
ring = { version = "0.17.4", features = ["std"] }
Expand All @@ -50,6 +51,7 @@ criterion = { version = "0.4", default-features = false }
[features]
default = ["use_pem"]
use_pem = ["pem", "simple_asn1"]
fips = ["aws-lc-rs"]

[[bench]]
name = "jwt"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,7 @@ you can add some leeway to the `iat`, `exp`, and `nbf` validation by setting the
Last but not least, you will need to set the algorithm(s) allowed for this token if you are not using `HS256`.

Look at `examples/validation.rs` for a full working example.

## FIPS compliance

This library exports a feature that replaces `ring` with `aws_lc_rs` to achieve FIPS compliance. The name of the feature is `fips`.
21 changes: 21 additions & 0 deletions src/crypto/ecdsa.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#[cfg(feature = "fips")]
use aws_lc_rs as ring;

#[cfg(not(feature = "fips"))]
use ring;

use ring::{rand, signature};

use crate::algorithms::Algorithm;
Expand Down Expand Up @@ -26,6 +32,7 @@ pub(crate) fn alg_to_ec_signing(alg: Algorithm) -> &'static signature::EcdsaSign

/// The actual ECDSA signing + encoding
/// The key needs to be in PKCS8 format
#[cfg(not(feature = "fips"))]
pub fn sign(
alg: &'static signature::EcdsaSigningAlgorithm,
key: &[u8],
Expand All @@ -36,3 +43,17 @@ pub fn sign(
let out = signing_key.sign(&rng, message)?;
Ok(b64_encode(out))
}

/// The actual ECDSA signing + encoding
/// The key needs to be in PKCS8 format
#[cfg(feature = "fips")]
pub fn sign(
alg: &'static signature::EcdsaSigningAlgorithm,
key: &[u8],
message: &[u8],
) -> Result<String> {
let rng = rand::SystemRandom::new();
let signing_key = signature::EcdsaKeyPair::from_pkcs8(alg, key)?;
let out = signing_key.sign(&rng, message)?;
Ok(b64_encode(out))
}
12 changes: 8 additions & 4 deletions src/crypto/eddsa.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
use ring::signature;
#[cfg(feature = "fips")]
use aws_lc_rs as ring;

#[cfg(not(feature = "fips"))]
use ring;

use crate::algorithms::Algorithm;
use crate::errors::Result;
use crate::serialization::b64_encode;

/// Only used internally when signing or validating EdDSA, to map from our enum to the Ring EdDSAParameters structs.
pub(crate) fn alg_to_ec_verification(alg: Algorithm) -> &'static signature::EdDSAParameters {
pub(crate) fn alg_to_ec_verification(alg: Algorithm) -> &'static ring::signature::EdDSAParameters {
// To support additional key subtypes, like Ed448, we would need to match on the JWK's ("crv")
// parameter.
match alg {
Algorithm::EdDSA => &signature::ED25519,
Algorithm::EdDSA => &ring::signature::ED25519,
_ => unreachable!("Tried to get EdDSA alg for a non-EdDSA algorithm"),
}
}

/// The actual EdDSA signing + encoding
/// The key needs to be in PKCS8 format
pub fn sign(key: &[u8], message: &[u8]) -> Result<String> {
let signing_key = signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(key)?;
let signing_key = ring::signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(key)?;
let out = signing_key.sign(message);
Ok(b64_encode(out))
}
6 changes: 6 additions & 0 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#[cfg(feature = "fips")]
use aws_lc_rs as ring;

#[cfg(not(feature = "fips"))]
use ring;

use ring::constant_time::verify_slices_are_equal;
use ring::{hmac, signature};

Expand Down
19 changes: 18 additions & 1 deletion src/crypto/rsa.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#[cfg(feature = "fips")]
use aws_lc_rs as ring;

#[cfg(not(feature = "fips"))]
use ring;

use ring::{rand, signature};

use crate::algorithms::Algorithm;
Expand Down Expand Up @@ -41,7 +47,8 @@ pub(crate) fn sign(
let key_pair = signature::RsaKeyPair::from_der(key)
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;

let mut signature = vec![0; key_pair.public().modulus_len()];
let mut signature = get_signature(&key_pair);

let rng = rand::SystemRandom::new();
key_pair.sign(alg, &rng, message, &mut signature).map_err(|_| ErrorKind::RsaFailedSigning)?;

Expand All @@ -60,3 +67,13 @@ pub(crate) fn verify_from_components(
let res = pubkey.verify(alg, message, &signature_bytes);
Ok(res.is_ok())
}

#[cfg(feature = "fips")]
fn get_signature(key_pair: &signature::RsaKeyPair) -> Vec<u8> {
vec![0; key_pair.public_modulus_len()]
}

#[cfg(not(feature = "fips"))]
fn get_signature(key_pair: &signature::RsaKeyPair) -> Vec<u8> {
vec![0; key_pair.public().modulus_len()]
}
15 changes: 10 additions & 5 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[cfg(feature = "fips")]
use aws_lc_rs as ring;

#[cfg(not(feature = "fips"))]
use ring;
use std::error::Error as StdError;
use std::fmt;
use std::result;
Expand Down Expand Up @@ -77,7 +82,7 @@ pub enum ErrorKind {
/// Some of the text was invalid UTF-8
Utf8(::std::string::FromUtf8Error),
/// Something unspecified went wrong with crypto
Crypto(::ring::error::Unspecified),
Crypto(ring::error::Unspecified),
}

impl StdError for Error {
Expand Down Expand Up @@ -159,14 +164,14 @@ impl From<::std::string::FromUtf8Error> for Error {
}
}

impl From<::ring::error::Unspecified> for Error {
fn from(err: ::ring::error::Unspecified) -> Error {
impl From<ring::error::Unspecified> for Error {
fn from(err: ring::error::Unspecified) -> Error {
new_error(ErrorKind::Crypto(err))
}
}

impl From<::ring::error::KeyRejected> for Error {
fn from(_err: ::ring::error::KeyRejected) -> Error {
impl From<ring::error::KeyRejected> for Error {
fn from(_err: ring::error::KeyRejected) -> Error {
new_error(ErrorKind::InvalidEcdsaKey)
}
}
Expand Down

0 comments on commit 6126206

Please sign in to comment.