mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-18 20:47:58 +00:00
Xfer HIRS_Provisioner.NET to main (#663)
* Moving HIRS_Provisioner.NET and dotnet_provisioner_unit_tests.yml into main branch * Adding fixed dotnet provisioner workflow * Updated files to match updated master branch, including hirs.sln, Directory.Build.targets, HIRS_Provisioner.NET.csproj, and hirsTest.csproj
This commit is contained in:
parent
2efb1a98f3
commit
e9f5d7245c
136
.github/workflows/dotnet_provisioner_unit_tests.yml
vendored
Normal file
136
.github/workflows/dotnet_provisioner_unit_tests.yml
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
name: Dotnet Provisioner Unit Tests
|
||||
|
||||
on: push
|
||||
env:
|
||||
DOTNET_VERSION: '6.0'
|
||||
jobs:
|
||||
dotnet_provisioner_unit_tests:
|
||||
name: Restore and Run Unit Tests
|
||||
continue-on-error: true
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2022
|
||||
- os: ubuntu-20.04
|
||||
# - os: windows-2019 Cannot Target windows-2019 because the .NET 6 SDK won't receive security patches for this image
|
||||
steps:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Restore Project
|
||||
working-directory: HIRS_Provisioner.NET
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: Build on Windows
|
||||
working-directory: HIRS_Provisioner.NET
|
||||
if: contains(matrix.os, 'windows')
|
||||
run: |
|
||||
cd hirs
|
||||
dotnet build -r win-x64 --configuration Release --no-restore
|
||||
cd ..
|
||||
|
||||
- name: Build on Ubuntu
|
||||
working-directory: HIRS_Provisioner.NET
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
dotnet build --configuration Release --no-restore
|
||||
|
||||
- name: Run Unit Tests and Save Logs - Windows
|
||||
id: window_result
|
||||
if: contains(matrix.os, 'windows') && always()
|
||||
working-directory: HIRS_Provisioner.NET
|
||||
run: |
|
||||
$logs = dotnet test /p:PublishSingleFile=false --no-restore -v m
|
||||
$results = [string]$logs
|
||||
$results = $results.Contains("Passed!")
|
||||
if($results) { $results = "Pass" } else { $results = "Fail"}
|
||||
echo "::set-output name=result::$results"
|
||||
$logName = "${{matrix.os}}-unit-tests-" + $results + ".log"
|
||||
New-Item $logName
|
||||
Set-Content $logName $logs
|
||||
Get-Content $logName
|
||||
|
||||
- name: Run Unit Tests Ubuntu
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
working-directory: HIRS_Provisioner.NET
|
||||
run: |
|
||||
logName="${{matrix.os}}-unit-tests.log"
|
||||
dotnet test --no-restore -v m > $logName
|
||||
|
||||
- name: Extract Ubuntu Unit Test Results
|
||||
id: ubuntu_result
|
||||
if: contains(matrix.os, 'ubuntu') && always()
|
||||
working-directory: HIRS_Provisioner.NET
|
||||
run: |
|
||||
logName="${{matrix.os}}-unit-tests.log"
|
||||
if grep -rnw $logName -e "Passed\!" ;
|
||||
then
|
||||
result="Pass"
|
||||
else
|
||||
result="Fail"
|
||||
fi
|
||||
echo "::set-output name=result::$result"
|
||||
more $logName
|
||||
|
||||
- name: Upload Logs Ubuntu
|
||||
uses: actions/upload-artifact@v2
|
||||
if: contains(matrix.os, 'ubuntu') && always()
|
||||
with:
|
||||
name: "${{matrix.os}}-unit-tests-${{steps.ubuntu_result.outputs.result}}.log"
|
||||
path: HIRS_Provisioner.NET/*.log
|
||||
|
||||
- name: Upload Logs Windows
|
||||
uses: actions/upload-artifact@v2
|
||||
if: contains(matrix.os, 'windows') && always()
|
||||
with:
|
||||
name: "${{matrix.os}}-unit-tests-${{steps.window_result.outputs.result}}.log"
|
||||
path: HIRS_Provisioner.NET/*.log
|
||||
|
||||
Evaluator:
|
||||
name: Evaluate Tests
|
||||
needs: [dotnet_provisioner_unit_tests]
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: false
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Make artifact directory
|
||||
run: |
|
||||
mkdir artifacts
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Determine if a test failed
|
||||
working-directory: artifacts
|
||||
run: |
|
||||
result=""
|
||||
suffix="-unit-tests-Fail.log"
|
||||
msg=" OS did not pass all the unit tests."
|
||||
|
||||
# Generate Annotations and Console Output
|
||||
for file in *.log; do
|
||||
if [[ "$file" == *"Fail"* ]]; then
|
||||
title=${file%"$suffix"}
|
||||
echo "::error title=$title Unit Tests Failed::The $title $msg"
|
||||
result="Failed"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$result" ]
|
||||
then
|
||||
exit 1
|
||||
fi
|
201
HIRS_Provisioner.NET/.editorconfig
Normal file
201
HIRS_Provisioner.NET/.editorconfig
Normal file
@ -0,0 +1,201 @@
|
||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
#### Core EditorConfig Options ####
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# New line preferences
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
#### .NET Coding Conventions ####
|
||||
|
||||
# Organize usings
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = false
|
||||
file_header_template = unset
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
|
||||
# Field preferences
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
|
||||
# 'using' directive preferences
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
|
||||
#### C# Formatting Rules ####
|
||||
|
||||
# New line preferences
|
||||
csharp_new_line_before_catch = false
|
||||
csharp_new_line_before_else = false
|
||||
csharp_new_line_before_finally = false
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = none
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_blocks = false
|
||||
csharp_preserve_single_line_statements = false
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
158
HIRS_Provisioner.NET/hirs.sln
Normal file
158
HIRS_Provisioner.NET/hirs.sln
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32421.90
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hirs", "hirs\HIRS_Provisioner.NET.csproj", "{300FF15E-1E10-4586-843D-D652BA40DEE5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E61D6E28-B993-436D-AA88-165857AAEEC0}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hirsTest", "hirsTest\hirsTest.csproj", "{C6458436-D548-428C-B250-23E3084F74FC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "pcrextend", "tools\pcrextend\pcrextend.csproj", "{2D518622-5C95-4180-87CE-9F730B2714AD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{300FF15E-1E10-4586-843D-D652BA40DEE5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C6458436-D548-428C-B250-23E3084F74FC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2D518622-5C95-4180-87CE-9F730B2714AD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{08A014E3-3E70-4E8B-9870-5000F3429E9F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{34463663-1DEF-46FB-99AC-D8FABB71E7F0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|x64.Build.0 = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{540546BE-36E3-4C3A-B84B-70A4F0393546}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6F78678F-F528-4DE8-BC2A-71FA403D68B8}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
44
HIRS_Provisioner.NET/hirs/Directory.Build.targets
Normal file
44
HIRS_Provisioner.NET/hirs/Directory.Build.targets
Normal file
@ -0,0 +1,44 @@
|
||||
<Project>
|
||||
<Target Name="RenameBeforePublishLinux" BeforeTargets="CreatePackageProperties" Condition="$(RuntimeIdentifier.Contains('linux'))">
|
||||
<PropertyGroup>
|
||||
<SymlinkAppHostInBin Condition="'$(SymlinkAppHostInBin)' == ''">false</SymlinkAppHostInBin> <!-- If true, this will place a symlink in /usr/local/bin/, which is not on $PATH for root by default. We need the symlink in /bin or /sbin -->
|
||||
</PropertyGroup>
|
||||
<Move SourceFiles="$(OUTDIR)publish\$(AssemblyName)" DestinationFiles="$(OUTDIR)publish\tpm_aca_provision" />
|
||||
<Message Text="Renamed linux binary file." Importance="high" />
|
||||
<PropertyGroup>
|
||||
<Prefix>/usr/share/hirs</Prefix>
|
||||
<PostInstallScript>/usr/bin/chmod 644 /usr/share/hirs/appsettings.json; /usr/bin/ln -s /usr/share/hirs/tpm_aca_provision /usr/bin/tpm_aca_provision</PostInstallScript>
|
||||
<PostRemoveScript>rm -f /usr/bin/tpm_aca_provision; rm -rf /usr/share/hirs</PostRemoveScript>
|
||||
</PropertyGroup>
|
||||
<Message Text="Set installed directory prefix to $(PREFIX)." Importance="high" />
|
||||
</Target>
|
||||
<Target Name="RenameBeforePublishWindows" BeforeTargets="SetWixPath" Condition="$(RuntimeIdentifier.Contains('win'))">
|
||||
<Move SourceFiles="$(OUTDIR)publish\$(AssemblyName).exe" DestinationFiles="$(OUTDIR)publish\tpm_aca_provision.exe" />
|
||||
<Message Text="Renamed exe binary file." Importance="high" />
|
||||
</Target>
|
||||
<Target Name="SetWixPath" BeforeTargets="Msi">
|
||||
<PropertyGroup>
|
||||
<ProductSourceFilePath>$(MSBuildThisFileDirectory)\Resources\Product.wxs</ProductSourceFilePath>
|
||||
<WixInstallPath>$(NuGetPackageRoot)wix\3.11.2\tools\</WixInstallPath>
|
||||
<Heat>$(WixInstallPath)heat.exe</Heat>
|
||||
<Candle>$(WixInstallPath)candle.exe</Candle>
|
||||
<Light>$(WixInstallPath)light.exe</Light>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
<Target Name="DeletePDB" AfterTargets="RenameBeforePublishLinux;RenameBeforePublishWindows">
|
||||
<ItemGroup>
|
||||
<PDBToDelete Include="$(PublishDir)*.pdb"/>
|
||||
</ItemGroup>
|
||||
<Delete Files="@(PDBToDelete)" />
|
||||
<Message Text="Deleted PDB files." Importance="high" />
|
||||
</Target>
|
||||
<Target Name="CopyFiles" AfterTargets="DeletePDB">
|
||||
<ItemGroup>
|
||||
<PaccorScriptsDll Include="$(OUTDIR)paccor_scripts.dll"/>
|
||||
</ItemGroup>
|
||||
<Copy
|
||||
SourceFiles="@(PaccorScriptsDll)"
|
||||
DestinationFolder="$(PublishDir)plugins"
|
||||
/>
|
||||
</Target>
|
||||
</Project>
|
102
HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj
Normal file
102
HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj
Normal file
@ -0,0 +1,102 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RuntimeIdentifiers>linux-x64;win-x64</RuntimeIdentifiers>
|
||||
<StartupObject>hirs.Program</StartupObject>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageVersion>2.2.0</PackageVersion>
|
||||
<Release></Release>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.20.1" />
|
||||
<PackageReference Include="Google.Protobuf.Tools" Version="3.20.1">
|
||||
<PrivateAssets>all</PrivateAssets> <!-- These assets will be consumed but won't flow to the parent project -->
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.TSS" Version="2.1.1" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="paccor.HardwareManifestPlugin" Version="1.0.0" />
|
||||
<PackageReference Include="paccor.HardwareManifestPluginManager" Version="1.0.0" />
|
||||
<PackageReference Include="paccor.paccor_scripts" Version="1.0.1" />
|
||||
<PackageReference Include="Packaging.Targets" Version="0.1.220">
|
||||
<PrivateAssets>all</PrivateAssets> <!-- These assets will be consumed but won't flow to the parent project -->
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="System.Management" Version="6.0.0" />
|
||||
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
|
||||
<PackageReference Include="WiX" Version="3.11.2">
|
||||
<PrivateAssets>all</PrivateAssets> <!-- These assets will be consumed but won't flow to the parent project -->
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Protobuf Include="**/*.proto" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="BuildProto" BeforeTargets="PreBuildEvent">
|
||||
<PropertyGroup>
|
||||
<FOLDER_PROTO>$(ProjectDir)Resources</FOLDER_PROTO>
|
||||
<FOLDER_OUT>$(ProjectDir)generated</FOLDER_OUT>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<protoc Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)'=='X64'">$(protoc_linux64)</protoc>
|
||||
<protoc Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)'=='X86'">$(protoc_linux86)</protoc>
|
||||
<protoc Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)'=='X64'">$(protoc_macosx64)</protoc>
|
||||
<protoc Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)'=='X86'">$(protoc_macosx86)</protoc>
|
||||
<protoc Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)'=='X64'">$(protoc_windows64)</protoc>
|
||||
<protoc Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' And '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)'=='X86'">$(protoc_windows86)</protoc>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Condition="!Exists('$(FOLDER_OUT)')" Include="generated/ProvisionerTpm2.cs" /> <!-- Necessary to include the proto file(s) compiled during this prebuild phase, if they didn't exist before. CANNOT use wildcards! -->
|
||||
</ItemGroup>
|
||||
<Exec Condition="!Exists('$(FOLDER_OUT)')" Command="mkdir $(FOLDER_OUT)" />
|
||||
<Exec Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))'" Command="for /f %%i in ('dir /s /b $(FOLDER_PROTO)\*.proto') do ( $(protoc) -I=$(FOLDER_PROTO) --csharp_out=$(FOLDER_OUT) %%i )" />
|
||||
<Exec Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'" Command="for file in `ls -1R $(FOLDER_PROTO)/*.proto` ; do $(protoc) -I=$(FOLDER_PROTO) --csharp_out=$(FOLDER_OUT) $file; done " />
|
||||
</Target>
|
||||
<Import Project="$(NuGetPackageRoot)paccor.paccor_scripts/1.0.1/contentFiles/any/net6.0/resources/paccor.paccor_scripts.targets" Condition="Exists('$(NuGetPackageRoot)paccor.paccor_scripts/1.0.1/contentFiles/any/net6.0/resources/paccor.paccor_scripts.targets')" />
|
||||
<Target Name="ImportPaccorScripts" BeforeTargets="PreBuildEvent">
|
||||
<ItemGroup>
|
||||
<PaccorScriptsLinux Include="$(dotnet_paccor_scripts_directory)/*" />
|
||||
<PaccorScriptsWindows Include="$(dotnet_paccor_scripts_windows_directory)/*" />
|
||||
</ItemGroup>
|
||||
<Message Text="Adding files to plugins/scripts: @(PaccorScriptsLinux)" Importance="high" />
|
||||
<Message Text="Adding files to plugins/scripts/windows: @(PaccorScriptsWindows)" Importance="high" />
|
||||
<Copy SourceFiles="@(PaccorScriptsLinux)" DestinationFolder="$(ProjectDir)/plugins/scripts/" />
|
||||
<Copy SourceFiles="@(PaccorScriptsWindows)" DestinationFolder="$(ProjectDir)/plugins/scripts/windows/" />
|
||||
<ItemGroup>
|
||||
<Content Include="plugins\**\*.*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
35
HIRS_Provisioner.NET/hirs/Resources/Product.wxs
Normal file
35
HIRS_Provisioner.NET/hirs/Resources/Product.wxs
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Name="$(var.SetupProductName)" Manufacturer="$(var.SetupProductManufacturer)" Language="$(var.SetupProductLanguage)" Version="$(var.SetupProductVersion)">
|
||||
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
|
||||
|
||||
<!--
|
||||
Because we don't have a way (yet) to create unique product codes, we can't include the MajorUpgrade element, either
|
||||
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||
-->
|
||||
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
|
||||
<Feature Id="$(var.SetupFeatureId)" Title="$(var.SetupFeatureName)" Level="1">
|
||||
<ComponentGroupRef Id="ProductComponents" />
|
||||
<Component Directory='INSTALLFOLDER'>
|
||||
<RegistryValue Root='HKLM' Key='Software\HIRS' Name='InstallFolder' Value='[INSTALLFOLDER]' Type='string' />
|
||||
<Environment Id='UpdatePath' Name='PATH' Action='set' System='yes' Part='last' Value='[INSTALLFOLDER]' />
|
||||
</Component>
|
||||
</Feature>
|
||||
</Product>
|
||||
|
||||
<Fragment>
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="ProgramFilesFolder">
|
||||
<Directory Id="INSTALLFOLDER" Name="$(var.SetupInstallFolderName)" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
|
||||
<ComponentGroupRef Id="SourceComponentGroup" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
100
HIRS_Provisioner.NET/hirs/Resources/ProvisionerTpm2.proto
Normal file
100
HIRS_Provisioner.NET/hirs/Resources/ProvisionerTpm2.proto
Normal file
@ -0,0 +1,100 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package hirs.pb;
|
||||
option java_package="hirs.attestationca.configuration.provisionerTpm2";
|
||||
|
||||
message FirmwareInfo {
|
||||
required string biosVendor = 1;
|
||||
required string biosVersion = 2;
|
||||
required string biosReleaseDate = 3;
|
||||
}
|
||||
|
||||
message HardwareInfo {
|
||||
required string manufacturer = 1;
|
||||
required string productName = 2;
|
||||
required string productVersion = 3;
|
||||
required string systemSerialNumber = 4;
|
||||
repeated ComponentInfo chassisInfo = 5;
|
||||
repeated ComponentInfo baseboardInfo = 6;
|
||||
repeated ComponentInfo processorInfo = 7;
|
||||
repeated ComponentInfo biosOrUefiInfo = 8;
|
||||
repeated ComponentInfo nicInfo = 9;
|
||||
repeated ComponentInfo hardDriveInfo = 10;
|
||||
repeated ComponentInfo memoryInfo = 11;
|
||||
}
|
||||
|
||||
message ComponentInfo {
|
||||
required string manufacturer = 1;
|
||||
required string model = 2;
|
||||
optional string serialNumber = 3;
|
||||
optional string revision = 4;
|
||||
}
|
||||
|
||||
message NetworkInfo {
|
||||
required string hostname = 1;
|
||||
required string ipAddress = 2;
|
||||
required string macAddress = 3;
|
||||
}
|
||||
|
||||
message OsInfo {
|
||||
required string osName = 1;
|
||||
required string osVersion = 2;
|
||||
required string osArch = 3;
|
||||
required string distribution = 4;
|
||||
required string distributionRelease = 5;
|
||||
}
|
||||
|
||||
message TpmInfo {
|
||||
required string tpmMake = 1;
|
||||
required string tpmVersionMajor = 2;
|
||||
required string tpmVersionMinor = 3;
|
||||
required string tpmRevMajor = 4;
|
||||
required string tpmRevMinor = 5;
|
||||
}
|
||||
|
||||
message DeviceInfo {
|
||||
required FirmwareInfo fw = 1;
|
||||
required HardwareInfo hw = 2;
|
||||
required NetworkInfo nw = 3;
|
||||
required OsInfo os = 4;
|
||||
optional bytes pcrslist = 5;
|
||||
repeated bytes logfile = 6;
|
||||
repeated bytes swidfile = 7;
|
||||
optional bytes livelog = 8;
|
||||
}
|
||||
|
||||
message IdentityClaim {
|
||||
required DeviceInfo dv = 1;
|
||||
required bytes ak_public_area = 2;
|
||||
required bytes ek_public_area = 3;
|
||||
optional bytes endorsement_credential = 4;
|
||||
repeated bytes platform_credential = 5;
|
||||
optional string client_version = 6;
|
||||
optional string paccorOutput = 7;
|
||||
}
|
||||
|
||||
message TpmQuote {
|
||||
required string success = 1;
|
||||
}
|
||||
|
||||
enum ResponseStatus {
|
||||
PASS = 0;
|
||||
FAIL = 1;
|
||||
}
|
||||
|
||||
message IdentityClaimResponse {
|
||||
optional bytes credential_blob = 1;
|
||||
optional string pcr_mask = 2;
|
||||
optional ResponseStatus status = 3 [default = FAIL];
|
||||
}
|
||||
|
||||
message CertificateRequest {
|
||||
required bytes nonce = 1;
|
||||
optional bytes quote = 2;
|
||||
}
|
||||
|
||||
message CertificateResponse {
|
||||
optional bytes certificate = 1;
|
||||
optional ResponseStatus status = 2 [default = FAIL];
|
||||
}
|
||||
|
38
HIRS_Provisioner.NET/hirs/appsettings.json
Normal file
38
HIRS_Provisioner.NET/hirs/appsettings.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"auto_detect_tpm": "TRUE",
|
||||
"aca_address_port": "https://127.0.0.1:8443",
|
||||
"efi_prefix": "",
|
||||
"paccor_output_file": "",
|
||||
"event_log_file": "",
|
||||
"hardware_manifest_collectors": "paccor_scripts",
|
||||
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Debug",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"outputTemplate": "{Message}{NewLine}",
|
||||
"theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Grayscale, Serilog.Sinks.Console",
|
||||
"restrictedToMinimumLevel": "Information"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"path": "hirs.log",
|
||||
"rollingInterval": "Day",
|
||||
"retainedFileCountLimit": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
69
HIRS_Provisioner.NET/hirs/src/Program.cs
Normal file
69
HIRS_Provisioner.NET/hirs/src/Program.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using CommandLine;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace hirs {
|
||||
class Program {
|
||||
public static readonly string VERSION = "17";
|
||||
|
||||
static async Task<int> Main(string[] args) {
|
||||
ClientExitCodes result = 0;
|
||||
try {
|
||||
Settings settings = Settings.LoadSettingsFromDefaultFile();
|
||||
settings.SetUpLog();
|
||||
Log.Information("Starting hirs version " + VERSION);
|
||||
if (!IsRunningAsAdmin()) {
|
||||
result = ClientExitCodes.NOT_PRIVILEGED;
|
||||
Log.Warning("The HIRS provisioner is not running as administrator.");
|
||||
}
|
||||
settings.CompleteSetUp();
|
||||
CLI cli = new();
|
||||
Log.Debug("Parsing CLI args.");
|
||||
ParserResult<CLI> cliParseResult =
|
||||
CommandLine.Parser.Default.ParseArguments<CLI>(args)
|
||||
.WithParsed(parsed => cli = parsed)
|
||||
.WithNotParsed(HandleParseError);
|
||||
|
||||
if (cliParseResult.Tag == ParserResultType.NotParsed) {
|
||||
// Help text requested, or parsing failed. Exit.
|
||||
Log.Warning("Could not parse command line arguments. Set --tcp --sim, --tcp <ip>:<port>, --nix, or --win. See documentation for further assistance.");
|
||||
} else {
|
||||
Provisioner p = new(settings, cli);
|
||||
IHirsAcaTpm tpm = p.ConnectTpm();
|
||||
p.UseClassicDeviceInfoCollector();
|
||||
result = (ClientExitCodes)await p.Provision(tpm);
|
||||
Log.Information("----> Provisioning " + (result == 0 ? "successful" : "failed") + ".");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result = ClientExitCodes.FAIL;
|
||||
Log.Fatal(e, "Application stopped.");
|
||||
}
|
||||
Log.CloseAndFlush();
|
||||
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
private static void HandleParseError(IEnumerable<Error> errs) {
|
||||
//handle errors
|
||||
Log.Error("There was a CLI error: " + errs.ToString());
|
||||
}
|
||||
|
||||
private static bool IsRunningAsAdmin() {
|
||||
bool isAdmin = false;
|
||||
try {
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
WindowsIdentity user = WindowsIdentity.GetCurrent();
|
||||
WindowsPrincipal principal = new(user);
|
||||
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
} else {
|
||||
isAdmin = Mono.Unix.Native.Syscall.geteuid() == 0;
|
||||
}
|
||||
} catch { }
|
||||
return isAdmin;
|
||||
}
|
||||
}
|
||||
}
|
130
HIRS_Provisioner.NET/hirs/src/client/Client.cs
Normal file
130
HIRS_Provisioner.NET/hirs/src/client/Client.cs
Normal file
@ -0,0 +1,130 @@
|
||||
using Google.Protobuf;
|
||||
using Hirs.Pb; // Imports ProvisionerTpm2.proto (compiled and generated by protobuf)
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Buffers.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace hirs {
|
||||
public class Client : IHirsAcaClient {
|
||||
public static readonly string POST_IDENTITY_CLAIM_PATH = "HIRS_AttestationCA/identity-claim-tpm2/process";
|
||||
public static readonly string POST_REQUEST_CERT_TPM2_PATH = "HIRS_AttestationCA/request-certificate-tpm2";
|
||||
|
||||
private readonly Uri uri;
|
||||
private static readonly HttpClientHandler handler = new() {
|
||||
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
||||
}; // TODO: Overhaul ACA security
|
||||
private readonly HttpClient client;
|
||||
|
||||
/**
|
||||
* This method will create an HttpClient that will accept any server certificate.
|
||||
*/
|
||||
public Client(string address) {
|
||||
uri = new(address);
|
||||
client = new HttpClient(handler);
|
||||
}
|
||||
|
||||
public Client(string address, HttpClient httpClient) {
|
||||
uri = new(address);
|
||||
client = httpClient;
|
||||
}
|
||||
|
||||
public async Task<IdentityClaimResponse> PostIdentityClaim(IdentityClaim identityClaim) {
|
||||
MemoryStream stream = new(identityClaim.ToByteArray());
|
||||
// serialize to stream
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
Uri full_address = new(uri.AbsoluteUri + POST_IDENTITY_CLAIM_PATH);
|
||||
// send data via HTTP
|
||||
StreamContent streamContent = new(stream);
|
||||
streamContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
|
||||
streamContent.Headers.TryAddWithoutValidation("Accept", "application/octet-stream, application/json");
|
||||
|
||||
IdentityClaimResponse icr = null;
|
||||
try {
|
||||
Log.Debug("Attempting to send IdentityClaim to " + full_address);
|
||||
HttpResponseMessage response = await client.PostAsync(full_address, streamContent).ConfigureAwait(continueOnCapturedContext: false);
|
||||
Log.Debug(response.ToString());
|
||||
if (response.StatusCode == HttpStatusCode.OK) {
|
||||
byte[] contentBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
icr = IdentityClaimResponse.Parser.ParseFrom(contentBytes);
|
||||
Log.Debug("IdentityClaim delivery succeeded.");
|
||||
} else {
|
||||
Log.Debug("IdentityClaim delivery failed.");
|
||||
Log.Debug("Request reason phrase: " + response.ReasonPhrase);
|
||||
Log.Debug("Request content: " + response.Content);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.Debug(e, "Error during post of the identity claim.");
|
||||
}
|
||||
return icr;
|
||||
}
|
||||
|
||||
public IdentityClaim CreateIdentityClaim(DeviceInfo dv, byte[] akPublicArea, byte[] ekPublicArea,
|
||||
byte[] endorsementCredential, List<byte[]> platformCredentials,
|
||||
string paccoroutput) {
|
||||
IdentityClaim identityClaim = new();
|
||||
identityClaim.Dv = dv;
|
||||
identityClaim.AkPublicArea = ByteString.CopyFrom(akPublicArea);
|
||||
identityClaim.EkPublicArea = ByteString.CopyFrom(ekPublicArea);
|
||||
identityClaim.EndorsementCredential = ByteString.CopyFrom(endorsementCredential);
|
||||
if (platformCredentials != null) {
|
||||
foreach (byte[] platformCertificate in platformCredentials) {
|
||||
identityClaim.PlatformCredential.Add(ByteString.CopyFrom(platformCertificate));
|
||||
}
|
||||
}
|
||||
identityClaim.PaccorOutput = paccoroutput;
|
||||
|
||||
return identityClaim;
|
||||
}
|
||||
|
||||
public async Task<CertificateResponse> PostCertificateRequest(CertificateRequest certReq) {
|
||||
MemoryStream stream = new(certReq.ToByteArray());
|
||||
// serialize to stream
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
Uri full_address = new(uri.AbsoluteUri + POST_REQUEST_CERT_TPM2_PATH);
|
||||
// send data via HTTP
|
||||
StreamContent streamContent = new(stream);
|
||||
streamContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
|
||||
streamContent.Headers.TryAddWithoutValidation("Accept", "application/octet-stream, application/json");
|
||||
|
||||
CertificateResponse cr = null;
|
||||
try {
|
||||
Log.Debug("Attempting to send the Certificate Request to " + full_address);
|
||||
HttpResponseMessage response = await client.PostAsync(full_address, streamContent).ConfigureAwait(continueOnCapturedContext: false);
|
||||
Log.Debug(response.ToString());
|
||||
if (response.StatusCode == HttpStatusCode.OK) {
|
||||
byte[] contentBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
cr = CertificateResponse.Parser.ParseFrom(contentBytes);
|
||||
Log.Debug("Certificate Response recevied.");
|
||||
} else {
|
||||
Log.Debug("Certificate Response failed.");
|
||||
Log.Debug("Request reason phrase: " + response.ReasonPhrase);
|
||||
Log.Debug("Request content: " + response.Content);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.Debug(e, "Error during post of the certificate request.");
|
||||
}
|
||||
return cr;
|
||||
}
|
||||
|
||||
public CertificateRequest CreateAkCertificateRequest(byte[] secret, CommandTpmQuoteResponse ctqr) {
|
||||
CertificateRequest akCertReq = new();
|
||||
akCertReq.Nonce = ByteString.CopyFrom(secret);
|
||||
CommandTpmQuoteResponse.formatQuoteInfoSigForAca(ctqr.quoted, ctqr.signature, out string quoteInfoSigStr);
|
||||
akCertReq.Quote = ByteString.CopyFromUtf8(quoteInfoSigStr);
|
||||
//formatPcrValuesForAca(pcrValues, out string pcrValuesStr);
|
||||
//akCertReq.Pcrslist = ByteString.CopyFromUtf8(pcrValuesStr);
|
||||
|
||||
return akCertReq;
|
||||
}
|
||||
}
|
||||
}
|
53
HIRS_Provisioner.NET/hirs/src/client/IHirsAcaClient.cs
Normal file
53
HIRS_Provisioner.NET/hirs/src/client/IHirsAcaClient.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using Hirs.Pb;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace hirs {
|
||||
public interface IHirsAcaClient {
|
||||
/// <summary>
|
||||
/// Send the <see cref="IdentityClaim"/> to the ACA. The claim is delivered
|
||||
/// asynchronously to the ACA. However, the client will wait for the response.
|
||||
/// </summary>
|
||||
/// <param name="identityClaim">Evidence about the client.</param>
|
||||
/// <returns>The <see cref="Task"/><<see cref="IdentityClaimResponse"/>> from the
|
||||
/// ACA. The response is wrapped in a Task.</returns>
|
||||
Task<IdentityClaimResponse> PostIdentityClaim(IdentityClaim identityClaim);
|
||||
/// <summary>
|
||||
/// Send the <see cref="CertificateRequest"/> to the ACA. The request is delivered
|
||||
/// asynchronously to the ACA. However, the client will wait for the response.
|
||||
/// </summary>
|
||||
/// <param name="certReq">The request for a certificate. Should contain evidence from
|
||||
/// client to enable nonce verification.</param>
|
||||
/// <returns>The <see cref="Task"/><<see cref="CertificateResponse"/>> from the ACA.
|
||||
/// The response is wrapped in a Task. It will contain a certificate or the reason why
|
||||
/// the certificate request was rejected.</returns>
|
||||
Task<CertificateResponse> PostCertificateRequest(CertificateRequest certReq);
|
||||
/// <summary>
|
||||
/// Collect client evidence regarding a Device into an object that can be interpreted by
|
||||
/// the ACA.
|
||||
/// </summary>
|
||||
/// <param name="dv">Facts about the Device.</param>
|
||||
/// <param name="akPublicArea">The public AK retrieved as a TPM2B_PUBLIC.</param>
|
||||
/// <param name="ekPublicArea">The public EK retrieved as a TPM2B_PUBLIC.</param>
|
||||
/// <param name="endorsementCredential">The public EK certificate, encoded in DER or
|
||||
/// PEM.</param>
|
||||
/// <param name="platformCredentials">Any platform certificates relevant to the Device,
|
||||
/// encoded in DER or PEM.</param>
|
||||
/// <param name="paccoroutput">Platform Manifest in a JSON format.</param>
|
||||
/// <returns>An <see cref="IdentityClaim"/> object that can be sent to the ACA.</returns>
|
||||
IdentityClaim CreateIdentityClaim(DeviceInfo dv, byte[] akPublicArea, byte[] ekPublicArea,
|
||||
byte[] endorsementCredential,
|
||||
List<byte[]> platformCredentials, string paccoroutput);
|
||||
/// <summary>
|
||||
/// Collect answers to verification requirements regarding a Device into an object that
|
||||
/// can be interpreted by the ACA.
|
||||
/// </summary>
|
||||
/// <param name="secret">Verification data.</param>
|
||||
/// <param name="ctqr">TPM Quote data from the client Device.</param>
|
||||
/// <returns>A <see cref="CertificateRequest"/> object that can be sent to the
|
||||
/// ACA.</returns>
|
||||
CertificateRequest CreateAkCertificateRequest(byte[] secret, CommandTpmQuoteResponse ctqr);
|
||||
}
|
||||
}
|
179
HIRS_Provisioner.NET/hirs/src/client/TbsWrapper.cs
Normal file
179
HIRS_Provisioner.NET/hirs/src/client/TbsWrapper.cs
Normal file
@ -0,0 +1,179 @@
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
namespace hirs {
|
||||
class TbsWrapper {
|
||||
public class NativeMethods {
|
||||
[DllImport("tbs.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern TBS_RESULT
|
||||
Tbsi_Context_Create(
|
||||
ref TBS_CONTEXT_PARAMS ContextParams,
|
||||
ref UIntPtr Context);
|
||||
|
||||
[DllImport("tbs.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern TBS_RESULT
|
||||
Tbsip_Context_Close(
|
||||
UIntPtr Context);
|
||||
|
||||
[DllImport("tbs.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern TBS_RESULT
|
||||
Tbsi_Get_OwnerAuth(
|
||||
UIntPtr Context,
|
||||
[System.Runtime.InteropServices.MarshalAs(UnmanagedType.U4), In]
|
||||
TBS_OWNERAUTH_TYPE OwnerAuthType,
|
||||
[System.Runtime.InteropServices.MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3), In, Out]
|
||||
byte[] OutBuffer,
|
||||
ref uint OutBufferSize);
|
||||
|
||||
[DllImport("tbs.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern TBS_RESULT
|
||||
Tbsi_Get_TCG_Log(
|
||||
UIntPtr Context,
|
||||
[System.Runtime.InteropServices.MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In, Out]
|
||||
byte[] pOutputBuf,
|
||||
ref uint pOutputBufLen);
|
||||
}
|
||||
|
||||
public enum TBS_RESULT : uint {
|
||||
TBS_SUCCESS = 0,
|
||||
TBS_E_BLOCKED = 0x80280400,
|
||||
TBS_E_INTERNAL_ERROR = 0x80284001,
|
||||
TBS_E_BAD_PARAMETER = 0x80284002,
|
||||
TBS_E_INSUFFICIENT_BUFFER = 0x80284005,
|
||||
TBS_E_COMMAND_CANCELED = 0x8028400D,
|
||||
TBS_E_OWNERAUTH_NOT_FOUND = 0x80284015
|
||||
}
|
||||
|
||||
public enum TBS_OWNERAUTH_TYPE : uint {
|
||||
TBS_OWNERAUTH_TYPE_FULL = 1,
|
||||
TBS_OWNERAUTH_TYPE_ADMIN = 2,
|
||||
TBS_OWNERAUTH_TYPE_USER = 3,
|
||||
TBS_OWNERAUTH_TYPE_ENDORSEMENT = 4,
|
||||
TBS_OWNERAUTH_TYPE_ENDORSEMENT_20 = 12,
|
||||
TBS_OWNERAUTH_TYPE_STORAGE_20 = 13
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TBS_CONTEXT_PARAMS {
|
||||
public TBS_CONTEXT_VERSION Version;
|
||||
public TBS_CONTEXT_CREATE_FLAGS Flags;
|
||||
}
|
||||
|
||||
public enum TBS_CONTEXT_VERSION : uint {
|
||||
ONE = 1,
|
||||
TWO = 2
|
||||
}
|
||||
|
||||
public enum TBS_CONTEXT_CREATE_FLAGS : uint {
|
||||
RequestRaw = 0x00000001,
|
||||
IncludeTpm12 = 0x00000002,
|
||||
IncludeTpm20 = 0x00000004,
|
||||
}
|
||||
|
||||
// This method is only intended to be called from Windows.
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
||||
public static bool GetOwnerAuthFromOS(out byte[] ownerAuth) {
|
||||
ownerAuth = Array.Empty<byte>();
|
||||
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
||||
WindowsPrincipal principal = new(identity);
|
||||
if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) {
|
||||
Log.Error("GetOwnerAuthFromOS: run the client with Administrator privileges");
|
||||
return false;
|
||||
}
|
||||
|
||||
// open context
|
||||
TbsWrapper.TBS_CONTEXT_PARAMS contextParams;
|
||||
UIntPtr tbsContext = UIntPtr.Zero;
|
||||
contextParams.Version = TbsWrapper.TBS_CONTEXT_VERSION.TWO;
|
||||
contextParams.Flags = TbsWrapper.TBS_CONTEXT_CREATE_FLAGS.IncludeTpm20;
|
||||
TbsWrapper.TBS_RESULT result = TbsWrapper.NativeMethods.Tbsi_Context_Create(ref contextParams, ref tbsContext);
|
||||
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
if (tbsContext == UIntPtr.Zero) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get owner auth size
|
||||
uint ownerAuthSize = 0;
|
||||
TbsWrapper.TBS_OWNERAUTH_TYPE ownerType = TbsWrapper.TBS_OWNERAUTH_TYPE.TBS_OWNERAUTH_TYPE_STORAGE_20;
|
||||
result = TbsWrapper.NativeMethods.Tbsi_Get_OwnerAuth(tbsContext, ownerType, ownerAuth, ref ownerAuthSize);
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS &&
|
||||
result != TbsWrapper.TBS_RESULT.TBS_E_INSUFFICIENT_BUFFER) {
|
||||
ownerType = TbsWrapper.TBS_OWNERAUTH_TYPE.TBS_OWNERAUTH_TYPE_FULL;
|
||||
result = TbsWrapper.NativeMethods.Tbsi_Get_OwnerAuth(tbsContext, ownerType, ownerAuth, ref ownerAuthSize);
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS &&
|
||||
result != TbsWrapper.TBS_RESULT.TBS_E_INSUFFICIENT_BUFFER) {
|
||||
Log.Debug("Failed to get ownerAuthSize.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// get owner auth itself
|
||||
ownerAuth = new byte[ownerAuthSize];
|
||||
result = TbsWrapper.NativeMethods.Tbsi_Get_OwnerAuth(tbsContext, ownerType, ownerAuth, ref ownerAuthSize);
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS) {
|
||||
Log.Debug("Failed to get ownerAuth.");
|
||||
return false;
|
||||
}
|
||||
|
||||
TbsWrapper.NativeMethods.Tbsip_Context_Close(tbsContext);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method is only intended to be called from Windows.
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
||||
public static bool GetEventLog(out byte[] eventLog) {
|
||||
eventLog = Array.Empty<byte>();
|
||||
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
||||
WindowsPrincipal principal = new(identity);
|
||||
if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) {
|
||||
Log.Debug("GetEventLog: run the client with Administrator privileges");
|
||||
return false;
|
||||
}
|
||||
|
||||
// open context
|
||||
TbsWrapper.TBS_CONTEXT_PARAMS contextParams;
|
||||
UIntPtr tbsContext = UIntPtr.Zero;
|
||||
contextParams.Version = TbsWrapper.TBS_CONTEXT_VERSION.TWO;
|
||||
contextParams.Flags = TbsWrapper.TBS_CONTEXT_CREATE_FLAGS.IncludeTpm12 | TbsWrapper.TBS_CONTEXT_CREATE_FLAGS.IncludeTpm20;
|
||||
TbsWrapper.TBS_RESULT result = TbsWrapper.NativeMethods.Tbsi_Context_Create(ref contextParams, ref tbsContext);
|
||||
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
if (tbsContext == UIntPtr.Zero) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Two calls needed
|
||||
// First gets the log size
|
||||
uint eventLogSize = 0;
|
||||
Log.Debug("Attempting to get the event log size from Tbsi.");
|
||||
result = TbsWrapper.NativeMethods.Tbsi_Get_TCG_Log(tbsContext, eventLog, ref eventLogSize);
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS &&
|
||||
result != TbsWrapper.TBS_RESULT.TBS_E_INSUFFICIENT_BUFFER) {
|
||||
Log.Debug("Failed to get eventLogSize.");
|
||||
return false;
|
||||
}
|
||||
// Second gets the log
|
||||
Log.Debug("Attempting to get the event log from Tbsi.");
|
||||
eventLog = new byte[eventLogSize];
|
||||
result = TbsWrapper.NativeMethods.Tbsi_Get_TCG_Log(tbsContext, eventLog, ref eventLogSize);
|
||||
if (result != TbsWrapper.TBS_RESULT.TBS_SUCCESS) {
|
||||
Log.Debug("Failed to get eventLog.");
|
||||
return false;
|
||||
}
|
||||
|
||||
TbsWrapper.NativeMethods.Tbsip_Context_Close(tbsContext);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
39
HIRS_Provisioner.NET/hirs/src/config/CLI.cs
Normal file
39
HIRS_Provisioner.NET/hirs/src/config/CLI.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using CommandLine;
|
||||
|
||||
namespace hirs {
|
||||
public class CLI {
|
||||
[Option("tcp", SetName="type", Default = false, HelpText = "Connect to the TPM by IP. Use the format ip:port. By default will connect to " + CommandTpm.DefaultSimulatorNamePort + ".")]
|
||||
public bool Tcp {
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Option("win", SetName = "type", Default = false, HelpText = "Connect to a Windows TPM device.")]
|
||||
public bool Win {
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Option("nix", SetName = "type", Default = false, HelpText = "Connect to a Linux TPM device.")]
|
||||
public bool Nix {
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Option("sim", Default = false, HelpText = "Notify the program of intent to connect to a TPM simulator.")]
|
||||
public bool Sim {
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Option("ip", Default = CommandTpm.DefaultSimulatorNamePort, HelpText = "IP of the TPM Device. Use the format ip:port.")]
|
||||
public string Ip {
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Option("replaceAK", Default = false, HelpText = "Clear any existing hirs AK and create a new one.")]
|
||||
public bool ReplaceAK {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public static string[] SplitArgs(string argString) {
|
||||
return argString.SplitArgs(true);
|
||||
}
|
||||
}
|
||||
}
|
18
HIRS_Provisioner.NET/hirs/src/config/ClientExitCodes.cs
Normal file
18
HIRS_Provisioner.NET/hirs/src/config/ClientExitCodes.cs
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
namespace hirs {
|
||||
public enum ClientExitCodes {
|
||||
SUCCESS = 0, // Full successful program completion
|
||||
FAIL = 1, // Unknown/Generic failure resulting in exit
|
||||
USER_ERROR = 20, // Generic user error
|
||||
MISSING_CONFIG = 21, // Config file missing
|
||||
ACA_UNREACHABLE = 22, // Nothing found at the address specified
|
||||
NOT_PRIVILEGED = 23, // Client not run as root
|
||||
EXTERNAL_APP_ERROR = 40, // Generic external application error
|
||||
TPM_ERROR = 41, // Encountered error with the TPM, log the TPM Return Code
|
||||
HW_COLLECTION_ERROR = 42, // Encountered error when gathering hardware details
|
||||
PROVISIONING_ERROR = 60, // Generic provisioning error |
|
||||
PASS_1_STATUS_FAIL = 61,
|
||||
PASS_2_STATUS_FAIL = 62,
|
||||
MAKE_CREDENTIAL_BLOB_MALFORMED = 63 // The TPM2_MakeCredential blob was not correct
|
||||
}
|
||||
}
|
547
HIRS_Provisioner.NET/hirs/src/config/Settings.cs
Normal file
547
HIRS_Provisioner.NET/hirs/src/config/Settings.cs
Normal file
@ -0,0 +1,547 @@
|
||||
using HardwareManifestPlugin;
|
||||
using HardwareManifestPluginManager;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace hirs {
|
||||
public class Settings {
|
||||
public enum Options {
|
||||
paccor_output_file,
|
||||
aca_address_port,
|
||||
efi_prefix,
|
||||
auto_detect_tpm,
|
||||
event_log_file,
|
||||
hardware_manifest_collectors,
|
||||
hardware_manifest_collection_swid_enforced,
|
||||
linux_bios_vendor_file,
|
||||
linux_bios_version_file,
|
||||
linux_bios_date_file,
|
||||
linux_sys_vendor_file,
|
||||
linux_product_name_file,
|
||||
linux_product_version_file,
|
||||
linux_product_serial_file
|
||||
}
|
||||
|
||||
private static readonly string DEFAULT_SETTINGS_FILE = "appsettings.json";
|
||||
private static readonly string EFI_ARTIFACT_PATH_COMPAT = "/boot/tcg/";
|
||||
private static readonly string EFI_ARTIFACT_PATH = "/EFI/tcg/";
|
||||
private static readonly string EFI_ARTIFACT_LINUX_PREFIX = "/boot/efi";
|
||||
|
||||
private readonly string settingsFile;
|
||||
private readonly IConfiguration configFromSettingsFile;
|
||||
|
||||
// Storage of options collected from the settingsFile, with some default values
|
||||
public virtual string paccor_output {
|
||||
get; private set;
|
||||
}
|
||||
public virtual Uri aca_address_port {
|
||||
get; private set;
|
||||
}
|
||||
public string efi_prefix {
|
||||
get; private set;
|
||||
}
|
||||
public bool auto_detect_tpm {
|
||||
get; private set;
|
||||
}
|
||||
public virtual byte[] event_log {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_bios_vendor {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_bios_version {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_bios_date {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_sys_vendor {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_product_name {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_product_version {
|
||||
get; private set;
|
||||
}
|
||||
public virtual string linux_product_serial {
|
||||
get; private set;
|
||||
}
|
||||
private List<IHardwareManifest> hardwareManifests = new();
|
||||
private Dictionary<string, string> hardware_manifest_collectors_with_args = new();
|
||||
private bool hardware_manifest_collection_swid_enforced = false;
|
||||
|
||||
private Settings() : this(Settings.DEFAULT_SETTINGS_FILE) { }
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="file">The path to the appsettings.json file on the file system.</param>
|
||||
private Settings(string file) {
|
||||
settingsFile = file;
|
||||
configFromSettingsFile = ReadSettingsFile();
|
||||
}
|
||||
|
||||
public static Settings LoadSettingsFromDefaultFile() {
|
||||
return new(DEFAULT_SETTINGS_FILE);
|
||||
}
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the settings JSON file on the file system.</param>
|
||||
public static Settings LoadSettingsFromFile(string path) {
|
||||
Settings settings = new(path);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static string GetBasePath() {
|
||||
return AppContext.BaseDirectory;
|
||||
}
|
||||
|
||||
private IConfiguration ReadSettingsFile() {
|
||||
string basePath = GetBasePath();
|
||||
IConfiguration configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(basePath)
|
||||
.AddJsonFile(settingsFile, false, true)
|
||||
.Build();
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void SetUpLog() {
|
||||
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configFromSettingsFile).CreateLogger();
|
||||
Log.Debug("Reading settings file: " + Path.GetFullPath(Path.Combine(GetBasePath(), settingsFile)));
|
||||
}
|
||||
|
||||
public void CompleteSetUp() {
|
||||
try {
|
||||
ConfigureHardwareManifestManagement();
|
||||
|
||||
IngestPaccorDataFromFile();
|
||||
|
||||
ParseAcaAddress();
|
||||
|
||||
CheckAutoDetectTpm();
|
||||
|
||||
CheckEfiPrefix();
|
||||
|
||||
IngestEventLogFromFile();
|
||||
|
||||
StoreCustomDeviceInfoCollectorOptions();
|
||||
|
||||
} catch (Exception e) {
|
||||
if (Log.Logger == null) {
|
||||
Console.WriteLine("Could not set up logging.");
|
||||
}
|
||||
Log.Error(e, "Error reading the settings file.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region Hardware Manifest
|
||||
private void ConfigureHardwareManifestManagement() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.hardware_manifest_collectors.ToString()])) {
|
||||
Log.Debug("Configuring Hardware Manifest Plugin Manager");
|
||||
string hardware_manifest_collectors = $"{ configFromSettingsFile[Options.hardware_manifest_collectors.ToString()] }";
|
||||
hardware_manifest_collectors_with_args = ParseHardwareManifestCollectorsString(hardware_manifest_collectors);
|
||||
// Collectors are identified by Name.
|
||||
// Multiple collectors can be identified with a comma delimiter between collector names.
|
||||
// There is a field in the HardwareManifestPlugin Interface that must match this Name.
|
||||
// Each Name can be optionally followed by a space and command-line style arguments.
|
||||
// Those arguments must not break the JSON encoding of the settings file.
|
||||
// ex: collector1_name -a --b=c,collector2_name,collector3_name
|
||||
// If SWID enforcement is enabled, Collectors must also pass validation prior to loading.
|
||||
// Once loaded, the command-line arguments are passed directly to the collector by the Configure method of the Interface.
|
||||
List<string> names = hardware_manifest_collectors_with_args.Keys.ToList();
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.hardware_manifest_collection_swid_enforced.ToString()])) {
|
||||
string hardware_manifest_collection_swid_enforced_str = $"{ configFromSettingsFile[Options.hardware_manifest_collection_swid_enforced.ToString()] }";
|
||||
hardware_manifest_collection_swid_enforced = Boolean.Parse(hardware_manifest_collection_swid_enforced_str);
|
||||
Log.Debug("SWID enforcement of Hardware Manifest Plugins are " + (hardware_manifest_collection_swid_enforced ? "en" : "dis") + "abled in settings.");
|
||||
}
|
||||
hardwareManifests = HardwareManifestPluginManagerUtils.LoadPlugins(names, hardware_manifest_collection_swid_enforced);
|
||||
CleanHardwareManifestCollectors();
|
||||
Log.Debug("Finished configuring the Hardware Manifest Plugin Manager.");
|
||||
} else {
|
||||
Log.Debug("Hardware Manifest Plugin Manager will not be used. No collectors were identified in settings.");
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> ParseHardwareManifestCollectorsString(string hardware_manifest_collectors) {
|
||||
Dictionary<string, string> dict = new();
|
||||
List<string> names = hardware_manifest_collectors.Split(',').Select(s => s.Trim()).ToList();
|
||||
foreach (string name in names) {
|
||||
string[] parts = name.Split(' ', 2); // split on first space
|
||||
dict.Add(parts[0], parts.Length == 2 ? parts[1] : "");
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
private void CleanHardwareManifestCollectors() {
|
||||
List<string> names = hardwareManifests.Select(x => x.Name).ToList();
|
||||
Dictionary<string, string> dict = new();
|
||||
foreach (string name in names) {
|
||||
dict.Add(name, hardware_manifest_collectors_with_args[name]);
|
||||
}
|
||||
hardware_manifest_collectors_with_args.Clear();
|
||||
hardware_manifest_collectors_with_args = dict;
|
||||
}
|
||||
|
||||
public virtual string RunHardwareManifestCollectors() {
|
||||
Log.Debug("Gathering data from loaded hardware manifest collectors.");
|
||||
string manifestJson = "";
|
||||
foreach (IHardwareManifest manifest in hardwareManifests) {
|
||||
try {
|
||||
Log.Debug(" Configuring " + manifest.Name);
|
||||
if (hardware_manifest_collectors_with_args.ContainsKey(manifest.Name)) {
|
||||
manifest.Configure(CLI.SplitArgs(hardware_manifest_collectors_with_args[manifest.Name]));
|
||||
}
|
||||
// TODO: Combine JSON Better
|
||||
// OR Return proto objects
|
||||
Log.Debug(" Gathering from " + manifest.Name);
|
||||
manifestJson = string.Join(manifestJson, manifest.GatherHardwareManifestAsJsonString());
|
||||
} catch (Exception e) {
|
||||
Log.Debug($"Problem retrieving hardware manifest from {manifest.Name}.", e.InnerException);
|
||||
}
|
||||
}
|
||||
//TODO: Verify JSON?
|
||||
return manifestJson;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Ingest paccor data from file
|
||||
private void IngestPaccorDataFromFile() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.paccor_output_file.ToString()])) {
|
||||
Log.Debug("Checking location of the paccor output file.");
|
||||
string paccor_output_path = $"{ configFromSettingsFile[Options.paccor_output_file.ToString()] }";
|
||||
if (DoesFileExist(paccor_output_path, out paccor_output_path)) {
|
||||
if (HasHardwareManifestPlugins()) {
|
||||
Log.Warning("The settings file specified hardware manifest collectors and a paccor output file. Fresh data is preferred over data from a file. If you want to use the file data, clear the collectors field from the settings file.");
|
||||
} else {
|
||||
Log.Debug("Retrieving components from " + Options.paccor_output_file.ToString() + ".");
|
||||
paccor_output = File.ReadAllText(paccor_output_path);
|
||||
if (string.IsNullOrWhiteSpace(paccor_output)) {
|
||||
Log.Warning(Options.paccor_output_file.ToString() + " Paccor output was empty. Cannot perform Platform Attribute validation.");
|
||||
} else {
|
||||
Log.Debug("Output file contains:\n" + paccor_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Debug(Options.paccor_output_file.ToString() + " not set in the settings file.");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ACA Address
|
||||
private void ParseAcaAddress() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.aca_address_port.ToString()])) {
|
||||
Log.Debug("Parsing the ACA Address.");
|
||||
string aca_address_port_str = $"{ configFromSettingsFile[Options.aca_address_port.ToString()] }";
|
||||
if (!string.IsNullOrWhiteSpace(aca_address_port_str)) {
|
||||
aca_address_port = new Uri(aca_address_port_str);
|
||||
Log.Debug(" Found " + aca_address_port);
|
||||
}
|
||||
}
|
||||
if (!HasAcaAddress()) {
|
||||
Log.Error(Options.aca_address_port.ToString() + " not set in the settings file. No HIRS ACA server to talk to. Looking for the format: \"https://<aca_server>:<port>\"");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Auto Detect TPM
|
||||
private void CheckAutoDetectTpm() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.auto_detect_tpm.ToString()])) {
|
||||
Log.Debug("Checking Auto Detect TPM setting.");
|
||||
string auto_detect_tpm_str = $"{ configFromSettingsFile[Options.auto_detect_tpm.ToString()] }";
|
||||
try {
|
||||
auto_detect_tpm = Boolean.Parse(auto_detect_tpm_str);
|
||||
Log.Debug(" Auto Detect TPM is " + (auto_detect_tpm ? "en" : "dis") + "abled.");
|
||||
} catch (FormatException) {
|
||||
auto_detect_tpm = false;
|
||||
Log.Warning(Options.auto_detect_tpm.ToString() + " did not contain a readable true/false setting. Setting to default of false.");
|
||||
}
|
||||
} else {
|
||||
auto_detect_tpm = false;
|
||||
Log.Debug(Options.auto_detect_tpm.ToString() + " not set in the settings file. Setting to default of false.");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region EFI
|
||||
private void CheckEfiPrefix() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.efi_prefix.ToString()])) {
|
||||
Log.Debug("Checking EFI Prefix setting.");
|
||||
efi_prefix = $"{ configFromSettingsFile[Options.efi_prefix.ToString()] }";
|
||||
if (string.IsNullOrWhiteSpace(efi_prefix)) { // If not explicitly set in appsettings, try to use default EFI location on Linux
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
efi_prefix = EFI_ARTIFACT_LINUX_PREFIX + EFI_ARTIFACT_PATH;
|
||||
}
|
||||
} else {
|
||||
if (!Directory.Exists(efi_prefix)) {
|
||||
Log.Debug(Options.efi_prefix.ToString() + ": " + efi_prefix + " did not exist.");
|
||||
efi_prefix = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (efi_prefix == null) {
|
||||
Log.Warning(Options.efi_prefix.ToString() + " not set in the settings file. Will not attempt to scan for artifacts in EFI.");
|
||||
} else {
|
||||
Log.Debug(" Will scan for artifacts in " + efi_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual List<byte[]> gatherPlatformCertificatesFromEFI() {
|
||||
// According to FIM: EFIPREFIX/boot/tcg/{cert,pccert,platform}
|
||||
List<byte[]> platformCerts = null;
|
||||
if (!string.IsNullOrWhiteSpace(efi_prefix)) {
|
||||
EnumerationOptions enumOpts = new EnumerationOptions();
|
||||
enumOpts.MatchCasing = MatchCasing.CaseInsensitive;
|
||||
enumOpts.RecurseSubdirectories = true;
|
||||
List<FileInfo> files = new List<FileInfo>();
|
||||
string[] paths = { "cert", "pccert", "platform" };
|
||||
foreach (string subdir in paths) {
|
||||
string path = efi_prefix + EFI_ARTIFACT_PATH + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles("*base*", enumOpts));
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles("*delta*", enumOpts));
|
||||
} else {
|
||||
path = efi_prefix + EFI_ARTIFACT_PATH_COMPAT + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles("*base*", enumOpts));
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles("*delta*", enumOpts));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (files.Count > 0) { // if none found, don't initialize platformCerts
|
||||
// At least one base platform cert found
|
||||
platformCerts = new List<byte[]>();
|
||||
foreach (FileInfo file in files) {
|
||||
platformCerts.Add(File.ReadAllBytes(file.FullName));
|
||||
Log.Debug("gatherPlatformCertificatesFromEFI: Gathering " + file.FullName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Warning("gatherPlatformCertificatesFromEFI was called without verifying HasEfiPrefix.");
|
||||
}
|
||||
Log.Debug("Found " + (platformCerts == null ? 0 : platformCerts.Count) + " platform certs.");
|
||||
return platformCerts;
|
||||
}
|
||||
|
||||
public virtual List<byte[]> gatherRIMBasesFromEFI() {
|
||||
// According to PC Client RIM
|
||||
List<byte[]> baseRims = null;
|
||||
|
||||
// /boot/tcg/manifest/swidtag Base RIM Files
|
||||
// <name of the tag creator> + <product name> + <RIM version>.swidtag
|
||||
if (!string.IsNullOrWhiteSpace(efi_prefix)) {
|
||||
EnumerationOptions enumOpts = new EnumerationOptions();
|
||||
enumOpts.MatchCasing = MatchCasing.CaseInsensitive;
|
||||
enumOpts.RecurseSubdirectories = true;
|
||||
List<FileInfo> files = new List<FileInfo>();
|
||||
|
||||
string[] paths = { "manifest", "swidtag" };
|
||||
string ext = "*swidtag";
|
||||
foreach (string subdir in paths) {
|
||||
string path = efi_prefix + EFI_ARTIFACT_PATH + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles(ext, enumOpts));
|
||||
} else {
|
||||
path = efi_prefix + EFI_ARTIFACT_PATH_COMPAT + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles(ext, enumOpts));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (files.Count() > 0) { // if none found, don't initialize baseRims
|
||||
// At least one base platform cert found
|
||||
baseRims = new List<byte[]>();
|
||||
foreach (FileInfo file in files) {
|
||||
baseRims.Add(File.ReadAllBytes(file.FullName));
|
||||
Log.Debug("gatherRIMBasesFromEFI: Gathering " + file.FullName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Warning("gatherRIMBasesFromEFI was called without verifying HasEfiPrefix.");
|
||||
}
|
||||
Log.Debug("Found " + (baseRims == null ? 0 : baseRims.Count) + " base RIMs.");
|
||||
return baseRims;
|
||||
}
|
||||
|
||||
public virtual List<byte[]> gatherSupportRIMELsFromEFI() {
|
||||
// According to PC Client RIM
|
||||
List<byte[]> supportRimELs = null;
|
||||
// /boot/tcg/manifest/rim Support RIM Files
|
||||
// <name of the tag creator> + <product name> + <product version>.rimel
|
||||
if (!string.IsNullOrWhiteSpace(efi_prefix)) {
|
||||
EnumerationOptions enumOpts = new EnumerationOptions();
|
||||
enumOpts.MatchCasing = MatchCasing.CaseInsensitive;
|
||||
enumOpts.RecurseSubdirectories = true;
|
||||
List<FileInfo> files = new List<FileInfo>();
|
||||
|
||||
string[] paths = { "manifest", "rim" };
|
||||
string ext = "*rimel";
|
||||
foreach (string subdir in paths) {
|
||||
string path = efi_prefix + EFI_ARTIFACT_PATH + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles(ext, enumOpts));
|
||||
} else {
|
||||
path = efi_prefix + EFI_ARTIFACT_PATH_COMPAT + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles(ext, enumOpts));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (files.Count() > 0) { // if none found, don't initialize baseRims
|
||||
// At least one base platform cert found
|
||||
supportRimELs = new List<byte[]>();
|
||||
foreach (FileInfo file in files) {
|
||||
supportRimELs.Add(File.ReadAllBytes(file.FullName));
|
||||
Log.Debug("gatherSupportRIMELsFromEFI: Gathering " + file.FullName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Warning("gatherSupportRIMELsFromEFI was called without verifying HasEfiPrefix.");
|
||||
}
|
||||
Log.Debug("Found " + (supportRimELs == null ? 0 : supportRimELs.Count) + " support rimel files.");
|
||||
return supportRimELs;
|
||||
}
|
||||
|
||||
public virtual List<byte[]> gatherSupportRIMPCRsFromEFI() {
|
||||
// According to PC Client RIM
|
||||
List<byte[]> supportRimPCRs = null;
|
||||
// /boot/tcg/manifest/rim Support RIM Files
|
||||
// <name of the tag creator> + <product name> + <product version>.rimpcr
|
||||
if (!string.IsNullOrWhiteSpace(efi_prefix)) {
|
||||
EnumerationOptions enumOpts = new EnumerationOptions();
|
||||
enumOpts.MatchCasing = MatchCasing.CaseInsensitive;
|
||||
enumOpts.RecurseSubdirectories = true;
|
||||
List<FileInfo> files = new List<FileInfo>();
|
||||
|
||||
string[] paths = { "manifest", "rim" };
|
||||
string ext = "*rimpcr";
|
||||
foreach (string subdir in paths) {
|
||||
string path = efi_prefix + EFI_ARTIFACT_PATH + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles(ext, enumOpts));
|
||||
} else {
|
||||
path = efi_prefix + EFI_ARTIFACT_PATH_COMPAT + subdir;
|
||||
if (Directory.Exists(path)) {
|
||||
files.AddRange(new DirectoryInfo(path).GetFiles(ext, enumOpts));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (files.Count() > 0) { // if none found, don't initialize baseRims
|
||||
// At least one base platform cert found
|
||||
supportRimPCRs = new List<byte[]>();
|
||||
foreach (FileInfo file in files) {
|
||||
supportRimPCRs.Add(File.ReadAllBytes(file.FullName));
|
||||
Log.Debug("gatherSupportRIMPCRsFromEFI: Gathering " + file.FullName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Warning("gatherSupportRIMPCRsFromEFI was called without verifying HasEfiPrefix.");
|
||||
}
|
||||
Log.Debug("Found " + (supportRimPCRs == null ? 0 : supportRimPCRs.Count) + " support rimpcr files.");
|
||||
return supportRimPCRs;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Ingest Event Log from File
|
||||
private void IngestEventLogFromFile() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.event_log_file.ToString()])) {
|
||||
Log.Debug("Checking location of the event log.");
|
||||
string event_log_path = $"{ configFromSettingsFile[Options.event_log_file.ToString()] }";
|
||||
if (DoesFileExist(event_log_path, out event_log_path)) {
|
||||
Log.Debug("Retrieving the Event Log. ");
|
||||
event_log = File.ReadAllBytes(event_log_path);
|
||||
if (event_log == null || event_log.Length == 0) {
|
||||
Log.Warning(Options.event_log_file.ToString() + " The event log was empty.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.Debug(Options.event_log_file.ToString() + " not set in the settings file.");
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Store Custom Device Info Collector Options
|
||||
private void StoreCustomDeviceInfoCollectorOptions() {
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.linux_bios_vendor_file.ToString()])) {
|
||||
Log.Debug("Custom bios vendor file specified for the Device Info Collector on Linux.");
|
||||
string path = $"{ configFromSettingsFile[Options.linux_bios_vendor_file.ToString()] }";
|
||||
linux_bios_vendor = ReadFileText(path);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.linux_bios_version_file.ToString()])) {
|
||||
Log.Debug("Custom bios version file specified for the Device Info Collector on Linux.");
|
||||
string path = $"{ configFromSettingsFile[Options.linux_bios_version_file.ToString()] }";
|
||||
linux_bios_version = ReadFileText(path);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.linux_sys_vendor_file.ToString()])) {
|
||||
Log.Debug("Custom hardware manufacturer file specified for the Device Info Collector on Linux.");
|
||||
string path = $"{ configFromSettingsFile[Options.linux_sys_vendor_file.ToString()] }";
|
||||
linux_sys_vendor = ReadFileText(path);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.linux_product_name_file.ToString()])) {
|
||||
Log.Debug("Custom hardware product name file specified for the Device Info Collector on Linux.");
|
||||
string path = $"{ configFromSettingsFile[Options.linux_product_name_file.ToString()] }";
|
||||
linux_product_name = ReadFileText(path);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.linux_product_version_file.ToString()])) {
|
||||
Log.Debug("Custom hardware product version file specified for the Device Info Collector on Linux.");
|
||||
string path = $"{ configFromSettingsFile[Options.linux_product_version_file.ToString()] }";
|
||||
linux_product_version = ReadFileText(path);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.linux_product_serial_file.ToString()])) {
|
||||
Log.Debug("Custom hardware product serial file specified for the Device Info Collector on Linux.");
|
||||
string path = $"{ configFromSettingsFile[Options.linux_product_serial_file.ToString()] }";
|
||||
linux_product_serial = ReadFileText(path);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
public static bool DoesFileExist(string path, out string out_full_path) {
|
||||
bool found = false;
|
||||
out_full_path = "";
|
||||
if (!string.IsNullOrWhiteSpace(path)) {
|
||||
out_full_path = Path.GetFullPath(path);
|
||||
found = File.Exists(out_full_path);
|
||||
if (!found) {
|
||||
Log.Debug(" File identified in settings did not exist: " + out_full_path);
|
||||
} else {
|
||||
Log.Debug(" File exists: " + out_full_path);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public static string ReadFileText(string path) {
|
||||
string text = "";
|
||||
if (DoesFileExist(path, out string full_path)) {
|
||||
Log.Debug(" Reading file: " + full_path + ".");
|
||||
text = File.ReadAllText(full_path);
|
||||
Log.Debug(" " + (string.IsNullOrWhiteSpace(text) ? "File was empty." : text));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public bool HasHardwareManifestPlugins() {
|
||||
return hardwareManifests.Count > 0;
|
||||
}
|
||||
public bool HasPaccorOutputFromFile() {
|
||||
return !string.IsNullOrEmpty(paccor_output);
|
||||
}
|
||||
public bool HasAcaAddress() {
|
||||
return aca_address_port != null;
|
||||
}
|
||||
public bool HasEfiPrefix() {
|
||||
return !string.IsNullOrEmpty(efi_prefix);
|
||||
}
|
||||
public bool IsAutoDetectTpmEnabled() {
|
||||
return auto_detect_tpm;
|
||||
}
|
||||
public bool HasEventLogFromFile() {
|
||||
return event_log != null && event_log.Length > 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
using Hirs.Pb;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using Serilog;
|
||||
|
||||
namespace hirs {
|
||||
public class ClassicDeviceInfoCollector : IHirsDeviceInfoCollector {
|
||||
public static readonly string NOT_SPECIFIED = "Not Specified";
|
||||
public static readonly string LINUX_DEFAULT_BIOS_VENDOR_PATH = "/sys/class/dmi/id/bios_vendor";
|
||||
public static readonly string LINUX_DEFAULT_BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version";
|
||||
public static readonly string LINUX_DEFAULT_BIOS_DATE_PATH = "/sys/class/dmi/id/bios_date";
|
||||
public static readonly string LINUX_DEFAULT_SYS_VENDOR_PATH = "/sys/class/dmi/id/sys_vendor";
|
||||
public static readonly string LINUX_DEFAULT_PRODUCT_NAME_PATH = "/sys/class/dmi/id/product_name";
|
||||
public static readonly string LINUX_DEFAULT_PRODUCT_VERSION_PATH = "/sys/class/dmi/id/product_version";
|
||||
public static readonly string LINUX_DEFAULT_PRODUCT_SERIAL_PATH = "/sys/class/dmi/id/product_serial";
|
||||
private readonly Settings? settings;
|
||||
|
||||
public ClassicDeviceInfoCollector() {
|
||||
settings = null;
|
||||
}
|
||||
public ClassicDeviceInfoCollector(Settings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public static string FileToString(string path, string def) {
|
||||
string result;
|
||||
try {
|
||||
result = File.ReadAllText(path).Trim();
|
||||
} catch {
|
||||
result = def;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(result)) {
|
||||
result = def;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public DeviceInfo CollectDeviceInfo(string acaAddress) {
|
||||
DeviceInfo dv = new();
|
||||
dv.Fw = CollectFirmwareInfo();
|
||||
dv.Hw = CollectHardwareInfo();
|
||||
dv.Nw = CollectNetworkInfo(acaAddress);
|
||||
dv.Os = CollectOsInfo();
|
||||
return dv;
|
||||
}
|
||||
|
||||
public FirmwareInfo CollectFirmwareInfo() {
|
||||
FirmwareInfo fw = new();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
ManagementScope myScope = new("root\\CIMV2");
|
||||
ManagementObjectSearcher s = new("SELECT * FROM Win32_BIOS");
|
||||
fw.BiosVendor = NOT_SPECIFIED;
|
||||
fw.BiosVersion = NOT_SPECIFIED;
|
||||
fw.BiosReleaseDate = NOT_SPECIFIED;
|
||||
foreach (ManagementObject o in s.Get()) {
|
||||
string manufacturer = (string)o.GetPropertyValue("Manufacturer");
|
||||
string version = (string)o.GetPropertyValue("Version");
|
||||
string releasedate = (string)o.GetPropertyValue("ReleaseDate");
|
||||
fw.BiosVendor = string.IsNullOrEmpty(manufacturer) ? NOT_SPECIFIED : manufacturer;
|
||||
fw.BiosVersion = string.IsNullOrEmpty(version) ? NOT_SPECIFIED : version;
|
||||
fw.BiosReleaseDate = string.IsNullOrEmpty(releasedate) ? NOT_SPECIFIED : releasedate;
|
||||
break;
|
||||
}
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
if (settings != null) {
|
||||
if (!string.IsNullOrEmpty(settings.linux_bios_vendor)) {
|
||||
fw.BiosVendor = settings.linux_bios_vendor.Trim();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(settings.linux_bios_version)) {
|
||||
fw.BiosVersion = settings.linux_bios_version.Trim();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(settings.linux_bios_date)) {
|
||||
fw.BiosReleaseDate = settings.linux_bios_date.Trim();
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(fw.BiosVendor)) {
|
||||
fw.BiosVendor = FileToString(LINUX_DEFAULT_BIOS_VENDOR_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
if (string.IsNullOrEmpty(fw.BiosVersion)) {
|
||||
fw.BiosVersion = FileToString(LINUX_DEFAULT_BIOS_VERSION_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
if (string.IsNullOrEmpty(fw.BiosReleaseDate)) {
|
||||
fw.BiosReleaseDate = FileToString(LINUX_DEFAULT_BIOS_DATE_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
// tbd
|
||||
} else {
|
||||
// tbd
|
||||
}
|
||||
|
||||
Log.Debug("Bios Vendor: " + fw.BiosVendor);
|
||||
Log.Debug("Bios Version: " + fw.BiosVersion);
|
||||
Log.Debug("Bios Date: " + fw.BiosReleaseDate);
|
||||
|
||||
return fw;
|
||||
}
|
||||
|
||||
public HardwareInfo CollectHardwareInfo() {
|
||||
HardwareInfo hw = new();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
ManagementScope myScope = new("root\\CIMV2");
|
||||
ManagementObjectSearcher s = new("SELECT * FROM Win32_ComputerSystemProduct");
|
||||
hw.Manufacturer = NOT_SPECIFIED;
|
||||
hw.ProductName = NOT_SPECIFIED;
|
||||
hw.ProductVersion = NOT_SPECIFIED;
|
||||
hw.SystemSerialNumber = NOT_SPECIFIED;
|
||||
foreach (ManagementObject o in s.Get()) {
|
||||
string vendor = (string)o.GetPropertyValue("Vendor");
|
||||
string name = (string)o.GetPropertyValue("Name");
|
||||
string version = (string)o.GetPropertyValue("Version");
|
||||
string identifyingnumber = (string)o.GetPropertyValue("IdentifyingNumber");
|
||||
hw.Manufacturer = string.IsNullOrWhiteSpace(vendor) ? NOT_SPECIFIED : vendor;
|
||||
hw.ProductName = string.IsNullOrWhiteSpace(name) ? NOT_SPECIFIED : name;
|
||||
hw.ProductVersion = string.IsNullOrWhiteSpace(version) ? NOT_SPECIFIED : version;
|
||||
hw.SystemSerialNumber = string.IsNullOrWhiteSpace(identifyingnumber) ? NOT_SPECIFIED : identifyingnumber;
|
||||
break;
|
||||
}
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
if (settings != null) {
|
||||
if (!string.IsNullOrEmpty(settings.linux_sys_vendor)) {
|
||||
hw.Manufacturer = settings.linux_sys_vendor.Trim();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(settings.linux_product_name)) {
|
||||
hw.ProductName = settings.linux_product_name.Trim();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(settings.linux_product_version)) {
|
||||
hw.ProductVersion = settings.linux_product_version.Trim();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(settings.linux_product_serial)) {
|
||||
hw.SystemSerialNumber = settings.linux_product_serial.Trim();
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(hw.Manufacturer)) {
|
||||
hw.Manufacturer = FileToString(LINUX_DEFAULT_SYS_VENDOR_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
if (string.IsNullOrEmpty(hw.ProductName)) {
|
||||
hw.ProductName = FileToString(LINUX_DEFAULT_PRODUCT_NAME_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
if (string.IsNullOrEmpty(hw.ProductVersion)) {
|
||||
hw.ProductVersion = FileToString(LINUX_DEFAULT_PRODUCT_VERSION_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
if (string.IsNullOrEmpty(hw.SystemSerialNumber)) {
|
||||
hw.SystemSerialNumber = FileToString(LINUX_DEFAULT_PRODUCT_SERIAL_PATH, NOT_SPECIFIED);
|
||||
}
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
// tbd
|
||||
} else {
|
||||
// tbd
|
||||
}
|
||||
|
||||
Log.Debug("System Manufacturer: " + hw.Manufacturer);
|
||||
Log.Debug("Product Name: " + hw.ProductName);
|
||||
Log.Debug("Product Version: " + hw.ProductVersion);
|
||||
Log.Debug("System Serial Number: " + hw.SystemSerialNumber);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
public NetworkInfo CollectNetworkInfo(string acaAddress) {
|
||||
NetworkInfo nw = new();
|
||||
|
||||
NetworkInterface iface = NetworkInterface
|
||||
.GetAllNetworkInterfaces()
|
||||
.Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)
|
||||
.FirstOrDefault();
|
||||
|
||||
nw.MacAddress = iface.GetPhysicalAddress().ToString();
|
||||
|
||||
nw.ClearIpAddress();
|
||||
// First attempt to find local ip by connecting ACA
|
||||
if (string.IsNullOrWhiteSpace(acaAddress)) {
|
||||
Uri uri = new(acaAddress);
|
||||
try {
|
||||
Socket socket = new(AddressFamily.InterNetwork, SocketType.Dgram, 0);
|
||||
socket.Connect(uri.Host, uri.Port);
|
||||
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
|
||||
nw.IpAddress = endPoint.Address.ToString();
|
||||
} catch {
|
||||
Log.Debug("Not connected to the internet. Trying another search.");
|
||||
}
|
||||
}
|
||||
// Second attempt to find local ip by scanning first interface that is up and not a loopback address
|
||||
if (!nw.HasIpAddress) {
|
||||
foreach (UnicastIPAddressInformation ip in iface.GetIPProperties().UnicastAddresses) {
|
||||
if (ip.Address.AddressFamily == AddressFamily.InterNetwork) {
|
||||
nw.IpAddress = ip.Address.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search for hostname
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
nw.Hostname = Dns.GetHostName().ToLower();
|
||||
string domainName = IPGlobalProperties.GetIPGlobalProperties().DomainName;
|
||||
if (!string.IsNullOrWhiteSpace(domainName)) {
|
||||
nw.Hostname = nw.Hostname + "." + domainName;
|
||||
}
|
||||
} else if (nw.HasIpAddress) {
|
||||
nw.Hostname = Dns.GetHostEntry(nw.IpAddress).HostName;
|
||||
} else {
|
||||
nw.Hostname = Dns.GetHostName();
|
||||
}
|
||||
|
||||
|
||||
Log.Debug("Network Info IP: " + nw.IpAddress);
|
||||
Log.Debug("Network Info MAC: " + nw.MacAddress);
|
||||
Log.Debug("Network Info Hostname: " + nw.Hostname);
|
||||
|
||||
return nw;
|
||||
}
|
||||
|
||||
public OsInfo CollectOsInfo() {
|
||||
OsInfo info = new();
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
info.OsName = OSPlatform.Windows.ToString();
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
info.OsName = OSPlatform.Linux.ToString();
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
info.OsName = OSPlatform.OSX.ToString();
|
||||
} else {
|
||||
info.OsName = RuntimeInformation.OSDescription;
|
||||
}
|
||||
info.OsVersion = RuntimeInformation.OSDescription;
|
||||
info.OsArch = RuntimeInformation.OSArchitecture.ToString();
|
||||
info.Distribution = RuntimeInformation.FrameworkDescription;
|
||||
info.DistributionRelease = RuntimeInformation.FrameworkDescription;
|
||||
|
||||
Log.Debug("OS Name: " + info.OsName);
|
||||
Log.Debug("OS Version: " + info.OsVersion);
|
||||
Log.Debug("Architecture: " + info.OsArch);
|
||||
Log.Debug("Distribution: " + info.Distribution);
|
||||
Log.Debug("Distribution Release: " + info.DistributionRelease);
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using Hirs.Pb;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace hirs {
|
||||
public interface IHirsDeviceInfoCollector {
|
||||
DeviceInfo CollectDeviceInfo(string address);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace hirs {
|
||||
public interface IHirsProvisioner {
|
||||
void SetSettings(Settings settings);
|
||||
void SetCLI(CLI cli);
|
||||
IHirsAcaTpm ConnectTpm();
|
||||
void SetClient(IHirsAcaClient clientWithAddress);
|
||||
void SetDeviceInfoCollector(IHirsDeviceInfoCollector collector);
|
||||
Task<int> Provision(IHirsAcaTpm tpm);
|
||||
}
|
||||
}
|
296
HIRS_Provisioner.NET/hirs/src/provisioner/Provisioner.cs
Normal file
296
HIRS_Provisioner.NET/hirs/src/provisioner/Provisioner.cs
Normal file
@ -0,0 +1,296 @@
|
||||
using Google.Protobuf;
|
||||
using Hirs.Pb;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace hirs {
|
||||
|
||||
public class Provisioner : IHirsProvisioner {
|
||||
private CLI cli = null;
|
||||
private Settings settings = null;
|
||||
private IHirsDeviceInfoCollector deviceInfoCollector = null;
|
||||
private IHirsAcaClient acaClient = null;
|
||||
|
||||
public Provisioner() {
|
||||
}
|
||||
|
||||
public Provisioner(Settings settings, CLI cli) {
|
||||
SetSettings(settings);
|
||||
SetCLI(cli);
|
||||
}
|
||||
|
||||
public void SetSettings(Settings settings) {
|
||||
if (settings == null) {
|
||||
Log.Error("Unknown error. Settings were supposed to have been parsed.");
|
||||
}
|
||||
this.settings = settings!;
|
||||
}
|
||||
|
||||
public void SetCLI(CLI cli) {
|
||||
if (cli == null) {
|
||||
Log.Error("Unknown error. CLI arguments were supposed to have been parsed.");
|
||||
}
|
||||
this.cli = cli;
|
||||
}
|
||||
|
||||
public IHirsAcaTpm ConnectTpm() {
|
||||
IHirsAcaTpm tpm = null;
|
||||
// If tpm device type is set on the command line
|
||||
if (cli.Nix) {
|
||||
tpm = new CommandTpm(CommandTpm.Devices.NIX);
|
||||
} else if (cli.Tcp && cli.Ip != null) {
|
||||
string[] split = cli.Ip.Split(":");
|
||||
if (split.Length == 2) {
|
||||
tpm = new CommandTpm(cli.Sim, split[0], Int32.Parse(split[1]));
|
||||
Log.Debug("Connected to TPM via TCP at " + cli.Ip);
|
||||
} else {
|
||||
Log.Error("ip input should have the format servername:port. The given input was '" + cli.Ip + "'.");
|
||||
}
|
||||
} else if (cli.Win) {
|
||||
tpm = new CommandTpm(CommandTpm.Devices.WIN);
|
||||
}
|
||||
|
||||
// If command line not set, check if auto detect is enabled
|
||||
if ((tpm == null) && settings.IsAutoDetectTpmEnabled()) {
|
||||
Log.Debug("Auto Detect TPM is Enabled. Starting search for the TPM.");
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
try {
|
||||
tpm = new CommandTpm(CommandTpm.Devices.WIN);
|
||||
Log.Debug("Auto Detect found a WIN TPM Device.");
|
||||
} catch (Exception) {
|
||||
Log.Debug("No WIN TPM Device found by auto detect.");
|
||||
}
|
||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
||||
try {
|
||||
tpm = new CommandTpm(CommandTpm.Devices.NIX);
|
||||
Log.Debug("Auto Detect found a Linux TPM Device.");
|
||||
} catch (Exception) {
|
||||
Log.Debug("No Linux TPM Device found by auto detect.");
|
||||
}
|
||||
}
|
||||
|
||||
// if tpm still null, try set up TcpTpmDevice on sim, catch exception
|
||||
if (tpm == null) {
|
||||
try {
|
||||
string[] split = CommandTpm.DefaultSimulatorNamePort.Split(":");
|
||||
tpm = new CommandTpm(true, split[0], Int32.Parse(split[1]));
|
||||
Log.Debug("Auto Detect found a TPM simulator at " + CommandTpm.DefaultSimulatorNamePort + ".");
|
||||
} catch (Exception) {
|
||||
Log.Debug("No TPM simulator found by auto detect.");
|
||||
}
|
||||
}
|
||||
} else if ((tpm != null) && settings.IsAutoDetectTpmEnabled()) {
|
||||
Log.Debug("Auto detect TPM was enabled in settings, but command line options were also given. Using command line options.");
|
||||
}
|
||||
|
||||
// If TPM is still not set up, offer help message
|
||||
if (tpm == null) {
|
||||
Log.Fatal(
|
||||
"To connect to a TPM device on Windows, add the command line argument --win\n" +
|
||||
"To connect to a TPM device on LINUX, add the command line argument --nix\n" +
|
||||
"To connect to a TPM via TCP, add the command line arguments --tcp <address>:<port>\n" +
|
||||
"To connect to a TPM simulator at the default TCP socket of " + CommandTpm.DefaultSimulatorNamePort + ", add the command line arguments --tcp --sim\n" +
|
||||
"To connect to a TPM simulator at any other socket, add the command line arguments --tcp --sim <address>:<port>\n");
|
||||
}
|
||||
return tpm;
|
||||
}
|
||||
|
||||
public void UseBuiltInClient(string addr) {
|
||||
acaClient = new Client(addr);
|
||||
}
|
||||
|
||||
public void SetClient(IHirsAcaClient client) {
|
||||
acaClient = client;
|
||||
}
|
||||
|
||||
public void UseClassicDeviceInfoCollector() {
|
||||
deviceInfoCollector = new ClassicDeviceInfoCollector(settings);
|
||||
}
|
||||
|
||||
public void SetDeviceInfoCollector(IHirsDeviceInfoCollector collector) {
|
||||
if (collector == null) {
|
||||
UseClassicDeviceInfoCollector();
|
||||
} else {
|
||||
deviceInfoCollector = collector;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> Provision(IHirsAcaTpm tpm) {
|
||||
ClientExitCodes result = ClientExitCodes.SUCCESS;
|
||||
if (tpm != null) {
|
||||
Log.Information("--> Provisioning");
|
||||
Log.Information("----> Gathering Endorsement Key Certificate.");
|
||||
byte[] ekc = tpm.GetCertificateFromNvIndex(CommandTpm.DefaultEkcNvIndex);
|
||||
if (ekc.Length == 0) {
|
||||
Log.Information("------> No Endorsement Key Certificate found at the expected index. The ACA may have one uploaded for this TPM.");
|
||||
}
|
||||
Log.Debug("Checking EK PUBLIC");
|
||||
tpm.CreateEndorsementKey(CommandTpm.DefaultEkHandle); // Will not create key if obj already exists at handle
|
||||
byte[] ekPublicArea = tpm.ReadPublicArea(CommandTpm.DefaultEkHandle, out byte[] name, out byte[] qualifiedName);
|
||||
|
||||
Log.Information("----> " + (cli.ReplaceAK ? "Creating new" : "Verifying existence of") + " Attestation Key.");
|
||||
tpm.CreateAttestationKey(CommandTpm.DefaultEkHandle, CommandTpm.DefaultAkHandle, cli.ReplaceAK);
|
||||
|
||||
Log.Debug("Gathering AK PUBLIC.");
|
||||
byte[] akPublicArea = tpm.ReadPublicArea(CommandTpm.DefaultAkHandle, out name, out qualifiedName);
|
||||
|
||||
List<byte[]> pcs = null, baseRims = null, supportRimELs = null, supportRimPCRs = null;
|
||||
if (settings.HasEfiPrefix()) {
|
||||
Log.Information("----> Gathering artifacts from EFI.");
|
||||
pcs = settings.gatherPlatformCertificatesFromEFI();
|
||||
baseRims = settings.gatherRIMBasesFromEFI();
|
||||
supportRimELs = settings.gatherSupportRIMELsFromEFI();
|
||||
supportRimPCRs = settings.gatherSupportRIMPCRsFromEFI();
|
||||
}
|
||||
|
||||
Log.Debug("Setting up the Client.");
|
||||
Uri acaAddress = settings.aca_address_port;
|
||||
if (acaClient == null) {
|
||||
UseBuiltInClient(acaAddress.AbsoluteUri);
|
||||
}
|
||||
|
||||
Log.Information("----> Collecting device information.");
|
||||
DeviceInfo dv = deviceInfoCollector.CollectDeviceInfo(acaAddress.AbsoluteUri);
|
||||
if (baseRims != null) {
|
||||
foreach (byte[] baseRim in baseRims) {
|
||||
dv.Swidfile.Add(ByteString.CopyFrom(baseRim));
|
||||
}
|
||||
}
|
||||
if (supportRimELs != null) {
|
||||
foreach (byte[] supportRimEL in supportRimELs) {
|
||||
dv.Logfile.Add(ByteString.CopyFrom(supportRimEL));
|
||||
}
|
||||
}
|
||||
if (supportRimPCRs != null) {
|
||||
foreach (byte[] supportRimPCR in supportRimPCRs) {
|
||||
dv.Logfile.Add(ByteString.CopyFrom(supportRimPCR));
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug("Gathering hardware component information:");
|
||||
string manifest = "";
|
||||
if (settings.HasHardwareManifestPlugins()) {
|
||||
manifest = settings.RunHardwareManifestCollectors();
|
||||
} else if (settings.HasPaccorOutputFromFile()) {
|
||||
manifest = settings.paccor_output;
|
||||
} else {
|
||||
Log.Warning("No hardware collectors nor paccor output file were identified.");
|
||||
}
|
||||
Log.Debug("Hardware component information that will be sent to the ACA: " + manifest);
|
||||
|
||||
Log.Debug("Gathering the event log.");
|
||||
byte[] eventLog;
|
||||
if (settings.HasEventLogFromFile()) {
|
||||
Log.Debug(" Using the event log identified in settings.");
|
||||
eventLog = settings.event_log;
|
||||
} else {
|
||||
Log.Debug(" Attempting to collect the event log from the system.");
|
||||
eventLog = tpm.GetEventLog();
|
||||
}
|
||||
|
||||
if (eventLog != null) {
|
||||
Log.Debug("Event log gathered is " + eventLog.Length + " bytes.");
|
||||
dv.Livelog = ByteString.CopyFrom(eventLog);
|
||||
}
|
||||
|
||||
Log.Debug("Gathering PCR data from the TPM.");
|
||||
string pcrsList, pcrsSha1, pcrsSha256;
|
||||
CommandTpm.FormatPcrValuesForAca(tpm.GetPcrList(Tpm2Lib.TpmAlgId.Sha1), "sha1", out pcrsSha1);
|
||||
CommandTpm.FormatPcrValuesForAca(tpm.GetPcrList(Tpm2Lib.TpmAlgId.Sha256), "sha256", out pcrsSha256);
|
||||
pcrsList = pcrsSha1 + pcrsSha256;
|
||||
Log.Debug("Result of formatting pcr values for the ACA:");
|
||||
Log.Debug("\n" + pcrsList);
|
||||
dv.Pcrslist = ByteString.CopyFromUtf8(pcrsList);
|
||||
|
||||
Log.Debug("Create identity claim");
|
||||
IdentityClaim idClaim = acaClient.CreateIdentityClaim(dv, akPublicArea, ekPublicArea, ekc, pcs, manifest);
|
||||
|
||||
Log.Information("----> Sending identity claim to Attestation CA");
|
||||
IdentityClaimResponse icr = await acaClient.PostIdentityClaim(idClaim);
|
||||
Log.Information("----> Received response. Attempting to decrypt nonce");
|
||||
if (icr.HasStatus) {
|
||||
if (icr.Status == ResponseStatus.Pass) {
|
||||
Log.Debug("The ACA accepted the identity claim.");
|
||||
} else {
|
||||
Log.Debug("The ACA did not accept the identity claim. See details on the ACA.");
|
||||
result = ClientExitCodes.PASS_1_STATUS_FAIL;
|
||||
return (int)result;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] integrityHMAC = null, encIdentity = null, encryptedSecret = null;
|
||||
if (icr.HasCredentialBlob) {
|
||||
byte[] credentialBlob = icr.CredentialBlob.ToByteArray(); // look for the nonce
|
||||
Log.Debug("ACA delivered IdentityClaimResponse credentialBlob " + BitConverter.ToString(credentialBlob));
|
||||
int credentialBlobLen = credentialBlob[0] | (credentialBlob[1] << 8);
|
||||
int integrityHmacLen = (credentialBlob[2] << 8) | credentialBlob[3];
|
||||
integrityHMAC = new byte[integrityHmacLen];
|
||||
Array.Copy(credentialBlob, 4, integrityHMAC, 0, integrityHmacLen);
|
||||
int encIdentityLen = credentialBlobLen - integrityHmacLen - 2;
|
||||
encIdentity = new byte[encIdentityLen];
|
||||
Array.Copy(credentialBlob, 4 + integrityHmacLen, encIdentity, 0, encIdentityLen);
|
||||
// The following offsets are bound tightly to the way makecredential is implemented on the ACA.
|
||||
int encryptedSecretLen = credentialBlob[134] | (credentialBlob[135] << 8);
|
||||
encryptedSecret = new byte[encryptedSecretLen];
|
||||
Array.Copy(credentialBlob, 136, encryptedSecret, 0, encryptedSecretLen);
|
||||
Log.Debug("Prepared values to give to activateCredential.");
|
||||
Log.Debug(" integrityHMAC: " + BitConverter.ToString(integrityHMAC));
|
||||
Log.Debug(" encIdentity: " + BitConverter.ToString(encIdentity));
|
||||
Log.Debug(" encryptedSecret: " + BitConverter.ToString(encryptedSecret));
|
||||
} else {
|
||||
result = ClientExitCodes.MAKE_CREDENTIAL_BLOB_MALFORMED;
|
||||
Log.Error("The response from the ACA did not contain a CredentialBlob.");
|
||||
}
|
||||
|
||||
if (integrityHMAC != null && encIdentity != null && encryptedSecret != null) {
|
||||
Log.Debug("Executing activateCredential.");
|
||||
byte[] recoveredSecret = tpm.ActivateCredential(CommandTpm.DefaultAkHandle, CommandTpm.DefaultEkHandle, integrityHMAC, encIdentity, encryptedSecret);
|
||||
Log.Debug("Gathering quote.");
|
||||
uint[] selectPcrs = null;
|
||||
if (icr.HasPcrMask) {
|
||||
// For now, the ACA will send a comma separated selection of PCRs as a string
|
||||
try {
|
||||
selectPcrs = icr.PcrMask.Split(',').Select(uint.Parse).ToList().ToArray();
|
||||
} catch (Exception) {
|
||||
Log.Warning("PcrMask was included in the IdentityClaimResponse, but could not be parsed." +
|
||||
"Collecting quote over default PCR selection.");
|
||||
Log.Debug("This PcrMask could not be parsed: " + icr.PcrMask);
|
||||
}
|
||||
}
|
||||
tpm.GetQuote(CommandTpm.DefaultAkHandle, Tpm2Lib.TpmAlgId.Sha256, recoveredSecret, out CommandTpmQuoteResponse ctqr, selectPcrs);
|
||||
Log.Information("----> Nonce successfully decrypted. Sending attestation certificate request");
|
||||
CertificateRequest akCertReq = acaClient.CreateAkCertificateRequest(recoveredSecret, ctqr);
|
||||
byte[] certificate;
|
||||
Log.Debug("Communicate certificate request to the ACA.");
|
||||
CertificateResponse cr = await acaClient.PostCertificateRequest(akCertReq);
|
||||
Log.Debug("Response received from the ACA regarding the certificate request.");
|
||||
if (cr.HasStatus) {
|
||||
if (cr.Status == ResponseStatus.Pass) {
|
||||
Log.Debug("ACA returned a positive response to the Certificate Request.");
|
||||
} else {
|
||||
Log.Debug("The ACA did not return any certificates. See details on the ACA.");
|
||||
result = ClientExitCodes.PASS_2_STATUS_FAIL;
|
||||
return (int)result;
|
||||
}
|
||||
}
|
||||
if (cr.HasCertificate) {
|
||||
certificate = cr.Certificate.ToByteArray(); // contains certificate
|
||||
Log.Debug("Printing attestation key certificate: " + BitConverter.ToString(certificate));
|
||||
}
|
||||
} else {
|
||||
result = ClientExitCodes.MAKE_CREDENTIAL_BLOB_MALFORMED;
|
||||
Log.Error("Credential elements could not be extracted from the ACA's response.");
|
||||
}
|
||||
} else {
|
||||
result = ClientExitCodes.TPM_ERROR;
|
||||
Log.Error("Could not provision because the TPM object was null.");
|
||||
}
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
497
HIRS_Provisioner.NET/hirs/src/tpm/CommandTpm.cs
Normal file
497
HIRS_Provisioner.NET/hirs/src/tpm/CommandTpm.cs
Normal file
@ -0,0 +1,497 @@
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using Tpm2Lib;
|
||||
|
||||
namespace hirs {
|
||||
public class CommandTpm : IHirsAcaTpm {
|
||||
public enum Devices {
|
||||
NIX,
|
||||
TCP,
|
||||
WIN
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If using a TCP connection, the default DNS name/IP address for the
|
||||
/// simulator.
|
||||
/// </summary>
|
||||
public const string DefaultSimulatorNamePort = "127.0.0.1:2321";
|
||||
|
||||
public const uint DefaultEkcNvIndex = 0x1c00002;
|
||||
public const uint DefaultEkHandle = 0x81010001;
|
||||
public const uint DefaultAkHandle = 0x81010002;
|
||||
|
||||
private readonly Tpm2 tpm;
|
||||
|
||||
private readonly Boolean simulator;
|
||||
|
||||
private List<AuthSession> sessionTracking = new List<AuthSession>();
|
||||
|
||||
/**
|
||||
* For TCP TpmDevices
|
||||
*/
|
||||
public CommandTpm(Boolean sim, string ip, int port) {
|
||||
simulator = sim;
|
||||
Tpm2Device tpmDevice = new TcpTpmDevice(ip, port);
|
||||
tpm = TpmSetupByType(tpmDevice);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a TPM device on Linux and Windows
|
||||
*/
|
||||
public CommandTpm(Devices dev) {
|
||||
Tpm2Device tpmDevice = null;
|
||||
switch (dev) {
|
||||
case Devices.NIX:
|
||||
// LinuxTpmDevice will first try to connect tpm2-abrmd and second try to connect directly to device
|
||||
StringWriter writer = new();
|
||||
Console.SetOut(writer);
|
||||
// The LinuxTpmDevice will print to Console/Stdout an error when it cannot find a resource manager
|
||||
// This will redirect the Console messages
|
||||
tpmDevice = new LinuxTpmDevice();
|
||||
// Reset the Console messages
|
||||
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
|
||||
break;
|
||||
case Devices.WIN:
|
||||
tpmDevice = new TbsDevice();
|
||||
break;
|
||||
default:
|
||||
Log.Error("Unknown option selected in CommandTpm(Devices) constructor.");
|
||||
break;
|
||||
}
|
||||
tpm = TpmSetupByType(tpmDevice);
|
||||
}
|
||||
|
||||
public CommandTpm(Tpm2 tpm) {
|
||||
this.tpm = tpm;
|
||||
}
|
||||
|
||||
~CommandTpm() {
|
||||
if (tpm != null) {
|
||||
tpm.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetCertificateFromNvIndex(uint index) {
|
||||
Log.Debug("GetCertificateFromNvIndex 0x" + index.ToString("X"));
|
||||
byte[] certificate = Array.Empty<byte>();
|
||||
|
||||
TpmHandle nvHandle = new(index);
|
||||
try {
|
||||
byte[] nvName; // not used for this function. have to collect from NvReadPublic.
|
||||
NvPublic obj = tpm.NvReadPublic(nvHandle, out nvName);
|
||||
if (obj != null) {
|
||||
byte[] indexData = NvBufferedRead(TpmHandle.RhOwner, nvHandle, obj.dataSize, 0);
|
||||
if (indexData != null) {
|
||||
certificate = ExtractFirstCertificate(indexData); // the nvIndex could contain random fill around the certificate
|
||||
if (certificate != null) {
|
||||
Log.Debug("GetCertificateFromNvIndex: Read: " + BitConverter.ToString(certificate));
|
||||
} else {
|
||||
Log.Debug("GetCertificateFromNvIndex: No certificate found within data at index.");
|
||||
}
|
||||
} else {
|
||||
Log.Debug("GetCertificateFromNvIndex: Could not read any data.");
|
||||
}
|
||||
} else {
|
||||
Log.Debug("GetCertificateFromNvIndex: Nothing found at index: " + DefaultEkcNvIndex);
|
||||
}
|
||||
} catch (TpmException e) {
|
||||
Log.Debug(e, "GetCertificateFromNvIndex TPM error");
|
||||
}
|
||||
return certificate;
|
||||
}
|
||||
|
||||
private byte[] NvBufferedRead(TpmHandle authHandle, TpmHandle nvIndex, ushort size, ushort offset) {
|
||||
ushort maxReadSize = 256;
|
||||
byte[] buffer = new byte[size];
|
||||
|
||||
ushort ptr = 0;
|
||||
while (offset < size) {
|
||||
int q = Math.DivRem(size - offset, maxReadSize, out int r);
|
||||
ushort sizeToRead = q > 0 ? maxReadSize : (ushort)r;
|
||||
byte[] block = tpm.NvRead(authHandle, nvIndex, sizeToRead, offset);
|
||||
Array.Copy(block, 0, buffer, ptr, sizeToRead);
|
||||
offset += sizeToRead;
|
||||
ptr += sizeToRead;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static byte[] ExtractFirstCertificate(byte[] data) {
|
||||
byte[] extracted = null;
|
||||
|
||||
if (data != null) {
|
||||
// search for first instance of 30 82
|
||||
int pos = 0;
|
||||
bool found = false;
|
||||
while (pos < (data.Length - 1)) {
|
||||
if (data[pos] == 0x30) {
|
||||
if (data[pos + 1] == 0x82) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
// find the size of the structure.
|
||||
// 30 82 means the size will be described in next 2 bytes
|
||||
// Data from NV should be BIG ENDIAN since 3082 was found in step 1.
|
||||
int size = 0;
|
||||
if (found && data.Length > (pos + 3)) {
|
||||
byte[] sizeBuffer = new byte[2];
|
||||
sizeBuffer[0] = data[pos + 3];
|
||||
sizeBuffer[1] = data[pos + 2];
|
||||
size = 4 + BitConverter.ToInt16(sizeBuffer); // 4 bytes added to final count for pos+3
|
||||
}
|
||||
|
||||
// copy the structure to the output buffer
|
||||
if (size > 0) {
|
||||
extracted = new byte[size];
|
||||
Array.Copy(data, pos, extracted, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
return extracted;
|
||||
}
|
||||
|
||||
// allows client to access the readpublic function
|
||||
public TpmPublic ReadPublicArea(uint handleInt, out byte[] name, out byte[] qualifiedName) {
|
||||
TpmHandle handle = new(handleInt);
|
||||
TpmPublic obj = null;
|
||||
name = null;
|
||||
qualifiedName = null;
|
||||
try {
|
||||
obj = tpm.ReadPublic(handle, out byte[] localName, out byte[] localQualifiedName);
|
||||
name = localName;
|
||||
qualifiedName = localQualifiedName;
|
||||
} catch {
|
||||
// Don't think I need an exception here. Let the calling method throw if needed.
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static TpmPublic GenerateEKTemplateL1() {
|
||||
TpmAlgId nameAlg = TpmAlgId.Sha256;
|
||||
ObjectAttr attributes = ObjectAttr.FixedTPM | ObjectAttr.FixedParent | ObjectAttr.SensitiveDataOrigin | ObjectAttr.AdminWithPolicy | ObjectAttr.Restricted | ObjectAttr.Decrypt;
|
||||
byte[] auth_policy = { // Template L-1
|
||||
0x83, 0x71, 0x97, 0x67, 0x44, 0x84,
|
||||
0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D,
|
||||
0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52,
|
||||
0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64,
|
||||
0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14,
|
||||
0x69, 0xAA
|
||||
};
|
||||
// ASYM: RSA 2048 with NULL scheme, SYM: AES-128 with CFB mode
|
||||
RsaParms rsa = new(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), 2048, 0);
|
||||
// unique buffer must be filled with 0 for the EK Template L-1.
|
||||
byte[] zero256 = new byte[256];
|
||||
Array.Fill<byte>(zero256, 0x00);
|
||||
Tpm2bPublicKeyRsa unique = new(zero256);
|
||||
TpmPublic inPublic = new(nameAlg, attributes, auth_policy, rsa, unique);
|
||||
return inPublic;
|
||||
}
|
||||
|
||||
public void CreateEndorsementKey(uint ekHandleInt) {
|
||||
TpmHandle ekHandle = new(ekHandleInt);
|
||||
|
||||
TpmPublic existingObject;
|
||||
try {
|
||||
existingObject = tpm.ReadPublic(ekHandle, out byte[] name, out byte[] qualifiedName);
|
||||
Log.Debug("EK already exists.");
|
||||
return;
|
||||
} catch (TpmException) {
|
||||
Log.Debug("Verified EK does not exist at expected handle. Creating EK.");
|
||||
}
|
||||
|
||||
SensitiveCreate inSens = new(); // key password (no params = no key password)
|
||||
TpmPublic inPublic = CommandTpm.GenerateEKTemplateL1();
|
||||
|
||||
TpmHandle newTransientEkHandle = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inPublic,
|
||||
new byte[] { }, new PcrSelection[] { }, out TpmPublic outPublic,
|
||||
out CreationData creationData, out byte[] creationHash, out TkCreation ticket);
|
||||
|
||||
Log.Debug("New EK Handle: " + BitConverter.ToString(newTransientEkHandle));
|
||||
Log.Debug("New EK PUB Name: " + BitConverter.ToString(outPublic.GetName()));
|
||||
Log.Debug("New EK PUB 2BREP: " + BitConverter.ToString(outPublic.GetTpm2BRepresentation()));
|
||||
|
||||
// Make the object persistent
|
||||
tpm.EvictControl(TpmRh.Owner, newTransientEkHandle, ekHandle);
|
||||
Log.Debug("Successfully made the new EK persistent at handle " + BitConverter.ToString(ekHandle) + ".");
|
||||
|
||||
tpm.FlushContext(newTransientEkHandle);
|
||||
Log.Debug("Flushed the context for the transient EK.");
|
||||
}
|
||||
|
||||
private static RsaParms AkRsaParms() {
|
||||
TpmAlgId digestAlg = TpmAlgId.Sha256;
|
||||
RsaParms parms = new(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(digestAlg), 2048, 0);
|
||||
return parms;
|
||||
}
|
||||
|
||||
private static ObjectAttr AkAttributes() {
|
||||
ObjectAttr attrib = ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
|
||||
| ObjectAttr.SensitiveDataOrigin | ObjectAttr.UserWithAuth;
|
||||
return attrib;
|
||||
}
|
||||
|
||||
private static TpmPublic GenerateAKTemplate(TpmAlgId nameAlg) {
|
||||
RsaParms rsa = AkRsaParms();
|
||||
ObjectAttr attributes = AkAttributes();
|
||||
TpmPublic inPublic = new(nameAlg, attributes, null, rsa, new Tpm2bPublicKeyRsa());
|
||||
return inPublic;
|
||||
}
|
||||
|
||||
public void CreateAttestationKey(uint ekHandleInt, uint akHandleInt, bool replace) {
|
||||
TpmHandle ekHandle = new(ekHandleInt);
|
||||
TpmHandle akHandle = new(akHandleInt);
|
||||
|
||||
TpmPublic existingObject = null;
|
||||
try {
|
||||
existingObject = tpm.ReadPublic(akHandle, out byte[] name, out byte[] qualifiedName);
|
||||
} catch { }
|
||||
|
||||
if (!replace && existingObject != null) {
|
||||
// Do Nothing
|
||||
Log.Debug("AK exists at expected handle. Flag to not replace the AK is set in the settings file.");
|
||||
return;
|
||||
} else if (replace && existingObject != null) {
|
||||
// Clear the object and continue
|
||||
tpm.EvictControl(TpmRh.Owner, akHandle, akHandle);
|
||||
Log.Debug("Removed previous AK.");
|
||||
}
|
||||
|
||||
// Create a new key and make it persistent at akHandle
|
||||
TpmAlgId nameAlg = TpmAlgId.Sha256;
|
||||
|
||||
SensitiveCreate inSens = new();
|
||||
TpmPublic inPublic = GenerateAKTemplate(nameAlg);
|
||||
|
||||
var policyEK = new PolicyTree(nameAlg);
|
||||
policyEK.SetPolicyRoot(new TpmPolicySecret(TpmRh.Endorsement, false, 0, null, null));
|
||||
|
||||
AuthSession sessEK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);
|
||||
sessEK.RunPolicy(tpm, policyEK);
|
||||
|
||||
TpmPrivate kAK = tpm[sessEK].Create(ekHandle, inSens, inPublic, null, null, out TpmPublic outPublic,
|
||||
out CreationData creationData, out byte[] creationHash, out TkCreation ticket);
|
||||
|
||||
Log.Debug("New AK PUB Name: " + BitConverter.ToString(outPublic.GetName()));
|
||||
Log.Debug("New AK PUB 2BREP: " + BitConverter.ToString(outPublic.GetTpm2BRepresentation()));
|
||||
Log.Debug("New AK PUB unique: " + BitConverter.ToString((Tpm2bPublicKeyRsa)(outPublic.unique)));
|
||||
|
||||
tpm.FlushContext(sessEK);
|
||||
|
||||
sessEK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);
|
||||
sessEK.RunPolicy(tpm, policyEK);
|
||||
|
||||
TpmHandle hAK = tpm[sessEK].Load(ekHandle, kAK, outPublic);
|
||||
|
||||
tpm.EvictControl(TpmRh.Owner, hAK, akHandle);
|
||||
Log.Debug("Created and persisted new AK at handle 0x" + akHandle.handle.ToString("X") + ".");
|
||||
|
||||
tpm.FlushContext(sessEK);
|
||||
}
|
||||
|
||||
public Tpm2bDigest[] GetPcrList(TpmAlgId pcrBankDigestAlg, uint[] pcrs = null) {
|
||||
if (pcrs == null) {
|
||||
pcrs = new uint[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
|
||||
}
|
||||
Log.Debug("Retrieving PCR LIST for pcrs: " + string.Join(",", pcrs));
|
||||
|
||||
PcrSelection[] pcrSelection = new PcrSelection[] {
|
||||
new PcrSelection(pcrBankDigestAlg, pcrs, (uint)pcrs.Length)
|
||||
};
|
||||
Tpm2bDigest[] pcrValues = MultiplePcrRead(pcrSelection[0]);
|
||||
return pcrValues;
|
||||
}
|
||||
|
||||
// qualifying data hashed with SHA256, quote set to use RSASSA scheme with SHA256-- TODO: enable usage of ECC and other digest alg
|
||||
// if no pcrs are requested (parameter pcrs == null), all pcrs wil be returned. The function does not check if any pcr is available before asking for the quote
|
||||
public void GetQuote(uint akHandleInt, TpmAlgId pcrBankDigestAlg, byte[] nonce, out CommandTpmQuoteResponse ctqr, uint[] pcrs = null) {
|
||||
TpmHandle akHandle = new(akHandleInt);
|
||||
|
||||
if (pcrs == null) {
|
||||
pcrs = new uint[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
|
||||
}
|
||||
Log.Debug("Retrieving TPM quote for pcrs: " + string.Join(",", pcrs));
|
||||
|
||||
|
||||
PcrSelection[] pcrSelection = new PcrSelection[] {
|
||||
new PcrSelection(pcrBankDigestAlg, pcrs, (uint)pcrs.Length)
|
||||
};
|
||||
|
||||
// for test only
|
||||
TpmHash qualifyingData = TpmHash.FromData(TpmAlgId.Sha256, nonce);
|
||||
|
||||
Attest localQuotedInfo = tpm.Quote(akHandle, qualifyingData, new SchemeRsassa(TpmAlgId.Sha256), pcrSelection, out ISignatureUnion localQuoteSig);
|
||||
Tpm2bDigest[] localPcrValues = MultiplePcrRead(pcrSelection[0]);
|
||||
|
||||
TpmPublic pub = tpm.ReadPublic(akHandle, out byte[] name, out byte[] qualifiedName);
|
||||
|
||||
bool verified = pub.VerifyQuote(TpmAlgId.Sha256, pcrSelection, localPcrValues, qualifyingData, localQuotedInfo, localQuoteSig, qualifiedName);
|
||||
Log.Debug("Quote " + (verified ? "was" : "was not") + " verified.");
|
||||
ctqr = null;
|
||||
if (verified) {
|
||||
ctqr = new CommandTpmQuoteResponse(localQuotedInfo, localQuoteSig, localPcrValues);
|
||||
}
|
||||
}
|
||||
|
||||
public Tpm2bDigest[] MultiplePcrRead(PcrSelection pcrs) {
|
||||
if (pcrs == null) {
|
||||
return Array.Empty<Tpm2bDigest>();
|
||||
}
|
||||
|
||||
List<Tpm2bDigest> pcrValues = new();
|
||||
|
||||
const int MAX_NUM_PCRS_PER_READ = 8; // anticipate TPM has a limit on the number of PCRs read at a time
|
||||
Queue<uint> selectedPcrs = new(pcrs.GetSelectedPcrs());
|
||||
|
||||
while (selectedPcrs.Count() > 0) {
|
||||
int numPcrsToRead = (selectedPcrs.Count > MAX_NUM_PCRS_PER_READ) ? MAX_NUM_PCRS_PER_READ : selectedPcrs.Count;
|
||||
|
||||
List<uint> subset = new();
|
||||
for (int i = 0; i < numPcrsToRead; i++) {
|
||||
subset.Add(selectedPcrs.Dequeue());
|
||||
}
|
||||
PcrSelection selection = new(pcrs.hash, subset.ToArray());
|
||||
PcrSelection[] pcrsIn = { // Need to wrap into an array
|
||||
selection
|
||||
};
|
||||
uint count = tpm.PcrRead(pcrsIn, out PcrSelection[] pcrsOut, out Tpm2bDigest[] pcrValuesRetrieved); // TODO incorporate check on count to handle race condition
|
||||
if (pcrValuesRetrieved != null && pcrValuesRetrieved.Length > 0) {
|
||||
pcrValues.AddRange(pcrValuesRetrieved);
|
||||
}
|
||||
}
|
||||
return pcrValues.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ActivateCredential(uint akHandleInt, uint ekHandleInt, byte[] integrityHMAC, byte[] encIdentity, byte[] encryptedSecret) {
|
||||
byte[] recoveredSecret;
|
||||
|
||||
TpmHandle ekHandle = new(ekHandleInt);
|
||||
TpmHandle akHandle = new(akHandleInt);
|
||||
|
||||
IdObject credentialBlob = new(integrityHMAC, encIdentity);
|
||||
|
||||
TpmAlgId nameAlg = TpmAlgId.Sha256;
|
||||
var policyEK = new PolicyTree(nameAlg);
|
||||
policyEK.SetPolicyRoot(new TpmPolicySecret(TpmRh.Endorsement, false, 0, null, null));
|
||||
|
||||
AuthSession sessEK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);
|
||||
sessEK.RunPolicy(tpm, policyEK);
|
||||
|
||||
AuthSession sessAK = tpm.StartAuthSessionEx(TpmSe.None, nameAlg);
|
||||
recoveredSecret = tpm[sessAK, sessEK].ActivateCredential(akHandle, ekHandle, credentialBlob, encryptedSecret);
|
||||
Log.Debug("encryptedSecret: " + BitConverter.ToString(encryptedSecret));
|
||||
|
||||
tpm.FlushContext(sessEK);
|
||||
tpm.FlushContext(sessAK);
|
||||
|
||||
return recoveredSecret;
|
||||
}
|
||||
|
||||
public byte[] GetEventLog() {
|
||||
byte[] eventLog = null;
|
||||
if (tpm._GetUnderlyingDevice().GetType() == typeof(TbsDevice)) { // if windows TPM
|
||||
if (!TbsWrapper.GetEventLog(out eventLog)) {
|
||||
eventLog = null;
|
||||
Log.Debug("Could not retrieve the event log from Tbsi");
|
||||
}
|
||||
}
|
||||
|
||||
if (eventLog == null) {
|
||||
if (tpm._GetUnderlyingDevice().GetType() == typeof(TcpTpmDevice) && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // if TCP TPM on Windows
|
||||
// attempt to read from the measuredboot log folder
|
||||
string windir = System.Environment.GetEnvironmentVariable("windir");
|
||||
string path = windir + "\\Logs\\MeasuredBoot\\";
|
||||
DirectoryInfo directory = new(path);
|
||||
FileInfo mostRecent = directory.GetFiles()
|
||||
.OrderByDescending(f => f.LastWriteTime)
|
||||
.FirstOrDefault();
|
||||
if (mostRecent != null && File.Exists(mostRecent.FullName)) {
|
||||
eventLog = File.ReadAllBytes(mostRecent.FullName);
|
||||
} else {
|
||||
Log.Debug("Windows boot configuration log does not exist at expected location");
|
||||
}
|
||||
} else if (tpm._GetUnderlyingDevice().GetType() == typeof(LinuxTpmDevice) || (tpm._GetUnderlyingDevice().GetType() == typeof(TcpTpmDevice) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux))) { // if Linux TPM or TCP TPM on Linux
|
||||
// attempt to read from the binary_bios_measurements file created by the kernel
|
||||
string path = "/sys/kernel/security/tpm0/binary_bios_measurements";
|
||||
if (File.Exists(path)) {
|
||||
eventLog = File.ReadAllBytes(path);
|
||||
} else {
|
||||
Log.Debug("Linux bios measurements log does not exist at expected location");
|
||||
}
|
||||
}
|
||||
}
|
||||
return eventLog;
|
||||
}
|
||||
|
||||
private Tpm2 TpmSetupByType(Tpm2Device tpmDevice) {
|
||||
try {
|
||||
tpmDevice.Connect();
|
||||
} catch (AggregateException e) {
|
||||
Log.Error(e, "tpmSetupByType: Error connecting to tpmDevice");
|
||||
throw e;
|
||||
}
|
||||
|
||||
Tpm2 tpm = new(tpmDevice);
|
||||
if (tpmDevice is TcpTpmDevice) {
|
||||
//
|
||||
// If we are using the simulator, we have to do a few things the
|
||||
// firmware would usually do. These actions have to occur after
|
||||
// the connection has been established.
|
||||
//
|
||||
if (simulator) {
|
||||
uint rc = 0;
|
||||
try {
|
||||
rc = tpm.PcrRead(new PcrSelection[] { new PcrSelection(TpmAlgId.Sha1, new uint[] { 0 }) }, out _, out _);
|
||||
} catch (TpmException e) {
|
||||
if (e.RawResponse == TpmRc.Initialize) {
|
||||
Log.Debug("TPM simulator not initialized. Running startup with clear.");
|
||||
tpmDevice.PowerCycle();
|
||||
tpm.Startup(Su.Clear);
|
||||
} else {
|
||||
Log.Debug("TPM simulator already initialized. Skipping TPM2_Startup.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (tpmDevice is TbsDevice) {
|
||||
/**
|
||||
* For device TPMs on Windows, we have to use Windows Identity
|
||||
*/
|
||||
// ask windows for owner auth
|
||||
byte[] ownerAuth;
|
||||
if (TbsWrapper.GetOwnerAuthFromOS(out ownerAuth)) {
|
||||
// if found, ownerauth will be delivered with the tpm object
|
||||
tpm.OwnerAuth = ownerAuth;
|
||||
} else {
|
||||
Log.Warning("Could not retrieve owner auth from registry. Trying empty auth.");
|
||||
}
|
||||
} else if (tpmDevice is LinuxTpmDevice) {
|
||||
|
||||
}
|
||||
return tpm;
|
||||
}
|
||||
|
||||
//TODO Fix ACA so that I don't have to re-format data in this way
|
||||
public static void FormatPcrValuesForAca(Tpm2bDigest[] pcrValues, string algName, out string pcrValuesStr) {
|
||||
pcrValuesStr = "";
|
||||
if (pcrValues != null && pcrValues.Length > 0) {
|
||||
pcrValuesStr = algName + " :\n";
|
||||
}
|
||||
for (int i = 0; i < pcrValues.Length; i++) {
|
||||
Tpm2bDigest pcrValue = pcrValues[i];
|
||||
pcrValuesStr += " " + i;
|
||||
pcrValuesStr += ((i > 9) ? " " : " ") + ": ";
|
||||
pcrValuesStr += BitConverter.ToString(pcrValue.buffer).Replace("-", "").ToLower().Trim() + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
HIRS_Provisioner.NET/hirs/src/tpm/CommandTpmQuoteResponse.cs
Normal file
30
HIRS_Provisioner.NET/hirs/src/tpm/CommandTpmQuoteResponse.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Tpm2Lib;
|
||||
|
||||
namespace hirs {
|
||||
public class CommandTpmQuoteResponse : Tpm2QuoteResponse {
|
||||
|
||||
private readonly Attest quoted1;
|
||||
private readonly ISignatureUnion signature1;
|
||||
private readonly Tpm2bDigest[] pcrValues1;
|
||||
|
||||
public CommandTpmQuoteResponse(Attest quoted, ISignatureUnion signature, Tpm2bDigest[] pcrValues) {
|
||||
quoted1 = quoted;
|
||||
signature1 = signature;
|
||||
pcrValues1 = pcrValues != null ? (Tpm2bDigest[])pcrValues.Clone() : null;
|
||||
}
|
||||
public new Attest quoted => quoted1;
|
||||
public new ISignatureUnion signature => signature1;
|
||||
public Tpm2bDigest[] pcrValues => pcrValues1;
|
||||
|
||||
//TODO Fix ACA so that I don't have to re-format data in this way
|
||||
public static void formatQuoteInfoSigForAca(Attest quoteInfo, ISignatureUnion quoteSig, out string quoteInfoSigStr) {
|
||||
quoteInfoSigStr = "quoted:";
|
||||
quoteInfoSigStr += BitConverter.ToString(quoteInfo.GetTpm2BRepresentation()).Replace("-", "").ToLower().Trim();
|
||||
quoteInfoSigStr += "signature:";
|
||||
quoteInfoSigStr += BitConverter.ToString(((SignatureRsassa)quoteSig).GetTpm2BRepresentation()).Replace("-", "").ToLower().Trim();
|
||||
}
|
||||
}
|
||||
}
|
18
HIRS_Provisioner.NET/hirs/src/tpm/IHirsAcaTpm.cs
Normal file
18
HIRS_Provisioner.NET/hirs/src/tpm/IHirsAcaTpm.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Tpm2Lib;
|
||||
|
||||
namespace hirs {
|
||||
public interface IHirsAcaTpm {
|
||||
byte[] GetCertificateFromNvIndex(uint index);
|
||||
TpmPublic ReadPublicArea(uint handleInt, out byte[] name, out byte[] qualifiedName);
|
||||
void CreateEndorsementKey(uint ekHandleInt);
|
||||
void CreateAttestationKey(uint ekHandleInt, uint akHandleInt, bool replace);
|
||||
Tpm2bDigest[] GetPcrList(TpmAlgId pcrBankDigestAlg, uint[] pcrs = null);
|
||||
void GetQuote(uint akHandleInt, TpmAlgId pcrBankDigestAlg, byte[] nonce, out CommandTpmQuoteResponse ctqr, uint[] pcrs = null);
|
||||
byte[] ActivateCredential(uint akHandleInt, uint ekHandleInt, byte[] integrityHMAC, byte[] encIdentity, byte[] encryptedSecret);
|
||||
byte[] GetEventLog();
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
{
|
||||
"auto_detect_tpm": "FALSE",
|
||||
"aca_address_port": "https://127.0.0.1:8443",
|
||||
"efi_prefix": "./Resources/test/settings_test/efi/",
|
||||
"paccor_output_file": "./Resources/test/settings_test/component_list",
|
||||
"event_log_file": "./Resources/test/settings_test/event_log",
|
||||
"hardware_manifest_collectors": "",
|
||||
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Debug",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"outputTemplate": "[{Timestamp:HH:mm:ss} {SourceContext} [{Level}] {Message}{NewLine}{Exception}",
|
||||
"theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Grayscale, Serilog.Sinks.Console"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"path": "hirs.log",
|
||||
"rollingInterval": "Day",
|
||||
"retainedFileCountLimit": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
component list
|
@ -0,0 +1 @@
|
||||
Base Platform Cert Serial
|
@ -0,0 +1 @@
|
||||
Delta Platform Certificate Serial
|
@ -0,0 +1 @@
|
||||
RIM EL Model 1
|
@ -0,0 +1 @@
|
||||
RIM PCR Model 1
|
@ -0,0 +1 @@
|
||||
RIM Swidtag Model 1
|
@ -0,0 +1 @@
|
||||
Delta Platform Certificiate Model
|
@ -0,0 +1 @@
|
||||
event log
|
38
HIRS_Provisioner.NET/hirsTest/hirsTest.csproj
Normal file
38
HIRS_Provisioner.NET/hirsTest/hirsTest.csproj
Normal file
@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FakeItEasy" Version="7.3.1" />
|
||||
<PackageReference Include="FakeItEasy.Analyzer.CSharp" Version="6.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Resources\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\hirs\HIRS_Provisioner.NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties resources_4settings_3test_4appsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
|
||||
|
||||
</Project>
|
53
HIRS_Provisioner.NET/hirsTest/src/client/ClientTests.cs
Normal file
53
HIRS_Provisioner.NET/hirsTest/src/client/ClientTests.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using hirs;
|
||||
using Hirs.Pb;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Tpm2Lib;
|
||||
|
||||
namespace hirsTest {
|
||||
public class ClientTests {
|
||||
public static readonly string localhost = "https://127.0.0.1:8443/";
|
||||
|
||||
[Test]
|
||||
public void TestCreateIdentityClaim() {
|
||||
IHirsAcaClient client = new Client(ClientTests.localhost);
|
||||
|
||||
DeviceInfo dv = new DeviceInfo();
|
||||
byte[] akPub = new byte[] { };
|
||||
byte[] ekPub = new byte[] { };
|
||||
byte[] ekc = new byte[] { };
|
||||
List<byte[]> pcs = new List<byte[]>();
|
||||
pcs.Add(new byte[] { });
|
||||
string componentList= "";
|
||||
|
||||
IdentityClaim obj = client.CreateIdentityClaim(dv, akPub, ekPub, ekc, pcs, componentList);
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(obj.Dv, Is.Not.Null);
|
||||
Assert.That(obj.HasAkPublicArea, Is.True);
|
||||
Assert.That(obj.HasEkPublicArea, Is.True);
|
||||
Assert.That(obj.HasEndorsementCredential, Is.True);
|
||||
Assert.That(obj.PlatformCredential, Has.Count.EqualTo(1));
|
||||
Assert.That(obj.HasPaccorOutput, Is.True);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateAkCertificateRequest() {
|
||||
IHirsAcaClient client = new Client(ClientTests.localhost);
|
||||
|
||||
byte[] secret = Encoding.UTF8.GetBytes("secret");
|
||||
Attest quoted = new Attest(Generated.None, Encoding.UTF8.GetBytes("QUALIFIED SIGNER"), Encoding.UTF8.GetBytes("EXTRA DATA"), new ClockInfo(0, 0, 0, 0), 0, new QuoteInfo());
|
||||
ISignatureUnion signature = new SignatureRsassa();
|
||||
Tpm2bDigest[] pcrValues = new Tpm2bDigest[] { new Tpm2bDigest(Encoding.UTF8.GetBytes("SHA1 DIGEST1")) };
|
||||
|
||||
CommandTpmQuoteResponse ctqr = new CommandTpmQuoteResponse(quoted, signature, pcrValues);
|
||||
|
||||
CertificateRequest obj = client.CreateAkCertificateRequest(secret, ctqr);
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(obj.HasNonce, Is.True);
|
||||
Assert.That(obj.HasQuote, Is.True);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
59
HIRS_Provisioner.NET/hirsTest/src/config/SettingsTests.cs
Normal file
59
HIRS_Provisioner.NET/hirsTest/src/config/SettingsTests.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using hirs;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace hirsTest {
|
||||
public class SettingsTests {
|
||||
[Test]
|
||||
public void TestConstructorWithAppsettings() {
|
||||
Settings settings = Settings.LoadSettingsFromFile("./Resources/test/settings_test/appsettings.json");
|
||||
settings.SetUpLog();
|
||||
settings.CompleteSetUp();
|
||||
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(settings.IsAutoDetectTpmEnabled(), Is.False);
|
||||
Assert.That(settings.HasAcaAddress(), Is.True);
|
||||
Assert.That(settings.aca_address_port.ToString(), Is.EqualTo("https://127.0.0.1:8443/"));
|
||||
Assert.That(settings.HasEfiPrefix(), Is.True);
|
||||
Assert.That(settings.HasPaccorOutputFromFile(), Is.True);
|
||||
Assert.That(settings.HasEventLogFromFile(), Is.True);
|
||||
});
|
||||
|
||||
const string baseSerial = "Base Platform Cert Serial\n";
|
||||
const string deltaSerial = "Delta Platform Certificate Serial\n";
|
||||
const string deltaModel = "Delta Platform Certificiate Model\n";
|
||||
const string swidtagModel = "RIM Swidtag Model 1\n";
|
||||
const string rimelModel = "RIM EL Model 1\n";
|
||||
const string rimpcrModel = "RIM PCR Model 1\n";
|
||||
const string eventLogModel = "event log\n";
|
||||
const string componentList = "component list\n";
|
||||
|
||||
string paccorOutput = settings.paccor_output;
|
||||
List<byte[]> platformCerts = settings.gatherPlatformCertificatesFromEFI();
|
||||
List<byte[]> rims = settings.gatherRIMBasesFromEFI();
|
||||
List<byte[]> rimELs = settings.gatherSupportRIMELsFromEFI();
|
||||
List<byte[]> rimPCRs = settings.gatherSupportRIMPCRsFromEFI();
|
||||
byte[] eventLog = settings.event_log;
|
||||
//Assert.Multiple(() => {
|
||||
Assert.That(paccorOutput, Is.EqualTo(componentList));
|
||||
Assert.That(platformCerts, Has.Count.EqualTo(3));
|
||||
|
||||
Assert.That(platformCerts[0], Is.EqualTo(Encoding.ASCII.GetBytes(baseSerial)));
|
||||
Assert.That(platformCerts[1], Is.EqualTo(Encoding.ASCII.GetBytes(deltaSerial)));
|
||||
Assert.That(platformCerts[2], Is.EqualTo(Encoding.ASCII.GetBytes(deltaModel)));
|
||||
|
||||
Assert.That(rims, Has.Count.EqualTo(1));
|
||||
Assert.That(rims[0], Is.EqualTo(Encoding.ASCII.GetBytes(swidtagModel)));
|
||||
|
||||
Assert.That(rimELs, Has.Count.EqualTo(1));
|
||||
Assert.That(rimELs[0], Is.EqualTo(Encoding.ASCII.GetBytes(rimelModel)));
|
||||
|
||||
Assert.That(rimPCRs, Has.Count.EqualTo(1));
|
||||
Assert.That(rimPCRs[0], Is.EqualTo(Encoding.ASCII.GetBytes(rimpcrModel)));
|
||||
|
||||
Assert.That(Encoding.ASCII.GetString(eventLog), Is.EqualTo(eventLogModel));
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
using Hirs.Pb;
|
||||
using hirs;
|
||||
using FakeItEasy;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Tpm2Lib;
|
||||
|
||||
namespace hirsTest {
|
||||
public class ProvisionerTests {
|
||||
[Test]
|
||||
public async Task TestGoodAsync() {
|
||||
const string address = "https://127.0.0.1:8443/";
|
||||
byte[] ekCert = Encoding.UTF8.GetBytes("EK CERTIFICATE");
|
||||
byte[] secret = Encoding.UTF8.GetBytes("AuthCredential Secret");
|
||||
byte[] acaIssuedCert = Encoding.UTF8.GetBytes("ACA ISSUED CERTIFICATE");
|
||||
byte[] integrityHMAC = Convert.FromBase64String("VAtedc1RlNA1w0XfrtwmhE0ILBlILP6163Tur5HRIo0=");
|
||||
byte[] encIdentity = Convert.FromBase64String("6e2oGBsK3H9Vzbj667ZsjnVOtvpSpQ==");
|
||||
byte[] encryptedSecret = Convert.FromBase64String("NekvnOX8RPRdyd0/cxBI4FTCuNkiu0KAnS28yT7yYJUL5Lwfcv5ctEK6zQA0fq0IsX5TlAYSidGKxrAilOSwALJmJ+m7sMiXwMKrZn1cd4gzXObZEQimQoWgSEQbPO7rfpUn1UfI8K5SzmUFUTxc5X3D8zFonaEBp6QCjtdLegKGgioCDcQFdz20Y0PFAa1Itug7YbZdCFpfit570eQQinmqdVryiNyn6CLQdMgIejuBxoEpoTSWszB5eFKEdn5g/+8wcvhp6RpNBQ0hikF+6688TOVK/j8n3JDwKVltJ/WNHjVO+lxa2aLIMJRgs5ZRuzuz6OSMf10KqJjSWZE04w==");
|
||||
byte[] credentialBlob = Convert.FromBase64String("OAAAIFQLXnXNUZTQNcNF367cJoRNCCwZSCz+tet07q+R0SKN6e2oGBsK3H9Vzbj667ZsjnVOtvpSpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATXpL5zl/ET0XcndP3MQSOBUwrjZIrtCgJ0tvMk+8mCVC+S8H3L+XLRCus0ANH6tCLF+U5QGEonRisawIpTksACyZifpu7DIl8DCq2Z9XHeIM1zm2REIpkKFoEhEGzzu636VJ9VHyPCuUs5lBVE8XOV9w/MxaJ2hAaekAo7XS3oChoIqAg3EBXc9tGNDxQGtSLboO2G2XQhaX4ree9HkEIp5qnVa8ojcp+gi0HTICHo7gcaBKaE0lrMweXhShHZ+YP/vMHL4aekaTQUNIYpBfuuvPEzlSv4/J9yQ8ClZbSf1jR41TvpcWtmiyDCUYLOWUbs7s+jkjH9dCqiY0lmRNOM=");
|
||||
TpmPublic ekPublic = CommandTpm.GenerateEKTemplateL1();
|
||||
TpmPublic akPublic = new(TpmAlgId.Sha256, ObjectAttr.None, System.Text.Encoding.UTF8.GetBytes("AK PUBLIC AUTH POLICY"), new RsaParms(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa());
|
||||
Tpm2bDigest[] sha1Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA1 DIGEST1")) };
|
||||
Tpm2bDigest[] sha256Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA256 DIGEST1")) };
|
||||
DeviceInfo dv = new();
|
||||
string paccorOutput = "paccor output";
|
||||
|
||||
CommandTpmQuoteResponse ctqr = null;
|
||||
IdentityClaimResponse idClaimResp = new();
|
||||
idClaimResp.Status = ResponseStatus.Pass;
|
||||
idClaimResp.CredentialBlob = Google.Protobuf.ByteString.CopyFrom(credentialBlob);
|
||||
CertificateResponse certResp = new();
|
||||
certResp.Status = ResponseStatus.Pass;
|
||||
certResp.Certificate = Google.Protobuf.ByteString.CopyFrom(acaIssuedCert);
|
||||
|
||||
IHirsAcaTpm tpm = A.Fake<IHirsAcaTpm>();
|
||||
byte[] name = null, qualifiedName = null;
|
||||
A.CallTo(() => tpm.GetCertificateFromNvIndex(CommandTpm.DefaultEkcNvIndex)).Returns(ekCert);
|
||||
A.CallTo(() => tpm.CreateEndorsementKey(CommandTpm.DefaultEkHandle)).DoesNothing();
|
||||
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultEkHandle, out name, out qualifiedName)).Returns(ekPublic);
|
||||
A.CallTo(() => tpm.CreateAttestationKey(CommandTpm.DefaultEkHandle, CommandTpm.DefaultAkHandle, false)).DoesNothing();
|
||||
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultAkHandle, out name, out qualifiedName)).Returns(akPublic);
|
||||
//A.CallTo(() => tpm.getPcrList(TpmAlgId.Sha1, A<uint[]>.Ignored)).Returns(sha1Values);
|
||||
//A.CallTo(() => tpm.getPcrList(TpmAlgId.Sha256, A<uint[]>.Ignored)).Returns(sha256Values);
|
||||
A.CallTo(() => tpm.GetQuote(CommandTpm.DefaultAkHandle, TpmAlgId.Sha256, secret, out ctqr, A<uint[]>.Ignored)).DoesNothing();
|
||||
|
||||
IHirsDeviceInfoCollector collector = A.Fake<IHirsDeviceInfoCollector>();
|
||||
A.CallTo(() => collector.CollectDeviceInfo(address)).Returns(dv);
|
||||
|
||||
IHirsAcaClient client = A.Fake<IHirsAcaClient>();
|
||||
IdentityClaim idClaim = client.CreateIdentityClaim(dv, akPublic, ekPublic, ekCert, null, paccorOutput);
|
||||
CertificateRequest certReq = client.CreateAkCertificateRequest(secret, ctqr);
|
||||
A.CallTo(() => client.PostIdentityClaim(idClaim)).Returns(Task.FromResult<IdentityClaimResponse>(idClaimResp));
|
||||
A.CallTo(() => client.PostCertificateRequest(certReq)).Returns(Task.FromResult<CertificateResponse>(certResp));
|
||||
|
||||
Settings settings = Settings.LoadSettingsFromFile("./Resources/test/settings_test/appsettings.json");
|
||||
settings.SetUpLog();
|
||||
settings.CompleteSetUp();
|
||||
|
||||
CLI cli = A.Fake<CLI>();
|
||||
|
||||
IHirsProvisioner p = A.Fake<Provisioner>();
|
||||
p.SetSettings(settings);
|
||||
p.SetCLI(cli);
|
||||
p.SetClient(client);
|
||||
|
||||
p.SetDeviceInfoCollector(collector); // Give the provisioner the mocked collector
|
||||
int result = await p.Provision(tpm);
|
||||
|
||||
A.CallTo(() => tpm.ActivateCredential(CommandTpm.DefaultAkHandle, CommandTpm.DefaultEkHandle, A<byte[]>.That.IsSameSequenceAs(integrityHMAC), A<byte[]>.That.IsSameSequenceAs(encIdentity), A<byte[]>.That.IsSameSequenceAs(encryptedSecret))).MustHaveHappenedOnceExactly();
|
||||
Assert.That(result, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestIssueWithIdentityClaimResponse() {
|
||||
const string address = "https://127.0.0.1:8443/";
|
||||
byte[] ekCert = Encoding.UTF8.GetBytes("EK CERTIFICATE");
|
||||
byte[] acaIssuedCert = Encoding.UTF8.GetBytes("ACA ISSUED CERTIFICATE");
|
||||
TpmPublic ekPublic = CommandTpm.GenerateEKTemplateL1();
|
||||
TpmPublic akPublic = new(TpmAlgId.Sha256, ObjectAttr.None, System.Text.Encoding.UTF8.GetBytes("AK PUBLIC AUTH POLICY"), new RsaParms(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa());
|
||||
Tpm2bDigest[] sha1Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA1 DIGEST1")) };
|
||||
Tpm2bDigest[] sha256Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA256 DIGEST1")) };
|
||||
DeviceInfo dv = new();
|
||||
string paccorOutput = "paccor output";
|
||||
IdentityClaimResponse idClaimResp = new();
|
||||
idClaimResp.ClearCredentialBlob();
|
||||
|
||||
IHirsAcaTpm tpm = A.Fake<IHirsAcaTpm>();
|
||||
byte[] name = null, qualifiedName = null;
|
||||
A.CallTo(() => tpm.GetCertificateFromNvIndex(CommandTpm.DefaultEkcNvIndex)).Returns(ekCert);
|
||||
A.CallTo(() => tpm.CreateEndorsementKey(CommandTpm.DefaultEkHandle)).DoesNothing();
|
||||
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultEkHandle, out name, out qualifiedName)).Returns(ekPublic);
|
||||
A.CallTo(() => tpm.CreateAttestationKey(CommandTpm.DefaultEkHandle, CommandTpm.DefaultAkHandle, false)).DoesNothing();
|
||||
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultAkHandle, out name, out qualifiedName)).Returns(ekPublic);
|
||||
A.CallTo(() => tpm.GetPcrList(TpmAlgId.Sha1, A<uint[]>.Ignored)).Returns(sha1Values);
|
||||
A.CallTo(() => tpm.GetPcrList(TpmAlgId.Sha256, A<uint[]>.Ignored)).Returns(sha256Values);
|
||||
|
||||
IHirsDeviceInfoCollector collector = A.Fake<IHirsDeviceInfoCollector>();
|
||||
A.CallTo(() => collector.CollectDeviceInfo(address)).Returns(dv);
|
||||
|
||||
IHirsAcaClient client = A.Fake<IHirsAcaClient>();
|
||||
IdentityClaim idClaim = client.CreateIdentityClaim(dv, akPublic, ekPublic, ekCert, null, paccorOutput);
|
||||
A.CallTo(() => client.PostIdentityClaim(idClaim)).WithAnyArguments().Returns(Task.FromResult<IdentityClaimResponse>(idClaimResp));
|
||||
|
||||
Settings settings = Settings.LoadSettingsFromFile("./Resources/test/settings_test/appsettings.json");
|
||||
settings.SetUpLog();
|
||||
settings.CompleteSetUp();
|
||||
|
||||
CLI cli = A.Fake<CLI>();
|
||||
|
||||
IHirsProvisioner p = A.Fake<Provisioner>();
|
||||
p.SetSettings(settings);
|
||||
p.SetCLI(cli);
|
||||
p.SetClient(client);
|
||||
|
||||
p.SetDeviceInfoCollector(collector); // Give the provisioner the mocked collector
|
||||
int result = await p.Provision(tpm);
|
||||
|
||||
Assert.That(result, Is.EqualTo((int)ClientExitCodes.MAKE_CREDENTIAL_BLOB_MALFORMED));
|
||||
}
|
||||
}
|
||||
}
|
16
HIRS_Provisioner.NET/tools/pcrextend/pcrextend.csproj
Normal file
16
HIRS_Provisioner.NET/tools/pcrextend/pcrextend.csproj
Normal file
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="Microsoft.TSS" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
42
HIRS_Provisioner.NET/tools/pcrextend/src/Program.cs
Normal file
42
HIRS_Provisioner.NET/tools/pcrextend/src/Program.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using CommandLine;
|
||||
|
||||
namespace pcrextend {
|
||||
class Program {
|
||||
static void Main(string[] args) {
|
||||
bool result = false;
|
||||
try {
|
||||
CLI cli = new();
|
||||
ParserResult<CLI> cliParseResult =
|
||||
CommandLine.Parser.Default.ParseArguments<CLI>(args)
|
||||
.WithParsed(parsed => cli = parsed)
|
||||
.WithNotParsed(HandleParseError);
|
||||
|
||||
if (cliParseResult.Tag == ParserResultType.Parsed) {
|
||||
// filter pci index
|
||||
int pcr = cli.Pcr;
|
||||
if (pcr < 0 || pcr > 23) {
|
||||
Console.WriteLine("Unknown PCR index: " + pcr + ". Should be from 0 to 23.");
|
||||
return;
|
||||
}
|
||||
PcrExtendTool p = new(cli);
|
||||
CommandTpmSimulator? tpm = p.connectTpm();
|
||||
if (tpm != null) {
|
||||
result = p.Extend(tpm);
|
||||
}
|
||||
Console.WriteLine("PCR Extend " + (result ? "" : "un") + "successful.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine("Application stopped.");
|
||||
Console.WriteLine(e.ToString());
|
||||
Console.WriteLine(e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleParseError(IEnumerable<Error> errs) {
|
||||
if (!errs.IsHelp() && !errs.IsVersion()) {
|
||||
//handle errors
|
||||
Console.WriteLine("There was a CLI error: " + errs.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
HIRS_Provisioner.NET/tools/pcrextend/src/config/CLI.cs
Normal file
29
HIRS_Provisioner.NET/tools/pcrextend/src/config/CLI.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using CommandLine;
|
||||
|
||||
namespace pcrextend {
|
||||
public class CLI {
|
||||
// These fields are controlled by the CommandLineParser library.
|
||||
// CS8618 is not relevant at this time.
|
||||
// Non-nullable field must contain a non-null value when exiting constructor.
|
||||
#pragma warning disable CS8618
|
||||
[Option('i', "ip", Default = CommandTpmSimulator.DefaultSimulatorNamePort, HelpText = "IP of the TPM Simulator. Use the format ip:port.")]
|
||||
public string Ip {
|
||||
|
||||
get; set;
|
||||
}
|
||||
[Option('p', "pcr", HelpText = "PCR Index 0 thru 23")]
|
||||
public short Pcr {
|
||||
get; set;
|
||||
}
|
||||
[Option('a', "hashalg", HelpText = "sha1, sha256, sha384, or sha512. OR their ID Values in decimal (4, 11, 12, 13) or in hex (0x4, 0xB, 0xC, 0xD).")]
|
||||
public string HashAlg {
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Option('d', "digests", HelpText = "Comma separated digest values in hex. e.g. AB,34F53,9785")]
|
||||
public string Digests {
|
||||
get; set;
|
||||
}
|
||||
#pragma warning restore CS8618
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
namespace pcrextend {
|
||||
public class PcrExtendTool {
|
||||
private CLI? cli = null;
|
||||
|
||||
public PcrExtendTool(CLI cli) {
|
||||
SetCLI(cli);
|
||||
}
|
||||
|
||||
public void SetCLI(CLI cli) {
|
||||
this.cli = cli;
|
||||
}
|
||||
|
||||
public CommandTpmSimulator? connectTpm() {
|
||||
CommandTpmSimulator? tpm = null;
|
||||
if (cli != null && cli.Ip != null) {
|
||||
string[] split = cli.Ip.Split(":");
|
||||
if (split.Length == 2) {
|
||||
try {
|
||||
tpm = new CommandTpmSimulator(split[0], Int32.Parse(split[1]));
|
||||
} catch (Exception) {
|
||||
Console.WriteLine("No tpm found at " + cli.Ip);
|
||||
}
|
||||
} else {
|
||||
Console.WriteLine("ip input should have the format servername:port. The given input was '" + cli.Ip + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
return tpm;
|
||||
}
|
||||
|
||||
public bool Extend(CommandTpmSimulator tpm) {
|
||||
bool result = false;
|
||||
if (tpm != null && cli != null) {
|
||||
// parse hashAlg
|
||||
string hashAlg = cli.HashAlg;
|
||||
if (hashAlg.StartsWith("0x", StringComparison.OrdinalIgnoreCase) || hashAlg.EndsWith("h")) {
|
||||
hashAlg = hashAlg.Replace("0x", "");
|
||||
hashAlg = hashAlg.TrimEnd('h');
|
||||
hashAlg = "" + Convert.ToInt64(hashAlg, 16);
|
||||
}
|
||||
|
||||
string digestCSV = cli.Digests;
|
||||
digestCSV = digestCSV.ToUpper().Replace("0X", "").Replace("H", "");
|
||||
string[] digestArray = digestCSV.Split(",");
|
||||
List<byte[]> digestList = new();
|
||||
foreach (string digest in digestArray) {
|
||||
digestList.Add(Convert.FromHexString(digest));
|
||||
}
|
||||
tpm.pcrextend(cli.Pcr, hashAlg, digestList);
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
using Tpm2Lib;
|
||||
|
||||
namespace pcrextend {
|
||||
public class CommandTpmSimulator {
|
||||
/// <summary>
|
||||
/// If using a TCP connection, the default DNS name/IP address for the
|
||||
/// simulator.
|
||||
/// </summary>
|
||||
public const string DefaultSimulatorNamePort = "127.0.0.1:2321";
|
||||
|
||||
private readonly Tpm2 tpm;
|
||||
|
||||
private readonly Boolean simulator;
|
||||
|
||||
/**
|
||||
* For TCP TpmDevices
|
||||
*/
|
||||
public CommandTpmSimulator(string ip, int port) {
|
||||
simulator = true;
|
||||
Tpm2Device tpmDevice = new TcpTpmDevice(ip, port);
|
||||
Console.WriteLine("Connecting to TPM at " + ip + ":" + port);
|
||||
tpm = tpmSetupByType(tpmDevice);
|
||||
}
|
||||
|
||||
~CommandTpmSimulator() {
|
||||
if (tpm != null) {
|
||||
tpm.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void pcrextend(int pcr, string hashAlgStr, List<byte[]> digestList) {
|
||||
TpmHandle pcrHandle = TpmHandle.Pcr(pcr);
|
||||
TpmAlgId hashAlg = Enum.Parse<TpmAlgId>(hashAlgStr, true);
|
||||
List<TpmHash> digests = new();
|
||||
foreach (byte[] digest in digestList) {
|
||||
digests.Add(new TpmHash(hashAlg, digest));
|
||||
}
|
||||
tpm.PcrExtend(pcrHandle, digests.ToArray());
|
||||
}
|
||||
|
||||
private Tpm2 tpmSetupByType(Tpm2Device tpmDevice) {
|
||||
tpmDevice.Connect();
|
||||
|
||||
Tpm2 tpm = new Tpm2(tpmDevice);
|
||||
if (tpmDevice is TcpTpmDevice) {
|
||||
//
|
||||
// If we are using the simulator, we have to do a few things the
|
||||
// firmware would usually do. These actions have to occur after
|
||||
// the connection has been established.
|
||||
//
|
||||
if (simulator) {
|
||||
uint rc = 0;
|
||||
try {
|
||||
rc = tpm.PcrRead(new PcrSelection[] { new PcrSelection(TpmAlgId.Sha1, new uint[] { 0 }) }, out _, out _);
|
||||
} catch (TpmException e) {
|
||||
if (e.RawResponse == TpmRc.Initialize) {
|
||||
Console.WriteLine("TPM simulator not initialized. Running startup with clear.");
|
||||
tpmDevice.PowerCycle();
|
||||
tpm.Startup(Su.Clear);
|
||||
} else {
|
||||
Console.WriteLine("TPM simulator already initialized. Skipping TPM2_Startup.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tpm;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user