Skip to content

Commit 9750c7e

Browse files
author
Steve Lee (POWERSHELL HE/HIM) (from Dev Box)
committed
Add warning on Windows if files aren't authenticode signed
1 parent aa4db08 commit 9750c7e

File tree

12 files changed

+396
-9
lines changed

12 files changed

+396
-9
lines changed

dsc/Cargo.lock

Lines changed: 60 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dsc/src/util.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use crate::args::{SchemaType, OutputFormat, TraceFormat};
55
use crate::resolve::Include;
6+
use dsc_lib::security::check_file_security;
67
use dsc_lib::{
78
configure::{
89
config_doc::{
@@ -461,6 +462,10 @@ pub fn get_input(input: Option<&String>, file: Option<&String>, parameters_from_
461462
}
462463
}
463464
} else {
465+
if let Err(err) = check_file_security(Path::new(path)) {
466+
warn!("{err}");
467+
}
468+
464469
// see if an extension should handle this file
465470
let mut discovery = Discovery::new();
466471
for extension in discovery.get_extensions(&Capability::Import) {

dsc/tests/dsc_security.tests.ps1

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
Describe 'Tests for security features' {
5+
It 'Unsigned config file gives warning' -Skip:(!$IsWindows) {
6+
$null = dsc config get -f $PSScriptRoot/../examples/osinfo_parameters.dsc.yaml 2>$TestDrive/error.log
7+
$LASTEXITCODE | Should -Be 0
8+
(Get-Content $TestDrive/error.log -Raw) | Should -Match "WARN Authenticode: The file '.*?\\osinfo_parameters.dsc.yaml' is not signed.*?"
9+
}
10+
11+
It 'Unsigned resource manifest gives warning' -Skip:(!$IsWindows) {
12+
$null = dsc resource get -r Microsoft/OSInfo 2>$TestDrive/error.log
13+
$LASTEXITCODE | Should -Be 0
14+
(Get-Content $TestDrive/error.log -Raw) | Should -Match "WARN Authenticode: The file '.*?\\osinfo.dsc.resource.json' is not signed.*?"
15+
}
16+
17+
It 'Unsigned resource executable gives warning' -Skip:(!$IsWindows) {
18+
$null = dsc resource get -r Microsoft/OSInfo 2>$TestDrive/error.log
19+
$LASTEXITCODE | Should -Be 0
20+
(Get-Content $TestDrive/error.log -Raw) | Should -Match "WARN Authenticode: The file '.*?\\osinfo.exe' is not signed.*?"
21+
}
22+
}

dsc_lib/Cargo.lock

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dsc_lib/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ tree-sitter-rust = "0.24"
4949
tree-sitter-dscexpression = { path = "../tree-sitter-dscexpression" }
5050
uuid = { version = "1.18", features = ["v4"] }
5151
which = "8.0"
52+
windows = { version = "0.62", features = [
53+
"Win32_Foundation",
54+
"Win32_Security",
55+
"Win32_Security_Cryptography",
56+
"Win32_Security_WinTrust",
57+
] }
58+
windows-result = "0.4"
59+
windows-strings = "0.5"
5260

5361
[dev-dependencies]
5462
serde_yaml = "0.9"

dsc_lib/src/discovery/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ pub mod discovery_trait;
66

77
use crate::discovery::discovery_trait::{DiscoveryKind, ResourceDiscovery, DiscoveryFilter};
88
use crate::extensions::dscextension::{Capability, DscExtension};
9+
use crate::security::check_file_security;
910
use crate::{dscresources::dscresource::DscResource, progress::ProgressFormat};
1011
use core::result::Result::Ok;
1112
use semver::{Version, VersionReq};
12-
use std::collections::BTreeMap;
13+
use std::{collections::BTreeMap, path::Path};
1314
use command_discovery::{CommandDiscovery, ImportedManifest};
14-
use tracing::error;
15+
use tracing::{error, warn};
1516

1617
#[derive(Clone)]
1718
pub struct Discovery {
@@ -94,7 +95,7 @@ impl Discovery {
9495
}
9596

9697
let type_name = type_name.to_lowercase();
97-
if let Some(resources) = self.resources.get(&type_name) {
98+
let resource = if let Some(resources) = self.resources.get(&type_name) {
9899
if let Some(version) = version_string {
99100
let version = fix_semver(version);
100101
if let Ok(version_req) = VersionReq::parse(&version) {
@@ -119,7 +120,15 @@ impl Discovery {
119120
}
120121
} else {
121122
None
123+
};
124+
125+
if let Some(found_resource) = &resource {
126+
if let Err(err) = check_file_security(Path::new(&found_resource.path)) {
127+
warn!("{err}");
128+
}
122129
}
130+
131+
resource
123132
}
124133

125134
/// Find resources based on the required resource types.

dsc_lib/src/dscerror.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ pub enum DscError {
1414
#[error("{t}: {0}", t = t!("dscerror.adapterNotFound"))]
1515
AdapterNotFound(String),
1616

17+
#[error("Authenticode: {0}")]
18+
AuthenticodeError(String),
19+
1720
#[error("{t}: {0}", t = t!("dscerror.booleanConversion"))]
1821
BooleanConversion(#[from] std::str::ParseBoolError),
1922

@@ -131,6 +134,9 @@ pub enum DscError {
131134
#[error("{t}: {0}", t = t!("dscerror.validation"))]
132135
Validation(String),
133136

137+
#[error("Which: {0}")]
138+
Which(#[from] which::Error),
139+
134140
#[error("YAML: {0}")]
135141
Yaml(#[from] serde_yaml::Error),
136142

dsc_lib/src/dscresources/command_resource.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use jsonschema::Validator;
66
use rust_i18n::t;
77
use serde::Deserialize;
88
use serde_json::{Map, Value};
9+
use which::which;
910
use std::{collections::HashMap, env, process::Stdio};
10-
use crate::configure::{config_doc::ExecutionKind, config_result::{ResourceGetResult, ResourceTestResult}};
11+
use crate::{configure::{config_doc::ExecutionKind, config_result::{ResourceGetResult, ResourceTestResult}}, security::check_file_security};
1112
use crate::dscerror::DscError;
1213
use super::{dscresource::get_diff, invoke_result::{ExportResult, GetResult, ResolveResult, SetResult, TestResult, ValidateResult, ResourceGetResponse, ResourceSetResponse, ResourceTestResponse, get_in_desired_state}, resource_manifest::{ArgKind, InputKind, Kind, ResourceManifest, ReturnKind, SchemaKind}};
1314
use tracing::{error, warn, info, debug, trace};
@@ -596,6 +597,11 @@ async fn run_process_async(executable: &str, args: Option<Vec<String>>, input: O
596597
// the value is based on list result of largest of built-in adapters - WMI adapter ~500KB
597598
const INITIAL_BUFFER_CAPACITY: usize = 1024*1024;
598599

600+
let exe = which(executable)?;
601+
if let Err(err) = check_file_security(&exe) {
602+
warn!("{err}");
603+
}
604+
599605
let mut command = Command::new(executable);
600606
if input.is_some() {
601607
command.stdin(Stdio::piped());

dsc_lib/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub mod parser;
2020
pub mod progress;
2121
pub mod util;
2222
pub mod schemas;
23+
pub mod security;
2324

2425
i18n!("locales", fallback = "en-us");
2526

0 commit comments

Comments
 (0)