280 lines
14 KiB
C++
280 lines
14 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
#pragma once
|
|
|
|
#include "azure/attestation/attestation_client_models.hpp"
|
|
#include "azure/attestation/attestation_client_options.hpp"
|
|
|
|
#include <azure/core/context.hpp>
|
|
#include <azure/core/internal/tracing/service_tracing.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 {
|
|
|
|
/**
|
|
*
|
|
* The AttestationAsyncClient implements the functionality required by the "Attest" family of
|
|
* APIs.
|
|
*
|
|
* An enclave (or Trusted Execution Environment) is a chunk of code that is isolated from the host
|
|
* (think: "encrypted VM" or "encrypted container"). But there's one key attribute of the enclave:
|
|
* It is encrypted.That means that
|
|
* if data is sent from the enclave, there is no way of knowing that the data came from the
|
|
* enclave. And even worse, there is no way of securely communicating with the enclave (since the
|
|
* enclave is fully isolated from the host, all information passed into the enclave has to go
|
|
* through its host first).
|
|
*
|
|
* To solve the communication problem, the Attest API can be used to facilitate what is
|
|
* known as the "Secure Key Release" (SKR) protocol.
|
|
*
|
|
* There are 4 parties involved in an attestation operation:
|
|
*
|
|
* - The host (which hosts the enclave)
|
|
* - The enclave (which is the enclave :) - encrypted, nobody can see what goes on inside it),
|
|
* - The "verifier" which verifies the evidence from the enclave (this is the attestation service)
|
|
* and generates a token which can be received by a relying party, and
|
|
* - The "relying party" which will interpret the token from the service. For the Secure Key
|
|
* Release Protocol, this is the entity which wishes to communicate with the enclave.
|
|
*
|
|
* It's possible that all these parties are on the same computer, it's possible they're on
|
|
* multiple computers.<br> It's possible that the host is also the relying party. It's possible
|
|
* that the relying party is a component like Azure Managed HSM.
|
|
*
|
|
* There are three primary pieces of data received by the service for the Attest family of APIs.
|
|
* All of them are arrays of bytes, and all of them originate from code running in the enclave
|
|
* (thus they need to be treated as opaque arrays of bytes by the SDK):
|
|
*
|
|
* -# Evidence. For Intel SGX enclaves, this has two forms, either an SGX 'Quote' or an
|
|
* OpenEnclave 'Report'. It is required for attestation operations.
|
|
* -# InitTimeData - This is data which is specified at Initialization Time. It is optional
|
|
* (and not currently supported on all enclave types in Azure)
|
|
* -# RunTimeData - this is data which is specified at the time the quote is generated (at
|
|
* "runtime"). It is optional, but required for the Secure Key Release protocol.
|
|
*
|
|
* The Evidence is cryptographically signed by a known authority (for Intel SGX Quotes or
|
|
* OpenEnclave reports, this is a key owned by Intel which represents that the SGX enclave is
|
|
* valid and can be trusted).<br> The core idea for all attestation operations is to take
|
|
* advantage of a region within the Evidence which is controlled by enclave. For SGX Enclaves,
|
|
* this is the 64 bytes of "user data" contained within SGX quote.
|
|
*
|
|
* For the Secure Key Release protocol, code inside the enclave generates an asymmetric key and
|
|
* serializes the public key into a byte buffer. It then calculates the SHA256 hash of the
|
|
* serialized key and creates a quote containing that SHA256 hash. We now have a cryptographically
|
|
* validated indication that the contents of the byte buffer was known inside the enclave.
|
|
*
|
|
* The enclave then hands the byte buffer and the quote to its host. The host sends the quote and
|
|
* byte buffer as the "RunTime Data" to the via the AttestationClient.AttestSgxEnclave or
|
|
* AttestationClient.AttestOpenEnclave} API. Assuming the byte buffer and quote are
|
|
* valid, and the quote contains the hash of the byte buffer, the attestation service responds
|
|
* with an AttestationToken signed by the attestation service, whose body is an
|
|
* AttestationResult.
|
|
*
|
|
* The token generated also includes the contents of the InitTimeData and/or RunTimeData if it was
|
|
* provided in the Attest API call.
|
|
*
|
|
* The host then sends the token to the relying party. The relying party verifies the token
|
|
* and verifies the claims within the token indicate that the enclave is the correct enclave.
|
|
* It then takes the key from the token and uses it to encrypt the data to be sent to the
|
|
* enclave and sends that back to the host, which passes it into the enclave.
|
|
*
|
|
*
|
|
* That completes the secure key release protocol.
|
|
*
|
|
* When the Attestation Token is generated by the attestation service, as mentioned, it contains
|
|
* the InitTime and RunTime data.
|
|
*
|
|
* There are two possible representations for RunTime Data in the attestation token, depending on
|
|
* the requirements of the relying party:<br> The first is as JSON formatted data. That can be
|
|
* convenient if the relying party expects to receive its public key as a JSON Web Key The second
|
|
* is as a binary blob of data. That is needed if either the data sent by the enclave isn't a JSON
|
|
* object - for instance, if the RunTime data contained an asymmetric key which is formatted as a
|
|
* PEM encoded key, it should be interpreted as a binary blob
|
|
*
|
|
* If you ask for the RunTime data to be included in the token as binary, then it will be
|
|
* base64url encoded in the "x-ms-maa-enclavehelddata" claim in the output token (the
|
|
* AttestationResult::EnclaveHeldData property).
|
|
*
|
|
* If you ask for the RunTime data to be included in the token as JSON, then it will be included
|
|
* in the "x-ms-maa-runtimeClaims" claim in the output token (the AttestationResult::RunTimeClaims
|
|
* property).
|
|
*
|
|
* In addition to the Attest APIs, the AttestationClient object also contains helper APIs
|
|
* which can be used to retrieve the OpenId Metadata document and signing keys from the service.
|
|
*
|
|
* The OpenId Metadata document contains properties which describe the attestation service.
|
|
*
|
|
* The Attestation Signing Keys describe the keys which will be used to sign tokens generated by
|
|
* the attestation service. All tokens emitted by the attestation service will be signed by one
|
|
* of the certificates listed in the attestation signing keys.
|
|
*
|
|
*/
|
|
|
|
class AttestationClient final {
|
|
|
|
public:
|
|
/** @brief Construct a new Attestation Client object
|
|
*
|
|
* @details Constructs a new attestation client. Follows the
|
|
* factory pattern in [C++ Core Guidelines
|
|
* C.50](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c50-use-a-factory-function-if-you-need-virtual-behavior-during-initialization)
|
|
*
|
|
* @param endpoint The URL address where the client will send the requests to.
|
|
* @param credential The authentication method to use (required for TPM attestation). If the
|
|
* credential parameter is not supplied, the connection will be unauthenticated.
|
|
* @param options The options to customize the client behavior.
|
|
* @param context The context for cancelling long running operations.
|
|
* @return The newly created client.
|
|
*/
|
|
static AttestationClient Create(
|
|
std::string const& endpoint,
|
|
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
|
|
AttestationClientOptions const& options = AttestationClientOptions{},
|
|
Azure::Core::Context const& context = Azure::Core::Context{});
|
|
|
|
/** @brief Construct a new anonymous Attestation Client object
|
|
*
|
|
* @details Constructs a new anonymous (unauthenticated) attestation client. Follows the
|
|
* factory pattern in [C++ Core Guidelines
|
|
* C.50](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c50-use-a-factory-function-if-you-need-virtual-behavior-during-initialization)
|
|
*
|
|
* @param endpoint The URL address where the client will send the requests to.
|
|
* @param options The options to customize the client behavior.
|
|
* @param context The context for cancelling long running operations.
|
|
* @return The newly created attestation client.
|
|
*
|
|
* @note TPM attestation requires an authenticated attestation client.
|
|
*
|
|
*/
|
|
static AttestationClient Create(
|
|
std::string const& endpoint,
|
|
AttestationClientOptions options = AttestationClientOptions{},
|
|
Azure::Core::Context const& context = Azure::Core::Context{});
|
|
|
|
/**
|
|
* @brief Destructor.
|
|
*
|
|
*/
|
|
virtual ~AttestationClient() = default;
|
|
|
|
/** @brief Construct a new Attestation Client object from an existing attestation client.
|
|
*
|
|
* @param attestationClient An existing attestation client.
|
|
*/
|
|
AttestationClient(AttestationClient const& attestationClient) = default;
|
|
|
|
/** @brief Returns the Absolute URL for this attestation client.
|
|
*
|
|
* @returns The absolute URL for this attestation client.
|
|
*/
|
|
std::string const Endpoint() const { return m_endpoint.GetAbsoluteUrl(); }
|
|
|
|
/**
|
|
* Retrieves metadata about the attestation signing keys in use by the attestation service.
|
|
*
|
|
* Retrieve the OpenID metadata for this attestation service instance..
|
|
*
|
|
* @return an \ref Models::OpenIdMetadata object containing metadata about the
|
|
* specified service instance.
|
|
*/
|
|
Response<Models::OpenIdMetadata> GetOpenIdMetadata(
|
|
Azure::Core::Context const& context = Azure::Core::Context::ApplicationContext) const;
|
|
|
|
/**
|
|
* @brief Retrieve the attestation signing certificates for this attestation instance.
|
|
*
|
|
* @returns A Models::AttestationSigningCertificateResult containing a list of certificates one
|
|
* of which will be used to validate tokens received by the attestation service.
|
|
*/
|
|
Response<Models::TokenValidationCertificateResult> GetTokenValidationCertificates(
|
|
Azure::Core::Context const& context = Azure::Core::Context{}) const;
|
|
|
|
/**
|
|
* @brief Attest an SGX enclave, returning an attestation token representing the result
|
|
* of the attestation operation.
|
|
*
|
|
* @param sgxQuoteToAttest - SGX Quote to be validated by the attestation service.
|
|
* @param options - Options to the attestation request (runtime data, inittime data, etc).
|
|
* @param context - Context for the operation.
|
|
*
|
|
* @returns Response<AttestationToken<AttestationResult>> - The result of the
|
|
* attestation operation.
|
|
*
|
|
*/
|
|
Response<Models::AttestationToken<Models::AttestationResult>> AttestSgxEnclave(
|
|
std::vector<uint8_t> const& sgxQuoteToAttest,
|
|
AttestSgxEnclaveOptions options = AttestSgxEnclaveOptions{},
|
|
Azure::Core::Context const& context = Azure::Core::Context{}) const;
|
|
|
|
/**
|
|
* @brief Attest an OpenEnclave report, returning an attestation token representing the result
|
|
* of the attestation operation.
|
|
*
|
|
* @param openEnclaveReportToAttest - OpenEnclave Report to be validated by the attestation
|
|
* service.
|
|
* @param options - Options to the attestation request (runtime data, inittime data, etc).
|
|
* @param context - Context for the operation.
|
|
*
|
|
* @returns Response<AttestationToken<AttestationResult>> - The result of the attestation
|
|
* operation
|
|
|
|
*/
|
|
Response<Models::AttestationToken<Models::AttestationResult>> AttestOpenEnclave(
|
|
std::vector<uint8_t> const& openEnclaveReportToAttest,
|
|
AttestOpenEnclaveOptions options = AttestOpenEnclaveOptions{},
|
|
Azure::Core::Context const& context = Azure::Core::Context{}) const;
|
|
|
|
/**
|
|
* @brief Sends TPM-based attestation data to the service.
|
|
* The TPM attestation protocol is defined
|
|
* [here](https://docs.microsoft.com/azure/attestation/virtualization-based-security-protocol')
|
|
*
|
|
*
|
|
* @param dataToAttest - Attestation request data.
|
|
* @param options - Options to the attestation request.
|
|
* @param context - Context for the operation.
|
|
*
|
|
* @return Response<TpmAttestationResult> - The result of the attestation operation
|
|
*/
|
|
Response<Models::TpmAttestationResult> AttestTpm(
|
|
std::vector<uint8_t> const& dataToAttest,
|
|
AttestTpmOptions const& options = AttestTpmOptions{},
|
|
Azure::Core::Context const& context = Azure::Core::Context{}) const;
|
|
|
|
private:
|
|
Azure::Core::Url m_endpoint;
|
|
std::string m_apiVersion;
|
|
std::shared_ptr<Azure::Core::Http::_internal::HttpPipeline> m_pipeline;
|
|
AttestationTokenValidationOptions m_tokenValidationOptions;
|
|
std::vector<Models::AttestationSigner> m_attestationSigners;
|
|
Azure::Core::Tracing::_internal::TracingContextFactory m_tracingFactory;
|
|
|
|
/** @brief Construct a new Attestation Client object
|
|
*
|
|
* @param endpoint The URL address where the client will send the requests to.
|
|
* @param credential The authentication method to use (required for TPM attestation).
|
|
* @param options The options to customize the client behavior.
|
|
*/
|
|
AttestationClient(
|
|
std::string const& endpoint,
|
|
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
|
|
AttestationClientOptions options = AttestationClientOptions{});
|
|
|
|
/**
|
|
* @brief Retrieves the information needed to validate a response from the attestation service.
|
|
*
|
|
* @note: This method MUST be called before any calls to the attestation service which must be
|
|
* validated.
|
|
*/
|
|
void RetrieveResponseValidationCollateral(
|
|
Azure::Core::Context const& context = Azure::Core::Context{});
|
|
};
|
|
|
|
}}} // namespace Azure::Security::Attestation
|