Skip to content

Commit

Permalink
Add bundled feature and improve support for windows.
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Epperson <thomas.epperson@gmail.com>
  • Loading branch information
uglyoldbob committed Apr 27, 2024
1 parent b75d2ad commit a4e61d4
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 3 deletions.
8 changes: 7 additions & 1 deletion tss-esapi-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
211 changes: 209 additions & 2 deletions tss-esapi-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -59,19 +69,158 @@ 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,
tss2_tcti_tbs: Option<Library>,
}

impl Installation {
fn platform_args() -> Option<Vec<String>> {
cfg_if::cfg_if! {
if #[cfg(windows)] {
let mut clang_args: Vec<String> = 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<std::path::Path>,
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,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tss-esapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
4 changes: 4 additions & 0 deletions tss-esapi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
use semver::{Version, VersionReq};

fn main() {
#[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");

Expand Down
5 changes: 5 additions & 0 deletions tss-esapi/src/tcti_ldr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -174,6 +177,7 @@ impl TryFrom<TctiNameConf> for CString {
TctiNameConf::Mssim(..) => MSSIM,
TctiNameConf::Swtpm(..) => SWTPM,
TctiNameConf::Tabrmd(..) => TABRMD,
TctiNameConf::Tbs => TBS,
};

let tcti_conf = match tcti {
Expand Down Expand Up @@ -204,6 +208,7 @@ impl TryFrom<TctiNameConf> 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() {
Expand Down

0 comments on commit a4e61d4

Please sign in to comment.