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