Skip to content

Commit a4fab51

Browse files
committed
Build against openssl-sys low-level bindings
Linking applications against different bindings to the same library (openssl) is undefined behavior in rust ecosystem. This is removing the low-level bindings and bindgen dependency, delefating this to the openssl-sys crate providing all the low-level functions. Unfortunately, it does not expose all the constants and defines, that need to be defined manually. The direct static linking to libfips is preserved. Signed-off-by: Jakub Jelen <jjelen@redhat.com>
1 parent b7a9aee commit a4fab51

14 files changed

Lines changed: 305 additions & 89 deletions

File tree

.github/workflows/rpm.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
'crate(num-integer/default)' 'crate(num-traits/default)' \
5757
'crate(pkg-config/default)' 'crate(rusqlite/default)' \
5858
'crate(serde/default)' 'crate(serde/derive)' 'crate(serde_json/default)' \
59-
'crate(serial_test/default)' \
59+
'crate(serial_test/default)' '(crate(itertools/default)' '(crate(openssl-sys/bindgen)' \
6060
'crate(toml)' 'crate(toml/display)' 'crate(toml/parse)' 'crate(toml/serde)' \
6161
'crate(uuid/default)' 'crate(uuid/v4)' 'crate(uuid/v8)' 'crate(cryptoki/default)' \
6262
'crate(vsprintf/default)' 'crate(quick-xml/default)' 'crate(quick-xml/serialize)'

ossl/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[package]
22
name = "ossl"
3-
links = "openssl"
43
version.workspace = true
54
edition.workspace = true
65
description = "OpenSSL version 3+ bindings to modern EVP APIs"
@@ -12,14 +11,15 @@ license = "Apache-2.0"
1211
test = true
1312

1413
[build-dependencies]
15-
bindgen = "0.72"
14+
bindgen = { version = "0.72", optional = true}
1615
pkg-config = "0.3"
1716

1817
[dependencies]
1918
cfg-if = "1.0.0"
2019
libc = "0.2.151"
2120
log = { version = "0.4.27", default-features = false, features = ["std"], optional = true }
2221
vsprintf = { version = "2.0.0", optional = true }
22+
openssl-sys = { version = "0.9.117", features = ["bindgen"], optional = true }
2323

2424
[dev-dependencies]
2525
hex = "0.4.3"
@@ -29,8 +29,8 @@ serial_test = "3.1.1"
2929
ossl320 = [] # Requires at a minimum OpenSSL 3.2.0
3030
ossl350 = [] # Requires at a minimum OpenSSL 3.5.0
3131
ossl400 = [] # Requires at minimum OpenSSL 4.0
32-
dynamic = [] # Builds against system libcrypto.so
33-
fips = ["ossl350"] # Builds against sources and libfips.a instead of libcrypto
32+
dynamic = ["dep:openssl-sys"] # Builds against system libcrypto.so
33+
fips = ["ossl350", "dep:bindgen"] # Builds against sources and libfips.a instead of libcrypto
3434
log = ["dep:log", "dep:vsprintf"] # Error tracing using log crate
3535
rfc9580 = [] # Enables features required for OpenPGP implementations
3636

ossl/build.rs

Lines changed: 66 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use std::env;
55
use std::panic::set_hook;
6+
#[cfg(not(feature = "dynamic"))]
67
use std::path::{Path, PathBuf};
78

89
#[derive(Debug)]
@@ -12,68 +13,63 @@ const OPENSSL_3_2_0: i64 = 0x30200000;
1213
const OPENSSL_3_5_0: i64 = 0x30500000;
1314
const OPENSSL_4_0_0: i64 = 0x40000000;
1415

16+
fn check_ossl_version(version: i64) {
17+
if version < OPENSSL_4_0_0 {
18+
#[cfg(feature = "ossl400")]
19+
panic!("OpenSSL 4.0.0 or later is required");
20+
}
21+
if version < OPENSSL_3_5_0 {
22+
#[cfg(feature = "ossl350")]
23+
panic!("OpenSSL 3.5.0 or later is required");
24+
}
25+
if version < OPENSSL_3_2_0 {
26+
#[cfg(feature = "ossl320")]
27+
panic!("OpenSSL 3.2.0 or later is required");
28+
}
29+
if version < OPENSSL_3_0_7 {
30+
panic!(
31+
"OpenSSL 3.0.7 is the minimum viable version. Found {:x}",
32+
version
33+
);
34+
}
35+
/* Emit versions we found, versions stack, so code
36+
* just need to build conditionalized just to the older version
37+
* that introduced the desired feature */
38+
println!("cargo::rustc-cfg=ossl_v307");
39+
if version >= OPENSSL_3_2_0 {
40+
println!("cargo::rustc-cfg=ossl_v320");
41+
}
42+
if version >= OPENSSL_3_5_0 {
43+
println!("cargo::rustc-cfg=ossl_v350");
44+
}
45+
if version >= OPENSSL_4_0_0 {
46+
println!("cargo::rustc-cfg=ossl_v400");
47+
}
48+
}
49+
50+
#[cfg(not(feature = "dynamic"))]
1551
impl bindgen::callbacks::ParseCallbacks for OsslCallbacks {
1652
fn int_macro(
1753
&self,
1854
name: &str,
1955
value: i64,
2056
) -> Option<bindgen::callbacks::IntKind> {
2157
if name == "OPENSSL_VERSION_NUMBER" {
22-
if value < OPENSSL_4_0_0 {
23-
#[cfg(feature = "ossl400")]
24-
panic!("OpenSSL 4.0.0 or later is required");
25-
}
26-
if value < OPENSSL_3_5_0 {
27-
#[cfg(feature = "ossl350")]
28-
panic!("OpenSSL 3.5.0 or later is required");
29-
}
30-
if value < OPENSSL_3_2_0 {
31-
#[cfg(feature = "ossl320")]
32-
panic!("OpenSSL 3.2.0 or later is required");
33-
}
34-
if value < OPENSSL_3_0_7 {
35-
panic!(
36-
"OpenSSL 3.0.7 is the minimum viable version. Found {:x}",
37-
value
38-
);
39-
}
40-
/* Emit versions we found, versions stack, so code
41-
* just need to build conditionalized just to the older version
42-
* that introduced the desired feature */
43-
println!("cargo::rustc-cfg=ossl_v307");
44-
if value >= OPENSSL_3_2_0 {
45-
println!("cargo::rustc-cfg=ossl_v320");
46-
}
47-
if value >= OPENSSL_3_5_0 {
48-
println!("cargo::rustc-cfg=ossl_v350");
49-
}
50-
if value >= OPENSSL_4_0_0 {
51-
println!("cargo::rustc-cfg=ossl_v400");
52-
}
58+
check_ossl_version(value);
5359
}
5460

5561
None
5662
}
5763

58-
fn str_macro(&self, name: &str, _value: &[u8]) {
59-
if name == "OSSL_PKEY_PARAM_SLH_DSA_SEED" {
60-
println!("cargo::rustc-cfg=ossl_slhdsa")
61-
}
62-
if name == "OSSL_PKEY_PARAM_ML_DSA_SEED" {
63-
println!("cargo::rustc-cfg=ossl_mldsa")
64-
}
65-
if name == "OSSL_PKEY_PARAM_ML_KEM_SEED" {
66-
println!("cargo::rustc-cfg=ossl_mlkem")
67-
}
68-
}
69-
64+
// FIXME for openssl-sys
7065
fn func_macro(&self, name: &str, _value: &[&[u8]]) {
7166
if name == "OSSL_PARAM_clear_free" {
7267
println!("cargo::rustc-cfg=param_clear_free")
7368
}
7469
}
7570
}
7671

72+
#[cfg(not(feature = "dynamic"))]
7773
fn ossl_bindings(args: &mut Vec<String>, out_file: &Path) {
7874
if let Some(var) = env::var("OSSL_BINDGEN_CLANG_ARGS").ok() {
7975
for arg in var.split_whitespace() {
@@ -108,6 +104,7 @@ fn ossl_bindings(args: &mut Vec<String>, out_file: &Path) {
108104
.expect("Couldn't write bindings!");
109105
}
110106

107+
#[cfg(not(feature = "dynamic"))]
111108
fn build_ossl(out_file: &Path) {
112109
let sources = std::env::var("KRYOPTIC_OPENSSL_SOURCES")
113110
.expect("Env var KRYOPTIC_OPENSSL_SOURCES is not defined");
@@ -281,19 +278,19 @@ fn build_ossl(out_file: &Path) {
281278
ossl_bindings(&mut args, out_file);
282279
}
283280

284-
fn use_system_ossl(out_file: &Path) {
285-
let library = pkg_config::Config::new()
286-
.atleast_version("3.0.7")
287-
.probe("openssl")
288-
.unwrap();
289-
290-
let mut args: Vec<String> = Vec::new();
291-
for include_path in library.include_paths {
292-
args.push(["-I", include_path.to_str().unwrap()].concat());
293-
}
294-
295-
ossl_bindings(&mut args, out_file);
296-
}
281+
//fn use_system_ossl(out_file: &Path) {
282+
// let library = pkg_config::Config::new()
283+
// .atleast_version("3.0.7")
284+
// .probe("openssl")
285+
// .unwrap();
286+
//
287+
// let mut args: Vec<String> = Vec::new();
288+
// for include_path in library.include_paths {
289+
// args.push(["-I", include_path.to_str().unwrap()].concat());
290+
// }
291+
//
292+
// ossl_bindings(&mut args, out_file);
293+
//}
297294

298295
fn set_pretty_panic() {
299296
set_hook(Box::new(|panic_info| {
@@ -322,20 +319,26 @@ fn set_pretty_panic() {
322319
fn main() {
323320
set_pretty_panic();
324321

325-
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
326-
let ossl_bindings = out_path.join("ossl_bindings.rs");
327-
328322
/* Always emit known configs */
329323
println!(
330-
"cargo::rustc-check-cfg=cfg(ossl_v307,ossl_v320,ossl_v350,ossl_v400,ossl_mldsa,ossl_mlkem,ossl_slhdsa,param_clear_free)"
324+
"cargo::rustc-check-cfg=cfg(ossl_v307,ossl_v320,ossl_v350,ossl_v400,param_clear_free)"
331325
);
332326

333327
/* OpenSSL Cryptography */
334-
if cfg!(feature = "dynamic") {
335-
use_system_ossl(&ossl_bindings);
336-
} else {
328+
#[cfg(not(feature = "dynamic"))]
329+
{
330+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
331+
let ossl_bindings = out_path.join("ossl_bindings.rs");
337332
build_ossl(&ossl_bindings);
338333
}
339334

335+
#[cfg(feature = "dynamic")]
336+
if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") {
337+
let version = i64::from_str_radix(&v, 16).unwrap();
338+
check_ossl_version(version);
339+
// Proxy it also to the code for the api_level() API
340+
println!("cargo:rustc-env=DEP_OPENSSL_VERSION_NUMBER={}", version);
341+
}
342+
340343
println!("cargo:rerun-if-changed=build.rs");
341344
}

ossl/src/asymcipher.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::bindings::*;
88
use crate::digest::{digest_to_string, DigestAlg};
99
use crate::pkey::{EvpPkey, EvpPkeyCtx};
1010
use crate::{cstr, trace_ossl, Error, ErrorKind, OsslContext, OsslParam};
11+
#[cfg(feature = "dynamic")]
12+
use openssl_sys::*;
1113

1214
/// Known algorithms selectable for OsslAsymcipher
1315
#[derive(Clone, Copy, Debug, PartialEq)]

ossl/src/cipher.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crate::{
1111
cstr, trace_ossl, Error, ErrorKind, OsslContext, OsslParam,
1212
OsslParamBuilder, OsslSecret,
1313
};
14+
#[cfg(feature = "dynamic")]
15+
use openssl_sys::*;
1416

1517
/// Wrapper around OpenSSL's `EVP_CIPHER`, managing its lifecycle.
1618
#[derive(Debug)]

ossl/src/derive.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use crate::{
1414
cstr, trace_ossl, Error, ErrorKind, OsslContext, OsslParam,
1515
OsslParamBuilder,
1616
};
17+
#[cfg(feature = "dynamic")]
18+
use openssl_sys::*;
1719

1820
/// Wrapper around OpenSSL's `EVP_KDF_CTX`, managing its lifecycle.
1921
#[derive(Debug)]

ossl/src/digest.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use std::ffi::{c_uint, c_void, CStr};
77

88
use crate::bindings::*;
9+
#[cfg(feature = "dynamic")]
10+
use openssl_sys::*;
911

1012
use crate::{cstr, trace_ossl, Error, ErrorKind, OsslContext, OsslParam};
1113

ossl/src/fips.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crate::bindings::*;
1111
use crate::pkey::EvpPkey;
1212
use crate::signature::SigAlg;
1313
use crate::{Error, ErrorKind, OsslContext};
14+
#[cfg(feature = "dynamic")]
15+
use openssl_sys::*;
1416

1517
pub fn set_error_state() {
1618
unsafe {

ossl/src/lib.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
/// Part of this module is automatically generated by bindgen from the OpenSSL
99
/// Headers and includes a selection of functions and other items needed to
1010
/// access the libcrypto/libfips functions needed.
11+
#[cfg(not(feature = "dynamic"))]
1112
pub mod bindings {
1213
#![allow(non_upper_case_globals)]
1314
#![allow(non_camel_case_types)]
@@ -16,11 +17,19 @@ pub mod bindings {
1617
#![allow(unnecessary_transmutes)]
1718
include!(concat!(env!("OUT_DIR"), "/ossl_bindings.rs"));
1819
}
20+
#[cfg(feature = "dynamic")]
21+
pub mod bindings {
22+
#![allow(non_upper_case_globals)]
23+
include!("missing_ossl_bindings.rs");
24+
}
1925

2026
use std::borrow::Cow;
2127
use std::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, CStr};
2228

29+
#[allow(unused_imports)]
2330
use crate::bindings::*;
31+
#[cfg(feature = "dynamic")]
32+
use openssl_sys::*;
2433

2534
pub mod asymcipher;
2635
pub mod cipher;
@@ -34,6 +43,8 @@ pub mod signature;
3443
#[cfg(feature = "fips")]
3544
pub mod fips;
3645

46+
pub const OSSL_PARAM_UTF8_STRING: u32 = 4;
47+
3748
/// Export the API level of the OpenSSL library these bindings
3849
/// were built against. This should be used only when probing
3950
/// for behavior is difficult as it is only a proxy for what was
@@ -43,10 +54,24 @@ pub mod fips;
4354
/// This returns a triplet of u8 values representing Major, Minor, and
4455
/// Patch version.
4556
pub fn api_level() -> (u8, u8, u8) {
46-
let patch: u8 = (OPENSSL_API_LEVEL & 0xff) as u8;
47-
let minor: u8 = ((OPENSSL_API_LEVEL & 0xff00) >> 8) as u8;
48-
let major: u8 = ((OPENSSL_API_LEVEL & 0xff0000) >> 16) as u8;
49-
(major, minor, patch)
57+
#[cfg(not(feature = "dynamic"))]
58+
{
59+
let patch: u8 = (OPENSSL_API_LEVEL & 0xff) as u8;
60+
let minor: u8 = ((OPENSSL_API_LEVEL & 0xff00) >> 8) as u8;
61+
let major: u8 = ((OPENSSL_API_LEVEL & 0xff0000) >> 16) as u8;
62+
return (major, minor, patch);
63+
}
64+
65+
#[cfg(feature = "dynamic")]
66+
{
67+
let v = env!("DEP_OPENSSL_VERSION_NUMBER");
68+
let version = u64::from_str_radix(&v, 16).unwrap();
69+
70+
let patch: u8 = (version & 0xff) as u8;
71+
let minor: u8 = ((version & 0xff00) >> 8) as u8;
72+
let major: u8 = ((version & 0xff0000) >> 16) as u8;
73+
(major, minor, patch)
74+
}
5075
}
5176

5277
/// Securely zeroizes a memory slice using `OPENSSL_cleanse`.

ossl/src/mac.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crate::{
1111
cstr, trace_ossl, Error, ErrorKind, OsslContext, OsslParamBuilder,
1212
OsslSecret,
1313
};
14+
#[cfg(feature = "dynamic")]
15+
use openssl_sys::*;
1416

1517
/// Wrapper around OpenSSL's `EVP_MAC_CTX`, managing its lifecycle.
1618
#[derive(Debug)]

0 commit comments

Comments
 (0)