1 //! Bindings to OpenSSL
2 //!
3 //! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through
4 //! 3.x.x and LibreSSL versions 2.5 through 3.7.x are supported.
5 //!
6 //! # Building
7 //!
8 //! Both OpenSSL libraries and headers are required to build this crate. There are multiple options available to locate
9 //! OpenSSL.
10 //!
11 //! ## Vendored
12 //!
13 //! If the `vendored` Cargo feature is enabled, the `openssl-src` crate will be used to compile and statically link to
14 //! a copy of OpenSSL. The build process requires a C compiler, perl (and perl-core), and make. The OpenSSL version will generally track
15 //! the newest OpenSSL release, and changes to the version are *not* considered breaking changes.
16 //!
17 //! ```toml
18 //! [dependencies]
19 //! openssl = { version = "0.10", features = ["vendored"] }
20 //! ```
21 //!
22 //! The vendored copy will not be configured to automatically find the system's root certificates, but the
23 //! `openssl-probe` crate can be used to do that instead.
24 //!
25 //! ## Automatic
26 //!
27 //! The `openssl-sys` crate will automatically detect OpenSSL installations via Homebrew on macOS and vcpkg on Windows.
28 //! Additionally, it will use `pkg-config` on Unix-like systems to find the system installation.
29 //!
30 //! ```not_rust
31 //! # macOS (Homebrew)
32 //! $ brew install openssl@3
33 //!
34 //! # macOS (MacPorts)
35 //! $ sudo port install openssl
36 //!
37 //! # macOS (pkgsrc)
38 //! $ sudo pkgin install openssl
39 //!
40 //! # Arch Linux
41 //! $ sudo pacman -S pkg-config openssl
42 //!
43 //! # Debian and Ubuntu
44 //! $ sudo apt-get install pkg-config libssl-dev
45 //!
46 //! # Fedora
47 //! $ sudo dnf install pkg-config perl-FindBin openssl-devel
48 //!
49 //! # Alpine Linux
50 //! $ apk add pkgconfig openssl-dev
51 //!
52 //! # openSUSE
53 //! $ sudo zypper in libopenssl-devel
54 //! ```
55 //!
56 //! ## Manual
57 //!
58 //! A set of environment variables can be used to point `openssl-sys` towards an OpenSSL installation. They will
59 //! override the automatic detection logic.
60 //!
61 //! * `OPENSSL_DIR` - If specified, the directory of an OpenSSL installation. The directory should contain `lib` and
62 //! `include` subdirectories containing the libraries and headers respectively.
63 //! * `OPENSSL_LIB_DIR` and `OPENSSL_INCLUDE_DIR` - If specified, the directories containing the OpenSSL libraries and
64 //! headers respectively. This can be used if the OpenSSL installation is split in a nonstandard directory layout.
65 //! * `OPENSSL_STATIC` - If set, the crate will statically link to OpenSSL rather than dynamically link.
66 //! * `OPENSSL_LIBS` - If set, a `:`-separated list of library names to link to (e.g. `ssl:crypto`). This can be used
67 //! if nonstandard library names were used for whatever reason.
68 //! * `OPENSSL_NO_VENDOR` - If set, always find OpenSSL in the system, even if the `vendored` feature is enabled.
69 //!
70 //! Additionally, these variables can be prefixed with the upper-cased target architecture (e.g.
71 //! `X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR`), which can be useful when cross compiling.
72 //!
73 //! # Feature Detection
74 //!
75 //! APIs have been added to and removed from the various supported OpenSSL versions, and this library exposes the
76 //! functionality available in the version being linked against. This means that methods, constants, and even modules
77 //! will be present when building against one version of OpenSSL but not when building against another! APIs will
78 //! document any version-specific availability restrictions.
79 //!
80 //! A build script can be used to detect the OpenSSL or LibreSSL version at compile time if needed. The `openssl-sys`
81 //! crate propagates the version via the `DEP_OPENSSL_VERSION_NUMBER` and `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER`
82 //! environment variables to build scripts. The version format is a hex-encoding of the OpenSSL release version:
83 //! `0xMNNFFPPS`. For example, version 1.0.2g's encoding is `0x1_00_02_07_0`.
84 //!
85 //! For example, let's say we want to adjust the TLSv1.3 cipher suites used by a client, but also want to compile
86 //! against OpenSSL versions that don't support TLSv1.3:
87 //!
88 //! Cargo.toml:
89 //!
90 //! ```toml
91 //! [dependencies]
92 //! openssl-sys = "0.9"
93 //! openssl = "0.10"
94 //! ```
95 //!
96 //! build.rs:
97 //!
98 //! ```
99 //! use std::env;
100 //!
101 //! fn main() {
102 //! if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") {
103 //! let version = u64::from_str_radix(&v, 16).unwrap();
104 //!
105 //! if version >= 0x1_01_01_00_0 {
106 //! println!("cargo:rustc-cfg=openssl111");
107 //! }
108 //! }
109 //! }
110 //! ```
111 //!
112 //! lib.rs:
113 //!
114 //! ```
115 //! use openssl::ssl::{SslConnector, SslMethod};
116 //!
117 //! let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap();
118 //!
119 //! // set_ciphersuites was added in OpenSSL 1.1.1, so we can only call it when linking against that version
120 //! #[cfg(openssl111)]
121 //! ctx.set_ciphersuites("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256").unwrap();
122 //! ```
123 #![doc(html_root_url = "https://docs.rs/openssl/0.10")]
124 #![warn(rust_2018_idioms)]
125 #![allow(clippy::uninlined_format_args, clippy::needless_doctest_main)]
126
127 #[cfg(all(soong, boringssl))]
128 extern crate bssl_sys as ffi;
129
130 #[doc(inline)]
131 pub use ffi::init;
132
133 use libc::c_int;
134 #[cfg(ossl300)]
135 use libc::c_long;
136
137 use crate::error::ErrorStack;
138
139 #[macro_use]
140 mod macros;
141
142 mod bio;
143 #[macro_use]
144 mod util;
145 pub mod aes;
146 pub mod asn1;
147 pub mod base64;
148 pub mod bn;
149 pub mod cipher;
150 pub mod cipher_ctx;
151 #[cfg(all(not(libressl), not(osslconf = "OPENSSL_NO_CMS"), not(boringssl)))]
152 pub mod cms;
153 pub mod conf;
154 pub mod derive;
155 pub mod dh;
156 pub mod dsa;
157 pub mod ec;
158 pub mod ecdsa;
159 pub mod encrypt;
160 #[cfg(not(boringssl))]
161 pub mod envelope;
162 pub mod error;
163 pub mod ex_data;
164 #[cfg(not(any(libressl, ossl300)))]
165 pub mod fips;
166 pub mod hash;
167 #[cfg(boringssl)]
168 pub mod hkdf;
169 #[cfg(boringssl)]
170 pub mod hmac;
171 #[cfg(ossl300)]
172 pub mod lib_ctx;
173 pub mod md;
174 pub mod md_ctx;
175 pub mod memcmp;
176 pub mod nid;
177 #[cfg(all(not(osslconf = "OPENSSL_NO_OCSP"), not(boringssl)))]
178 pub mod ocsp;
179 pub mod pkcs12;
180 pub mod pkcs5;
181 #[cfg(not(boringssl))]
182 pub mod pkcs7;
183 pub mod pkey;
184 pub mod pkey_ctx;
185 #[cfg(ossl300)]
186 pub mod provider;
187 pub mod rand;
188 pub mod rsa;
189 pub mod sha;
190 pub mod sign;
191 pub mod srtp;
192 pub mod ssl;
193 pub mod stack;
194 pub mod string;
195 pub mod symm;
196 pub mod version;
197 pub mod x509;
198
199 #[cfg(boringssl)]
200 type LenType = libc::size_t;
201 #[cfg(not(boringssl))]
202 type LenType = libc::c_int;
203
204 #[cfg(boringssl)]
205 type SLenType = libc::ssize_t;
206 #[cfg(not(boringssl))]
207 type SLenType = libc::c_int;
208
209 #[inline]
cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack>210 fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
211 if r.is_null() {
212 Err(ErrorStack::get())
213 } else {
214 Ok(r)
215 }
216 }
217
218 #[inline]
cvt_p_const<T>(r: *const T) -> Result<*const T, ErrorStack>219 fn cvt_p_const<T>(r: *const T) -> Result<*const T, ErrorStack> {
220 if r.is_null() {
221 Err(ErrorStack::get())
222 } else {
223 Ok(r)
224 }
225 }
226
227 #[inline]
cvt(r: c_int) -> Result<c_int, ErrorStack>228 fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
229 if r <= 0 {
230 Err(ErrorStack::get())
231 } else {
232 Ok(r)
233 }
234 }
235
236 // cvt_long is currently only used in functions that require openssl >= 3.0.0,
237 // so this cfg statement is used to avoid "unused function" errors when
238 // compiling with openssl < 3.0.0
239 #[inline]
240 #[cfg(ossl300)]
cvt_long(r: c_long) -> Result<c_long, ErrorStack>241 fn cvt_long(r: c_long) -> Result<c_long, ErrorStack> {
242 if r <= 0 {
243 Err(ErrorStack::get())
244 } else {
245 Ok(r)
246 }
247 }
248
249 #[inline]
cvt_n(r: c_int) -> Result<c_int, ErrorStack>250 fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
251 if r < 0 {
252 Err(ErrorStack::get())
253 } else {
254 Ok(r)
255 }
256 }
257