diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b7988b..70fa3d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ endif() if(NOT NUGET_EXE) message(FATAL_ERROR "CMake could not find the nuget command line tool. Please install it from https://www.nuget.org/downloads and move it to ${CMAKE_CURRENT_SOURCE_DIR}!") else() - execute_process(COMMAND ${NUGET_EXE} install "Microsoft.Attestation.Client" -Version 1.1.133870390-preview -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages) + execute_process(COMMAND ${NUGET_EXE} install "Microsoft.Attestation.Client" -Version 1.1.134193605-preview -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages) if(NUGET_RESULT) message(FATAL_ERROR "NuGet package installation failed: ${NUGET_ERROR}") else() diff --git a/README.md b/README.md index 651a1b7..f172370 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,14 @@ This sample provides the code implementation to perform boot attestation and ret This sample provides the code implementation to perform boot and TPM key attestation and retrieve an attestation token from Microsoft Azure Attestation. This sample creates a TPM key named "att_sample_key" which is attested by Microsoft Azure Attestation. The creation of a TPM key may take up to a few minutes depending on the TPM hardware. +### **VBS-Protected key attestation (sample_vbs_protected_key_att.exe)** + +This sample provides the code implementation to perform VBS-Protected key attestation and retrieve an attestation token from Microsoft Azure Attestation. +This sample creates a VBS-Protected key named "att_sample_vbs_key" which is attested by Microsoft Azure Attestation. The sample must be run with Virtualization-Based Security enabled on the device. + +WARNING: Information regarding VBS-Protected Keys relates to prerelease product that may be substantially modified before it's commercially released. +Microsoft makes no warranties, express or implied, with respect to the information provided here. + ### **VBS enclave attestation (sample_enclave_att.exe)** This sample provides the code implementation to perform VBS enclave attestation and retrieve an attestation token from Microsoft Azure Attestation. A sample enclave is provided in the "enclave" directory. diff --git a/attestation/CMakeLists.txt b/attestation/CMakeLists.txt index aa071f4..5044bc5 100644 --- a/attestation/CMakeLists.txt +++ b/attestation/CMakeLists.txt @@ -40,4 +40,5 @@ endmacro() define_sample(sample_boot_att FALSE) define_sample(sample_tpm_key_att FALSE) -define_sample(sample_enclave_att TRUE) \ No newline at end of file +define_sample(sample_enclave_att TRUE) +define_sample(sample_vbs_protected_key_att FALSE) \ No newline at end of file diff --git a/attestation/sample_tpm_key_att.cpp b/attestation/sample_tpm_key_att.cpp index cd8fdb3..bf07086 100644 --- a/attestation/sample_tpm_key_att.cpp +++ b/attestation/sample_tpm_key_att.cpp @@ -63,7 +63,7 @@ int main() 0 // other_keys_count }; - attest(ATT_SESSION_TYPE_TPM, ¶ms, "report_key.jwt"); + attest(ATT_SESSION_TYPE_TPM, ¶ms, "report_tpm_key.jwt"); } catch (const std::exception& ex) { diff --git a/attestation/sample_vbs_protected_key_att.cpp b/attestation/sample_vbs_protected_key_att.cpp new file mode 100644 index 0000000..e498609 --- /dev/null +++ b/attestation/sample_vbs_protected_key_att.cpp @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +/** + * WARNING: Information regarding VBS-Protected Keys relates to prerelease product that may be substantially modified before it's commercially released. + * Microsoft makes no warranties, express or implied, with respect to the information provided here. + */ + +/** + * @brief This sample provides the code implementation to perform VBS-Protected key attestation, + * and retrieve an attestation token from Microsoft Azure Attestation. + * + * @remark The following environment variables must be set before running the sample. + * + * - AZURE_TENANT_ID: Tenant ID for the Azure account. Used for authenticated calls to the attestation service. + * - AZURE_CLIENT_ID: The client ID to authenticate the request. Used for authenticated calls to the attestation service. + * - AZURE_CLIENT_SECRET: The client secret. Used for authenticated calls to the attestation service. + * - AZURE_MAA_URI: Microsoft Azure Attestation provider's Attest URI (as shown in portal). Format is similar to "https://..attest.azure.net". + * + * In addition, a TPM attestation identity key named 'att_sample_aik' must be created. See README.md for instructions. + * + * Finally, a fixed relying party id and nonce are used in this sample. An application should obtain a per-session nonce from the relying party before making + * the call to the attestation service. TODOs in the code below mark the locations to be updated. + * + */ + +#include "utils.h" +#include "attest.h" +#include +#include +#include + +#include +#include + +using namespace std; + +#define AIK_NAME L"att_sample_aik" + +int main() +{ + // Adjust log level to your desired level of output. + att_set_log_level(att_log_level_none); + att_set_log_listener(sample_log_listener); + + // TODO: Use relying party's id in the line below. + string rp_id{ "https://contoso.com" }; + // TODO: Use relying party's per-session nonce below. + vector rp_nonce{ 'R', 'E','P','L','A','C','E',' ','W','I','T','H', ' ','R','P', ' ','N','O','N','C','E' }; + + try + { + auto tpm_aik = load_tpm_key(AIK_NAME, true); + auto vbs_protected_key = create_vbs_protected_key(L"att_sample_vbs_key", false); + + att_tpm_aik aik = ATT_TPM_AIK_NCRYPT(tpm_aik.get()); + att_tpm_key key = ATT_TPM_KEY_VBS_NCRYPT(vbs_protected_key.get()); + + att_session_params_tpm params + { + rp_nonce.data(), // relying_party_nonce + rp_nonce.size(), // relying_party_nonce_size + rp_id.c_str(), // relying_party_unique_id + &aik, // aik + &key, // request_key + nullptr, // other_keys + 0 // other_keys_count + }; + + attest(ATT_SESSION_TYPE_TPM, ¶ms, "report_vbs_protected_key.jwt"); + } + catch (const std::exception& ex) + { + cout << ex.what() << endl; + } + + return 0; + + // + // Notice that the report will contain the claim "x-ms-tpm-request-key", which includes the public part of the VBS-protected key in the "jwk" field. + // In addition, the "info" section will contain "vbs_ncrypt", indicating that a VBS-protected key was certified. The fields inside "vbs_ncrypt" attest to the VBS-protected key properties. + // These properties are described in the NCrypt library documentation (https://learn.microsoft.com/en-us/windows/win32/api/ncrypt/nf-ncrypt-ncryptverifyclaim#protectingattesting-private-keys-using-virtualization-based-security-vbs). + // A relying party (RP) should validate several important fields inside "vbs_ncrypt.vbs_trustlet_report" to ensure the key was generated and protected inside a trusted VBS-protected environment: + // + // trustlet_identity - Identifies the VBS trustlet that created or protects the key. The RP should compare this value against an expected trustlet identity to ensure the key originates from a trusted environment. + // + // trustlet_svn - The security version number (SVN) of the trustlet. The RP should verify this meets its minimum required SVN. + // + // flags.trustlet_debugged - Indicates whether the trustlet was debugged during key creation or protection. RPs should reject keys where this value is true, as debugged trustlets cannot be trusted. + // + // trustlet_policy - A set of policy entries describing protections applied to the trustlet. For example, policy entry ID=2 determines whether the trustlet is debuggable. RPs should verify policy values to verify that the trustlet meets its security requirements. + // + // These validations allow a relying party to establish that the key is genuinely VBS-backed, it comes from the correct trustlet that has sufficient security level, the environment was not debugged or weakened, and policy constraints match the RP's requirements. + // + + } \ No newline at end of file diff --git a/attestation/utils.cpp b/attestation/utils.cpp index 490622c..8e642ab 100644 --- a/attestation/utils.cpp +++ b/attestation/utils.cpp @@ -62,6 +62,18 @@ wil::unique_ncrypt_key create_ephemeral_software_key() return ephemeral_software_key; } +wil::unique_ncrypt_key create_vbs_protected_key(const wstring& name, bool machine_key) +{ + cout << "Creating VBS-Protected key..."; + + // Pass in nullptr instead of "name.cstr()" if you require an ephemeral key. + wil::unique_ncrypt_key vbs_protected_key = create_key(MS_KEY_STORAGE_PROVIDER, name.c_str(), NCRYPT_OVERWRITE_KEY_FLAG | NCRYPT_REQUIRE_VBS_FLAG | (machine_key ? NCRYPT_MACHINE_KEY_FLAG : 0)); + + cout << " Done." << endl; + + return vbs_protected_key; +} + void sample_log_listener(att_log_source, att_log_level, const char* message) { cout << "[LOG] " << message << endl; diff --git a/attestation/utils.h b/attestation/utils.h index e780fa3..0b7d26c 100644 --- a/attestation/utils.h +++ b/attestation/utils.h @@ -19,6 +19,9 @@ wil::unique_ncrypt_key create_tpm_key(const std::wstring& name, bool machine_key // Creates a 2048-bit ephemeral software key using the Software Key Storage Provider. wil::unique_ncrypt_key create_ephemeral_software_key(); +// Creates a 2048-bit VBS-Protected key using the Software Key Storage Provider. +wil::unique_ncrypt_key create_vbs_protected_key(const std::wstring& name, bool machine_key); + // Creates a sample log listener to enable logging from the MAA SDK. void sample_log_listener(att_log_source, att_log_level, const char* message);