• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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