1 #[cfg(feature = "bindgen")]
2 use bindgen::callbacks::{MacroParsingBehavior, ParseCallbacks};
3 #[cfg(feature = "bindgen")]
4 use bindgen::{MacroTypeVariation, RustTarget};
5 use std::io::Write;
6 use std::path::PathBuf;
7 #[cfg(not(feature = "bindgen"))]
8 use std::process;
9 use std::{env, fs};
10
11 const INCLUDES: &str = "
12 #include <openssl/aes.h>
13 #include <openssl/asn1.h>
14 #include <openssl/bio.h>
15 #include <openssl/cmac.h>
16 #include <openssl/conf.h>
17 #include <openssl/crypto.h>
18 #include <openssl/dh.h>
19 #include <openssl/dsa.h>
20 #include <openssl/ec.h>
21 #include <openssl/err.h>
22 #include <openssl/evp.h>
23 #include <openssl/hmac.h>
24 #include <openssl/objects.h>
25 #include <openssl/opensslv.h>
26 #include <openssl/pem.h>
27 #include <openssl/pkcs12.h>
28 #include <openssl/pkcs7.h>
29 #include <openssl/rand.h>
30 #include <openssl/rsa.h>
31 #include <openssl/safestack.h>
32 #include <openssl/sha.h>
33 #include <openssl/ssl.h>
34 #include <openssl/stack.h>
35 #include <openssl/x509.h>
36 #include <openssl/x509_vfy.h>
37 #include <openssl/x509v3.h>
38
39 // this must be included after ssl.h for libressl!
40 #include <openssl/srtp.h>
41
42 #if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
43 #include <openssl/cms.h>
44 #endif
45
46 #if !defined(OPENSSL_IS_BORINGSSL)
47 #include <openssl/comp.h>
48 #include <openssl/ocsp.h>
49 #endif
50
51 #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
52 #include <openssl/kdf.h>
53 #endif
54
55 #if OPENSSL_VERSION_NUMBER >= 0x30000000
56 #include <openssl/provider.h>
57 #endif
58
59 #if defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL)
60 #include <openssl/poly1305.h>
61 #endif
62 ";
63
64 #[cfg(feature = "bindgen")]
run(include_dirs: &[PathBuf])65 pub fn run(include_dirs: &[PathBuf]) {
66 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
67
68 let mut builder = bindgen::builder()
69 .parse_callbacks(Box::new(OpensslCallbacks))
70 .rust_target(RustTarget::Stable_1_47)
71 .ctypes_prefix("::libc")
72 .raw_line("use libc::*;")
73 .raw_line("type evp_pkey_st = EVP_PKEY;")
74 .allowlist_file(".*/openssl/[^/]+\\.h")
75 .allowlist_recursively(false)
76 // libc is missing pthread_once_t on macOS
77 .blocklist_type("CRYPTO_ONCE")
78 .blocklist_function("CRYPTO_THREAD_run_once")
79 // we don't want to mess with va_list
80 .blocklist_function("BIO_vprintf")
81 .blocklist_function("BIO_vsnprintf")
82 .blocklist_function("ERR_vset_error")
83 .blocklist_function("ERR_add_error_vdata")
84 .blocklist_function("EVP_KDF_vctrl")
85 .blocklist_type("OSSL_FUNC_core_vset_error_fn")
86 .blocklist_type("OSSL_FUNC_BIO_vprintf_fn")
87 .blocklist_type("OSSL_FUNC_BIO_vsnprintf_fn")
88 // Maintain compatibility for existing enum definitions
89 .rustified_enum("point_conversion_form_t")
90 // Maintain compatibility for pre-union definitions
91 .blocklist_type("GENERAL_NAME")
92 .blocklist_type("GENERAL_NAME_st")
93 .blocklist_type("EVP_PKEY")
94 .blocklist_type("evp_pkey_st")
95 .layout_tests(false)
96 .header_contents("includes.h", INCLUDES);
97
98 for include_dir in include_dirs {
99 builder = builder
100 .clang_arg("-I")
101 .clang_arg(include_dir.display().to_string());
102 }
103
104 builder
105 .generate()
106 .unwrap()
107 .write_to_file(out_dir.join("bindgen.rs"))
108 .unwrap();
109 }
110
111 #[cfg(feature = "bindgen")]
run_boringssl(include_dirs: &[PathBuf])112 pub fn run_boringssl(include_dirs: &[PathBuf]) {
113 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
114 let mut builder = bindgen::builder()
115 .rust_target(RustTarget::Stable_1_47)
116 .ctypes_prefix("::libc")
117 .raw_line("use libc::*;")
118 .derive_default(false)
119 .enable_function_attribute_detection()
120 .default_macro_constant_type(MacroTypeVariation::Signed)
121 .rustified_enum("point_conversion_form_t")
122 .allowlist_file(".*/openssl/[^/]+\\.h")
123 .allowlist_recursively(false)
124 .blocklist_function("BIO_vsnprintf")
125 .blocklist_function("OPENSSL_vasprintf")
126 .wrap_static_fns(true)
127 .wrap_static_fns_path(out_dir.join("boring_static_wrapper").display().to_string())
128 .layout_tests(false)
129 .header_contents("includes.h", INCLUDES);
130
131 for include_dir in include_dirs {
132 builder = builder
133 .clang_arg("-I")
134 .clang_arg(include_dir.display().to_string());
135 }
136
137 builder
138 .generate()
139 .unwrap()
140 .write_to_file(out_dir.join("bindgen.rs"))
141 .unwrap();
142
143 fs::File::create(out_dir.join("boring_static_wrapper.h"))
144 .expect("Failed to create boring_static_wrapper.h")
145 .write_all(INCLUDES.as_bytes())
146 .expect("Failed to write contents to boring_static_wrapper.h");
147
148 cc::Build::new()
149 .file(out_dir.join("boring_static_wrapper.c"))
150 .includes(include_dirs)
151 .flag("-include")
152 .flag(
153 &out_dir
154 .join("boring_static_wrapper.h")
155 .display()
156 .to_string(),
157 )
158 .compile("boring_static_wrapper");
159 }
160
161 #[cfg(not(feature = "bindgen"))]
run_boringssl(include_dirs: &[PathBuf])162 pub fn run_boringssl(include_dirs: &[PathBuf]) {
163 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
164
165 fs::File::create(out_dir.join("boring_static_wrapper.h"))
166 .expect("Failed to create boring_static_wrapper.h")
167 .write_all(INCLUDES.as_bytes())
168 .expect("Failed to write contents to boring_static_wrapper.h");
169
170 let mut bindgen_cmd = process::Command::new("bindgen");
171 bindgen_cmd
172 .arg("-o")
173 .arg(out_dir.join("bindgen.rs"))
174 // Must be a valid version from
175 // https://docs.rs/bindgen/latest/bindgen/enum.RustTarget.html
176 .arg("--rust-target=1.47")
177 .arg("--ctypes-prefix=::libc")
178 .arg("--raw-line=use libc::*;")
179 .arg("--no-derive-default")
180 .arg("--enable-function-attribute-detection")
181 .arg("--default-macro-constant-type=signed")
182 .arg("--rustified-enum=point_conversion_form_t")
183 .arg("--allowlist-file=.*/openssl/[^/]+\\.h")
184 .arg("--no-recursive-allowlist")
185 .arg("--blocklist-function=BIO_vsnprintf")
186 .arg("--blocklist-function=OPENSSL_vasprintf")
187 .arg("--experimental")
188 .arg("--wrap-static-fns")
189 .arg("--wrap-static-fns-path")
190 .arg(out_dir.join("boring_static_wrapper").display().to_string())
191 .arg("--no-layout-tests")
192 .arg(out_dir.join("boring_static_wrapper.h"))
193 .arg("--")
194 .arg(format!("--target={}", env::var("TARGET").unwrap()));
195
196 for include_dir in include_dirs {
197 bindgen_cmd.arg("-I").arg(include_dir.display().to_string());
198 }
199
200 let result = bindgen_cmd.status().expect("bindgen failed to execute");
201 assert!(result.success());
202
203 cc::Build::new()
204 .file(out_dir.join("boring_static_wrapper.c"))
205 .includes(include_dirs)
206 .flag("-include")
207 .flag(
208 &out_dir
209 .join("boring_static_wrapper.h")
210 .display()
211 .to_string(),
212 )
213 .compile("boring_static_wrapper");
214 }
215
216 #[derive(Debug)]
217 struct OpensslCallbacks;
218
219 #[cfg(feature = "bindgen")]
220 impl ParseCallbacks for OpensslCallbacks {
221 // for now we'll continue hand-writing constants
will_parse_macro(&self, _name: &str) -> MacroParsingBehavior222 fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior {
223 MacroParsingBehavior::Ignore
224 }
225
item_name(&self, original_item_name: &str) -> Option<String>226 fn item_name(&self, original_item_name: &str) -> Option<String> {
227 match original_item_name {
228 // Our original definitions of these are wrong, so rename to avoid breakage
229 "CRYPTO_EX_new"
230 | "CRYPTO_EX_dup"
231 | "CRYPTO_EX_free"
232 | "BIO_meth_set_write"
233 | "BIO_meth_set_read"
234 | "BIO_meth_set_puts"
235 | "BIO_meth_set_ctrl"
236 | "BIO_meth_set_create"
237 | "BIO_meth_set_destroy"
238 | "CRYPTO_set_locking_callback"
239 | "CRYPTO_set_id_callback"
240 | "SSL_CTX_set_tmp_dh_callback"
241 | "SSL_set_tmp_dh_callback"
242 | "SSL_CTX_set_tmp_ecdh_callback"
243 | "SSL_set_tmp_ecdh_callback"
244 | "SSL_CTX_callback_ctrl"
245 | "SSL_CTX_set_alpn_select_cb" => Some(format!("{}__fixed_rust", original_item_name)),
246 _ => None,
247 }
248 }
249 }
250