Created Attestation Administration client (#3355)

* Created Attestation Administration client

* Integrated with main
This commit is contained in:
Larry Osterman 2022-02-18 17:56:35 -08:00 committed by GitHub
parent 9f58947056
commit cd9ae61a8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 2433 additions and 550 deletions

View File

@ -83,6 +83,7 @@ jobs:
Pool: azsdk-pool-mms-win-2019-general
OSVmImage: MMS2019
VCPKG_DEFAULT_TRIPLET: 'x86-windows-static'
VcpkgInstall: 'openssl'
CMAKE_GENERATOR: 'Visual Studio 16 2019'
CMAKE_GENERATOR_PLATFORM: Win32
CmakeArgs: ' -DBUILD_TESTING=ON -DRUN_LONG_UNIT_TESTS=ON -DBUILD_PERFORMANCE_TESTS=ON '
@ -91,7 +92,7 @@ jobs:
Win_x86_no_rtti_whit_unit_test:
Pool: azsdk-pool-mms-win-2019-general
OSVmImage: MMS2019
VcpkgInstall: 'libxml2'
VcpkgInstall: 'libxml2 openssl'
VCPKG_DEFAULT_TRIPLET: 'x86-windows-static'
CMAKE_GENERATOR: 'Visual Studio 16 2019'
CMAKE_GENERATOR_PLATFORM: Win32
@ -99,6 +100,7 @@ jobs:
BuildArgs: '-v --parallel 8'
Win_x64_with_unit_test_winHttp:
Pool: azsdk-pool-mms-win-2019-general
VcpkgInstall: 'openssl'
OSVmImage: MMS2019
VCPKG_DEFAULT_TRIPLET: 'x64-windows-static'
CMAKE_GENERATOR: 'Visual Studio 16 2019'

View File

@ -32,6 +32,7 @@ set(
AZURE_ATTESTATION_HEADER
inc/azure/attestation/dll_import_export.hpp
inc/azure/attestation/attestation_client.hpp
inc/azure/attestation/attestation_administration_client.hpp
inc/azure/attestation.hpp
inc/azure/attestation/attestation_client_models.hpp
inc/azure/attestation/attestation_client_options.hpp
@ -48,6 +49,7 @@ set(
set(
AZURE_ATTESTATION_SOURCE
src/attestation_client.cpp
src/attestation_administration_client.cpp
src/attestation_client_options.cpp
src/attestation_common_request.cpp
src/private/attestation_deserializers_private.cpp

View File

@ -1,51 +1,370 @@
# Azure Attestation Package client library for C++
Azure Template Package client library for C++ (`azure-security-attestation`) matches necessary patterns that the development team has established to create a unified SDK written in the C++ programming language. These libraries follow the Azure SDK Design Guidelines for C++.
Microsoft Azure Attestation is a unified solution for remotely verifying the trustworthiness of a platform and integrity of the binaries running inside it. The service supports attestation of the platforms backed by Trusted Platform Modules (TPMs) alongside the ability to attest to the state of Trusted Execution Environments (TEEs) such as Intel(tm) Software Guard Extensions (SGX) enclaves and Virtualization-based Security (VBS) enclaves.
The library allows client libraries to expose common functionality in a consistent fashion. Once you learn how to use these APIs in one client library, you will know how to use them in other client libraries.
Attestation is a process for demonstrating that software binaries were properly instantiated on a trusted platform. Remote
relying parties can then gain confidence that only such intended software is running on trusted hardware.
Azure Attestation enables cutting-edge security paradigms such as Azure Confidential computing and Intelligent Edge protection. Customers have been requesting the ability to independently verify the location of a machine, the posture of a virtual machine (VM) on that machine, and the environment within which enclaves are running on that VM. Azure Attestation will empower these and many additional customer requests.
Azure Attestation receives evidence from compute entities, turns them into a set of claims, validates them against configurable policies, and produces cryptographic proofs for claims-based applications (for example, relying parties and auditing authorities).
## Getting started
For a rich example of a well formatted readme, please check [here.](https://github.com/Azure/azure-sdk/blob/main/docs/policies/README-TEMPLATE.md) In addition, this is an [example readme](https://github.com/Azure/azure-sdk/blob/main/docs/policies/README-EXAMPLE.md) that should be emulated. Note that the top-level sections in this template align with that of the [template.](https://github.com/Azure/azure-sdk/blob/main/docs/policies/README-TEMPLATE.md)
For the best development experience, we recommend that developers use the [CMake projects in Visual Studio](https://docs.microsoft.com/cpp/build/cmake-projects-in-visual-studio?view=vs-2019) to view and build the source code together with its dependencies.
# Key concepts
### Prerequisites
Bullet point list of your library's main concepts.
- [Azure Subscription][azure_subscription]. Sign up for a [free trial](https://azure.microsoft.com/pricing/free-trial/) or use your [MSDN subscriber benefits](https://azure.microsoft.com/pricing/member-offers/msdn-benefits-details/).
- An existing [Azure Attestation instance][azure_attestation]. If you need to create an attestation instance, you can use the [Azure Cloud Shell][azure_cloud_shell] to create one with this Azure CLI command. Replace `<your-resource-group-name>` and `<your-instance-name>` with your own, unique names:
# Examples
```bash
az attestation create --resource-group <your-resource-group-name> --name <your-service instance name>
```
Examples of some of the key concepts for your library.
### Download & Install
# Troubleshooting
### Install Dependencies
Running into issues? This section should contain details as to what to do there.
#### Windows
# Next steps
On Windows, dependencies are managed by [vcpkg](https://github.com/microsoft/vcpkg). You can reference the [Quick Start](https://github.com/microsoft/vcpkg#quick-start-windows) to quickly set yourself up.
After Vcpkg is initialized and bootstrapped, you can install the dependencies:
More sample code should go here, along with links out to the appropriate example tests.
```BatchFile
vcpkg.exe install curl:x64-windows-static
vcpkg.exe install openssl:x64-windows-static
```
#### POSIX Platforms
You can use the package manager on different POSIX platforms to install the dependencies. The dependencies to be installed are:
- CMake 3.13.0 or higher.
- OpenSSL.
- libcurl.
### Build from Source
First, download the repository to your local folder:
```BatchFile
git clone https://github.com/Azure/azure-sdk-for-cpp.git
```
#### Windows
##### Use CMake to generate the solution file
In a new folder you created under the root directory:
```BatchFile
cmake .. -A x64 -DCMAKE_TOOLCHAIN_FILE=<YOUR_VCPKG_INSTALL_DIR>/scripts/buildsystems/vcpkg.cmake
cmake --build .
```
The built library will be in `.\sdk\<ProjectDir>\<Configuration>\` respectively for Azure Core and Azure Attestation. e.g. `azure_core.lib` will be in `.\sdk\core\azure-core\Debug` for debug configuration.
##### Use Visual Studio's Open by folder feature
Open the root folder of the library with Visual Studio's Open folder feature.
If Vcpkg is not globally integrated, then you need to open CMakeSettings.json and change the `Make toolchain file to be <YOUR_VCPKG_INSTALL_DIR>/scripts/buildsystems/vcpkg.cmake` and save.
Then you can build Azure Storage libraries by selecting the target in Visual Studio, or simply build all.
The libraries will be in `<ProjectRoot>\out\build\<Configuration>\sdk\<LibraryName>` respectively.
#### POSIX Platforms
You can run the following command in a new folder created under the downloaded code's root folder to build the code.
```bash
cmake .. -DCMAKE_BUILD_TYPE=Debug
cmake --build .
```
Then you can consume the built library with the header files.
make/ninja install is work in progress.
### Via vcpkg
The easiest way to acquire the C++ SDK is leveraging vcpkg package manager. See the corresponding [Azure SDK for C++ readme section][azsdk_vcpkg_install].
To install Azure Storage packages via vcpkg:
```cmd
> vcpkg install azure-security-attestation-cpp
```
Then, use in your CMake file:
```CMake
find_package(azure-security-attestation-cpp CONFIG REQUIRED)
target_link_libraries(<your project name> PRIVATE Azure::azure-security-attestation)
```
## Dependencies
- [Azure Core SDK](https://github.com/Azure/azure-sdk-for-cpp/blob/main/README.md)
- OpenSSL
### Authenticate the client
Many of the APIs supported by the Azure Attestation service require authentication (some do not, if an API does not require
authentication, the documentation for that API will reflect that the attestation service instance does not require authentication).
To interact with the authenticated APIs supported by the Azure Attestation service, your client must present an Azure Active Directory bearer token to the service.
The simplest way of providing a bearer token is to use the `DefaultAzureCredential` authentication method by providing client secret credentials is being used in this getting started section, but you can find more ways to authenticate with [azure-identity][azure_identity].
## Key concepts
The Microsoft Azure Attestation service runs in two separate modes: "Isolated" and "AAD". When the service is running in "Isolated" mode, the customer needs to
provide additional information beyond their authentication credentials to verify that they are authorized to modify the state of an attestation instance.
There are four major client types provided in this SDK:
- [SGX and TPM enclave attestation.](#attestation)
- [MAA Attestation Token signing certificate discovery and validation.](#attestation-token-signing-certificate-discovery-and-validation)
- [Attestation Policy management.](#policy-management)
- [Attestation policy management certificate management](#policy-management-certificate-management) (yes, policy management management).
Each attestation instance operates in one of three separate modes of operation:
- Isolated mode.
- AAD mode.
- Shared mode.
### Isolated Mode Attestation Instances
In "Isolated" mode, the customer indicates that they want to ensure that Microsoft administrators cannot influence the inputs or outputs of an attestation service instance. When the attestation service instance is running in Isolated mode, the customer is expected to provide additional proof that they are authorized to make changes to the attestation service instance.
### AAD Mode Attestation Instances
In "AAD" mode, access to the service is controlled solely by Azure Role Based Access Control. When the
### Shared Mode Attestation Instances
Each region in which the Microsoft Azure Attestation service is available supports a "shared" instance, which
can be used to attest SGX enclaves which only need verification against the azure baseline (there are no policies applied to the
shared instance).
The following APIs are available in the shared instance:
- AttestSgxEnclave
- AttestOpenEnclave
- GetAttestationPolicy
- GetPolicyManagementCertificates (always returns an empty set)
The following APIs are not available in the shared instance:
- AttestTPMEnclave
- SetAttestationPolicy
- ResetAttestationPolicy
- AddPolicyManagementCertificate
- RemovePolicyManagementCertificate
The APIs available in the shared instance do not require AAD authentication.
### Attestation
SGX or TPM attestation is the process of validating evidence collected from a trusted execution environment to ensure that it
meets both the Azure baseline for that environment and customer defined policies applied to that environment.
#### Attestation token signing certificate discovery and validation
Most responses from the MAA service are expressed in the form of a JSON Web Token. This token will be signed by a signing certificate
issued by the MAA service for the specified instance. If the MAA service instance is running in a region where the service runs in an SGX enclave, then
the certificate issued by the server can be verified using the [oe_verify_attestation_certificate() API](https://openenclave.github.io/openenclave/api/enclave_8h_a3b75c5638360adca181a0d945b45ad86.html).
### Policy Management
Each attestation service instance has a policy applied to it which defines additional criteria which the customer has defined.
For more information on attestation policies, see [Attestation Policy](https://docs.microsoft.com/azure/attestation/author-sign-policy)
### Policy Management certificate management
When an attestation instance is running in "Isolated" mode, the customer who created the instance will have provided
a policy management certificate at the time the instance is created. All policy modification operations require that the customer sign
the policy data with one of the existing policy management certificates. The Policy Management Certificate Management APIs enable
clients to add, remove or enumerate the policy management certificates.
### Examples
- [Instantiate a synchronous attestation client](#create-a-synchronous-attestation-client)
- [Retrieve token validation certificates](#retrieve-token-certificates)
- [Attest an SGX enclave](#attest-an-sgx-enclave)
- [Instantiate a synchronous administrative client](#create-a-synchronous-administrative-client)
- [Get attestation policy](#retrieve-current-attestation-policy-for-openenclave)
- [Set unsigned attestation policy](#set-unsigned-attestation-policy-aad-clients-only)
- [Set signed attestation policy](#set-signed-attestation-policy)
- [List policy management certificates](#list-attestation-signing-certificates)
- [Add policy management certificate](#add-attestation-signing-certificate)
#### Create a synchronous attestation client
The `AttestationClientBuilder` class is used to create instances of the attestation client:
```cpp readme-sample-create-synchronous-client
```
#### Retrieve Token Certificates
Use `listAttestationSigners` to retrieve the set of certificates, which can be used to validate the token returned from the attestation service.
Normally, this information is not required as the attestation SDK will perform the validation as a part of the interaction with the
attestation service, however the APIs are provided for completeness and to facilitate customer's independently validating
attestation results.
```cpp readme-sample-getSigningCertificates
```
#### Attest an SGX Enclave
Use the `AttestSgxEnclave` method to attest an SGX enclave.
```cpp readme-sample-attest-sgx-enclave
```
#### Create a synchronous administrative client
All administrative clients are authenticated.
```cpp readme-sample-create-admin-client
AttestationAdministrationClientBuilder attestationBuilder = new AttestationAdministrationClientBuilder();
// Note that the "policy" calls require authentication.
AttestationAdministrationClient client = attestationBuilder
.endpoint(endpoint)
.credential(new DefaultAzureCredentialBuilder().build())
.buildClient();
```
#### Retrieve current attestation policy for OpenEnclave
Use the `GetAttestationPolicy` API to retrieve the current attestation policy for a given TEE.
```java readme-sample-getCurrentPolicy
String currentPolicy = client.getAttestationPolicy(AttestationType.OPEN_ENCLAVE);
System.out.printf("Current policy for OpenEnclave is: %s\n", currentPolicy);
```
#### Set unsigned attestation policy (AAD clients only)
When an attestation instance is in AAD mode, the caller can use a convenience method to set an unsigned attestation
policy on the instance.
```java readme-sample-set-unsigned-policy
// Set the listed policy on an attestation instance. Please note that this particular policy will deny all
// attestation requests and should not be used in production.
PolicyResult policyResult = client.setAttestationPolicy(AttestationType.OPEN_ENCLAVE,
"version=1.0; authorizationrules{=> deny();}; issuancerules{};");
System.out.printf("Policy set for OpenEnclave result: %s\n", policyResult.getPolicyResolution());
```
#### Set signed attestation policy
For isolated mode attestation instances, the set or reset policy request must be signed using the key that is associated
with the attestation signing certificates configured on the attestation instance.
```java readme-sample-set-signed-policy
// Set the listed policy on an attestation instance using a signed policy token.
PolicyResult policyResult = client.setAttestationPolicy(AttestationType.SGX_ENCLAVE,
new AttestationPolicySetOptions()
.setAttestationPolicy("version=1.0; authorizationrules{=> permit();}; issuancerules{};")
.setAttestationSigner(new AttestationSigningKey(certificate, privateKey)));
System.out.printf("Policy set for Sgx result: %s\n", policyResult.getPolicyResolution());
```
#### List attestation signing certificates
When an attestation instance is in `Isolated` mode, the policy APIs need additional proof of authorization. This proof is
provided via the `AttestationSigningKey` parameter passed into the set and reset policy APIs.
Each `Isolated` mode instance has a set of certificates, which determine whether a caller has the authority to set an
attestation policy. When an attestation policy is set, the client presents a signed "token" to the service, which is signed
by the key in the `AttestationSigningKey`. The signed token, including the certificate in the `AttestationSigningKey` is
sent to the attestation service, which verifies that the token was signed with the private key corresponding to the
public key in the token. The set or reset policy operation will only succeed if the certificate in the token is one of
the policy management tokens. This interaction ensures that the client is in possession of the private key associated with
one of the policy management certificates and is thus authorized to perform the operation.
```java readme-sample-listPolicyCertificates
AttestationSignerCollection signers = client.listPolicyManagementCertificates();
System.out.printf("Instance %s contains %d signers.\n", endpoint, signers.getAttestationSigners().size());
for (AttestationSigner signer : signers.getAttestationSigners()) {
System.out.printf("Certificate Subject: %s", signer.getCertificates().get(0).getSubjectDN().toString());
}
```
#### Add attestation signing certificate
Adds a new certificate to the set of policy management certificates. The request to add the policy management certificate
must be signed with the private key associated with one of the existing policy management certificates (this ensures that
the caller is authorized to update the set of policy certificates).
Note: Adding the same certificate twice is not considered an error - if the certificate is already present, the addition is
ignored (this possibly surprising behavior is there because retries could cause the addition to be executed multiple times)
```java readme-sample-addPolicyManagementCertificate
System.out.printf("Adding new certificate %s\n", certificateToAdd.getSubjectDN().toString());
PolicyCertificatesModificationResult modificationResult = client.addPolicyManagementCertificate(
new PolicyManagementCertificateOptions(certificateToAdd,
new AttestationSigningKey(isolatedCertificate, isolatedKey)));
System.out.printf("Updated policy certificate, certificate add result: %s\n",
modificationResult.getCertificateResolution());
System.out.printf("Added certificate thumbprint: %s\n", modificationResult.getCertificateThumbprint());
```
#### Remove attestation signing certificate
Removes a certificate from the set of policy management certificates. The request to remove the policy management certificate
must be signed with the private key associated with one of the existing policy management certificates (this ensures that
the caller is authorized to update the set of policy certificates).
Note: Removing a non-existent certificate is not considered an error - if the certificate is not present, the removal is
ignored (this possibly surprising behavior is there because retries could cause the removal to be executed multiple times)
```java readme-sample-removePolicyManagementCertificate
System.out.printf("Removing existing certificate %s\n", certificateToRemove.getSubjectDN().toString());
PolicyCertificatesModificationResult modificationResult = client.deletePolicyManagementCertificate(
new PolicyManagementCertificateOptions(certificateToRemove,
new AttestationSigningKey(isolatedCertificate, isolatedKey)));
System.out.printf("Updated policy certificate, certificate remove result: %s\n",
modificationResult.getCertificateResolution());
System.out.printf("Removed certificate thumbprint: %s\n", modificationResult.getCertificateThumbprint());
```
## Troubleshooting
Troubleshooting information for the MAA service can be found [here](https://docs.microsoft.com/azure/attestation/troubleshoot-guide)
## Next steps
For more information about the Microsoft Azure Attestation service, please see our [documentation page](https://docs.microsoft.com/azure/attestation/).
## Contributing
For details on contributing to this repository, see the [contributing guide][azure_sdk_for_cpp_contributing].
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor
License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your
contribution. For details, visit <https://cla.microsoft.com>.
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate
the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to
do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
### Additional Helpful Links for Contributors
Many people all over the world have helped make this project better. You'll want to check out:
* [What are some good first issues for new contributors to the repo?](https://github.com/azure/azure-sdk-for-cpp/issues?q=is%3Aopen+is%3Aissue+label%3A%22up+for+grabs%22)
* [How to build and test your change][azure_sdk_for_cpp_contributing_developer_guide]
* [How you can make a change happen!][azure_sdk_for_cpp_contributing_pull_requests]
* Frequently Asked Questions (FAQ) and Conceptual Topics in the detailed [Azure SDK for C++ wiki](https://github.com/azure/azure-sdk-for-cpp/wiki).
- [What are some good first issues for new contributors to the repo?](https://github.com/azure/azure-sdk-for-cpp/issues?q=is%3Aopen+is%3Aissue+label%3A%22up+for+grabs%22)
- [How to build and test your change][azure_sdk_for_cpp_contributing_developer_guide]
- [How you can make a change happen!][azure_sdk_for_cpp_contributing_pull_requests]
- Frequently Asked Questions (FAQ) and Conceptual Topics in the detailed [Azure SDK for C++ wiki](https://github.com/azure/azure-sdk-for-cpp/wiki).
<!-- ### Community-->
### Reporting security issues and security bugs
@ -55,8 +374,16 @@ Security issues and bugs should be reported privately, via email, to the Microso
### License
Azure SDK for C++ is licensed under the [MIT](https://github.com/Azure/azure-sdk-for-cpp/blob/main/LICENSE.txt) license.
<!-- LINKS -->
[style-guide-msft]: https://docs.microsoft.com/style-guide/capitalization
[azure_attestation]: https://docs.microsoft.com/azure/attestation
[azure_identity]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/identity/azure-identity
[azure_subscription]: https://azure.microsoft.com/
[azure_cli]: https://docs.microsoft.com/cli/azure
[rest_api]: https://docs.microsoft.com/rest/api/attestation/
[azure_create_application_in_portal]: https://docs.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal
[azure_cloud_shell]: https://shell.azure.com/bash
[microsoft_code_of_conduct]: https://opensource.microsoft.com/codeofconduct/
[azure_sdk_for_cpp_contributing]: https://github.com/Azure/azure-sdk-for-cpp/blob/main/CONTRIBUTING.md
[azure_sdk_for_cpp_contributing_developer_guide]: https://github.com/Azure/azure-sdk-for-cpp/blob/main/CONTRIBUTING.md#developer-guide
[azure_sdk_for_cpp_contributing_pull_requests]: https://github.com/Azure/azure-sdk-for-cpp/blob/main/CONTRIBUTING.md#pull-requests
@ -68,3 +395,5 @@ Azure SDK for C++ is licensed under the [MIT](https://github.com/Azure/azure-sdk
[c_compiler]: https://visualstudio.microsoft.com/vs/features/cplusplus/
[cloud_shell]: https://docs.microsoft.com/azure/cloud-shell/overview
[cloud_shell_bash]: https://shell.azure.com/bash
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-cpp%2Fsdk%2Fattestation%2Fazure-security-attestation%2FREADME.png)

View File

@ -8,5 +8,6 @@
#pragma once
#include "attestation/attestation_administration_client.hpp"
#include "attestation/attestation_client.hpp"
#include "attestation/dll_import_export.hpp"

View File

@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "azure/attestation/attestation_client_models.hpp"
#include "azure/attestation/attestation_client_options.hpp"
#include <azure/core/context.hpp>
#include <azure/core/url.hpp>
#include <string>
namespace Azure { namespace Core { namespace Http { namespace _internal {
class HttpPipeline;
}}}} // namespace Azure::Core::Http::_internal
namespace Azure { namespace Security { namespace Attestation {
/**
*
* @brief The AttestationAdministrationClient implements the functionality required by the
* "Administration" family of attestation service APIs.
*
* @note: Attestation administration APIs cannot be used on shared attestation service instances.
*
* @details
* The Administration family of APIs provide APIs to manage:
*
* - Attestation policies.
* - Attestation policy management certificates (Isolated attestation service instances only).
*
* There are three flavors of attestation service instances:
* -# Shared Mode
* -# AAD Mode
* -# Isolated Mode
*
* Shared mode attestation service instances do not allow any administration actions at all. They
* exist to allow customers to perform attestation operations without requiring any
* customizations.
*
* AAD Mode instances allow customers to modify attestation policies. When the attestation
* instance is in AAD mode, the creator of the instance indicates that they trust ARM RBAC and
* Microsoft AAD to validate client connections to the service. As such, additional proof of
* authorization is not required for administrative operations.
*
*/
class AttestationAdministrationClient final {
public:
/**
* @brief Destructor.
*
*/
virtual ~AttestationAdministrationClient() = default;
/**
* @brief Construct a new Attestation Administration Client object.
*
* @param endpoint The URL address where the client will send the requests to.
* @param credential The authentication token to use.
* @param options The options to customize the client behavior.
*/
explicit AttestationAdministrationClient(
std::string const& endpoint,
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
AttestationAdministrationClientOptions const& options
= AttestationAdministrationClientOptions());
/**
* @brief Returns the API version the client was configured with.
*
* @returns The API version used when communicating with the attestation service.
*/
std::string const& ClientVersion() const { return m_apiVersion; }
/**
* @brief Construct a new Attestation Administration Client object from another attestation
* administration client.
*
* @param attestationClient An existing attestation client.
*/
explicit AttestationAdministrationClient(
AttestationAdministrationClient const& attestationClient)
: m_endpoint(attestationClient.m_endpoint), m_apiVersion(attestationClient.m_apiVersion),
m_pipeline(attestationClient.m_pipeline),
m_tokenValidationOptions(attestationClient.m_tokenValidationOptions){};
/** @brief Retrieves the attestation policy for the specified attestation type.
*/
Response<Models::AttestationToken<std::string>> GetAttestationPolicy(
Models::AttestationType const& attestationType,
GetPolicyOptions const& options = GetPolicyOptions(),
Azure::Core::Context const& context = Azure::Core::Context::ApplicationContext) const;
private:
Azure::Core::Url m_endpoint;
std::string m_apiVersion;
std::shared_ptr<Azure::Core::Credentials::TokenCredential const> m_credentials;
std::shared_ptr<Azure::Core::Http::_internal::HttpPipeline> m_pipeline;
AttestationTokenValidationOptions m_tokenValidationOptions;
mutable std::vector<Models::AttestationSigner> m_attestationSigners;
std::vector<Models::AttestationSigner> const& GetAttestationSigners(
Azure::Core::Context const& context) const;
};
}}} // namespace Azure::Security::Attestation

View File

@ -15,102 +15,6 @@ namespace Azure { namespace Core { namespace Http { namespace _internal {
namespace Azure { namespace Security { namespace Attestation {
/** An AttestationToken represents an RFC 7519 JSON Web Token returned from the attestation
* service with the specialized body type.
* <typeparam name="T"></typeparam> The type which represents the body of the attestation token.
*/
template <typename T> class AttestationToken final {
public:
/**
* @brief The full RFC 7515 JWS/JWT token returned by the attestation service.
*/
std::string RawToken;
/**
* @brief The elements of the raw token which will be signed by the Signature.
*/
std::string SignedElements;
/**
* @brief Signature (if present) for the attestation token.
*/
std::vector<uint8_t> Signature;
/**
* @brief RFC 7515 header properties.
*/
Models::AttestationTokenHeader Header;
// RFC 7519 properties.
/**
* The Expiration time for this attestation token.
*
* After this time, the token cannot be considered valid.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4'>RFC 7519
* Section 4.1.4</a> for more information.
*/
Azure::Nullable<Azure::DateTime> ExpiresOn;
/**
* The time at which this token was issued.
*
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6'>RFC 7519
* Section 4.1.6</a> for more information.
*/
Azure::Nullable<Azure::DateTime> IssuedOn;
/**
* The time before which this token cannot be considered valid.
*
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5'>RFC 7519
* Section 4.1.5</a> for more information.
*/
Azure::Nullable<Azure::DateTime> NotBefore;
/**
* The issuer of this attestation token
*
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1'>RFC 7519
* Section 4.1.1</a> for more information.
*/
Azure::Nullable<std::string> Issuer;
/**
* An identifier which uniquely identifies this token.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7'>RFC 7519
* Section 4.1.7</a> for more information.
*/
Azure::Nullable<std::string> UniqueIdentifier;
/**
* The subject for this attestation token.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2'>RFC 7519
* Section 4.1.2</a> for more information.
*/
Azure::Nullable<std::string> Subject;
/**
* The audience for this attestation token.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3'>RFC 7519
* Section 4.1.3</a> for more information.
*/
Azure::Nullable<std::string> Audience;
/**
* @brief The deserialized body of the attestation token.
*
*/
T Body;
};
/**
*
* The AttestationAsyncClient implements the functionality required by the "Attest" family of
@ -214,17 +118,6 @@ namespace Azure { namespace Security { namespace Attestation {
*/
class AttestationClient final {
private:
Azure::Core::Url m_endpoint;
std::string m_apiVersion;
std::shared_ptr<Azure::Core::Http::_internal::HttpPipeline> m_pipeline;
AttestationTokenValidationOptions m_tokenValidationOptions;
mutable std::vector<Models::AttestationSigner> m_attestationSigners;
std::vector<Models::AttestationSigner> const& GetAttestationSigners(
Azure::Core::Context const& context) const;
public:
/**
* @brief Destructor.
@ -298,7 +191,7 @@ namespace Azure { namespace Security { namespace Attestation {
* @returns Response<{@link AttestationToken}<{@link AttestationResult}>> - The result of the
* attestation operation.
*/
Response<AttestationToken<Models::AttestationResult>> AttestSgxEnclave(
Response<Models::AttestationToken<Models::AttestationResult>> AttestSgxEnclave(
std::vector<uint8_t> const& sgxQuoteToAttest,
AttestOptions options = AttestOptions(),
Azure::Core::Context const& context = Azure::Core::Context::ApplicationContext) const;
@ -315,10 +208,22 @@ namespace Azure { namespace Security { namespace Attestation {
* @returns Response<AttestationToken<AttestationResult>> - The result of the attestation
* operation
*/
Response<AttestationToken<Models::AttestationResult>> AttestOpenEnclave(
Response<Models::AttestationToken<Models::AttestationResult>> AttestOpenEnclave(
std::vector<uint8_t> const& openEnclaveReportToAttest,
AttestOptions options = AttestOptions(),
Azure::Core::Context const& context = Azure::Core::Context::ApplicationContext) const;
private:
Azure::Core::Url m_endpoint;
std::string m_apiVersion;
std::shared_ptr<Azure::Core::Credentials::TokenCredential const> m_credentials;
std::shared_ptr<Azure::Core::Http::_internal::HttpPipeline> m_pipeline;
AttestationTokenValidationOptions m_tokenValidationOptions;
mutable std::vector<Models::AttestationSigner> m_attestationSigners;
std::vector<Models::AttestationSigner> const& GetAttestationSigners(
Azure::Core::Context const& context) const;
};
}}} // namespace Azure::Security::Attestation

View File

@ -24,6 +24,58 @@
// cspell: words MRSIGNER MRENCLAVE
namespace Azure { namespace Security { namespace Attestation { namespace Models {
/**
* @brief The AttestationType type represent a Trusted Execution Environment supported by
* the attestation service.
*
*/
class AttestationType final {
private:
std::string m_attestationType;
public:
/**
* @brief Construct a new AttestationType object
*
* @param attestationType The string attestationType used for the attestation policy operation.
*/
AttestationType(std::string attestationType) : m_attestationType(std::move(attestationType)) {}
/**
* @brief Enable comparing the ext enum.
*
* @param other Another #AttestationType to be compared.
*/
bool operator==(AttestationType const& other) const
{
return m_attestationType == other.m_attestationType;
}
/**
* @brief Return the #AttestationType string representation.
*
*/
std::string const& ToString() const { return m_attestationType; }
/**
* @brief Specifies that this should apply to SGX enclaves.
*
*/
AZ_ATTESTATION_DLLEXPORT static const AttestationType SgxEnclave;
/**
* @brief Specifies that this should apply to SGX enclaves using the OpenEnclave APIs.
*
*/
AZ_ATTESTATION_DLLEXPORT static const AttestationType OpenEnclave;
/**
* @brief Specifies that this should apply to TPM enclaves.
*
*/
AZ_ATTESTATION_DLLEXPORT static const AttestationType Tpm;
};
/**
* @brief Contains information about this instance of the attestation service, which can be
* used to validate attestation service responses.
@ -187,6 +239,102 @@ namespace Azure { namespace Security { namespace Attestation { namespace Models
std::vector<AttestationSigner> Signers;
};
/** An AttestationToken represents an RFC 7519 JSON Web Token returned from the attestation
* service with the specialized body type.
* <typeparam name="T"></typeparam> The type which represents the body of the attestation token.
*/
template <typename T> class AttestationToken final {
public:
/**
* @brief The full RFC 7515 JWS/JWT token returned by the attestation service.
*/
std::string RawToken;
/**
* @brief The elements of the raw token which will be signed by the Signature.
*/
std::string SignedElements;
/**
* @brief Signature (if present) for the attestation token.
*/
std::vector<uint8_t> Signature;
/**
* @brief RFC 7515 header properties.
*/
Models::AttestationTokenHeader Header;
// RFC 7519 properties.
/**
* The Expiration time for this attestation token.
*
* After this time, the token cannot be considered valid.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4'>RFC 7519
* Section 4.1.4</a> for more information.
*/
Azure::Nullable<Azure::DateTime> ExpiresOn;
/**
* The time at which this token was issued.
*
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6'>RFC 7519
* Section 4.1.6</a> for more information.
*/
Azure::Nullable<Azure::DateTime> IssuedOn;
/**
* The time before which this token cannot be considered valid.
*
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5'>RFC 7519
* Section 4.1.5</a> for more information.
*/
Azure::Nullable<Azure::DateTime> NotBefore;
/**
* The issuer of this attestation token
*
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1'>RFC 7519
* Section 4.1.1</a> for more information.
*/
Azure::Nullable<std::string> Issuer;
/**
* An identifier which uniquely identifies this token.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7'>RFC 7519
* Section 4.1.7</a> for more information.
*/
Azure::Nullable<std::string> UniqueIdentifier;
/**
* The subject for this attestation token.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2'>RFC 7519
* Section 4.1.2</a> for more information.
*/
Azure::Nullable<std::string> Subject;
/**
* The audience for this attestation token.
*
* See <a href='https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3'>RFC 7519
* Section 4.1.3</a> for more information.
*/
Azure::Nullable<std::string> Audience;
/**
* @brief The deserialized body of the attestation token.
*
*/
T Body;
};
/** @brief An AttestationResult reflects the result of an Attestation operation.
*
* The fields in the AttestationResult represent the claims in the AttestationToken returned
@ -274,4 +422,73 @@ namespace Azure { namespace Security { namespace Attestation { namespace Models
Azure::Nullable<std::string> SgxCollateral;
};
/**
* @brief The PolicyModification enumeration represents the result of an attestation
* policy modification.
*
*/
class PolicyModification final {
private:
std::string m_policyModification;
public:
/**
* @brief Construct a new PolicyResolution object
*
* @param modification The string resolution used for the result of an attestation policy
* operation.
*/
PolicyModification(std::string modification) : m_policyModification(std::move(modification)) {}
/**
* @brief Enable comparing the ext enum.
*
* @param other Another #PolicyModification to be compared.
*/
bool operator==(PolicyModification const& other) const
{
return m_policyModification == other.m_policyModification;
}
/**
* @brief Return the #PolicyModification string representation.
*
*/
std::string const& ToString() const { return m_policyModification; }
/**
* @brief Specifies that the policy object was updated.
*
*/
AZ_ATTESTATION_DLLEXPORT static const PolicyModification Updated;
/**
* @brief Specifies that the policy object was removed.
*
*/
AZ_ATTESTATION_DLLEXPORT static const PolicyModification Removed;
};
/**
* @brief Result of a SetPolicy or ResetPolicy operation.
*/
struct PolicyResult
{
/**
* @brief Result of a modification.
*/
Azure::Nullable<PolicyModification> PolicyResolution;
/**
* @brief The SHA256 hash of the policy object which was received by the service.
*/
Azure::Nullable<std::vector<uint8_t>> PolicyTokenHash;
/**
* @brief A JSON Web Key containing the signer of the policy token. If not present, the token
* was unsecured.
*/
Azure::Nullable<AttestationSigner> PolicySigner;
};
}}}} // namespace Azure::Security::Attestation::Models

View File

@ -28,7 +28,7 @@ namespace Azure { namespace Security { namespace Attestation {
ServiceVersion(std::string version) : m_version(std::move(version)) {}
/**
* @brief Enable comparing the ext enum.
* @brief Enable comparing the extensible enum.
*
* @param other Another #ServiceVersion to be compared.
*/
@ -107,7 +107,7 @@ namespace Azure { namespace Security { namespace Attestation {
};
/**
* @brief Define the options to create an SDK Keys client.
* @brief Define the options to create an Attestation client.
*/
struct AttestationClientOptions final : public Azure::Core::_internal::ClientOptions
{
@ -129,6 +129,29 @@ namespace Azure { namespace Security { namespace Attestation {
}
};
/**
* @brief Define the options to create an Attestation Administration client.
*/
struct AttestationAdministrationClientOptions final : public Azure::Core::_internal::ClientOptions
{
ServiceVersion Version;
AttestationTokenValidationOptions TokenValidationOptions;
/**
* @brief Construct a new Attestation Client Options object.
*
* @param version Optional version for the client.
* @param tokenValidationOptions Options applied when validating attestation tokens returned by
* the service.
*/
AttestationAdministrationClientOptions(
ServiceVersion version = ServiceVersion::V2020_10_01,
AttestationTokenValidationOptions const& tokenValidationOptions = {})
: Azure::Core::_internal::ClientOptions(), Version(version),
TokenValidationOptions(tokenValidationOptions)
{
}
};
/** @brief The AttestationDataType represents how the attestation service should interpret the
* {@link AttestOptions::RuntimeData} and {@link AttestOptions::InittimeData} fields.
*/
@ -145,7 +168,7 @@ namespace Azure { namespace Security { namespace Attestation {
AttestationDataType(std::string dataType) : m_dataType(std::move(dataType)) {}
AttestationDataType() {}
/**
* @brief Enable comparing the ext enum.
* @brief Enable comparing the extensible enum.
*
* @param other Another AttestationDataType to be compared.
*/
@ -249,4 +272,16 @@ namespace Azure { namespace Security { namespace Attestation {
std::string PemEncodedX509Certificate;
};
/** @brief Parameters sent to the attestation service when retrieving an attestation policy.
*/
struct GetPolicyOptions final
{
/** @brief Specifies the options which should be used to validate the attestation token returned
* by the attestation service.
* @details If not provided by the caller, the token validation options
* specified when the @{link AttestationAdministrationClient} was created will be used.
*/
Azure::Nullable<AttestationTokenValidationOptions> TokenValidationOptions{};
};
}}} // namespace Azure::Security::Attestation

View File

@ -0,0 +1,160 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/attestation/attestation_administration_client.hpp"
#include "azure/attestation/attestation_client.hpp"
#include "private/attestation_client_models_private.hpp"
#include "private/attestation_client_private.hpp"
#include "private/attestation_common_request.hpp"
#include "private/attestation_deserializers_private.hpp"
#include "private/package_version.hpp"
#include <azure/core/base64.hpp>
#include <azure/core/http/policies/policy.hpp>
#include <azure/core/internal/diagnostics/log.hpp>
#include <azure/core/internal/http/pipeline.hpp>
#include <shared_mutex>
#include <string>
using namespace Azure::Security::Attestation;
using namespace Azure::Security::Attestation::Models;
using namespace Azure::Security::Attestation::_detail;
using namespace Azure::Security::Attestation::Models::_detail;
using namespace Azure::Core::Http;
using namespace Azure::Core::Http::Policies;
using namespace Azure::Core::Http::Policies::_internal;
using namespace Azure::Core::Http::_internal;
using namespace Azure::Core::Diagnostics::_internal;
using namespace Azure::Core::Diagnostics;
const Models::AttestationType AttestationType::SgxEnclave("SgxEnclave");
const Models::AttestationType AttestationType::OpenEnclave("OpenEnclave");
const Models::AttestationType AttestationType::Tpm("Tpm");
const Models::PolicyModification PolicyModification::Removed("Removed");
const Models::PolicyModification PolicyModification::Updated("Updated");
AttestationAdministrationClient::AttestationAdministrationClient(
std::string const& endpoint,
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
AttestationAdministrationClientOptions const& options)
: m_endpoint(endpoint), m_apiVersion(options.Version.ToString()),
m_tokenValidationOptions(options.TokenValidationOptions)
{
std::vector<std::unique_ptr<HttpPolicy>> perRetrypolicies;
if (credential)
{
m_credentials = credential;
Azure::Core::Credentials::TokenRequestContext const tokenContext
= {{"https://attest.azure.net/.default"}};
perRetrypolicies.emplace_back(
std::make_unique<BearerTokenAuthenticationPolicy>(credential, tokenContext));
}
m_apiVersion = options.Version.ToString();
std::vector<std::unique_ptr<HttpPolicy>> perCallpolicies;
m_pipeline = std::make_shared<Azure::Core::Http::_internal::HttpPipeline>(
options,
"Attestation",
PackageVersion::ToString(),
std::move(perRetrypolicies),
std::move(perCallpolicies));
}
namespace {
std::shared_timed_mutex SharedStateLock;
}
Azure::Response<Models::AttestationToken<std::string>>
AttestationAdministrationClient::GetAttestationPolicy(
AttestationType const& attestationType,
GetPolicyOptions const& options,
Azure::Core::Context const& context) const
{
Log::Write(
Logger::Level::Informational,
std::string("Get Policy for AttestationType:") + attestationType.ToString());
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint,
m_apiVersion,
HttpMethod::Get,
{"policies/" + attestationType.ToString()},
nullptr);
// Send the request to the service.
auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
// Deserialize the Service response token and return the JSON web token returned by the
// service.
std::string responseToken = AttestationServiceTokenResponseSerializer::Deserialize(response);
// Parse the JWT returned by the attestation service.
auto resultToken
= AttestationTokenInternal<Models::_detail::PolicyResult, PolicyResultSerializer>(
responseToken);
// Validate the token returned by the service. Use the cached attestation signers in the
// validation.
std::vector<AttestationSigner> const& signers = GetAttestationSigners(context);
resultToken.ValidateToken(
options.TokenValidationOptions ? options.TokenValidationOptions.Value()
: this->m_tokenValidationOptions,
signers);
// Extract the underlying policy token from the response.
std::string policyTokenValue
= static_cast<AttestationToken<Models::_detail::PolicyResult>>(resultToken)
.Body.PolicyToken.Value();
// TPM policies are empty by default, at least in our test instances, so handle the empty policy
// token case.
auto policyTokenI
= AttestationTokenInternal<StoredAttestationPolicy, StoredAttestationPolicySerializer>(
policyTokenValue);
AttestationToken<StoredAttestationPolicy> policyToken(policyTokenI);
std::string returnPolicy;
if (policyToken.Body.AttestationPolicy)
{
std::vector<uint8_t> policyUtf8 = policyToken.Body.AttestationPolicy.Value();
returnPolicy = std::string(policyUtf8.begin(), policyUtf8.end());
}
// Construct a token whose body is the policy, but whose token is the response from the
// service.
auto returnedToken = AttestationTokenInternal<std::string>(responseToken, returnPolicy);
return Response<AttestationToken<std::string>>(returnedToken, std::move(response));
}
/**
* @brief Retrieve the attestation signers to validate the attestation token returned from the
* service.
*
* @details Validating attestation tokens returned by the attestation service requires a set of
* possible signers for the attestation token. Retrieving this can take a significant amount of time
* (tens or hundreds of milliseconds), so we cache the results for the lifetime of this client.
*
* @param context Client context for the request to the service.
* @return std::vector<AttestationSigner> const& Returns a reference to the private member filled in
* with the signers returned by the service.
*/
std::vector<AttestationSigner> const& AttestationAdministrationClient::GetAttestationSigners(
Azure::Core::Context const& context) const
{
std::unique_lock<std::shared_timed_mutex> stateLock(SharedStateLock);
if (m_attestationSigners.size() == 0)
{
auto request
= AttestationCommonRequest::CreateRequest(m_endpoint, HttpMethod::Get, {"certs"}, nullptr);
auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
auto jsonWebKeySet(JsonWebKeySetSerializer::Deserialize(response));
AttestationSigningCertificateResult returnValue;
for (const auto& jwk : jsonWebKeySet.Keys)
{
AttestationSignerInternal internalSigner(jwk);
m_attestationSigners.push_back(internalSigner);
}
}
return m_attestationSigners;
}

View File

@ -2,12 +2,14 @@
// SPDX-License-Identifier: MIT
#include "azure/attestation/attestation_client.hpp"
#include "azure/attestation/attestation_administration_client.hpp"
#include "private/attestation_client_models_private.hpp"
#include "private/attestation_client_private.hpp"
#include "private/attestation_common_request.hpp"
#include "private/attestation_deserializers_private.hpp"
#include "private/package_version.hpp"
#include <azure/core/base64.hpp>
#include <azure/core/credentials/credentials.hpp>
#include <azure/core/http/policies/policy.hpp>
#include <azure/core/internal/diagnostics/log.hpp>
#include <azure/core/internal/http/pipeline.hpp>
@ -21,23 +23,25 @@ using namespace Azure::Security::Attestation::_detail;
using namespace Azure::Security::Attestation::Models::_detail;
using namespace Azure::Core::Http;
using namespace Azure::Core::Http::Policies;
using namespace Azure::Core::Http::Policies::_internal;
using namespace Azure::Core::Http::_internal;
AttestationClient::AttestationClient(
std::string const& endpoint,
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
AttestationClientOptions options)
: m_endpoint(endpoint), m_tokenValidationOptions(options.TokenValidationOptions)
: m_endpoint(endpoint), m_credentials(credential),
m_tokenValidationOptions(options.TokenValidationOptions)
{
std::vector<std::unique_ptr<HttpPolicy>> perRetrypolicies;
if (credential)
{
// Azure::Core::Credentials::TokenRequestContext const tokenContext
// = {{_internal::UrlScope::GetScopeFromUrl(m_vaultUrl)}};
m_credentials = credential;
Azure::Core::Credentials::TokenRequestContext const tokenContext
= {{"https://attest.azure.net/.default"}};
// perRetrypolicies.emplace_back(
// std::make_unique<BearerTokenAuthenticationPolicy>(credential,
// std::move(tokenContext)));
perRetrypolicies.emplace_back(
std::make_unique<BearerTokenAuthenticationPolicy>(credential, tokenContext));
}
m_apiVersion = options.Version.ToString();
std::vector<std::unique_ptr<HttpPolicy>> perCallpolicies;

View File

@ -8,4 +8,5 @@ namespace Azure { namespace Security { namespace Attestation {
const AttestationDataType AttestationDataType ::Binary("Binary");
const AttestationDataType AttestationDataType::Json("Json");
}}} // namespace Azure::Security::Attestation

View File

@ -241,4 +241,39 @@ namespace Azure {
Azure::Nullable<std::string> Nonce;
};
/**
* @brief Result of a GetPolicy, SetPolicy, or ResetPolicy operation.
*/
struct PolicyResult
{
/**
* @brief Result of a modification.
*/
Azure::Nullable<std::string> PolicyResolution;
/**
* @brief The SHA256 hash of the policy object which was received by the service.
*/
Azure::Nullable<std::string> PolicyTokenHash;
/**
* @brief A JSON Web Key containing the signer of the policy token.
*/
Azure::Nullable<JsonWebKey> PolicySigner;
/**
* @brief The policy token returned by the service.
*/
Azure::Nullable<std::string> PolicyToken;
};
/**
* @brief A StoredAttestationPolicy is a JWS object which represents a (possibly signed)
* attestation policy received by the attestation service.
*/
struct StoredAttestationPolicy
{
/** @brief UTF-8 encoded representation of the attestation policy.
*/
Azure::Nullable<std::vector<uint8_t>> AttestationPolicy;
};
}}}}} // namespace Azure::Security::Attestation::Models::_detail

View File

@ -28,9 +28,17 @@
namespace Azure { namespace Security { namespace Attestation { namespace _detail {
template <class T, typename TDeserializer> class AttestationTokenInternal {
template <class T> class EmptyDeserializer {
public:
static std::string Deserialize(Azure::Core::Json::_internal::json const&)
{
return std::string();
}
};
template <class T, class TDeserializer = EmptyDeserializer<T>> class AttestationTokenInternal {
private:
AttestationToken<T> m_token;
Models::AttestationToken<T> m_token;
/**
* @brief Validate the time elements in a JSON Web token as controlled by the provided
@ -211,7 +219,9 @@ namespace Azure { namespace Security { namespace Attestation { namespace _detail
*
* @param jwt - the JSON Web Token/JSON Web Signature to be parsed.
*/
AttestationTokenInternal(std::string const& jwt)
AttestationTokenInternal(
std::string const& jwt,
Azure::Nullable<T> preferredBody = Azure::Nullable<T>())
{
m_token.RawToken = jwt;
@ -259,35 +269,44 @@ namespace Azure { namespace Security { namespace Attestation { namespace _detail
// Now add the encoded body to the signed elements.
m_token.SignedElements += body;
if (!body.empty())
{
auto jsonBody(Azure::Core::Json::_internal::json::parse(
Azure::Core::_internal::Base64Url::Base64UrlDecode(body)));
auto jsonBody(Azure::Core::Json::_internal::json::parse(
Azure::Core::_internal::Base64Url::Base64UrlDecode(body)));
// Parse the RFC 7519 JSON Web Token body properties.
// Note that if this is a JWS, these properties will NOT be present.
Azure::Core::Json::_internal::JsonOptional::SetIfExists<int64_t, Azure::DateTime>(
m_token.ExpiresOn,
jsonBody,
"exp",
Azure::Core::_internal::PosixTimeConverter::PosixTimeToDateTime);
Azure::Core::Json::_internal::JsonOptional::SetIfExists<int64_t, Azure::DateTime>(
m_token.IssuedOn,
jsonBody,
"iat",
Azure::Core::_internal::PosixTimeConverter::PosixTimeToDateTime);
Azure::Core::Json::_internal::JsonOptional::SetIfExists<int64_t, Azure::DateTime>(
m_token.NotBefore,
jsonBody,
"nbf",
Azure::Core::_internal::PosixTimeConverter::PosixTimeToDateTime);
Azure::Core::Json::_internal::JsonOptional::SetIfExists(m_token.Issuer, jsonBody, "iss");
Azure::Core::Json::_internal::JsonOptional::SetIfExists(m_token.Subject, jsonBody, "sub");
Azure::Core::Json::_internal::JsonOptional::SetIfExists(m_token.Audience, jsonBody, "aud");
Azure::Core::Json::_internal::JsonOptional::SetIfExists(
m_token.UniqueIdentifier, jsonBody, "jti");
m_token.Body = TDeserializer::Deserialize(jsonBody);
// Parse the RFC 7519 JSON Web Token body properties.
// Note that if this is a JWS, these properties will NOT be present.
Azure::Core::Json::_internal::JsonOptional::SetIfExists<int64_t, Azure::DateTime>(
m_token.ExpiresOn,
jsonBody,
"exp",
Azure::Core::_internal::PosixTimeConverter::PosixTimeToDateTime);
Azure::Core::Json::_internal::JsonOptional::SetIfExists<int64_t, Azure::DateTime>(
m_token.IssuedOn,
jsonBody,
"iat",
Azure::Core::_internal::PosixTimeConverter::PosixTimeToDateTime);
Azure::Core::Json::_internal::JsonOptional::SetIfExists<int64_t, Azure::DateTime>(
m_token.NotBefore,
jsonBody,
"nbf",
Azure::Core::_internal::PosixTimeConverter::PosixTimeToDateTime);
Azure::Core::Json::_internal::JsonOptional::SetIfExists(m_token.Issuer, jsonBody, "iss");
Azure::Core::Json::_internal::JsonOptional::SetIfExists(m_token.Subject, jsonBody, "sub");
Azure::Core::Json::_internal::JsonOptional::SetIfExists(
m_token.Audience, jsonBody, "aud");
Azure::Core::Json::_internal::JsonOptional::SetIfExists(
m_token.UniqueIdentifier, jsonBody, "jti");
if (preferredBody)
{
m_token.Body = preferredBody.Value();
}
else
{
m_token.Body = TDeserializer::Deserialize(jsonBody);
}
}
// Remove the body from the token, we've remembered its contents.
token.erase(0, bodyIndex + 1);
}
@ -406,6 +425,6 @@ namespace Azure { namespace Security { namespace Attestation { namespace _detail
ValidateTokenIssuer(validationOptions);
}
operator AttestationToken<T>&&() { return std::move(m_token); }
operator Models::AttestationToken<T>&&() { return std::move(m_token); }
};
}}}} // namespace Azure::Security::Attestation::_detail

View File

@ -273,4 +273,31 @@ namespace Azure { namespace Security { namespace Attestation { namespace _detail
}
return returnValue;
}
Models::_detail::PolicyResult PolicyResultSerializer::Deserialize(
Azure::Core::Json::_internal::json const& parsedResult)
{
Models::_detail::PolicyResult returnValue;
JsonOptional::SetIfExists(returnValue.PolicyResolution, parsedResult, "x-ms-policy-result");
JsonOptional::SetIfExists(returnValue.PolicyTokenHash, parsedResult, "x-ms-policy-token-hash");
if (parsedResult.contains("x-ms-policy-signer"))
{
returnValue.PolicySigner
= JsonWebKeySerializer::Deserialize(parsedResult["x-ms-policy-signer"]);
}
JsonOptional::SetIfExists(returnValue.PolicyToken, parsedResult, "x-ms-policy");
return returnValue;
}
Models::_detail::StoredAttestationPolicy StoredAttestationPolicySerializer::Deserialize(
Azure::Core::Json::_internal::json const& parsedResult)
{
Models::_detail::StoredAttestationPolicy returnValue;
JsonOptional::SetIfExists<std::string, std::vector<uint8_t>>(
returnValue.AttestationPolicy,
parsedResult,
"AttestationPolicy",
Azure::Core::_internal::Base64Url::Base64UrlDecode);
return returnValue;
}
}}}} // namespace Azure::Security::Attestation::_detail

View File

@ -94,4 +94,23 @@ namespace Azure { namespace Security { namespace Attestation { namespace _detail
static std::string Serialize(Models::AttestationTokenHeader const& tokenHeader);
};
/**
* @brief Serializer/Deserializer for internal PolicyResult objects.
*/
struct PolicyResultSerializer final
{
static Models::_detail::PolicyResult Deserialize(
Azure::Core::Json::_internal::json const& json);
};
/**
* @brief Serializer/Deserializer for internal PolicyResult objects.
*/
struct StoredAttestationPolicySerializer final
{
static Models::_detail::StoredAttestationPolicy Deserialize(
Azure::Core::Json::_internal::json const& json);
static std::string Serialize(Models::_detail::StoredAttestationPolicy const& policy);
};
}}}} // namespace Azure::Security::Attestation::_detail

View File

@ -19,7 +19,8 @@ add_executable (
macro_guard.cpp
crypto_test.cpp
attestation_test.cpp
token_test.cpp)
token_test.cpp administration_test.cpp
attestation_collateral.cpp)
create_per_service_target_build(azure-security-attestation-test attestation)

View File

@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/attestation/attestation_administration_client.hpp"
#include "azure/identity/client_secret_credential.hpp"
#include <azure/attestation/attestation_client_models.hpp>
#include <azure/core/test/test_base.hpp>
#include <gtest/gtest.h>
#include <string>
#include <tuple>
using namespace Azure::Security::Attestation;
using namespace Azure::Security::Attestation::Models;
namespace Azure { namespace Security { namespace Attestation { namespace Test {
class AdministrationTests
: public Azure::Core::Test::TestBase,
public testing::WithParamInterface<std::tuple<std::string, AttestationType>> {
private:
protected:
std::shared_ptr<Azure::Core::Credentials::TokenCredential> m_credential;
std::string m_endpoint;
// Create
virtual void SetUp() override
{
Azure::Core::Test::TestBase::SetUpTestBase(AZURE_TEST_RECORDING_DIR);
std::string const mode(std::get<0>(GetParam()));
if (mode == "Shared")
{
std::string const shortLocation(GetEnv("LOCATION_SHORT_NAME"));
m_endpoint = "https://shared" + shortLocation + "." + shortLocation + ".attest.azure.net";
}
else if (mode == "Aad")
{
m_endpoint = GetEnv("ATTESTATION_AAD_URL");
}
else if (mode == "Isolated")
{
m_endpoint = GetEnv("ATTESTATION_ISOLATED_URL");
}
}
std::unique_ptr<AttestationAdministrationClient> CreateClient()
{
// `InitTestClient` takes care of setting up Record&Playback.
Azure::Security::Attestation::AttestationAdministrationClientOptions options;
if (m_testContext.IsPlaybackMode())
{
// Skip validating time stamps if using recordings.
options.TokenValidationOptions.ValidateNotBeforeTime = false;
options.TokenValidationOptions.ValidateExpirationTime = false;
}
std::shared_ptr<Azure::Core::Credentials::TokenCredential> credential
= std::make_shared<Azure::Identity::ClientSecretCredential>(
GetEnv("AZURE_TENANT_ID"), GetEnv("AZURE_CLIENT_ID"), GetEnv("AZURE_CLIENT_SECRET"));
return InitTestClient<
Azure::Security::Attestation::AttestationAdministrationClient,
Azure::Security::Attestation::AttestationAdministrationClientOptions>(
m_endpoint, credential, options);
}
};
TEST_P(AdministrationTests, GetPolicy)
{
auto adminClient(CreateClient());
EXPECT_FALSE(adminClient->ClientVersion().empty());
AttestationType attestationType(std::get<1>(GetParam()));
{
auto policy = adminClient->GetAttestationPolicy(attestationType);
// The policy should have a value, and the token should have been issued by the service.
if (policy.Value.Body.empty())
{
EXPECT_EQ(AttestationType::Tpm, attestationType);
}
else
{
EXPECT_EQ(0UL, policy.Value.Body.find("version"));
}
if (!m_testContext.IsPlaybackMode())
{
EXPECT_EQ(m_endpoint, policy.Value.Issuer.Value());
}
}
{
GetPolicyOptions gpOptions;
EXPECT_FALSE(gpOptions.TokenValidationOptions);
}
}
INSTANTIATE_TEST_SUITE_P(
Attestation,
AdministrationTests,
testing::Combine(
::testing::Values("Shared", "Aad", "Isolated"),
::testing::Values(
AttestationType::SgxEnclave,
AttestationType::OpenEnclave,
AttestationType::Tpm)),
[](testing::TestParamInfo<AdministrationTests::ParamType> const& info) -> std::string {
std::string instanceType = std::get<0>(info.param);
return instanceType + "_" + std::get<1>(info.param).ToString();
});
}}}} // namespace Azure::Security::Attestation::Test

View File

@ -0,0 +1,355 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "attestation_collateral.hpp"
#include <azure/core/base64.hpp>
namespace Azure { namespace Security { namespace Attestation { namespace Test {
// cspell:disable
const std::string OpenEnclaveQuote(
"AQAAAAIAAADoEQAAAAAAAAMAAgAAAAAABQAKAJOacjP3nEyplAoNs5V_Bgfl_"
"L18zrEJejtqk6RDB0IzAAAAABERAwX_"
"gAYAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAABwAAAAAAAAApKh9LUZ5GYn6yR4o9mFFAVlPFtLCmkl3"
"oQ4N"
"NkhaFDgAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAASupfmg7QSxH4iarf5qHTdiE6Kalahc5zN65vf-"
"zmYQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAA"
"AAAA"
"AAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKFQuRP5-c_ZhD2sxrnV2kl8JzNu0xWRlg-"
"zBVhM3qP8AAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAADQQAACJx8e27oQ0pijs3lXQ9HfKWP9NMqVHQFL9SOjC_KGDcbv-I2fCafTHJ__"
"AmNqVXy7XTXnzmLp1HhUCy1_9AORSAT"
"qGZ1PtvBf4Q2NfNxqVkNrGJAjYuqMPStdg0MuM21nN-Qc9BWNycRMMsU7YfHSzmw7eGjBb_"
"Ewfb3k6N4ZYRhERAwX_"
"gAYAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAAAAAABwAAAAAAAAA_sKzghp0uMPKOhtcMdmQDpU-"
"7zWWO7ODhuUipFVkXQAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAjE9XddeWUD6WE393xoqCmgBWrI3tcBQLCBsJRJDFe_"
"8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAUAAAA"
"AAAA"
"AAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_"
"mzVQFF8XbJCRGdNkA3SPx9ZUPgtx3874VyDYQnFRIAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAEUP2-pxe7LoyevtN5BdE4KKikxKK6-"
"hwG0xCDmxmfLphcnrVskSbKmiKUfzkWUBehrF8gHCGNGIPX3QQDwmtZ4gAAABAgME"
"BQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fBQDMDQAALS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVn"
"VEND"
"QkNhZ0F3SUJBZ0lVU3I5VmR"
"iSnFWbzVyZzRadUpCRWo2SjNoak9jd0NnWUlLb1pJemowRUF3SXcKY1RFak1DRUdBMVVFQXd3YVNXNTBaV3dnVTB"
"kWUl"
"GQkRTeUJRY205alpYTnpiM0"
"lnUTBFeEdqQVlCZ05WQkFvTQpFVWx1ZEdWc0lFTnZjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQk"
"RiR0"
"Z5WVRFTE1Ba0dBMVVFCkNBd"
"0NRMEV4Q3pBSkJnTlZCQVlUQWxWVE1CNFhEVEl4TURNeE9UQTBOVEl3T0ZvWERUSTRNRE14T1RBME5USXcKT0Zvd"
"2NER"
"WlNQ0FHQTFVRUF3d1pTVzUw"
"Wld3Z1UwZFlJRkJEU3lCRFpYSjBhV1pwWTJGMFpURWFNQmdHQTFVRQpDZ3dSU1c1MFpXd2dRMjl5Y0c5eVlYUnBi"
"MjR4"
"RkRBU0JnTlZCQWNNQzFOaGJ"
"uUmhJRU5zWVhKaE1Rc3dDUVlEClZRUUlEQUpEUVRFTE1Ba0dBMVVFQmhNQ1ZWTXdXVEFUQmdjcWhrak9QUUlCQmd"
"ncWh"
"rak9QUU1CQndOQ0FBUlQKVG"
"RNNVhTMGFiRTA2ZUdVTVU3S1JOQXJlRGRtTWJHK25KVHlucDZXankyeXJ6NmlEa3h1R1F3WGZ1b25uUVBuZApjdH"
"gwbH"
"IyR3I0WjF1YXNsQjM2Vm80S"
"UNtekNDQXBjd0h3WURWUjBqQkJnd0ZvQVUwT2lxMm5YWCtTNUpGNWc4CmV4UmwwTlh5V1Uwd1h3WURWUjBmQkZnd"
"1ZqQ"
"lVvRktnVUlaT2FIUjBjSE02"
"THk5aGNHa3VkSEoxYzNSbFpITmwKY25acFkyVnpMbWx1ZEdWc0xtTnZiUzl6WjNndlkyVnlkR2xtYVdOaGRHbHZi"
"aTky"
"TWk5d1kydGpjbXcvWTJFOQp"
"jSEp2WTJWemMyOXlNQjBHQTFVZERnUVdCQlRMejZNQ3VHcVZobFYrR2Q0ZGtacmx4YndCV2pBT0JnTlZIUThCCkF"
"mOEV"
"CQU1DQnNBd0RBWURWUjBUQV"
"FIL0JBSXdBRENDQWRRR0NTcUdTSWI0VFFFTkFRU0NBY1V3Z2dIQk1CNEcKQ2lxR1NJYjRUUUVOQVFFRUVMOEhhRE"
"xXWW"
"dVUFUzU3c3Tm1Ibkhrd2dnR"
"mtCZ29xaGtpRytFMEJEUUVDTUlJQgpWREFRQmdzcWhraUcrRTBCRFFFQ0FRSUJFVEFRQmdzcWhraUcrRTBCRFFFQ"
"0FnS"
"UJFVEFRQmdzcWhraUcrRTBC"
"CkRRRUNBd0lCQWpBUUJnc3Foa2lHK0UwQkRRRUNCQUlCQkRBUUJnc3Foa2lHK0UwQkRRRUNCUUlCQVRBUkJnc3EK"
"aGtp"
"RytFMEJEUUVDQmdJQ0FJQXd"
"FQVlMS29aSWh2aE5BUTBCQWdjQ0FRWXdFQVlMS29aSWh2aE5BUTBCQWdnQwpBUUF3RUFZTEtvWklodmhOQVEwQkF"
"na0N"
"BUUF3RUFZTEtvWklodmhOQV"
"EwQkFnb0NBUUF3RUFZTEtvWklodmhOCkFRMEJBZ3NDQVFBd0VBWUxLb1pJaHZoTkFRMEJBZ3dDQVFBd0VBWUxLb1"
"pJaH"
"ZoTkFRMEJBZzBDQVFBd0VBW"
"UwKS29aSWh2aE5BUTBCQWc0Q0FRQXdFQVlMS29aSWh2aE5BUTBCQWc4Q0FRQXdFQVlMS29aSWh2aE5BUTBCQWhBQ"
"wpBU"
"UF3RUFZTEtvWklodmhOQVEw"
"QkFoRUNBUW93SHdZTEtvWklodmhOQVEwQkFoSUVFQkVSQWdRQmdBWUFBQUFBCkFBQUFBQUF3RUFZS0tvWklodmhO"
"QVEw"
"QkF3UUNBQUF3RkFZS0tvWkl"
"odmhOQVEwQkJBUUdBSkJ1MVFBQU1BOEcKQ2lxR1NJYjRUUUVOQVFVS0FRQXdDZ1lJS29aSXpqMEVBd0lEU1FBd1J"
"nSWh"
"BSzZPMS9GNy80NFprcWhUN2"
"FhNgp5QVh6QlltRWxUVHRvL25rVUd4N1BtUktBaUVBMXliSWt6SjVwcXR1L21jOW5DUWNwRUJOdk5KZFNIcW1jc0"
"4rCk"
"V2dWJ3WlU9Ci0tLS0tRU5EI"
"ENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNsekNDQWo2Z0F3SUJBZ0lWQ"
"U5Eb"
"3F0cDExL2t1U1JlWVBIc1Va"
"ZERWOGxsTk1Bb0dDQ3FHU000OUJBTUMKTUdneEdqQVlCZ05WQkFNTUVVbHVkR1ZzSUZOSFdDQlNiMjkwSUVOQk1S"
"b3dH"
"QVlEVlFRS0RCRkpiblJsYkN"
"CRApiM0p3YjNKaGRHbHZiakVVTUJJR0ExVUVCd3dMVTJGdWRHRWdRMnhoY21FeEN6QUpCZ05WQkFnTUFrTkJNUXN"
"3CkN"
"RWURWUVFHRXdKVlV6QWVGdz"
"B4T0RBMU1qRXhNRFExTURoYUZ3MHpNekExTWpFeE1EUTFNRGhhTUhFeEl6QWgKQmdOVkJBTU1Ha2x1ZEdWc0lGTk"
"hXQ0"
"JRUTBzZ1VISnZZMlZ6YzI5e"
"UlFTkJNUm93R0FZRFZRUUtEQkZKYm5SbApiQ0JEYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnU"
"TJ4a"
"GNtRXhDekFKQmdOVkJBZ01B"
"a05CCk1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCTDlxK05NcDJJ"
"T2cK"
"dGRsMWJrL3VXWjUrVEdRbTh"
"hQ2k4ejc4ZnMrZktDUTNkK3VEelhuVlRBVDJaaERDaWZ5SXVKd3ZOM3dOQnA5aQpIQlNTTUpNSnJCT2pnYnN3Z2J"
"nd0h"
"3WURWUjBqQkJnd0ZvQVVJbV"
"VNMWxxZE5JbnpnN1NWVXI5UUd6a25CcXd3ClVnWURWUjBmQkVzd1NUQkhvRVdnUTRaQmFIUjBjSE02THk5alpYSj"
"BhV1"
"pwWTJGMFpYTXVkSEoxYzNSb"
"FpITmwKY25acFkyVnpMbWx1ZEdWc0xtTnZiUzlKYm5SbGJGTkhXRkp2YjNSRFFTNWpjbXd3SFFZRFZSME9CQllFR"
"k5Eb"
"wpxdHAxMS9rdVNSZVlQSHNV"
"WmREVjhsbE5NQTRHQTFVZER3RUIvd1FFQXdJQkJqQVNCZ05WSFJNQkFmOEVDREFHCkFRSC9BZ0VBTUFvR0NDcUdT"
"TTQ5"
"QkFNQ0EwY0FNRVFDSUMvOWo"
"rODRUK0h6dFZPL3NPUUJXSmJTZCsvMnVleEsKNCthQTBqY0ZCTGNwQWlBM2RoTXJGNWNENTJ0NkZxTXZBSXBqOFh"
"kR21"
"5MmJlZWxqTEpLK3B6cGNSQT"
"09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqakNDQW"
"pTZ0"
"F3SUJBZ0lVSW1VTTFscWROS"
"W56ZzdTVlVyOVFHemtuQnF3d0NnWUlLb1pJemowRUF3SXcKYURFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGS"
"nZiM"
"1FnUTBFeEdqQVlCZ05WQkFv"
"TUVVbHVkR1ZzSUVOdgpjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVF"
"Q0F3"
"Q1EwRXhDekFKCkJnTlZCQVl"
"UQWxWVE1CNFhEVEU0TURVeU1URXdOREV4TVZvWERUTXpNRFV5TVRFd05ERXhNRm93YURFYU1CZ0cKQTFVRUF3d1J"
"TVzU"
"wWld3Z1UwZFlJRkp2YjNRZ1"
"EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnZjbkJ2Y21GMAphVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYk"
"dGeV"
"lURUxNQWtHQTFVRUNBd0NRM"
"EV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVDNm5Fd01ESVlaT"
"2ova"
"VBXc0N6YUVLaTcKMU9pT1NM"
"UkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZamxCYWxUVll4RlAyc0pCSzV6bEtPQgp1ekNCdURB"
"ZkJn"
"TlZIU01FR0RBV2dCUWlaUXp"
"XV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdSYUJEaGtGb2RIUndjem92TDJObGNuUnB"
"abWx"
"qWVhSbGN5NTBjblZ6ZEdWa2"
"MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtTnliREFkQmdOVkhRNEVGZ1FVSW"
"1VTT"
"FscWROSW56ZzdTVgpVcjlRR"
"3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRRXdDZ1lJCktvWkl6a"
"jBFQ"
"XdJRFNBQXdSUUlnUVFzLzA4"
"cnljZFBhdUNGazhVUFFYQ01BbHNsb0JlN053YVFHVGNkcGEwRUMKSVFDVXQ4U0d2eEttanBjTS96MFdQOUR2bzho"
"Mms1"
"ZHUxaVdEZEJrQW4rMGlpQT0"
"9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAA");
const std::string OpenEnclaveNonDebugQuote(
"AQAAAAIAAADoEQAAAAAAAAMAAgAAAAAABQAKAJOacjP3nEyplAoNs5V_"
"BgfDYELtjmo1LWZEqF8xasaZAAAAABERAwX_"
"gAYAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAABwAAAAAAAAC3eSAmGL7LY2do5dkC8o1SQiJzX6-"
"1OeqboHw_wXGhwgAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAALBpElSroIHE1xsKbdbjAKTcu6UtnfhXCC9QjQPENQaoAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAAAAAAAAAAAAAA"
"AAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKFQuRP5-c_ZhD2sxrnV2kl8JzNu0xWRlg-"
"zBVhM3qP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQQAA"
"Ck3Zl7b4XERNDrAJfKbmzU0NSTIzY5rsFeyW_6deDzOyjXAnxA3b1WfBwrFrU9JKpfI9SDlpwms3YSQtJArmrD-"
"8i_"
"meLNk8sQSwSkR7TdIadTEAZdb7S-7qMt"
"Yt3kWMfQ7H3g338R0kcF9wcy0jZmeBrRLDXyEUDcPI63Fwvp_BERAwX_"
"gAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAAAA"
"AABwAAAAAAAAA_sKzghp0uMPKOhtcMdmQDpU-"
"7zWWO7ODhuUipFVkXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjE9XddeWUD6WE393xoqCmgBW"
"rI3tcBQLCBsJRJDFe_"
"8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAA"
"AAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAABAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAA"
"AAAAAAAAAAAAAAAAAAmm22hOMEcuVw"
"P_d08cVnQ2JF3uT3Q5as4s-"
"D4yNshB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgCuq8kIluOwzRvIHV3J7G-"
"62qz2UxkrKQ2aJHVWlzGwveCOd"
"GIgpSJVM7GNcJW12FOveof_7m_"
"nA78uk3D3C4gAAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fBQDMDQAALS0tLS1CRUdJTiBDRVJUSUZJ"
"Q0FU"
"RS0t"
"LS0tCk1JSUVnVENDQkNlZ0F3SUJBZ0lWQU9jMDJHVHYvUTRvOUhHS1Bndk8yeUpPMElWTk1Bb0dDQ3FHU000OUJB"
"TUMK"
"TUhFeEl6QWhCZ05WQkFNTUdrbHVkR1"
"ZzSUZOSFdDQlFRMHNnVUhKdlkyVnpjMjl5SUVOQk1Sb3dHQVlEVlFRSwpEQkZKYm5SbGJDQkRiM0p3YjNKaGRHbH"
"Ziak"
"VVTUJJR0ExVUVCd3dMVTJGdWRHRWdR"
"MnhoY21FeEN6QUpCZ05WCkJBZ01Ba05CTVFzd0NRWURWUVFHRXdKVlV6QWVGdzB5TVRBME1Ea3hNalU1TWpoYUZ3"
"MHlP"
"REEwTURreE1qVTUKTWpoYU1IQXhJak"
"FnQmdOVkJBTU1HVWx1ZEdWc0lGTkhXQ0JRUTBzZ1EyVnlkR2xtYVdOaGRHVXhHakFZQmdOVgpCQW9NRVVsdWRHVn"
"NJRU"
"52Y25CdmNtRjBhVzl1TVJRd0VnWURW"
"UVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHCkExVUVDQXdDUTBFeEN6QUpCZ05WQkFZVEFsVlRNRmt3RXdZSEtv"
"Wkl6"
"ajBDQVFZSUtvWkl6ajBEQVFjRFFnQU"
"UKYzZ1TjVuZGlFY25mWUp1OFU1MUgzc3lzWm5kQ05JamlwRVdEZjJuaXp6VU9XdlZjdjIxWUUwakxMdmxpL2s3NA"
"p2bj"
"FtUzYvbkNYV3MxOFVZeE1PMFM2T0NB"
"cHN3Z2dLWE1COEdBMVVkSXdRWU1CYUFGTkRvcXRwMTEva3VTUmVZClBIc1VaZERWOGxsTk1GOEdBMVVkSHdSWU1G"
"WXdW"
"S0JTb0ZDR1RtaDBkSEJ6T2k4dllYQn"
"BMblJ5ZFhOMFpXUnoKWlhKMmFXTmxjeTVwYm5SbGJDNWpiMjB2YzJkNEwyTmxjblJwWm1sallYUnBiMjR2ZGpJdm"
"NHTn"
"JZM0pzUDJOaApQWEJ5YjJObGMzTnZj"
"akFkQmdOVkhRNEVGZ1FVRzBZaHd5VEh2bFFUNFlQVU1lRGplMmFUUWNjd0RnWURWUjBQCkFRSC9CQVFEQWdiQU1B"
"d0dB"
"MVVkRXdFQi93UUNNQUF3Z2dIVUJna3"
"Foa2lHK0UwQkRRRUVnZ0hGTUlJQndUQWUKQmdvcWhraUcrRTBCRFFFQkJCRDBRZ2lrT3FkRWxVQnJYSWFPdCtVYU"
"1JSU"
"JaQVlLS29aSWh2aE5BUTBCQWpDQwpB"
"VlF3RUFZTEtvWklodmhOQVEwQkFnRUNBUkV3RUFZTEtvWklodmhOQVEwQkFnSUNBUkV3RUFZTEtvWklodmhOCkFR"
"MEJB"
"Z01DQVFJd0VBWUxLb1pJaHZoTkFRME"
"JBZ1FDQVFRd0VBWUxLb1pJaHZoTkFRMEJBZ1VDQVFFd0VRWUwKS29aSWh2aE5BUTBCQWdZQ0FnQ0FNQkFHQ3lxR1"
"NJYj"
"RUUUVOQVFJSEFnRUdNQkFHQ3lxR1NJ"
"YjRUUUVOQVFJSQpBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSUpBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSUtBZ0VBTUJB"
"R0N5"
"cUdTSWI0ClRRRU5BUUlMQWdFQU1CQU"
"dDeXFHU0liNFRRRU5BUUlNQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlOQWdFQU1CQUcKQ3lxR1NJYjRUUUVOQVFJT0"
"FnRU"
"FNQkFHQ3lxR1NJYjRUUUVOQVFJUEFn"
"RUFNQkFHQ3lxR1NJYjRUUUVOQVFJUQpBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSVJBZ0VLTUI4R0N5cUdTSWI0VFFF"
"TkFR"
"SVNCQkFSRVFJRUFZQUdBQUFBCkFBQU"
"FBQUFBTUJBR0NpcUdTSWI0VFFFTkFRTUVBZ0FBTUJRR0NpcUdTSWI0VFFFTkFRUUVCZ0NRYnRVQUFEQVAKQmdvcW"
"hraU"
"crRTBCRFFFRkNnRUFNQW9HQ0NxR1NN"
"NDlCQU1DQTBnQU1FVUNJUUNiNVBlMkd6ZkJTeWh2VDB4MgpXWEQ4MWlHYm8vMUs2cU9zRm1XNjg4R0FPZ0lnUzRi"
"ZjUr"
"R0R6VExPUXpNMitESVJEc0VPelpUR1"
"Jzc3pTOHFECm1lSVBKKzA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS"
"0tLS"
"0tCk1JSUNsekNDQWo2Z0F3SUJBZ0lW"
"QU5Eb3F0cDExL2t1U1JlWVBIc1VaZERWOGxsTk1Bb0dDQ3FHU000OUJBTUMKTUdneEdqQVlCZ05WQkFNTUVVbHVk"
"R1Zz"
"SUZOSFdDQlNiMjkwSUVOQk1Sb3dHQV"
"lEVlFRS0RCRkpiblJsYkNCRApiM0p3YjNKaGRHbHZiakVVTUJJR0ExVUVCd3dMVTJGdWRHRWdRMnhoY21FeEN6QU"
"pCZ0"
"5WQkFnTUFrTkJNUXN3CkNRWURWUVFH"
"RXdKVlV6QWVGdzB4T0RBMU1qRXhNRFExTURoYUZ3MHpNekExTWpFeE1EUTFNRGhhTUhFeEl6QWgKQmdOVkJBTU1H"
"a2x1"
"ZEdWc0lGTkhXQ0JRUTBzZ1VISnZZMl"
"Z6YzI5eUlFTkJNUm93R0FZRFZRUUtEQkZKYm5SbApiQ0JEYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRn"
"VkR0"
"VnUTJ4aGNtRXhDekFKQmdOVkJBZ01B"
"a05CCk1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCTDlxK05NcDJJ"
"T2cK"
"dGRsMWJrL3VXWjUrVEdRbThhQ2k4ej"
"c4ZnMrZktDUTNkK3VEelhuVlRBVDJaaERDaWZ5SXVKd3ZOM3dOQnA5aQpIQlNTTUpNSnJCT2pnYnN3Z2Jnd0h3WU"
"RWUj"
"BqQkJnd0ZvQVVJbVVNMWxxZE5Jbnpn"
"N1NWVXI5UUd6a25CcXd3ClVnWURWUjBmQkVzd1NUQkhvRVdnUTRaQmFIUjBjSE02THk5alpYSjBhV1pwWTJGMFpY"
"TXVk"
"SEoxYzNSbFpITmwKY25acFkyVnpMbW"
"x1ZEdWc0xtTnZiUzlKYm5SbGJGTkhXRkp2YjNSRFFTNWpjbXd3SFFZRFZSME9CQllFRk5EbwpxdHAxMS9rdVNSZV"
"lQSH"
"NVWmREVjhsbE5NQTRHQTFVZER3RUIv"
"d1FFQXdJQkJqQVNCZ05WSFJNQkFmOEVDREFHCkFRSC9BZ0VBTUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUMvOWor"
"ODRU"
"K0h6dFZPL3NPUUJXSmJTZCsvMnVleE"
"sKNCthQTBqY0ZCTGNwQWlBM2RoTXJGNWNENTJ0NkZxTXZBSXBqOFhkR215MmJlZWxqTEpLK3B6cGNSQT09Ci0tLS"
"0tRU"
"5EIENFUlRJRklDQVRFLS0tLS0KLS0t"
"LS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqakNDQWpTZ0F3SUJBZ0lVSW1VTTFscWROSW56ZzdTVlVyOVFH"
"emtu"
"QnF3d0NnWUlLb1pJemowRUF3SXcKYU"
"RFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM1FnUTBFeEdqQVlCZ05WQkFvTUVVbHVkR1ZzSUVOdgpjbk"
"J2Y2"
"1GMGFXOXVNUlF3RWdZRFZRUUhEQXRU"
"WVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXhDekFKCkJnTlZCQVlUQWxWVE1CNFhEVEU0TURVeU1URXdO"
"REV4"
"TVZvWERUTXpNRFV5TVRFd05ERXhNRm"
"93YURFYU1CZ0cKQTFVRUF3d1JTVzUwWld3Z1UwZFlJRkp2YjNRZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTn"
"Zjbk"
"J2Y21GMAphVzl1TVJRd0VnWURWUVFI"
"REF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6"
"ajBD"
"QVFZSUtvWkl6ajBEQVFjRFFnQUVDNm"
"5Fd01ESVlaT2ovaVBXc0N6YUVLaTcKMU9pT1NMUkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZam"
"xCYW"
"xUVll4RlAyc0pCSzV6bEtPQgp1ekNC"
"dURBZkJnTlZIU01FR0RBV2dCUWlaUXpXV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdS"
"YUJE"
"aGtGb2RIUndjem92TDJObGNuUnBabW"
"xqWVhSbGN5NTBjblZ6ZEdWa2MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtTn"
"liRE"
"FkQmdOVkhRNEVGZ1FVSW1VTTFscWRO"
"SW56ZzdTVgpVcjlRR3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FR"
"RXdD"
"Z1lJCktvWkl6ajBFQXdJRFNBQXdSUU"
"lnUVFzLzA4cnljZFBhdUNGazhVUFFYQ01BbHNsb0JlN053YVFHVGNkcGEwRUMKSVFDVXQ4U0d2eEttanBjTS96MF"
"dQOU"
"R2bzhoMms1ZHUxaVdEZEJrQW4rMGlp"
"QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAA");
std::string RuntimeJWKClaim = R"(
{
"jwk" : {
"kty":"EC",
"use":"sig",
"crv":"P-256",
"x":"18wHLeIgW9wVN6VD1Txgpqy2LszYkMf6J8njVAibvhM",
"y":"cV4dS4UaLMgP_4fY4j8ir7cl1TXlFdAgcx55o7TkcSA"
}
}
)";
std::string SgxEnclaveHeldData
= "CiAgICAgICAgewogICAgICAgICAgICAiandrIiA6IHsKICAgICAgICAgICAgICAgICJrdHkiOiJFQyI"
"sCiAgICAgICAgICAgICAgICAidXNlIjoic2lnIiwKICAgICAgICAgICAgICAgICJjcnYiOiJQLTI1Ni"
"IsCiAgICAgICAgICAgICAgICAieCI6IjE4d0hMZUlnVzl3Vk42VkQxVHhncHF5MkxzellrTWY2Sjhua"
"lZBaWJ2aE0iLAogICAgICAgICAgICAgICAgInkiOiJjVjRkUzRVYUxNZ1BfNGZZNGo4aXI3Y2wxVFhs"
"RmRBZ2N4NTVvN1RrY1NBIgogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIAA";
// cspell:enable
std::vector<uint8_t> AttestationCollateral::OpenEnclaveReport()
{
return Azure::Core::_internal::Base64Url::Base64UrlDecode(OpenEnclaveQuote);
}
std::vector<uint8_t> AttestationCollateral::SgxQuote()
{
// An OpenEnclave report is a wrapper around an SGX quote - there are
// 16 bytes of OpenEnclave header at the start of the report and what remains is
// an SGX quote, so to convert from an OE report to an SGX quote simply strip
// the first 16 bytes of the report.
auto openEnclaveReport = AttestationCollateral::OpenEnclaveReport();
openEnclaveReport.erase(openEnclaveReport.begin(), openEnclaveReport.begin() + 16);
return openEnclaveReport;
// return std::vector<uint8_t>(openEnclaveReport.begin() + 0x10,
// openEnclaveReport.end());
}
std::vector<uint8_t> AttestationCollateral::RuntimeData()
{
return Azure::Core::_internal::Base64Url::Base64UrlDecode(SgxEnclaveHeldData);
// return std::vector<uint8_t>(RuntimeJWKClaim.begin(), RuntimeJWKClaim.end());
}
}}}} // namespace Azure::Security::Attestation::Test

View File

@ -6,262 +6,10 @@
namespace Azure { namespace Security { namespace Attestation { namespace Test {
// cspell:disable
const std::string OpenEnclaveQuote(
"AQAAAAIAAADoEQAAAAAAAAMAAgAAAAAABQAKAJOacjP3nEyplAoNs5V_Bgfl_L18zrEJejtqk6RDB0IzAAAAABERAwX_"
"gAYAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAABwAAAAAAAAApKh9LUZ5GYn6yR4o9mFFAVlPFtLCmkl3oQ4N"
"NkhaFDgAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAASupfmg7QSxH4iarf5qHTdiE6Kalahc5zN65vf-"
"zmYQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKFQuRP5-c_ZhD2sxrnV2kl8JzNu0xWRlg-"
"zBVhM3qP8AAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAADQQAACJx8e27oQ0pijs3lXQ9HfKWP9NMqVHQFL9SOjC_KGDcbv-I2fCafTHJ__"
"AmNqVXy7XTXnzmLp1HhUCy1_9AORSAT"
"qGZ1PtvBf4Q2NfNxqVkNrGJAjYuqMPStdg0MuM21nN-Qc9BWNycRMMsU7YfHSzmw7eGjBb_Ewfb3k6N4ZYRhERAwX_"
"gAYAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAAAAAABwAAAAAAAAA_sKzghp0uMPKOhtcMdmQDpU-"
"7zWWO7ODhuUipFVkXQAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAjE9XddeWUD6WE393xoqCmgBWrI3tcBQLCBsJRJDFe_"
"8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAUAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH_"
"mzVQFF8XbJCRGdNkA3SPx9ZUPgtx3874VyDYQnFRIAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAEUP2-pxe7LoyevtN5BdE4KKikxKK6-"
"hwG0xCDmxmfLphcnrVskSbKmiKUfzkWUBehrF8gHCGNGIPX3QQDwmtZ4gAAABAgME"
"BQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fBQDMDQAALS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVnVEND"
"QkNhZ0F3SUJBZ0lVU3I5VmR"
"iSnFWbzVyZzRadUpCRWo2SjNoak9jd0NnWUlLb1pJemowRUF3SXcKY1RFak1DRUdBMVVFQXd3YVNXNTBaV3dnVTBkWUl"
"GQkRTeUJRY205alpYTnpiM0"
"lnUTBFeEdqQVlCZ05WQkFvTQpFVWx1ZEdWc0lFTnZjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0"
"Z5WVRFTE1Ba0dBMVVFCkNBd"
"0NRMEV4Q3pBSkJnTlZCQVlUQWxWVE1CNFhEVEl4TURNeE9UQTBOVEl3T0ZvWERUSTRNRE14T1RBME5USXcKT0Zvd2NER"
"WlNQ0FHQTFVRUF3d1pTVzUw"
"Wld3Z1UwZFlJRkJEU3lCRFpYSjBhV1pwWTJGMFpURWFNQmdHQTFVRQpDZ3dSU1c1MFpXd2dRMjl5Y0c5eVlYUnBiMjR4"
"RkRBU0JnTlZCQWNNQzFOaGJ"
"uUmhJRU5zWVhKaE1Rc3dDUVlEClZRUUlEQUpEUVRFTE1Ba0dBMVVFQmhNQ1ZWTXdXVEFUQmdjcWhrak9QUUlCQmdncWh"
"rak9QUU1CQndOQ0FBUlQKVG"
"RNNVhTMGFiRTA2ZUdVTVU3S1JOQXJlRGRtTWJHK25KVHlucDZXankyeXJ6NmlEa3h1R1F3WGZ1b25uUVBuZApjdHgwbH"
"IyR3I0WjF1YXNsQjM2Vm80S"
"UNtekNDQXBjd0h3WURWUjBqQkJnd0ZvQVUwT2lxMm5YWCtTNUpGNWc4CmV4UmwwTlh5V1Uwd1h3WURWUjBmQkZnd1ZqQ"
"lVvRktnVUlaT2FIUjBjSE02"
"THk5aGNHa3VkSEoxYzNSbFpITmwKY25acFkyVnpMbWx1ZEdWc0xtTnZiUzl6WjNndlkyVnlkR2xtYVdOaGRHbHZiaTky"
"TWk5d1kydGpjbXcvWTJFOQp"
"jSEp2WTJWemMyOXlNQjBHQTFVZERnUVdCQlRMejZNQ3VHcVZobFYrR2Q0ZGtacmx4YndCV2pBT0JnTlZIUThCCkFmOEV"
"CQU1DQnNBd0RBWURWUjBUQV"
"FIL0JBSXdBRENDQWRRR0NTcUdTSWI0VFFFTkFRU0NBY1V3Z2dIQk1CNEcKQ2lxR1NJYjRUUUVOQVFFRUVMOEhhRExXWW"
"dVUFUzU3c3Tm1Ibkhrd2dnR"
"mtCZ29xaGtpRytFMEJEUUVDTUlJQgpWREFRQmdzcWhraUcrRTBCRFFFQ0FRSUJFVEFRQmdzcWhraUcrRTBCRFFFQ0FnS"
"UJFVEFRQmdzcWhraUcrRTBC"
"CkRRRUNBd0lCQWpBUUJnc3Foa2lHK0UwQkRRRUNCQUlCQkRBUUJnc3Foa2lHK0UwQkRRRUNCUUlCQVRBUkJnc3EKaGtp"
"RytFMEJEUUVDQmdJQ0FJQXd"
"FQVlMS29aSWh2aE5BUTBCQWdjQ0FRWXdFQVlMS29aSWh2aE5BUTBCQWdnQwpBUUF3RUFZTEtvWklodmhOQVEwQkFna0N"
"BUUF3RUFZTEtvWklodmhOQV"
"EwQkFnb0NBUUF3RUFZTEtvWklodmhOCkFRMEJBZ3NDQVFBd0VBWUxLb1pJaHZoTkFRMEJBZ3dDQVFBd0VBWUxLb1pJaH"
"ZoTkFRMEJBZzBDQVFBd0VBW"
"UwKS29aSWh2aE5BUTBCQWc0Q0FRQXdFQVlMS29aSWh2aE5BUTBCQWc4Q0FRQXdFQVlMS29aSWh2aE5BUTBCQWhBQwpBU"
"UF3RUFZTEtvWklodmhOQVEw"
"QkFoRUNBUW93SHdZTEtvWklodmhOQVEwQkFoSUVFQkVSQWdRQmdBWUFBQUFBCkFBQUFBQUF3RUFZS0tvWklodmhOQVEw"
"QkF3UUNBQUF3RkFZS0tvWkl"
"odmhOQVEwQkJBUUdBSkJ1MVFBQU1BOEcKQ2lxR1NJYjRUUUVOQVFVS0FRQXdDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWh"
"BSzZPMS9GNy80NFprcWhUN2"
"FhNgp5QVh6QlltRWxUVHRvL25rVUd4N1BtUktBaUVBMXliSWt6SjVwcXR1L21jOW5DUWNwRUJOdk5KZFNIcW1jc04rCk"
"V2dWJ3WlU9Ci0tLS0tRU5EI"
"ENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNsekNDQWo2Z0F3SUJBZ0lWQU5Eb"
"3F0cDExL2t1U1JlWVBIc1Va"
"ZERWOGxsTk1Bb0dDQ3FHU000OUJBTUMKTUdneEdqQVlCZ05WQkFNTUVVbHVkR1ZzSUZOSFdDQlNiMjkwSUVOQk1Sb3dH"
"QVlEVlFRS0RCRkpiblJsYkN"
"CRApiM0p3YjNKaGRHbHZiakVVTUJJR0ExVUVCd3dMVTJGdWRHRWdRMnhoY21FeEN6QUpCZ05WQkFnTUFrTkJNUXN3CkN"
"RWURWUVFHRXdKVlV6QWVGdz"
"B4T0RBMU1qRXhNRFExTURoYUZ3MHpNekExTWpFeE1EUTFNRGhhTUhFeEl6QWgKQmdOVkJBTU1Ha2x1ZEdWc0lGTkhXQ0"
"JRUTBzZ1VISnZZMlZ6YzI5e"
"UlFTkJNUm93R0FZRFZRUUtEQkZKYm5SbApiQ0JEYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnUTJ4a"
"GNtRXhDekFKQmdOVkJBZ01B"
"a05CCk1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCTDlxK05NcDJJT2cK"
"dGRsMWJrL3VXWjUrVEdRbTh"
"hQ2k4ejc4ZnMrZktDUTNkK3VEelhuVlRBVDJaaERDaWZ5SXVKd3ZOM3dOQnA5aQpIQlNTTUpNSnJCT2pnYnN3Z2Jnd0h"
"3WURWUjBqQkJnd0ZvQVVJbV"
"VNMWxxZE5JbnpnN1NWVXI5UUd6a25CcXd3ClVnWURWUjBmQkVzd1NUQkhvRVdnUTRaQmFIUjBjSE02THk5alpYSjBhV1"
"pwWTJGMFpYTXVkSEoxYzNSb"
"FpITmwKY25acFkyVnpMbWx1ZEdWc0xtTnZiUzlKYm5SbGJGTkhXRkp2YjNSRFFTNWpjbXd3SFFZRFZSME9CQllFRk5Eb"
"wpxdHAxMS9rdVNSZVlQSHNV"
"WmREVjhsbE5NQTRHQTFVZER3RUIvd1FFQXdJQkJqQVNCZ05WSFJNQkFmOEVDREFHCkFRSC9BZ0VBTUFvR0NDcUdTTTQ5"
"QkFNQ0EwY0FNRVFDSUMvOWo"
"rODRUK0h6dFZPL3NPUUJXSmJTZCsvMnVleEsKNCthQTBqY0ZCTGNwQWlBM2RoTXJGNWNENTJ0NkZxTXZBSXBqOFhkR21"
"5MmJlZWxqTEpLK3B6cGNSQT"
"09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqakNDQWpTZ0"
"F3SUJBZ0lVSW1VTTFscWROS"
"W56ZzdTVlVyOVFHemtuQnF3d0NnWUlLb1pJemowRUF3SXcKYURFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM"
"1FnUTBFeEdqQVlCZ05WQkFv"
"TUVVbHVkR1ZzSUVOdgpjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3"
"Q1EwRXhDekFKCkJnTlZCQVl"
"UQWxWVE1CNFhEVEU0TURVeU1URXdOREV4TVZvWERUTXpNRFV5TVRFd05ERXhNRm93YURFYU1CZ0cKQTFVRUF3d1JTVzU"
"wWld3Z1UwZFlJRkp2YjNRZ1"
"EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnZjbkJ2Y21GMAphVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeV"
"lURUxNQWtHQTFVRUNBd0NRM"
"EV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVDNm5Fd01ESVlaT2ova"
"VBXc0N6YUVLaTcKMU9pT1NM"
"UkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZamxCYWxUVll4RlAyc0pCSzV6bEtPQgp1ekNCdURBZkJn"
"TlZIU01FR0RBV2dCUWlaUXp"
"XV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdSYUJEaGtGb2RIUndjem92TDJObGNuUnBabWx"
"qWVhSbGN5NTBjblZ6ZEdWa2"
"MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtTnliREFkQmdOVkhRNEVGZ1FVSW1VTT"
"FscWROSW56ZzdTVgpVcjlRR"
"3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRRXdDZ1lJCktvWkl6ajBFQ"
"XdJRFNBQXdSUUlnUVFzLzA4"
"cnljZFBhdUNGazhVUFFYQ01BbHNsb0JlN053YVFHVGNkcGEwRUMKSVFDVXQ4U0d2eEttanBjTS96MFdQOUR2bzhoMms1"
"ZHUxaVdEZEJrQW4rMGlpQT0"
"9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAA");
const std::string OpenEnclaveNonDebugQuote(
"AQAAAAIAAADoEQAAAAAAAAMAAgAAAAAABQAKAJOacjP3nEyplAoNs5V_BgfDYELtjmo1LWZEqF8xasaZAAAAABERAwX_"
"gAYAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAABwAAAAAAAAC3eSAmGL7LY2do5dkC8o1SQiJzX6-"
"1OeqboHw_wXGhwgAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAALBpElSroIHE1xsKbdbjAKTcu6UtnfhXCC9QjQPENQaoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKFQuRP5-c_ZhD2sxrnV2kl8JzNu0xWRlg-"
"zBVhM3qP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQQAA"
"Ck3Zl7b4XERNDrAJfKbmzU0NSTIzY5rsFeyW_6deDzOyjXAnxA3b1WfBwrFrU9JKpfI9SDlpwms3YSQtJArmrD-8i_"
"meLNk8sQSwSkR7TdIadTEAZdb7S-7qMt"
"Yt3kWMfQ7H3g338R0kcF9wcy0jZmeBrRLDXyEUDcPI63Fwvp_BERAwX_"
"gAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAAAA"
"AABwAAAAAAAAA_sKzghp0uMPKOhtcMdmQDpU-"
"7zWWO7ODhuUipFVkXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjE9XddeWUD6WE393xoqCmgBW"
"rI3tcBQLCBsJRJDFe_"
"8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAABAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAmm22hOMEcuVw"
"P_d08cVnQ2JF3uT3Q5as4s-"
"D4yNshB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgCuq8kIluOwzRvIHV3J7G-"
"62qz2UxkrKQ2aJHVWlzGwveCOd"
"GIgpSJVM7GNcJW12FOveof_7m_"
"nA78uk3D3C4gAAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fBQDMDQAALS0tLS1CRUdJTiBDRVJUSUZJQ0FU"
"RS0t"
"LS0tCk1JSUVnVENDQkNlZ0F3SUJBZ0lWQU9jMDJHVHYvUTRvOUhHS1Bndk8yeUpPMElWTk1Bb0dDQ3FHU000OUJBTUMK"
"TUhFeEl6QWhCZ05WQkFNTUdrbHVkR1"
"ZzSUZOSFdDQlFRMHNnVUhKdlkyVnpjMjl5SUVOQk1Sb3dHQVlEVlFRSwpEQkZKYm5SbGJDQkRiM0p3YjNKaGRHbHZiak"
"VVTUJJR0ExVUVCd3dMVTJGdWRHRWdR"
"MnhoY21FeEN6QUpCZ05WCkJBZ01Ba05CTVFzd0NRWURWUVFHRXdKVlV6QWVGdzB5TVRBME1Ea3hNalU1TWpoYUZ3MHlP"
"REEwTURreE1qVTUKTWpoYU1IQXhJak"
"FnQmdOVkJBTU1HVWx1ZEdWc0lGTkhXQ0JRUTBzZ1EyVnlkR2xtYVdOaGRHVXhHakFZQmdOVgpCQW9NRVVsdWRHVnNJRU"
"52Y25CdmNtRjBhVzl1TVJRd0VnWURW"
"UVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHCkExVUVDQXdDUTBFeEN6QUpCZ05WQkFZVEFsVlRNRmt3RXdZSEtvWkl6"
"ajBDQVFZSUtvWkl6ajBEQVFjRFFnQU"
"UKYzZ1TjVuZGlFY25mWUp1OFU1MUgzc3lzWm5kQ05JamlwRVdEZjJuaXp6VU9XdlZjdjIxWUUwakxMdmxpL2s3NAp2bj"
"FtUzYvbkNYV3MxOFVZeE1PMFM2T0NB"
"cHN3Z2dLWE1COEdBMVVkSXdRWU1CYUFGTkRvcXRwMTEva3VTUmVZClBIc1VaZERWOGxsTk1GOEdBMVVkSHdSWU1GWXdW"
"S0JTb0ZDR1RtaDBkSEJ6T2k4dllYQn"
"BMblJ5ZFhOMFpXUnoKWlhKMmFXTmxjeTVwYm5SbGJDNWpiMjB2YzJkNEwyTmxjblJwWm1sallYUnBiMjR2ZGpJdmNHTn"
"JZM0pzUDJOaApQWEJ5YjJObGMzTnZj"
"akFkQmdOVkhRNEVGZ1FVRzBZaHd5VEh2bFFUNFlQVU1lRGplMmFUUWNjd0RnWURWUjBQCkFRSC9CQVFEQWdiQU1Bd0dB"
"MVVkRXdFQi93UUNNQUF3Z2dIVUJna3"
"Foa2lHK0UwQkRRRUVnZ0hGTUlJQndUQWUKQmdvcWhraUcrRTBCRFFFQkJCRDBRZ2lrT3FkRWxVQnJYSWFPdCtVYU1JSU"
"JaQVlLS29aSWh2aE5BUTBCQWpDQwpB"
"VlF3RUFZTEtvWklodmhOQVEwQkFnRUNBUkV3RUFZTEtvWklodmhOQVEwQkFnSUNBUkV3RUFZTEtvWklodmhOCkFRMEJB"
"Z01DQVFJd0VBWUxLb1pJaHZoTkFRME"
"JBZ1FDQVFRd0VBWUxLb1pJaHZoTkFRMEJBZ1VDQVFFd0VRWUwKS29aSWh2aE5BUTBCQWdZQ0FnQ0FNQkFHQ3lxR1NJYj"
"RUUUVOQVFJSEFnRUdNQkFHQ3lxR1NJ"
"YjRUUUVOQVFJSQpBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSUpBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSUtBZ0VBTUJBR0N5"
"cUdTSWI0ClRRRU5BUUlMQWdFQU1CQU"
"dDeXFHU0liNFRRRU5BUUlNQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlOQWdFQU1CQUcKQ3lxR1NJYjRUUUVOQVFJT0FnRU"
"FNQkFHQ3lxR1NJYjRUUUVOQVFJUEFn"
"RUFNQkFHQ3lxR1NJYjRUUUVOQVFJUQpBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSVJBZ0VLTUI4R0N5cUdTSWI0VFFFTkFR"
"SVNCQkFSRVFJRUFZQUdBQUFBCkFBQU"
"FBQUFBTUJBR0NpcUdTSWI0VFFFTkFRTUVBZ0FBTUJRR0NpcUdTSWI0VFFFTkFRUUVCZ0NRYnRVQUFEQVAKQmdvcWhraU"
"crRTBCRFFFRkNnRUFNQW9HQ0NxR1NN"
"NDlCQU1DQTBnQU1FVUNJUUNiNVBlMkd6ZkJTeWh2VDB4MgpXWEQ4MWlHYm8vMUs2cU9zRm1XNjg4R0FPZ0lnUzRiZjUr"
"R0R6VExPUXpNMitESVJEc0VPelpUR1"
"Jzc3pTOHFECm1lSVBKKzA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS"
"0tCk1JSUNsekNDQWo2Z0F3SUJBZ0lW"
"QU5Eb3F0cDExL2t1U1JlWVBIc1VaZERWOGxsTk1Bb0dDQ3FHU000OUJBTUMKTUdneEdqQVlCZ05WQkFNTUVVbHVkR1Zz"
"SUZOSFdDQlNiMjkwSUVOQk1Sb3dHQV"
"lEVlFRS0RCRkpiblJsYkNCRApiM0p3YjNKaGRHbHZiakVVTUJJR0ExVUVCd3dMVTJGdWRHRWdRMnhoY21FeEN6QUpCZ0"
"5WQkFnTUFrTkJNUXN3CkNRWURWUVFH"
"RXdKVlV6QWVGdzB4T0RBMU1qRXhNRFExTURoYUZ3MHpNekExTWpFeE1EUTFNRGhhTUhFeEl6QWgKQmdOVkJBTU1Ha2x1"
"ZEdWc0lGTkhXQ0JRUTBzZ1VISnZZMl"
"Z6YzI5eUlFTkJNUm93R0FZRFZRUUtEQkZKYm5SbApiQ0JEYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0"
"VnUTJ4aGNtRXhDekFKQmdOVkJBZ01B"
"a05CCk1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCTDlxK05NcDJJT2cK"
"dGRsMWJrL3VXWjUrVEdRbThhQ2k4ej"
"c4ZnMrZktDUTNkK3VEelhuVlRBVDJaaERDaWZ5SXVKd3ZOM3dOQnA5aQpIQlNTTUpNSnJCT2pnYnN3Z2Jnd0h3WURWUj"
"BqQkJnd0ZvQVVJbVVNMWxxZE5Jbnpn"
"N1NWVXI5UUd6a25CcXd3ClVnWURWUjBmQkVzd1NUQkhvRVdnUTRaQmFIUjBjSE02THk5alpYSjBhV1pwWTJGMFpYTXVk"
"SEoxYzNSbFpITmwKY25acFkyVnpMbW"
"x1ZEdWc0xtTnZiUzlKYm5SbGJGTkhXRkp2YjNSRFFTNWpjbXd3SFFZRFZSME9CQllFRk5EbwpxdHAxMS9rdVNSZVlQSH"
"NVWmREVjhsbE5NQTRHQTFVZER3RUIv"
"d1FFQXdJQkJqQVNCZ05WSFJNQkFmOEVDREFHCkFRSC9BZ0VBTUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUMvOWorODRU"
"K0h6dFZPL3NPUUJXSmJTZCsvMnVleE"
"sKNCthQTBqY0ZCTGNwQWlBM2RoTXJGNWNENTJ0NkZxTXZBSXBqOFhkR215MmJlZWxqTEpLK3B6cGNSQT09Ci0tLS0tRU"
"5EIENFUlRJRklDQVRFLS0tLS0KLS0t"
"LS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqakNDQWpTZ0F3SUJBZ0lVSW1VTTFscWROSW56ZzdTVlVyOVFHemtu"
"QnF3d0NnWUlLb1pJemowRUF3SXcKYU"
"RFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM1FnUTBFeEdqQVlCZ05WQkFvTUVVbHVkR1ZzSUVOdgpjbkJ2Y2"
"1GMGFXOXVNUlF3RWdZRFZRUUhEQXRU"
"WVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXhDekFKCkJnTlZCQVlUQWxWVE1CNFhEVEU0TURVeU1URXdOREV4"
"TVZvWERUTXpNRFV5TVRFd05ERXhNRm"
"93YURFYU1CZ0cKQTFVRUF3d1JTVzUwWld3Z1UwZFlJRkp2YjNRZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnZjbk"
"J2Y21GMAphVzl1TVJRd0VnWURWUVFI"
"REF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6ajBD"
"QVFZSUtvWkl6ajBEQVFjRFFnQUVDNm"
"5Fd01ESVlaT2ovaVBXc0N6YUVLaTcKMU9pT1NMUkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZamxCYW"
"xUVll4RlAyc0pCSzV6bEtPQgp1ekNC"
"dURBZkJnTlZIU01FR0RBV2dCUWlaUXpXV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdSYUJE"
"aGtGb2RIUndjem92TDJObGNuUnBabW"
"xqWVhSbGN5NTBjblZ6ZEdWa2MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtTnliRE"
"FkQmdOVkhRNEVGZ1FVSW1VTTFscWRO"
"SW56ZzdTVgpVcjlRR3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRRXdD"
"Z1lJCktvWkl6ajBFQXdJRFNBQXdSUU"
"lnUVFzLzA4cnljZFBhdUNGazhVUFFYQ01BbHNsb0JlN053YVFHVGNkcGEwRUMKSVFDVXQ4U0d2eEttanBjTS96MFdQOU"
"R2bzhoMms1ZHUxaVdEZEJrQW4rMGlp"
"QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAA");
std::string RuntimeJWKClaim = R"(
{
"jwk" : {
"kty":"EC",
"use":"sig",
"crv":"P-256",
"x":"18wHLeIgW9wVN6VD1Txgpqy2LszYkMf6J8njVAibvhM",
"y":"cV4dS4UaLMgP_4fY4j8ir7cl1TXlFdAgcx55o7TkcSA"
}
}
)";
std::string SgxEnclaveHeldData
= "CiAgICAgICAgewogICAgICAgICAgICAiandrIiA6IHsKICAgICAgICAgICAgICAgICJrdHkiOiJFQyI"
"sCiAgICAgICAgICAgICAgICAidXNlIjoic2lnIiwKICAgICAgICAgICAgICAgICJjcnYiOiJQLTI1Ni"
"IsCiAgICAgICAgICAgICAgICAieCI6IjE4d0hMZUlnVzl3Vk42VkQxVHhncHF5MkxzellrTWY2Sjhua"
"lZBaWJ2aE0iLAogICAgICAgICAgICAgICAgInkiOiJjVjRkUzRVYUxNZ1BfNGZZNGo4aXI3Y2wxVFhs"
"RmRBZ2N4NTVvN1RrY1NBIgogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIAA";
// cspell:enable
class AttestationCollateral {
public:
static std::vector<uint8_t> OpenEnclaveReport()
{
return Azure::Core::_internal::Base64Url::Base64UrlDecode(OpenEnclaveQuote);
}
static std::vector<uint8_t> SgxQuote()
{
// An OpenEnclave report is a wrapper around an SGX quote - there are
// 16 bytes of OpenEnclave header at the start of the report and what remains is
// an SGX quote, so to convert from an OE report to an SGX quote simply strip
// the first 16 bytes of the report.
auto openEnclaveReport = OpenEnclaveReport();
openEnclaveReport.erase(openEnclaveReport.begin(), openEnclaveReport.begin() + 16);
return openEnclaveReport;
// return std::vector<uint8_t>(openEnclaveReport.begin() + 0x10, openEnclaveReport.end());
}
static std::vector<uint8_t> RuntimeData()
{
return Azure::Core::_internal::Base64Url::Base64UrlDecode(SgxEnclaveHeldData);
// return std::vector<uint8_t>(RuntimeJWKClaim.begin(), RuntimeJWKClaim.end());
}
static std::vector<uint8_t> OpenEnclaveReport();
static std::vector<uint8_t> SgxQuote();
static std::vector<uint8_t> RuntimeData();
};
}}}} // namespace Azure::Security::Attestation::Test

View File

@ -8,6 +8,7 @@
#include <gtest/gtest.h>
using namespace Azure::Security::Attestation;
using namespace Azure::Core;
namespace Azure { namespace Security { namespace Attestation { namespace Test {
@ -54,11 +55,19 @@ namespace Azure { namespace Security { namespace Attestation { namespace Test {
std::unique_ptr<AttestationClient> CreateAuthenticatedClient()
{
// `InitClientOptions` takes care of setting up Record&Playback.
auto options = InitClientOptions<Azure::Security::Attestation::AttestationClientOptions>();
auto credential = std::make_shared<Azure::Identity::ClientSecretCredential>(
GetEnv("AZURE_TENANT_ID"), GetEnv("AZURE_CLIENT_ID"), GetEnv("AZURE_CLIENT_SECRET"));
AttestationClientOptions options;
if (m_testContext.IsPlaybackMode())
{
// Skip validating time stamps if using recordings.
options.TokenValidationOptions.ValidateNotBeforeTime = false;
options.TokenValidationOptions.ValidateExpirationTime = false;
}
std::shared_ptr<Azure::Core::Credentials::TokenCredential> credential
= std::make_shared<Azure::Identity::ClientSecretCredential>(
GetEnv("AZURE_TENANT_ID"), GetEnv("AZURE_CLIENT_ID"), GetEnv("AZURE_CLIENT_SECRET"));
return std::make_unique<AttestationClient>(m_endpoint, credential, options);
return InitTestClient<AttestationClient, AttestationClientOptions>(
m_endpoint, credential, options);
}
};

View File

@ -4,7 +4,7 @@
"Headers": {
"content-type": "application/json",
"user-agent": "azsdk-cpp-Attestation/1.0.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)",
"x-ms-client-request-id": "e046efa1-c976-4b55-72dd-aa397b095785"
"x-ms-client-request-id": "2b846afd-db33-4a76-4c53-62ad37784ac7"
},
"Method": "GET",
"Response": {
@ -13,10 +13,10 @@
"STATUS_CODE": "200",
"content-length": "612",
"content-type": "application/json; charset=utf-8",
"date": "Tue, 15 Feb 2022 23:42:32 GMT",
"date": "Fri, 18 Feb 2022 22:54:35 GMT",
"server": "Kestrel",
"x-ms-maa-service-version": "1.10.01847.0002",
"x-ms-request-id": "00-5743d231cf8c458d2f1697e995e29ea0-0000000000000000-00"
"x-ms-request-id": "00-8681f02e670159945fc7e2739e960153-0000000000000000-00"
},
"Url": "https://REDACTED.wus.attest.azure.net/.well-known/openid-configuration"
}

View File

@ -4,7 +4,7 @@
"Headers": {
"content-type": "application/json",
"user-agent": "azsdk-cpp-Attestation/1.0.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)",
"x-ms-client-request-id": "77922c07-6bda-41fc-7400-2f5db58dee20"
"x-ms-client-request-id": "0f497567-f183-4d46-5d1c-9d29b13ba646"
},
"Method": "GET",
"Response": {
@ -13,10 +13,10 @@
"STATUS_CODE": "200",
"content-length": "612",
"content-type": "application/json; charset=utf-8",
"date": "Tue, 15 Feb 2022 23:42:32 GMT",
"date": "Fri, 18 Feb 2022 22:54:35 GMT",
"server": "Kestrel",
"x-ms-maa-service-version": "1.10.01847.0002",
"x-ms-request-id": "00-d1489f7996238011361c19ab5d2320e3-0000000000000000-00"
"x-ms-request-id": "00-37a7b30eb34898490aaee465889da23f-0000000000000000-00"
},
"Url": "https://REDACTED.wus.attest.azure.net/.well-known/openid-configuration"
}

View File

@ -4,7 +4,7 @@
"Headers": {
"content-type": "application/json",
"user-agent": "azsdk-cpp-Attestation/1.0.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)",
"x-ms-client-request-id": "f8a13526-14a5-4cf1-6426-4ac61aa2eaca"
"x-ms-client-request-id": "d5ce1416-62ce-4254-53f4-4e41106486c2"
},
"Method": "GET",
"Response": {
@ -13,10 +13,10 @@
"STATUS_CODE": "200",
"content-length": "573",
"content-type": "application/json; charset=utf-8",
"date": "Tue, 15 Feb 2022 23:42:31 GMT",
"date": "Fri, 18 Feb 2022 22:54:35 GMT",
"server": "Kestrel",
"x-ms-maa-service-version": "1.10.01847.0002",
"x-ms-request-id": "00-dc235c9a32f5f0088db57b1bcdf25057-0000000000000000-00"
"x-ms-request-id": "00-eb432378564692a729b975fcd4491565-0000000000000000-00"
},
"Url": "https://REDACTED.wus.attest.azure.net/.well-known/openid-configuration"
}

View File

@ -26,7 +26,9 @@ stages:
- template: ../../eng/pipelines/templates/stages/archetype-sdk-client.yml
parameters:
ServiceDirectory: attestation
Location: WestUS
CtestRegex: azure-security-attestation.*
LiveTestCtestRegex: azure-security-attestation.*
LineCoverageTarget: 90
BranchCoverageTarget: 45
Artifacts:
@ -47,5 +49,6 @@ stages:
Value: "non-real-client"
- Name: AZURE_CLIENT_SECRET
Value: "non-real-secret"
# NOTE: The LOCATION_SHORT_NAME *must* match the region in which the tests were created.
- Name: LOCATION_SHORT_NAME
Value: "wus"