Skip to main content

aws_lc_rs/
lib.rs

1// Copyright 2015-2016 Brian Smith.
2// SPDX-License-Identifier: ISC
3// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4// SPDX-License-Identifier: Apache-2.0 OR ISC
5#![cfg_attr(not(clippy), allow(unexpected_cfgs))]
6#![cfg_attr(not(clippy), allow(unknown_lints))]
7#![allow(clippy::doc_markdown)]
8//! A [*ring*](https://github.com/briansmith/ring)-compatible crypto library using the cryptographic
9//! operations provided by [*AWS-LC*](https://github.com/aws/aws-lc). It uses either the
10//! auto-generated [*aws-lc-sys*](https://crates.io/crates/aws-lc-sys) or
11//! [*aws-lc-fips-sys*](https://crates.io/crates/aws-lc-fips-sys)
12//! Foreign Function Interface (FFI) crates found in this repository for invoking *AWS-LC*.
13//!
14//! # Build
15//!
16//! `aws-lc-rs` is available through [crates.io](https://crates.io/crates/aws-lc-rs). It can
17//! be added to your project in the [standard way](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)
18//! using `Cargo.toml`:
19//!
20//! ```toml
21//! [dependencies]
22//! aws-lc-rs = "1"
23//! ```
24//! Consuming projects will need a C/C++ compiler to build.
25//!
26//! **Non-FIPS builds (default):**
27//! * CMake is **never** required
28//! * Bindgen is **never** required (pre-generated bindings are provided)
29//! * Go is **never** required
30//!
31//! **FIPS builds:** Require **CMake**, **Go**, and potentially **bindgen** depending on the target platform.
32//!
33//! See our [User Guide](https://aws.github.io/aws-lc-rs/) for guidance on installing build requirements.
34//!
35//! # Feature Flags
36//!
37//! #### alloc (default)
38//!
39//! Allows implementation to allocate values of arbitrary size. (The meaning of this feature differs
40//! from the "alloc" feature of *ring*.) Currently, this is required by the `io::writer` module.
41//!
42//! #### ring-io (default)
43//!
44//! Enable feature to access the  `io`  module.
45//!
46//! #### ring-sig-verify (default)
47//!
48//! Enable feature to preserve compatibility with ring's `signature::VerificationAlgorithm::verify`
49//! function. This adds a requirement on `untrusted = "0.7.1"`.
50//!
51//! #### fips
52//!
53//! Enable this feature to have aws-lc-rs use the [*aws-lc-fips-sys*](https://crates.io/crates/aws-lc-fips-sys)
54//! crate for the cryptographic implementations. The aws-lc-fips-sys crate provides bindings to the
55//! latest version of the AWS-LC-FIPS module that has completed FIPS validation testing by an
56//! accredited lab and has been submitted to NIST for certification. This will continue to be the
57//! case as we periodically submit new versions of the AWS-LC-FIPS module to NIST for certification.
58//! Currently, aws-lc-fips-sys binds to
59//! [AWS-LC-FIPS 3.0.x](https://github.com/aws/aws-lc/tree/fips-2024-09-27).
60//!
61//! Consult with your local FIPS compliance team to determine the version of AWS-LC-FIPS module that you require. Consumers
62//! needing to remain on a previous version of the AWS-LC-FIPS module should pin to specific versions of aws-lc-rs to avoid
63//! automatically being upgraded to a newer module version.
64//! (See [cargo's documentation](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)
65//! on how to specify dependency versions.)
66//!
67//! | AWS-LC-FIPS module | aws-lc-rs |
68//! |--------------------|-----------|
69//! | 2.0.x              | \<1.12.0  |
70//! | 3.0.x              | *latest*  |
71//!
72//! Refer to the
73//! [NIST Cryptographic Module Validation Program's Modules In Progress List](https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/Modules-In-Process-List)
74//! for the latest status of the static or dynamic AWS-LC Cryptographic Module. Please see the
75//! [FIPS.md in the aws-lc repository](https://github.com/aws/aws-lc/blob/main/crypto/fipsmodule/FIPS.md)
76//! for relevant security policies and information on supported operating environments.
77//! We will also update our release notes and documentation to reflect any changes in FIPS certification status.
78//!
79//! #### non-fips
80//!
81//! Enable this feature to guarantee that the non-FIPS [*aws-lc-sys*](https://crates.io/crates/aws-lc-sys)
82//! crate is used for cryptographic implementations. This feature is mutually exclusive with the `fips`
83//! feature - enabling both will result in a compile-time error. Use this feature when you need a
84//! compile-time guarantee that your build is using the non-FIPS cryptographic module.
85//!
86//! #### asan
87//!
88//! Performs an "address sanitizer" build. This can be used to help detect memory leaks. See the
89//! ["Address Sanitizer" section](https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#addresssanitizer)
90//! of the [Rust Unstable Book](https://doc.rust-lang.org/beta/unstable-book/).
91//!
92//! #### bindgen
93//!
94//! Causes `aws-lc-sys` or `aws-lc-fips-sys` to generates fresh bindings for AWS-LC instead of using
95//! the pre-generated bindings. This feature requires `libclang` to be installed. See the
96//! [requirements](https://rust-lang.github.io/rust-bindgen/requirements.html)
97//! for [rust-bindgen](https://github.com/rust-lang/rust-bindgen)
98//!
99//! #### prebuilt-nasm
100//!
101//! Enables the use of crate provided prebuilt NASM objects under certain conditions. This only affects builds for
102//! Windows x86-64 platforms. This feature is ignored if the "fips" feature is also enabled.
103//!
104//! Use of prebuilt NASM objects is prevented if either of the following conditions are true:
105//! * The NASM assembler is detected in the build environment
106//! * `AWS_LC_SYS_PREBUILT_NASM` environment variable is set with a value of `0`
107//!
108//! Be aware that [features are additive](https://doc.rust-lang.org/cargo/reference/features.html#feature-unification);
109//! by enabling this feature, it is enabled for all crates within the same build.
110//!
111//! #### dev-tests-only
112//!
113//! Enables the `rand::unsealed` module, which re-exports the normally sealed `SecureRandom` trait.
114//! This allows consumers to provide their own implementations of `SecureRandom` (e.g., a
115//! deterministic RNG) for testing purposes. When enabled, a `mut_fill` method is also available on
116//! `SecureRandom`.
117//!
118//! This feature is restricted to **dev/debug profile builds only** — attempting to use it in a
119//! release build will result in a compile-time error.
120//!
121//! It can be enabled in two ways:
122//! * **Feature flag:** `cargo test --features dev-tests-only`
123//! * **Environment variable:** `AWS_LC_RS_DEV_TESTS_ONLY=1 cargo test`
124//!
125//! **⚠️ Warning:** This feature is intended **only** for development and testing. It must not be
126//! used in production builds. The `rand::unsealed` module and `mut_fill` method are not part of the
127//! stable public API and may change without notice.
128//!
129//! # Use of prebuilt NASM objects
130//!
131//! Prebuilt NASM objects are **only** applicable to Windows x86-64 platforms. They are **never** used on any other platform (Linux, macOS, etc.).
132//!
133//! For Windows x86 and x86-64, NASM is required for assembly code compilation. On these platforms,
134//! we recommend that you install [the NASM assembler](https://www.nasm.us/). **If NASM is
135//! detected in the build environment, it is always used** to compile the assembly files. Prebuilt NASM objects are only used as a fallback.
136//!
137//! If a NASM assembler is not available, and the "fips" feature is not enabled, then the build fails unless one of the following conditions are true:
138//!
139//! * You are building for `x86-64` and either:
140//!    * The `AWS_LC_SYS_PREBUILT_NASM` environment variable is found and has a value of "1"; OR
141//!    * `AWS_LC_SYS_PREBUILT_NASM` is *not found* in the environment AND the "prebuilt-nasm" feature has been enabled.
142//!
143//! If the above cases apply, then the crate provided prebuilt NASM objects will be used for the build. To prevent usage of prebuilt NASM
144//! objects, install NASM in the build environment and/or set the variable `AWS_LC_SYS_PREBUILT_NASM` to `0` in the build environment to prevent their use.
145//!
146//! ## About prebuilt NASM objects
147//!
148//! Prebuilt NASM objects are generated using automation similar to the crate provided pregenerated bindings. See the repository's
149//! [GitHub workflow configuration](https://github.com/aws/aws-lc-rs/blob/main/.github/workflows/sys-bindings-generator.yml) for more information.
150//! The prebuilt NASM objects are checked into the repository
151//! and are [available for inspection](https://github.com/aws/aws-lc-rs/tree/main/aws-lc-sys/builder/prebuilt-nasm).
152//! For each PR submitted,
153//! [CI verifies](https://github.com/aws/aws-lc-rs/blob/main/.github/workflows/tests.yml)
154//! that the NASM objects newly built from source match the NASM objects currently in the repository.
155//!
156//! # *ring*-compatibility
157//!
158//! Although this library attempts to be fully compatible with *ring* (v0.16.x), there are a few places where our
159//! behavior is observably different.
160//!
161//! * Our implementation requires the `std` library. We currently do not support a
162//!   [`#![no_std]`](https://docs.rust-embedded.org/book/intro/no-std.html) build.
163//! * `aws-lc-rs` supports the platforms supported by `aws-lc-sys` and AWS-LC. See the
164//!   [Platform Support](https://aws.github.io/aws-lc-rs/platform_support.html) page in our User Guide.
165//! * `Ed25519KeyPair::from_pkcs8` and `Ed25519KeyPair::from_pkcs8_maybe_unchecked` both support
166//!   parsing of v1 or v2 PKCS#8 documents. If a v2 encoded key is provided to either function,
167//!   public key component, if present, will be verified to match the one derived from the encoded
168//!   private key.
169//!
170//! # Post-Quantum Cryptography
171//!
172//! Details on the post-quantum algorithms supported by aws-lc-rs can be found at
173//! [PQREADME](https://github.com/aws/aws-lc/tree/main/crypto/fipsmodule/PQREADME.md).
174//!
175//! # Motivation
176//!
177//! Rust developers increasingly need to deploy applications that meet US and Canadian government
178//! cryptographic requirements. We evaluated how to deliver FIPS validated cryptography in idiomatic
179//! and performant Rust, built around our AWS-LC offering. We found that the popular ring (v0.16)
180//! library fulfilled much of the cryptographic needs in the Rust community, but it did not meet the
181//! needs of developers with FIPS requirements. Our intention is to contribute a drop-in replacement
182//! for ring that provides FIPS support and is compatible with the ring API. Rust developers with
183//! prescribed cryptographic requirements can seamlessly integrate aws-lc-rs into their applications
184//! and deploy them into AWS Regions.
185
186#![warn(missing_docs)]
187#![warn(clippy::exhaustive_enums)]
188#![cfg_attr(aws_lc_rs_docsrs, feature(doc_cfg))]
189
190extern crate alloc;
191#[cfg(feature = "fips")]
192extern crate aws_lc_fips_sys as aws_lc;
193#[cfg(not(feature = "fips"))]
194extern crate aws_lc_sys as aws_lc;
195
196pub mod aead;
197pub mod agreement;
198pub mod cmac;
199pub mod constant_time;
200pub mod digest;
201pub mod error;
202pub mod hkdf;
203pub mod hmac;
204#[cfg(feature = "ring-io")]
205pub mod io;
206pub mod key_wrap;
207pub mod pbkdf2;
208pub mod pkcs8;
209pub mod rand;
210pub mod signature;
211pub mod test;
212
213mod bn;
214mod buffer;
215mod cbb;
216mod cbs;
217pub mod cipher;
218mod debug;
219mod ec;
220mod ed25519;
221pub mod encoding;
222mod endian;
223mod evp_pkey;
224mod fips;
225mod hex;
226pub mod iv;
227pub mod kdf;
228#[allow(clippy::module_name_repetitions)]
229pub mod kem;
230#[cfg(all(feature = "unstable", not(feature = "fips")))]
231mod pqdsa;
232mod ptr;
233pub mod rsa;
234pub mod tls_prf;
235pub mod unstable;
236
237pub(crate) use debug::derive_debug_via_id;
238// TODO: Uncomment when MSRV >= 1.64
239// use core::ffi::CStr;
240use std::ffi::CStr;
241
242use crate::aws_lc::{
243    CRYPTO_library_init, ERR_error_string, ERR_get_error, FIPS_mode, ERR_GET_FUNC, ERR_GET_LIB,
244    ERR_GET_REASON,
245};
246use std::sync::Once;
247
248static START: Once = Once::new();
249
250#[inline]
251/// Initialize the *AWS-LC* library. (This should generally not be needed.)
252pub fn init() {
253    START.call_once(|| unsafe {
254        CRYPTO_library_init();
255    });
256}
257
258#[cfg(feature = "fips")]
259/// Panics if the underlying implementation is not FIPS, otherwise it returns.
260///
261/// # Panics
262/// Panics if the underlying implementation is not FIPS.
263pub fn fips_mode() {
264    try_fips_mode().unwrap();
265}
266
267/// Indicates whether the underlying implementation is FIPS.
268///
269/// # Errors
270/// Return an error if the underlying implementation is not FIPS, otherwise Ok.
271pub fn try_fips_mode() -> Result<(), &'static str> {
272    init();
273    match unsafe { FIPS_mode() } {
274        1 => Ok(()),
275        _ => Err("FIPS mode not enabled!"),
276    }
277}
278
279#[cfg(feature = "fips")]
280/// Panics if the underlying implementation is not using CPU jitter entropy, otherwise it returns.
281///
282/// # Panics
283/// Panics if the underlying implementation is not using CPU jitter entropy.
284pub fn fips_cpu_jitter_entropy() {
285    try_fips_cpu_jitter_entropy().unwrap();
286}
287
288/// Indicates whether the underlying implementation is FIPS.
289///
290/// # Errors
291/// Return an error if the underlying implementation is not using CPU jitter entropy, otherwise Ok.
292pub fn try_fips_cpu_jitter_entropy() -> Result<(), &'static str> {
293    init();
294    // TODO: Delete once FIPS_is_entropy_cpu_jitter() available on FIPS branch
295    // https://github.com/aws/aws-lc/pull/2088
296    #[cfg(feature = "fips")]
297    if aws_lc::CFG_CPU_JITTER_ENTROPY() {
298        Ok(())
299    } else {
300        Err("FIPS CPU Jitter Entropy not enabled!")
301    }
302    #[cfg(not(feature = "fips"))]
303    match unsafe { aws_lc::FIPS_is_entropy_cpu_jitter() } {
304        1 => Ok(()),
305        _ => Err("FIPS CPU Jitter Entropy not enabled!"),
306    }
307}
308
309#[allow(dead_code)]
310unsafe fn dump_error() {
311    let err = ERR_get_error();
312    let lib = ERR_GET_LIB(err);
313    let reason = ERR_GET_REASON(err);
314    let func = ERR_GET_FUNC(err);
315    let mut buffer = [0u8; 256];
316    ERR_error_string(err, buffer.as_mut_ptr().cast());
317    let error_msg = CStr::from_bytes_with_nul_unchecked(&buffer);
318    eprintln!("Raw Error -- {error_msg:?}\nErr: {err}, Lib: {lib}, Reason: {reason}, Func: {func}");
319}
320
321mod sealed {
322    /// Traits that are designed to only be implemented internally in *aws-lc-rs*.
323    //
324    // Usage:
325    // ```
326    // use crate::sealed;
327    //
328    // pub trait MyType: sealed::Sealed {
329    //     // [...]
330    // }
331    //
332    // impl sealed::Sealed for MyType {}
333    // ```
334    pub trait Sealed {}
335}
336
337#[cfg(test)]
338mod tests {
339    use crate::{dump_error, init};
340
341    #[test]
342    fn test_init() {
343        init();
344    }
345
346    #[test]
347    fn test_dump() {
348        unsafe {
349            dump_error();
350        }
351    }
352
353    #[cfg(not(feature = "fips"))]
354    #[test]
355    fn test_fips() {
356        assert!({ crate::try_fips_mode().is_err() });
357        // Re-enable with fixed test after upstream has merged RAGDOLL
358        //assert!({ crate::try_fips_cpu_jitter_entropy().is_ok() });
359    }
360
361    #[test]
362    // FIPS mode is disabled for an ASAN build
363    #[cfg(feature = "fips")]
364    fn test_fips() {
365        #[cfg(not(feature = "asan"))]
366        crate::fips_mode();
367        if aws_lc::CFG_CPU_JITTER_ENTROPY() {
368            crate::fips_cpu_jitter_entropy();
369        }
370    }
371}