Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion crates/cargo-wdk/src/actions/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use wdk_build::{
metadata::{TryFromCargoMetadataError, Wdk},
};

use crate::actions::Profile;
use crate::actions::{Profile, SignMode};
#[double]
use crate::providers::{exec::CommandExec, fs::Fs, metadata::Metadata, wdk_build::WdkBuild};

Expand All @@ -38,6 +38,7 @@ pub struct BuildActionParams<'a> {
pub profile: Option<&'a Profile>,
pub target_arch: Option<CpuArchitecture>,
pub verify_signature: bool,
pub sign_mode: SignMode,
pub is_sample_class: bool,
pub verbosity_level: clap_verbosity_flag::Verbosity,
}
Expand All @@ -49,6 +50,7 @@ pub struct BuildAction<'a> {
profile: Option<&'a Profile>,
target_arch: Option<CpuArchitecture>,
verify_signature: bool,
sign_mode: SignMode,
is_sample_class: bool,
verbosity_level: clap_verbosity_flag::Verbosity,

Expand Down Expand Up @@ -90,6 +92,7 @@ impl<'a> BuildAction<'a> {
profile: params.profile,
target_arch: params.target_arch,
verify_signature: params.verify_signature,
sign_mode: params.sign_mode,
is_sample_class: params.is_sample_class,
verbosity_level: params.verbosity_level,
wdk_build,
Expand Down Expand Up @@ -386,6 +389,7 @@ impl<'a> BuildAction<'a> {
target_dir: &target_dir,
target_arch: &target_arch,
verify_signature: self.verify_signature,
sign_mode: self.sign_mode,
sample_class: self.is_sample_class,
driver_model,
},
Expand Down
54 changes: 38 additions & 16 deletions crates/cargo-wdk/src/actions/build/package_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ use windows::{

#[double]
use crate::providers::{exec::CommandExec, fs::Fs, wdk_build::WdkBuild};
use crate::{actions::build::error::PackageTaskError, providers::error::FileError};
use crate::{
actions::{SignMode, build::error::PackageTaskError},
providers::error::FileError,
};

// FIXME: This range is inclusive of 25798. Update with range end after /sample
// flag is added to InfVerif CLI
Expand All @@ -44,6 +47,7 @@ pub struct PackageTaskParams<'a> {
pub target_dir: &'a Path,
pub target_arch: &'a CpuArchitecture,
pub verify_signature: bool,
pub sign_mode: SignMode,
pub sample_class: bool,
pub driver_model: DriverConfig,
}
Expand All @@ -52,6 +56,7 @@ pub struct PackageTaskParams<'a> {
pub struct PackageTask<'a> {
package_name: String,
verify_signature: bool,
sign_mode: SignMode,
sample_class: bool,

// src paths
Expand Down Expand Up @@ -162,6 +167,7 @@ impl<'a> PackageTask<'a> {
Self {
package_name,
verify_signature: params.verify_signature,
sign_mode: params.sign_mode,
sample_class: params.sample_class,
src_inx_file_path,
src_driver_binary_file_path,
Expand Down Expand Up @@ -236,24 +242,36 @@ impl<'a> PackageTask<'a> {
self.copy(&self.src_map_file_path, &self.dest_map_file_path)?;
self.run_stampinf()?;
self.run_inf2cat()?;
self.generate_certificate()?;
self.copy(&self.src_cert_file_path, &self.dest_cert_file_path)?;
self.run_signtool_sign(
&self.dest_driver_binary_path,
WDR_TEST_CERT_STORE,
WDR_LOCAL_TEST_CERT,
)?;
self.run_signtool_sign(
&self.dest_cat_file_path,
WDR_TEST_CERT_STORE,
WDR_LOCAL_TEST_CERT,
)?;
match self.sign_mode {
SignMode::Test => {
self.generate_certificate()?;
self.copy(&self.src_cert_file_path, &self.dest_cert_file_path)?;
self.run_signtool_sign(
&self.dest_driver_binary_path,
WDR_TEST_CERT_STORE,
WDR_LOCAL_TEST_CERT,
)?;
self.run_signtool_sign(
&self.dest_cat_file_path,
WDR_TEST_CERT_STORE,
WDR_LOCAL_TEST_CERT,
)?;
}
SignMode::Off => {
info!("Sign mode is 'off'; skipping certificate generation and signing");
}
}
self.run_infverif()?;
// Verify signatures only when --verify-signature flag = true is passed
// and signing was done (sign mode is not 'off').
if self.verify_signature {
info!("Verifying signatures for driver binary and cat file using signtool");
self.run_signtool_verify(&self.dest_driver_binary_path)?;
self.run_signtool_verify(&self.dest_cat_file_path)?;
if matches!(self.sign_mode, SignMode::Off) {
warn!("Skipping signature verification because sign mode is 'off'");
} else {
info!("Verifying signatures for driver binary and cat file using signtool");
self.run_signtool_verify(&self.dest_driver_binary_path)?;
self.run_signtool_verify(&self.dest_cat_file_path)?;
}
}
Ok(())
}
Expand Down Expand Up @@ -636,6 +654,7 @@ mod tests {
driver_model: DriverConfig::Kmdf(KmdfConfig::default()),
sample_class: false,
verify_signature: false,
sign_mode: SignMode::Test,
};
let dest_root = target_dir.join(format!("{package_name}_package"));

Expand Down Expand Up @@ -699,6 +718,7 @@ mod tests {
driver_model: DriverConfig::Kmdf(KmdfConfig::default()),
sample_class: false,
verify_signature: false,
sign_mode: SignMode::Test,
};

let command_exec = CommandExec::default();
Expand All @@ -725,6 +745,7 @@ mod tests {
driver_model: DriverConfig::Kmdf(KmdfConfig::default()),
sample_class: false,
verify_signature: false,
sign_mode: SignMode::Test,
};

let command_exec = CommandExec::default();
Expand Down Expand Up @@ -760,6 +781,7 @@ mod tests {
driver_model: DriverConfig::Kmdf(KmdfConfig::default()),
sample_class: false,
verify_signature: false,
sign_mode: SignMode::Test,
};

let wdk_build = WdkBuild::default();
Expand Down
143 changes: 143 additions & 0 deletions crates/cargo-wdk/src/actions/build/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::providers::{
use crate::{
actions::{
Profile,
SignMode,
build::{BuildAction, BuildActionParams, error::BuildActionError},
to_target_triple,
},
Expand Down Expand Up @@ -265,6 +266,118 @@ pub fn given_a_driver_project_when_verify_signature_is_true_then_it_builds_succe
);
}

#[test]
pub fn given_a_driver_project_when_sign_mode_is_off_then_signing_and_verification_steps_are_skipped()
{
// Input CLI args
let cwd = PathBuf::from("C:\\tmp");
let profile = None;
let target_arch = CpuArchitecture::Amd64;
let verify_signature = false;
let sample_class = false;

// Driver project data
let driver_type = "KMDF";
let driver_name = "sample-kmdf";
let driver_version = "0.0.1";
let wdk_metadata = get_cargo_metadata_wdk_metadata(driver_type, 1, 33);
let (workspace_member, package) =
get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(&wdk_metadata));

let cargo_build_output =
create_cargo_build_output_json(driver_name, driver_version, &cwd, None, profile);
let test_build_action = &TestBuildAction::new(cwd.clone(), profile, None, sample_class)
.with_sign_mode(SignMode::Off)
.set_up_standalone_driver_project((workspace_member, package))
.expect_default_build_task_steps(driver_name, Some(cargo_build_output))
.expect_probe_target_arch_using_cargo_rustc(&cwd, target_arch, None)
.expect_package_task_steps_with_sign_mode_off(driver_name, driver_type, target_arch);

assert_build_action_run_with_env_is_success(
&cwd,
profile,
None,
verify_signature,
sample_class,
test_build_action,
);
}

#[test]
pub fn given_a_sample_class_driver_project_when_sign_mode_is_off_then_signing_is_skipped_and_sample_infverif_still_runs()
{
// Input CLI args
let cwd = PathBuf::from("C:\\tmp");
let profile = None;
let target_arch = CpuArchitecture::Amd64;
let verify_signature = false;
let sample_class = true;

// Driver project data
let driver_type = "KMDF";
let driver_name = "sample-kmdf";
let driver_version = "0.0.1";
let wdk_metadata = get_cargo_metadata_wdk_metadata(driver_type, 1, 33);
let (workspace_member, package) =
get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(&wdk_metadata));

let cargo_build_output =
create_cargo_build_output_json(driver_name, driver_version, &cwd, None, profile);
let test_build_action = &TestBuildAction::new(cwd.clone(), profile, None, sample_class)
.with_sign_mode(SignMode::Off)
.set_up_standalone_driver_project((workspace_member, package))
.expect_default_build_task_steps(driver_name, Some(cargo_build_output))
.expect_probe_target_arch_using_cargo_rustc(&cwd, target_arch, None)
.expect_package_task_steps_with_sign_mode_off(driver_name, driver_type, target_arch)
.expect_detect_wdk_build_number(25100u32);

assert_build_action_run_with_env_is_success(
&cwd,
profile,
None,
verify_signature,
sample_class,
test_build_action,
);
}

#[test]
pub fn given_a_driver_project_when_sign_mode_is_off_and_verify_signature_is_true_then_verification_is_skipped()
{
// Input CLI args
let cwd = PathBuf::from("C:\\tmp");
let profile = None;
let target_arch = CpuArchitecture::Amd64;
let verify_signature = true;
let sample_class = false;

// Driver project data
let driver_type = "KMDF";
let driver_name = "sample-kmdf";
let driver_version = "0.0.1";
let wdk_metadata = get_cargo_metadata_wdk_metadata(driver_type, 1, 33);
let (workspace_member, package) =
get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(&wdk_metadata));

let cargo_build_output =
create_cargo_build_output_json(driver_name, driver_version, &cwd, None, profile);
let test_build_action = &TestBuildAction::new(cwd.clone(), profile, None, sample_class)
.with_sign_mode(SignMode::Off)
.set_up_standalone_driver_project((workspace_member, package))
.expect_default_build_task_steps(driver_name, Some(cargo_build_output))
.expect_probe_target_arch_using_cargo_rustc(&cwd, target_arch, None)
.expect_package_task_steps_with_sign_mode_off(driver_name, driver_type, target_arch);

assert_build_action_run_with_env_is_success(
&cwd,
profile,
None,
verify_signature,
sample_class,
test_build_action,
);
}

#[test]
pub fn given_a_driver_project_when_self_signed_exists_then_it_should_skip_calling_makecert() {
// Input CLI args
Expand Down Expand Up @@ -1600,6 +1713,7 @@ fn initialize_build_action<'a>(
profile,
target_arch,
verify_signature,
sign_mode: test_build_action.sign_mode,
is_sample_class: sample_class,
verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0),
},
Expand Down Expand Up @@ -1662,6 +1776,7 @@ struct TestBuildAction {
profile: Option<Profile>,
target_arch: Option<CpuArchitecture>,
sample_class: bool,
sign_mode: SignMode,

cargo_metadata: Option<CargoMetadata>,
// mocks
Expand All @@ -1688,6 +1803,7 @@ impl TestBuildAction {
profile,
target_arch,
sample_class,
sign_mode: SignMode::Test,
mock_run_command,
mock_wdk_build_provider,
mock_fs_provider,
Expand All @@ -1696,6 +1812,11 @@ impl TestBuildAction {
}
}

fn with_sign_mode(mut self, sign_mode: SignMode) -> Self {
self.sign_mode = sign_mode;
self
}

fn set_up_standalone_driver_project(
mut self,
package_metadata: (TestMetadataWorkspaceMemberId, TestMetadataPackage),
Expand Down Expand Up @@ -1826,6 +1947,28 @@ impl TestBuildAction {
.expect_signtool_verify_cat_file(driver_name, &cwd, None)
}

/// Sets up package-task expectations for `SignMode::Off`: stampinf,
/// inf2cat, and infverif are still expected, but all certificate
/// generation, signing, and signature-verification steps are skipped.
fn expect_package_task_steps_with_sign_mode_off(
self,
driver_name: &str,
driver_type: &str,
target_arch: CpuArchitecture,
) -> Self {
let cwd = self.cwd.clone();
self.expect_final_package_dir_exists(driver_name, &cwd, true)
.expect_inx_file_exists(driver_name, &cwd, true)
.expect_rename_driver_binary_dll_to_sys(driver_name, &cwd)
.expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true)
.expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true)
.expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd)
.expect_copy_map_file_to_package_folder(driver_name, &cwd, true)
.expect_stampinf(driver_name, &cwd, target_arch, None)
.expect_inf2cat(driver_name, &cwd, target_arch, None)
.expect_infverif(driver_name, &cwd, driver_type, None)
}

fn expect_default_package_task_steps_for_workspace(
self,
driver_name: &str,
Expand Down
21 changes: 21 additions & 0 deletions crates/cargo-wdk/src/actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ impl Display for Profile {
}
}

/// Driver signing mode used during the package phase.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, clap::ValueEnum)]
#[value(rename_all = "lower")]
pub enum SignMode {
/// Skip signing entirely.
Off,
/// Use test-signing with an auto-generated self-signed certificate.
#[default]
Test,
}

impl Display for SignMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Off => "off",
Self::Test => "test",
};
write!(f, "{s}")
}
}

/// Converts `CpuArchitecture` to its corresponding target triple name.
#[must_use]
pub fn to_target_triple(cpu_arch: CpuArchitecture) -> String {
Expand Down
Loading
Loading