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
126
127
128
129
130
// 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"),
("CKV_", "CK_ULONG"),
("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 (in PKCS #11 before 3.0). The PKCS #11 3.0 introduces the new functions
// `C_GetInterface` and `C_GetInterfaceList` to request the hew functions from 3.0 API.
// These are the only function we need to create a binding for.
.allowlist_function("C_GetFunctionList")
.allowlist_function("C_GetInterfaceList")
.allowlist_function("C_GetInterface")
// 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!");
}
}