Skip to main content

boring/
lib.rs

1//! Bindings to BoringSSL
2//!
3//! This crate provides a safe interface to the BoringSSL cryptography library.
4//!
5//! # Versioning
6//!
7//! ## Crate versioning
8//!
9//! The crate and all the related crates (FFI bindings, etc.) are released simultaneously and all
10//! bumped to the same version disregard whether particular crate has any API changes or not.
11//! However, semantic versioning guarantees still hold, as all the crate versions will be updated
12//! based on the crate with most significant changes.
13//!
14//! ## BoringSSL version
15//!
16//! By default, the crate aims to statically link with the latest BoringSSL master branch.
17//! *Note*: any BoringSSL revision bumps will be released as a major version update of all crates.
18//!
19//! # Compilation and linking options
20//!
21//! ## Environment variables
22//!
23//! This crate uses various environment variables to tweak how boring is built. The variables
24//! are all prefixed by `BORING_BSSL_` for non-FIPS builds, and by `BORING_BSSL_FIPS_` for FIPS builds.
25//!
26//! ## Support for pre-built binaries or custom source
27//!
28//! While this crate can build BoringSSL on its own, you may want to provide pre-built binaries instead.
29//! To do so, specify the environment variable `BORING_BSSL{,_FIPS}_PATH` with the path to the binaries.
30//!
31//! You can also provide specific headers by setting `BORING_BSSL{,_FIPS}_INCLUDE_PATH`.
32//!
33//! _Notes_: The crate will look for headers in the`$BORING_BSSL{,_FIPS}_INCLUDE_PATH/openssl/`
34//! folder, make sure to place your headers there.
35//!
36//! In alternative a different path for the BoringSSL source code directory can be specified by setting
37//! `BORING_BSSL{,_FIPS}_SOURCE_PATH` which will automatically be compiled during the build process.
38//!
39//! _Warning_: When providing a different version of BoringSSL make sure to use a compatible one, the
40//! crate relies on the presence of certain functions.
41//!
42//! ## Building with a FIPS-validated module
43//!
44//! Only BoringCrypto module version `853ca1ea1168dff08011e5d42d94609cc0ca2e27`, as certified with
45//! [FIPS 140-2 certificate 4407](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4407)
46//! is supported by this crate. Support is enabled by this crate's `fips` feature.
47//!
48//! `boring-sys` comes with a test that FIPS is enabled/disabled depending on the feature flag. You can run it as follows:
49//!
50//! ```bash
51//! $ cargo test --features fips fips::is_enabled
52//! ```
53//!
54//! ## Linking current BoringSSL version with precompiled FIPS-validated module (`bcm.o`)
55//!
56//! It's possible to link latest supported version of BoringSSL with FIPS-validated crypto module
57//! (`bcm.o`). To enable this compilation option one should enable `fips-link-precompiled`
58//! compilation feature and provide a `BORING_BSSL_FIPS_PRECOMPILED_BCM_O` env variable with a path to the
59//! precompiled FIPS-validated `bcm.o` module.
60//!
61//! Note that `BORING_BSSL_PRECOMPILED_BCM_O` is never used, as linking BoringSSL with precompiled non-FIPS
62//! module is not supported.
63//!
64//! ## Linking with a C++ standard library
65//!
66//! Recent versions of boringssl require some C++ standard library features, so boring needs to link
67//! with a STL implementation. This can be controlled using the BORING_BSSL_RUST_CPPLIB variable. If
68//! no library is specified, libc++ is used on macOS and iOS whereas libstdc++ is used on other Unix
69//! systems.
70//!
71//! # Optional patches
72//!
73//! ## Raw Public Key
74//!
75//! The crate can be compiled with [RawPublicKey](https://datatracker.ietf.org/doc/html/rfc7250)
76//! support by turning on `rpk` compilation feature.
77//!
78//! ## Experimental post-quantum cryptography
79//!
80//! The crate can be compiled with [post-quantum cryptography](https://blog.cloudflare.com/post-quantum-for-all/)
81//! support by turning on `post-quantum` compilation feature.
82//!
83//! Upstream BoringSSL support the post-quantum hybrid key agreement `X25519Kyber768Draft00`. Most
84//! users should stick to that one for now. Enabling this feature, adds a few other post-quantum key
85//! agreements:
86//!
87//! - `X25519MLKEM768` is the successor of `X25519Kyber768Draft00`. We expect servers to switch
88//!   before the end of 2024.
89//! - `X25519Kyber768Draft00Old` is the same as `X25519Kyber768Draft00`, but under its old codepoint.
90//! - `X25519Kyber512Draft00`. Similar to `X25519Kyber768Draft00`, but uses level 1 parameter set for
91//!   Kyber. Not recommended. It's useful to test whether the shorter ClientHello upsets fewer middle
92//!   boxes.
93//! - `P256Kyber768Draft00`. Similar again to `X25519Kyber768Draft00`, but uses P256 as classical
94//!   part. It uses a non-standard codepoint. Not recommended.
95//!
96//! Presently all these key agreements are deployed by Cloudflare, but we do not guarantee continued
97//! support for them.
98
99#[macro_use]
100extern crate bitflags;
101#[macro_use]
102extern crate foreign_types;
103extern crate boring_sys as ffi;
104extern crate libc;
105
106#[cfg(test)]
107extern crate hex;
108
109use std::ffi::{c_int, c_long, c_void};
110use std::num::NonZeroUsize;
111
112#[doc(inline)]
113pub use crate::ffi::init;
114
115use crate::error::ErrorStack;
116
117#[macro_use]
118mod macros;
119
120mod bio;
121#[macro_use]
122mod util;
123pub mod aead;
124pub mod aes;
125pub mod asn1;
126pub mod base64;
127pub mod bn;
128pub mod conf;
129pub mod derive;
130pub mod dh;
131pub mod dsa;
132pub mod ec;
133pub mod ecdsa;
134pub mod error;
135pub mod ex_data;
136pub mod fips;
137pub mod hash;
138pub mod hmac;
139pub mod hpke;
140pub mod memcmp;
141#[cfg(feature = "mlkem")]
142pub mod mlkem;
143pub mod nid;
144pub mod pkcs12;
145pub mod pkcs5;
146pub mod pkey;
147#[cfg(feature = "prf")]
148pub mod prf;
149pub mod rand;
150pub mod rsa;
151pub mod sha;
152pub mod sign;
153pub mod srtp;
154pub mod ssl;
155pub mod stack;
156pub mod string;
157pub mod symm;
158pub mod version;
159pub mod x509;
160
161fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
162    if r.is_null() {
163        Err(ErrorStack::get())
164    } else {
165        Ok(r)
166    }
167}
168
169fn cvt_0(r: usize) -> Result<(), ErrorStack> {
170    if r == 0 {
171        Err(ErrorStack::get())
172    } else {
173        Ok(())
174    }
175}
176
177fn cvt_0i(r: c_int) -> Result<c_int, ErrorStack> {
178    if r == 0 {
179        Err(ErrorStack::get())
180    } else {
181        Ok(r)
182    }
183}
184
185fn cvt(r: c_int) -> Result<(), ErrorStack> {
186    if r <= 0 {
187        Err(ErrorStack::get())
188    } else {
189        Ok(())
190    }
191}
192
193fn cvt_nz(r: c_int) -> Result<NonZeroUsize, ErrorStack> {
194    usize::try_from(r)
195        .ok()
196        .and_then(NonZeroUsize::new)
197        .ok_or_else(ErrorStack::get)
198}
199
200fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
201    if r < 0 {
202        Err(ErrorStack::get())
203    } else {
204        Ok(r)
205    }
206}
207
208fn try_int<F, T>(from: F) -> Result<T, ErrorStack>
209where
210    F: TryInto<T> + Send + Sync + Copy + 'static,
211    T: Send + Sync + Copy + 'static,
212{
213    from.try_into()
214        .map_err(|_| ErrorStack::internal_error_str("int overflow"))
215}
216
217unsafe extern "C" fn free_data_box<T>(
218    _parent: *mut c_void,
219    ptr: *mut c_void,
220    _ad: *mut ffi::CRYPTO_EX_DATA,
221    _idx: c_int,
222    _argl: c_long,
223    _argp: *mut c_void,
224) {
225    if !ptr.is_null() {
226        drop(Box::<T>::from_raw(ptr.cast::<T>()));
227    }
228}