1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2021,2023 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
fn main() {
#[cfg(feature = "generate-bindings")]
{
generate::generate_bindings();
}
}
// Only on a specific feature
#[cfg(feature = "generate-bindings")]
mod generate {
use bindgen::callbacks;
#[derive(Debug)]
pub struct CargoCallbacks;
impl callbacks::ParseCallbacks for CargoCallbacks {
// skip processing CK_UNAVAILABLE_INFORMATION macro, more details in lib.rs
fn will_parse_macro(&self, name: &str) -> callbacks::MacroParsingBehavior {
if name == "CK_UNAVAILABLE_INFORMATION" {
callbacks::MacroParsingBehavior::Ignore
} else {
callbacks::MacroParsingBehavior::Default
}
}
fn int_macro(&self, name: &str, _: i64) -> Option<callbacks::IntKind> {
let prefixes = [
("CK_", "CK_ULONG"),
("CKA_", "CK_ATTRIBUTE_TYPE"),
("CKC_", "CK_CERTIFICATE_TYPE"),
("CKD_", "CK_EC_KDF_TYPE"),
("CKF_", "CK_FLAGS"),
("CKG_MGF1_", "CK_RSA_PKCS_MGF_TYPE"),
("CKG", "CK_GENERATOR_FUNCTION"),
("CKH_", "CK_HW_FEATURE_TYPE"),
("CKK_", "CK_KEY_TYPE"),
("CKM_", "CK_MECHANISM_TYPE"),
("CKN_", "CK_NOTIFICATION"),
("CKO_", "CK_OBJECT_CLASS"),
(
"CKP_PKCS5_PBKD2_",
"CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE",
),
("CKP_", "CK_PROFILE_ID"),
("CKR_", "CK_RV"),
("CKS_", "CK_STATE"),
("CKU_", "CK_USER_TYPE"),
("CKZ_DATA_SPECIFIED", "CK_RSA_PKCS_OAEP_SOURCE_TYPE"),
("CKZ_SALT_SPECIFIED", "CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE"),
("CRYPTOKI_VERSION_", "CK_BYTE"),
];
if ["CK_TRUE", "CK_FALSE"].contains(&name) {
Some(callbacks::IntKind::Custom {
name: "CK_BBOOL",
is_signed: false,
})
} else {
let mut result = None;
for (prefix, variable) in &prefixes {
if name.starts_with(prefix) {
result = Some(callbacks::IntKind::Custom {
name: variable,
is_signed: false,
})
}
}
result
}
}
}
pub fn generate_bindings() {
let make_generic: bool = std::env::var_os("MAKE_GENERIC_BINDINGS").is_some();
let mut builder = bindgen::Builder::default();
// to be fully compatible with 2.4
builder = builder.header_contents("enable-deprecated.h", "#define PKCS11_DEPRECATED 1\n");
if make_generic {
// only WIN32 bindings are "packed". It's easier to "unpack" for other architectures
// __declspec is not needed and causes problems
const GENERIC_PRELUDE: &str = "#define _WIN32 1\n#define __declspec(x)\n";
builder = builder
// layout tests are not generic
.layout_tests(false)
.header_contents("generic-prelude.h", GENERIC_PRELUDE)
}
builder = builder
.header("vendor/pkcs11.h")
.dynamic_library_name("Pkcs11")
// The PKCS11 library works in a slightly different way to most shared libraries. We have
// to call `C_GetFunctionList`, which returns a list of pointers to the _actual_ library
// functions. This is the only function we need to create a binding for.
.allowlist_function("C_GetFunctionList")
// This is needed because no types will be generated if `allowlist_function` is used.
// Unsure if this is a bug.
.allowlist_type("*")
.allowlist_file("vendor/pkcs11.h")
// See this issue: https://github.com/parallaxsecond/rust-cryptoki/issues/12
.blocklist_type("max_align_t")
// Derive the `Debug` trait for the generated structs where possible.
.derive_debug(true)
// Derive the `Default` trait for the generated structs where possible.
.derive_default(true)
.parse_callbacks(Box::new(CargoCallbacks))
// Support function like macros
// https://github.com/parallaxsecond/rust-cryptoki/issues/240
.clang_macro_fallback();
let bindings = builder.generate().expect("Unable to generate bindings");
let mut data = bindings.to_string();
if make_generic {
const PACK_ALWAYS: &str = "#[repr(C, packed)]";
const PACK_WINDOWS: &str = "#[repr(C)]\n#[cfg_attr(windows, repr(packed))]";
data = data.replace(PACK_ALWAYS, PACK_WINDOWS);
}
// Write the bindings to the $OUT_DIR/pkcs11_bindings.rs file.
let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
std::fs::write(out_path.join("pkcs11_bindings.rs"), data)
.expect("Couldn't write bindings!");
}
}