From fe7e959f68aa25d9e4fd4858ac2f609db01b606a Mon Sep 17 00:00:00 2001 From: Thomas Epperson Date: Sat, 20 Apr 2024 16:02:50 -0500 Subject: [PATCH 1/2] Add bundled feature and improve support for windows. --- tss-esapi-sys/Cargo.toml | 8 +- tss-esapi-sys/build.rs | 211 +++++++++++++++++++++++++++++++++++++- tss-esapi/Cargo.toml | 1 + tss-esapi/build.rs | 5 +- tss-esapi/src/tcti_ldr.rs | 5 + 5 files changed, 226 insertions(+), 4 deletions(-) diff --git a/tss-esapi-sys/Cargo.toml b/tss-esapi-sys/Cargo.toml index 0e8615fc..7bbf2e11 100644 --- a/tss-esapi-sys/Cargo.toml +++ b/tss-esapi-sys/Cargo.toml @@ -14,11 +14,17 @@ links = "tss2-esys" rust-version = "1.66.0" [build-dependencies] -bindgen = { version = "0.66.1", optional = true } +autotools = { version = "0.2.6", optional = true } +bindgen = { version = "0.69.4", optional = true } pkg-config = "0.3.18" target-lexicon = "0.12.0" cfg-if = "1.0.0" semver = "1.0.7" +[target.'cfg(windows)'.build-dependencies] +msbuild = { git = "https://github.com/uglyoldbob/msbuild.git", optional = true } +winreg = {version = "0.52", optional = true } + [features] generate-bindings = ["bindgen"] +bundled = ["dep:autotools", "dep:msbuild", "dep:winreg"] diff --git a/tss-esapi-sys/build.rs b/tss-esapi-sys/build.rs index d261d567..f3c14520 100644 --- a/tss-esapi-sys/build.rs +++ b/tss-esapi-sys/build.rs @@ -9,11 +9,21 @@ fn main() { cfg_if::cfg_if! { if #[cfg(feature = "generate-bindings")] { + #[cfg(feature = "bundled")] + let installation = tpm2_tss::Installation::bundled(); + #[cfg(not(feature = "bundled"))] let installation = tpm2_tss::Installation::probe(true); let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap()); installation.generate_bindings(&out_dir.join("tss_esapi_bindings.rs")); + installation.output_linker_arguments(); } else { target::ensure_supported(); + #[cfg(feature = "bundled")] + { + let installation = tpm2_tss::Installation::bundled(); + installation.pkg_config(); + } + #[cfg(not(feature = "bundled"))] let _ = tpm2_tss::Installation::probe(false); } } @@ -59,7 +69,7 @@ pub mod tpm2_tss { /// The installed tpm2-tss libraries that are of /// interest. pub struct Installation { - _tss2_sys: Library, + tss2_sys: Library, tss2_esys: Library, tss2_tctildr: Library, tss2_mu: Library, @@ -67,11 +77,150 @@ pub mod tpm2_tss { } impl Installation { + fn platform_args() -> Option> { + cfg_if::cfg_if! { + if #[cfg(windows)] { + let mut clang_args: Vec = Vec::new(); + let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE); + let sdk_entry = hklm.open_subkey("SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0").unwrap(); + let installation_path: String = sdk_entry.get_value("InstallationFolder").unwrap(); + let ip_pb = PathBuf::from(installation_path).join("Include"); + let windows_sdk = ip_pb.join("10.0.17134.0"); + clang_args.push(format!("-I{}", windows_sdk.join("ucrt").display())); + clang_args.push(format!("-I{}", windows_sdk.join("um").display())); + clang_args.push(format!("-I{}", windows_sdk.join("shared").display())); + Some(clang_args) + } + else { + None + } + } + } + + #[cfg(feature = "bundled")] + /// Fetch the given source repo using git + fn fetch_source( + dest_path: impl AsRef, + name: &str, + repo: &str, + branch: &str, + ) -> std::path::PathBuf { + let parent_path = dest_path.as_ref(); + let repo_path = parent_path.join(name); + if !repo_path.join("Makefile.am").exists() { + let output = std::process::Command::new("git") + .args(["clone", repo, "--depth", "1", "--branch", branch]) + .current_dir(parent_path) + .output() + .unwrap_or_else(|_| panic!("git clone for {} failed", name)); + let status = output.status; + if !status.success() { + panic!( + "git clone for {} returned failure status {}:\n{:?}", + name, status, output + ); + } + } + + repo_path + } + + #[cfg(feature = "bundled")] + fn compile_with_autotools(p: PathBuf) -> PathBuf { + let output1 = std::process::Command::new("./bootstrap") + .current_dir(&p) + .output() + .expect("bootstrap script failed"); + let status = output1.status; + if !status.success() { + panic!("bootstrap script failed with {}:\n{:?}", status, output1); + } + + let mut config = autotools::Config::new(p); + config.fast_build(true).reconf("-ivf").build() + } + + #[cfg(feature = "bundled")] + /// Uses a bundled build for an installation + pub fn bundled() -> Self { + use std::io::Write; + let out_path = std::env::var("OUT_DIR").expect("No output directory given"); + let source_path = Self::fetch_source( + out_path, + "tpm2-tss", + "https://github.com/tpm2-software/tpm2-tss.git", + MINIMUM_VERSION, + ); + let version_file_name = source_path.join("VERSION"); + let mut version_file = std::fs::File::create(version_file_name) + .expect("Unable to create version file for tpm2-tss"); + write!(version_file, "{}", MINIMUM_VERSION) + .unwrap_or_else(|e| panic!("Failed to write version file: {}", e)); + + cfg_if::cfg_if! { + if #[cfg(windows)] { + let mut msbuild = msbuild::MsBuild::find_msbuild(Some("2017")).unwrap(); + let profile = std::env::var("PROFILE").unwrap(); + let build_string = match profile.as_str() { + "debug" => "", + "release" => "/p:Configuration=Release", + _ => panic!("Unknown cargo profile:"), + }; + + msbuild.run(source_path.clone(), &[ + build_string, + "tpm2-tss.sln"]); + } + else { + let install_path = Self::compile_with_autotools(source_path.clone()); + std::env::set_var( + "PKG_CONFIG_PATH", + format!("{}", install_path.join("lib").join("pkgconfig").display()), + ); + } + } + std::env::set_var(PATH_ENV_VAR_NAME, source_path.clone()); + + let include_path = source_path.join("include").join("tss2"); + + #[cfg(windows)] + let tbs = Some(Library { + header_file: Some(include_path.join("tss2_tcti_tbs.h")), + version: MINIMUM_VERSION.into(), + name: "tss2-tbs".into(), + }); + #[cfg(not(windows))] + let tbs = None; + Self { + tss2_sys: Library { + header_file: Some(include_path.join("tss2_sys.h")), + version: MINIMUM_VERSION.into(), + name: "tss2-sys".into(), + }, + tss2_esys: Library { + header_file: Some(include_path.join("tss2_esys.h")), + version: MINIMUM_VERSION.into(), + name: "tss2-esys".into(), + }, + tss2_tctildr: Library { + header_file: Some(include_path.join("tss2_tctildr.h")), + version: MINIMUM_VERSION.into(), + name: "tss2-tctildr".into(), + }, + tss2_mu: Library { + header_file: Some(include_path.join("tss2_mu.h")), + version: MINIMUM_VERSION.into(), + name: "tss2-mu".into(), + }, + tss2_tcti_tbs: tbs, + } + } + /// Probes the system for an installation. pub fn probe(with_header_files: bool) -> Self { let install_path = Installation::installation_path_from_env_var(); Installation { - _tss2_sys: Library::probe_required( + tss2_sys: Library::probe_required( "tss2-sys", install_path.as_ref(), with_header_files, @@ -149,10 +298,58 @@ pub mod tpm2_tss { .clang_arg(tss2_tcti_tbs.include_dir_arg()) .header(tss2_tcti_tbs.header_file_arg()); } + if let Some(clang_args) = Self::platform_args() { + for arg in clang_args { + builder = builder.clang_arg(arg); + } + } builder } } } + + /// Run pkgconfig for bundled installations + #[cfg(feature = "bundled")] + pub fn pkg_config(&self) { + self.tss2_sys.pkg_config(); + self.tss2_esys.pkg_config(); + self.tss2_tctildr.pkg_config(); + self.tss2_mu.pkg_config(); + if let Some(lib) = &self.tss2_tcti_tbs { + lib.pkg_config(); + } + } + + pub fn output_linker_arguments(&self) { + #[cfg(windows)] + { + println!("cargo:rustc-link-lib=dylib=tss2-esys"); + println!("cargo:rustc-link-lib=dylib=tss2-mu"); + println!("cargo:rustc-link-lib=dylib=tss2-sys"); + println!("cargo:rustc-link-lib=dylib=tss2-tctildr"); + println!("cargo:rustc-link-lib=dylib=tss2-tcti-tbs"); + let profile = std::env::var("PROFILE").unwrap(); + let build_string = match profile.as_str() { + "debug" => "Debug", + "release" => "Release", + _ => panic!("Unknown cargo profile:"), + }; + let mut source_path = self + .tss2_esys + .header_file + .clone() + .expect("Expected a header file path"); + source_path.pop(); + source_path.pop(); + source_path.pop(); + println!("Source path is {}", source_path.display()); + println!( + "cargo:rustc-link-search=dylib={}", + source_path.join("x64").join(build_string).display() + ); + } + } + /// Retrieves the installation path from the environment variable and validates it. fn installation_path_from_env_var() -> Option<(PathBuf, String)> { std::env::var(PATH_ENV_VAR_NAME).map_or_else( @@ -372,6 +569,16 @@ pub mod tpm2_tss { ) } + /// Use the pkg config file for a bundled installation + #[cfg(feature = "bundled")] + fn pkg_config(&self) { + pkg_config::Config::new() + .atleast_version(MINIMUM_VERSION) + .statik(true) + .probe(&self.name) + .unwrap_or_else(|_| panic!("Failed to run pkg-config on {}", self.name)); + } + /// Probe the system for an optional library using pkg-config. /// /// # Args diff --git a/tss-esapi/Cargo.toml b/tss-esapi/Cargo.toml index f89fee56..96f4142c 100644 --- a/tss-esapi/Cargo.toml +++ b/tss-esapi/Cargo.toml @@ -49,3 +49,4 @@ default = ["abstraction"] generate-bindings = ["tss-esapi-sys/generate-bindings"] abstraction = ["oid", "picky-asn1", "picky-asn1-x509"] integration-tests = ["strum", "strum_macros"] +bundled = [ "tss-esapi-sys/bundled" ] \ No newline at end of file diff --git a/tss-esapi/build.rs b/tss-esapi/build.rs index 6831dbdf..fc3ef2c3 100644 --- a/tss-esapi/build.rs +++ b/tss-esapi/build.rs @@ -8,7 +8,10 @@ fn main() { println!("cargo:rustc-check-cfg=cfg(has_tss_base_rc_values_52_to_53)"); println!("cargo:rustc-check-cfg=cfg(has_tpmu_sensitive_create)"); println!("cargo:rustc-check-cfg=cfg(has_esys_tr_get_tpm_handle)"); - + #[cfg(feature = "bundled")] + { + std::env::set_var("DEP_TSS2_ESYS_VERSION", "3.2.2"); + } let tss_version_string = std::env::var("DEP_TSS2_ESYS_VERSION") .expect("Failed to parse ENV variable DEP_TSS2_ESYS_VERSION as string"); diff --git a/tss-esapi/src/tcti_ldr.rs b/tss-esapi/src/tcti_ldr.rs index f564baf8..814f80c3 100644 --- a/tss-esapi/src/tcti_ldr.rs +++ b/tss-esapi/src/tcti_ldr.rs @@ -21,6 +21,7 @@ const DEVICE: &str = "device"; const MSSIM: &str = "mssim"; const SWTPM: &str = "swtpm"; const TABRMD: &str = "tabrmd"; +const TBS: &str = "tbs"; /// TCTI Context created via a TCTI Loader Library. /// Wrapper around the TSS2_TCTI_CONTEXT structure. @@ -143,6 +144,8 @@ pub enum TctiNameConf { /// /// For more information about configuration, see [this page](https://www.mankier.com/3/Tss2_Tcti_Tabrmd_Init) Tabrmd(TabrmdConfig), + /// Connect to a TPM using windows services + Tbs, } impl TctiNameConf { @@ -174,6 +177,7 @@ impl TryFrom for CString { TctiNameConf::Mssim(..) => MSSIM, TctiNameConf::Swtpm(..) => SWTPM, TctiNameConf::Tabrmd(..) => TABRMD, + TctiNameConf::Tbs => TBS, }; let tcti_conf = match tcti { @@ -204,6 +208,7 @@ impl TryFrom for CString { TctiNameConf::Tabrmd(config) => { format!("bus_name={},bus_type={}", config.bus_name, config.bus_type) } + TctiNameConf::Tbs => String::new(), }; if tcti_conf.is_empty() { From 479e77efcecdbf46782f4f059ad74f03b84ea4cf Mon Sep 17 00:00:00 2001 From: Thomas Epperson Date: Fri, 31 May 2024 20:25:33 -0500 Subject: [PATCH 2/2] Update documentation. --- tss-esapi-sys/Cargo.toml | 2 +- tss-esapi-sys/README.md | 11 +++++++++++ tss-esapi-sys/build.rs | 10 +++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tss-esapi-sys/Cargo.toml b/tss-esapi-sys/Cargo.toml index 7bbf2e11..5df469f2 100644 --- a/tss-esapi-sys/Cargo.toml +++ b/tss-esapi-sys/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0.0" semver = "1.0.7" [target.'cfg(windows)'.build-dependencies] -msbuild = { git = "https://github.com/uglyoldbob/msbuild.git", optional = true } +msbuild = { version = "0.1.0", optional = true } winreg = {version = "0.52", optional = true } [features] diff --git a/tss-esapi-sys/README.md b/tss-esapi-sys/README.md index 6f87584f..c19982b6 100644 --- a/tss-esapi-sys/README.md +++ b/tss-esapi-sys/README.md @@ -41,6 +41,17 @@ available, feel free to raise a Pull Request to add it or to use build-time generation of bindings. All the committed bindings **MUST** be generated from the library version found under the `vendor` submodule. +## Bundled feature + +There is a feature called bundled which downloads tpm2-tss source from github and compiles it using visual studio. It will usually be paired with the generate-bindings feature. + +# Windows + +Compiling for windows requires a bit of setup to work with the bundled feature. + +* Openssl must be installed to a non-standard location at C:\OpenSSL-v11-Win64 +* Visual studio 2017 must be installed with the Clang/C2 experimental component, and windows sdk 10.0.17134.0. + ## Cross compiling Cross-compilation can be done as long as you have on your build system the TSS diff --git a/tss-esapi-sys/build.rs b/tss-esapi-sys/build.rs index f3c14520..3d288acf 100644 --- a/tss-esapi-sys/build.rs +++ b/tss-esapi-sys/build.rs @@ -77,15 +77,20 @@ pub mod tpm2_tss { } impl Installation { + /// Return an optional list of clang arguments that are platform specific + #[cfg(feature = "bundled")] fn platform_args() -> Option> { cfg_if::cfg_if! { if #[cfg(windows)] { let mut clang_args: Vec = Vec::new(); let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE); + // Find the windows sdk path from the windows registry let sdk_entry = hklm.open_subkey("SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0").unwrap(); + // add relevant paths to get to the windows 10.0.17134.0 sdk, which tpm2-tss uses on windows. let installation_path: String = sdk_entry.get_value("InstallationFolder").unwrap(); let ip_pb = PathBuf::from(installation_path).join("Include"); let windows_sdk = ip_pb.join("10.0.17134.0"); + // Add paths required for bindgen to find all required headers clang_args.push(format!("-I{}", windows_sdk.join("ucrt").display())); clang_args.push(format!("-I{}", windows_sdk.join("um").display())); clang_args.push(format!("-I{}", windows_sdk.join("shared").display())); @@ -125,7 +130,7 @@ pub mod tpm2_tss { repo_path } - #[cfg(feature = "bundled")] + #[cfg(all(feature = "bundled",not(windows)))] fn compile_with_autotools(p: PathBuf) -> PathBuf { let output1 = std::process::Command::new("./bootstrap") .current_dir(&p) @@ -332,7 +337,7 @@ pub mod tpm2_tss { let build_string = match profile.as_str() { "debug" => "Debug", "release" => "Release", - _ => panic!("Unknown cargo profile:"), + _ => panic!("Unknown cargo profile: {}", profile), }; let mut source_path = self .tss2_esys @@ -342,7 +347,6 @@ pub mod tpm2_tss { source_path.pop(); source_path.pop(); source_path.pop(); - println!("Source path is {}", source_path.display()); println!( "cargo:rustc-link-search=dylib={}", source_path.join("x64").join(build_string).display()