diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6330417..8917c7a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -5,7 +5,7 @@ on: pull_request: merge_group: schedule: - - cron: '0 18 * * *' + - cron: "0 18 * * *" jobs: check: @@ -71,6 +71,7 @@ jobs: - --all-features - --features=verify - --features=verify-aws + - --features=verify-aws-fips - --features=validate steps: - uses: actions/checkout@v4 @@ -78,6 +79,21 @@ jobs: uses: dtolnay/rust-toolchain@stable - run: cargo test --locked ${{ matrix.features }} + test_fips: + name: verify-aws-fips dependency on FIPS backend only + needs: check-all-features + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + # Ensure the non-FIPS aws-lc-sys crate is not part of the dependency tree. + # + # "cargo tree" exists 101 when queried for a crate that's not in the tree. + - run: "if cargo tree --features=verify-aws-fips -i aws-lc-sys; then false; else [ $? -eq 101 ]; fi" + # Ensure the optional FIPS crypto module is depended. + - run: "cargo tree --features=verify-aws-fips -i aws-lc-fips-sys" + fmt: name: Rustfmt runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index b3d3b29..cf131c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,14 +59,28 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-fips-sys" +version = "0.13.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6ea8e07e2df15b9f09f2ac5ee2977369b06d116f0c4eb5fa4ad443b73c7f53" +dependencies = [ + "bindgen 0.72.1", + "cc", + "cmake", + "dunce", + "fs_extra", + "regex", +] + [[package]] name = "aws-lc-rs" version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" dependencies = [ + "aws-lc-fips-sys", "aws-lc-sys", - "untrusted 0.7.1", "zeroize", ] @@ -76,7 +90,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -100,12 +114,32 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn", "which", ] +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn", +] + [[package]] name = "bitflags" version = "2.9.1" @@ -504,7 +538,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.16", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -514,6 +548,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rusticata-macros" version = "5.0.0" @@ -647,12 +687,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 1eb3e11..2d98ec5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,13 +38,14 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = [] -verify-aws = ["aws-lc-rs"] +verify-aws = ["aws-lc-rs/aws-lc-sys"] # Non-FIPS backend +verify-aws-fips = ["aws-lc-rs/fips"] # FIPS crypto backend verify = ["ring"] validate = [] [dependencies] -aws-lc-rs = { version = "1.0", optional = true } asn1-rs = { version = "0.8.0-beta.1", features=["bigint", "datetime"] } +aws-lc-rs = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } data-encoding = "2.2.1" lazy_static = "1.4" nom = "8.0" diff --git a/src/certificate.rs b/src/certificate.rs index 7d2ded6..c4775d2 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -10,7 +10,11 @@ use crate::x509::{ X509Name, X509Version, }; -#[cfg(any(feature = "verify", feature = "verify-aws"))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] use crate::verify::verify_signature; use asn1_rs::{ Alias, BerError, BigUint, BitString, DerParser, Error, FromDer, Header, Input, @@ -100,8 +104,19 @@ impl<'a> X509Certificate<'a> { /// It is usually an intermediate authority. /// /// Not all algorithms are supported, this function is limited to what `ring` supports. - #[cfg(any(feature = "verify", feature = "verify-aws"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "verify", feature = "verify-aws"))))] + #[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))] + #[cfg_attr( + docsrs, + doc(cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))) + )] pub fn verify_signature( &self, public_key: Option<&SubjectPublicKeyInfo>, diff --git a/src/certification_request.rs b/src/certification_request.rs index f1a3e3d..5bd617a 100644 --- a/src/certification_request.rs +++ b/src/certification_request.rs @@ -5,7 +5,11 @@ use crate::x509::{ parse_signature_value, AlgorithmIdentifier, SubjectPublicKeyInfo, X509Name, X509Version, }; -#[cfg(any(feature = "verify", feature = "verify-aws"))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] use crate::verify::verify_signature; use asn1_rs::{ BitString, DerParser, FromDer, Header, Input, Oid, OptTaggedImplicit, Sequence, Tag, Tagged, @@ -83,8 +87,19 @@ impl<'a> X509CertificationRequest<'a> { /// /// Uses the public key contained in the CSR, which must be the one of the entity /// requesting the certification for this verification to succeed. - #[cfg(any(feature = "verify", feature = "verify-aws"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "verify", feature = "verify-aws"))))] + #[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))] + #[cfg_attr( + docsrs, + doc(cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))) + )] pub fn verify_signature(&self) -> Result<(), X509Error> { let spki = &self.certification_request_info.subject_pki; verify_signature( diff --git a/src/lib.rs b/src/lib.rs index d7e1908..553544e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,10 +93,10 @@ //! to `X509Certificate`. //! //! ```rust -//! # #[cfg(any(feature = "verify", feature = "verify-aws"))] +//! # #[cfg(any(feature = "verify", feature = "verify-aws", feature = "verify-aws-fips"))] //! # use x509_parser::certificate::X509Certificate; //! /// Cryptographic signature verification: returns true if certificate was signed by issuer -//! #[cfg(any(feature = "verify", feature = "verify-aws"))] +//! #[cfg(any(feature = "verify", feature = "verify-aws", feature = "verify-aws-fips"))] //! pub fn check_signature(cert: &X509Certificate<'_>, issuer: &X509Certificate<'_>) -> bool { //! let issuer_public_key = issuer.public_key(); //! cert @@ -157,8 +157,19 @@ pub mod time; #[cfg(feature = "validate")] #[cfg_attr(docsrs, doc(cfg(feature = "validate")))] pub mod validate; -#[cfg(any(feature = "verify", feature = "verify-aws"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "verify", feature = "verify-aws"))))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] +#[cfg_attr( + docsrs, + doc(cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))) +)] pub mod verify; pub mod visitor; pub mod x509; diff --git a/src/revocation_list.rs b/src/revocation_list.rs index c20af6b..693e79d 100644 --- a/src/revocation_list.rs +++ b/src/revocation_list.rs @@ -5,9 +5,17 @@ use crate::x509::{ format_serial, parse_serial, AlgorithmIdentifier, ReasonCode, X509Name, X509Version, }; -#[cfg(any(feature = "verify", feature = "verify-aws"))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] use crate::verify::verify_signature; -#[cfg(any(feature = "verify", feature = "verify-aws"))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] use crate::x509::SubjectPublicKeyInfo; use asn1_rs::num_bigint::BigUint; use asn1_rs::{BitString, DerParser, FromDer, Header, Input, Sequence, Tag, Tagged}; @@ -137,8 +145,19 @@ impl<'a> CertificateRevocationList<'a> { /// `public_key` is the public key of the **signer**. /// /// Not all algorithms are supported, this function is limited to what `ring` supports. - #[cfg(any(feature = "verify", feature = "verify-aws"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "verify", feature = "verify-aws"))))] + #[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))] + #[cfg_attr( + docsrs, + doc(cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" + ))) + )] pub fn verify_signature(&self, public_key: &SubjectPublicKeyInfo) -> Result<(), X509Error> { verify_signature( public_key, diff --git a/src/verify.rs b/src/verify.rs index 6a73604..45689cd 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -11,9 +11,12 @@ use oid_registry::{ // Since the `signature` object is similar in ring and in aws-lc-rs, we just use simple logic // to determine which one to use. // If both verify and verify-aws features are enabled, aws will be used. -#[cfg(feature = "verify-aws")] +#[cfg(any(feature = "verify-aws", feature = "verify-aws-fips"))] use aws_lc_rs::signature; -#[cfg(all(feature = "verify", not(feature = "verify-aws")))] +#[cfg(all( + feature = "verify", + not(any(feature = "verify-aws", feature = "verify-aws-fips")) +))] use ring::signature; /// Verify the cryptographic signature of the raw data (can be a certificate, a CRL or a CSR). diff --git a/tests/readcrl.rs b/tests/readcrl.rs index cd483a9..206d60d 100644 --- a/tests/readcrl.rs +++ b/tests/readcrl.rs @@ -1,6 +1,10 @@ use x509_parser::prelude::*; -#[cfg(any(feature = "verify", feature = "verify-aws"))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] #[test] fn read_crl_verify() { const CA_DATA: &[u8] = include_bytes!("../assets/ca_minimalcrl.der"); diff --git a/tests/readcsr.rs b/tests/readcsr.rs index 13705b8..233f13f 100644 --- a/tests/readcsr.rs +++ b/tests/readcsr.rs @@ -115,7 +115,11 @@ fn read_csr_with_challenge_password() { assert!(found_san); } -#[cfg(any(feature = "verify", feature = "verify-aws"))] +#[cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] #[test] fn read_csr_verify() { let pem = pem::parse_x509_pem(CSR_DATA).unwrap().1; diff --git a/tests/verify.rs b/tests/verify.rs index d376aee..ac71cf9 100644 --- a/tests/verify.rs +++ b/tests/verify.rs @@ -1,4 +1,8 @@ -#![cfg(any(feature = "verify", feature = "verify-aws"))] +#![cfg(any( + feature = "verify", + feature = "verify-aws", + feature = "verify-aws-fips" +))] use x509_parser::parse_x509_certificate;