Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#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>

Expand Down Expand Up @@ -258,6 +259,7 @@ namespace Azure { namespace Security { namespace Attestation {
std::shared_ptr<Azure::Core::Credentials::TokenCredential const> m_credentials;
std::shared_ptr<Azure::Core::Http::_internal::HttpPipeline> m_pipeline;
AttestationTokenValidationOptions m_tokenValidationOptions;
Azure::Core::Tracing::_internal::TracingContextFactory m_tracingFactory;

std::vector<Models::AttestationSigner> m_attestationSigners;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#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>

Expand Down Expand Up @@ -162,11 +163,7 @@ namespace Azure { namespace Security { namespace Attestation {
*
* @param attestationClient An existing attestation client.
*/
AttestationClient(AttestationClient const& attestationClient)
: m_endpoint(attestationClient.m_endpoint), m_apiVersion(attestationClient.m_apiVersion),
m_pipeline(attestationClient.m_pipeline),
m_tokenValidationOptions(attestationClient.m_tokenValidationOptions),
m_attestationSigners(attestationClient.m_attestationSigners){};
AttestationClient(AttestationClient const& attestationClient) = default;

std::string const Endpoint() const { return m_endpoint.GetAbsoluteUrl(); }

Expand Down Expand Up @@ -255,6 +252,7 @@ namespace Azure { namespace Security { namespace Attestation {
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
*
Expand Down

Large diffs are not rendered by default.

278 changes: 174 additions & 104 deletions sdk/attestation/azure-security-attestation/src/attestation_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ 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::Tracing::_internal;
using namespace Azure::Core::Http;
using namespace Azure::Core::Http::Policies;
using namespace Azure::Core::Http::Policies::_internal;
Expand All @@ -31,7 +32,8 @@ AttestationClient::AttestationClient(
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
AttestationClientOptions options)
: m_endpoint(endpoint), m_credentials(credential),
m_tokenValidationOptions(options.TokenValidationOptions)
m_tokenValidationOptions(options.TokenValidationOptions),
m_tracingFactory(options, "security.attestation", PackageVersion::ToString())
{
std::vector<std::unique_ptr<HttpPolicy>> perRetrypolicies;
if (credential)
Expand All @@ -47,128 +49,184 @@ AttestationClient::AttestationClient(
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));
options, std::move(perRetrypolicies), std::move(perCallpolicies));
}

Azure::Response<OpenIdMetadata> AttestationClient::GetOpenIdMetadata(
Azure::Core::Context const& context) const
{
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, HttpMethod::Get, {".well-known/openid-configuration"}, nullptr);
auto tracingContext(m_tracingFactory.CreateTracingContext("GetOpenIdMetadata", context));
try
{
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, HttpMethod::Get, {".well-known/openid-configuration"}, nullptr);

auto response
= AttestationCommonRequest::SendRequest(*m_pipeline, request, tracingContext.Context);
auto openIdMetadata(OpenIdMetadataSerializer::Deserialize(response));

auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
auto openIdMetadata(OpenIdMetadataSerializer::Deserialize(response));
return Response<OpenIdMetadata>(std::move(openIdMetadata), std::move(response));
return Response<OpenIdMetadata>(std::move(openIdMetadata), std::move(response));
}
catch (std::runtime_error const& ex)
{
tracingContext.Span.AddEvent(ex);
tracingContext.Span.SetStatus(SpanStatus::Error);
throw;
}
}

Azure::Response<TokenValidationCertificateResult> AttestationClient::GetTokenValidationCertificates(
Azure::Core::Context const& context) const
{
auto request
= AttestationCommonRequest::CreateRequest(m_endpoint, HttpMethod::Get, {"certs"}, nullptr);
auto tracingContext(
m_tracingFactory.CreateTracingContext("GetTokenValidationCertificates", context));
try
{

auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
auto jsonWebKeySet(JsonWebKeySetSerializer::Deserialize(response));
TokenValidationCertificateResult returnValue;
for (const auto& jwk : jsonWebKeySet.Keys)
auto request
= AttestationCommonRequest::CreateRequest(m_endpoint, HttpMethod::Get, {"certs"}, nullptr);

auto response
= AttestationCommonRequest::SendRequest(*m_pipeline, request, tracingContext.Context);
auto jsonWebKeySet(JsonWebKeySetSerializer::Deserialize(response));
TokenValidationCertificateResult returnValue;
for (const auto& jwk : jsonWebKeySet.Keys)
{
AttestationSignerInternal internalSigner(jwk);
returnValue.Signers.push_back(internalSigner);
}
return Response<TokenValidationCertificateResult>(returnValue, std::move(response));
}
catch (std::runtime_error const& ex)
{
AttestationSignerInternal internalSigner(jwk);
returnValue.Signers.push_back(internalSigner);
tracingContext.Span.AddEvent(ex);
tracingContext.Span.SetStatus(SpanStatus::Error);
throw;
}
return Response<TokenValidationCertificateResult>(returnValue, std::move(response));
}

Azure::Response<AttestationToken<AttestationResult>> AttestationClient::AttestSgxEnclave(
std::vector<uint8_t> const& sgxQuote,
AttestSgxEnclaveOptions options,
Azure::Core::Context const& context) const
{
AttestSgxEnclaveRequest attestRequest{
sgxQuote,
options.InitTimeData,
options.RunTimeData,
options.DraftPolicyForAttestation,
options.Nonce};

const std::string serializedRequest(AttestSgxEnclaveRequestSerializer::Serialize(attestRequest));

const auto encodedVector
= std::vector<uint8_t>(serializedRequest.begin(), serializedRequest.end());
Azure::Core::IO::MemoryBodyStream stream(encodedVector);
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, m_apiVersion, HttpMethod::Post, {"attest/SgxEnclave"}, &stream);

// 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 const token
= AttestationTokenInternal<AttestationResult, AttestationResultSerializer>(responseToken);

// Validate the token returned by the service. Use the cached attestation signers in the
// validation.
token.ValidateToken(
options.TokenValidationOptionsOverride ? *options.TokenValidationOptionsOverride
: this->m_tokenValidationOptions,
m_attestationSigners);

// And return the attestation result to the caller.
auto returnedToken = AttestationToken<AttestationResult>(token);
return Response<AttestationToken<AttestationResult>>(returnedToken, std::move(response));
auto tracingContext(m_tracingFactory.CreateTracingContext("AttestSgxEnclave", context));
try
{

AttestSgxEnclaveRequest attestRequest{
sgxQuote,
options.InitTimeData,
options.RunTimeData,
options.DraftPolicyForAttestation,
options.Nonce};

const std::string serializedRequest(
AttestSgxEnclaveRequestSerializer::Serialize(attestRequest));

const auto encodedVector
= std::vector<uint8_t>(serializedRequest.begin(), serializedRequest.end());
Azure::Core::IO::MemoryBodyStream stream(encodedVector);
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, m_apiVersion, HttpMethod::Post, {"attest/SgxEnclave"}, &stream);

// Send the request to the service.
auto response
= AttestationCommonRequest::SendRequest(*m_pipeline, request, tracingContext.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 const token
= AttestationTokenInternal<AttestationResult, AttestationResultSerializer>(responseToken);

// Validate the token returned by the service. Use the cached attestation signers in the
// validation.
token.ValidateToken(
options.TokenValidationOptionsOverride ? *options.TokenValidationOptionsOverride
: this->m_tokenValidationOptions,
m_attestationSigners);

// And return the attestation result to the caller.
auto returnedToken = AttestationToken<AttestationResult>(token);
return Response<AttestationToken<AttestationResult>>(returnedToken, std::move(response));
}
catch (std::runtime_error const& ex)
{
tracingContext.Span.AddEvent(ex);
tracingContext.Span.SetStatus(SpanStatus::Error);
throw;
}
}

Azure::Response<AttestationToken<AttestationResult>> AttestationClient::AttestOpenEnclave(
std::vector<uint8_t> const& openEnclaveReport,
AttestOpenEnclaveOptions options,
Azure::Core::Context const& context) const
{
AttestOpenEnclaveRequest attestRequest{
openEnclaveReport,
options.InitTimeData,
options.RunTimeData,
options.DraftPolicyForAttestation,
options.Nonce};
std::string serializedRequest(AttestOpenEnclaveRequestSerializer::Serialize(attestRequest));

auto encodedVector = std::vector<uint8_t>(serializedRequest.begin(), serializedRequest.end());
Azure::Core::IO::MemoryBodyStream stream(encodedVector);
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, m_apiVersion, HttpMethod::Post, {"attest/OpenEnclave"}, &stream);

auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
std::string responseToken = AttestationServiceTokenResponseSerializer::Deserialize(response);
auto token
= AttestationTokenInternal<AttestationResult, AttestationResultSerializer>(responseToken);
token.ValidateToken(
options.TokenValidationOptionsOverride ? *options.TokenValidationOptionsOverride
: this->m_tokenValidationOptions,
m_attestationSigners);

return Response<AttestationToken<AttestationResult>>(token, std::move(response));
auto tracingContext(m_tracingFactory.CreateTracingContext("AttestOpenEnclave", context));
try
{
AttestOpenEnclaveRequest attestRequest{
openEnclaveReport,
options.InitTimeData,
options.RunTimeData,
options.DraftPolicyForAttestation,
options.Nonce};
std::string serializedRequest(AttestOpenEnclaveRequestSerializer::Serialize(attestRequest));

auto encodedVector = std::vector<uint8_t>(serializedRequest.begin(), serializedRequest.end());
Azure::Core::IO::MemoryBodyStream stream(encodedVector);
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, m_apiVersion, HttpMethod::Post, {"attest/OpenEnclave"}, &stream);

auto response
= AttestationCommonRequest::SendRequest(*m_pipeline, request, tracingContext.Context);
std::string responseToken = AttestationServiceTokenResponseSerializer::Deserialize(response);
auto token
= AttestationTokenInternal<AttestationResult, AttestationResultSerializer>(responseToken);
token.ValidateToken(
options.TokenValidationOptionsOverride ? *options.TokenValidationOptionsOverride
: this->m_tokenValidationOptions,
m_attestationSigners);

return Response<AttestationToken<AttestationResult>>(token, std::move(response));
}
catch (std::runtime_error const& ex)
{
tracingContext.Span.AddEvent(ex);
tracingContext.Span.SetStatus(SpanStatus::Error);
throw;
}
}

Azure::Response<TpmAttestationResult> AttestationClient::AttestTpm(
AttestTpmOptions const& attestTpmOptions,
Azure::Core::Context const& context) const
{
std::string jsonToSend = TpmDataSerializer::Serialize(attestTpmOptions.Payload);
auto encodedVector = std::vector<uint8_t>(jsonToSend.begin(), jsonToSend.end());
Azure::Core::IO::MemoryBodyStream stream(encodedVector);
auto tracingContext(m_tracingFactory.CreateTracingContext("AttestTpm", context));
try
{
std::string jsonToSend = TpmDataSerializer::Serialize(attestTpmOptions.Payload);
auto encodedVector = std::vector<uint8_t>(jsonToSend.begin(), jsonToSend.end());
Azure::Core::IO::MemoryBodyStream stream(encodedVector);

auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, m_apiVersion, HttpMethod::Post, {"attest/Tpm"}, &stream);
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, m_apiVersion, HttpMethod::Post, {"attest/Tpm"}, &stream);

// Send the request to the service.
auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
std::string returnedBody(TpmDataSerializer::Deserialize(response));
return Response<TpmAttestationResult>(TpmAttestationResult{returnedBody}, std::move(response));
// Send the request to the service.
auto response
= AttestationCommonRequest::SendRequest(*m_pipeline, request, tracingContext.Context);
std::string returnedBody(TpmDataSerializer::Deserialize(response));
return Response<TpmAttestationResult>(TpmAttestationResult{returnedBody}, std::move(response));
}
catch (std::runtime_error const& ex)
{
tracingContext.Span.AddEvent(ex);
tracingContext.Span.SetStatus(SpanStatus::Error);
throw;
}
}

namespace {
Expand All @@ -186,28 +244,40 @@ std::shared_timed_mutex SharedStateLock;
*/
void AttestationClient::RetrieveResponseValidationCollateral(Azure::Core::Context const& context)
{
std::unique_lock<std::shared_timed_mutex> stateLock(SharedStateLock);

if (m_attestationSigners.empty())
auto tracingContext(m_tracingFactory.CreateTracingContext("Create", context));
try
{
stateLock.unlock();
auto request
= AttestationCommonRequest::CreateRequest(m_endpoint, HttpMethod::Get, {"certs"}, nullptr);
auto response = AttestationCommonRequest::SendRequest(*m_pipeline, request, context);
auto jsonWebKeySet(JsonWebKeySetSerializer::Deserialize(response));
TokenValidationCertificateResult returnValue;
std::vector<AttestationSigner> newValue;
for (const auto& jwk : jsonWebKeySet.Keys)
{
AttestationSignerInternal internalSigner(jwk);
newValue.push_back(internalSigner);
}
stateLock.lock();
std::unique_lock<std::shared_timed_mutex> stateLock(SharedStateLock);

if (m_attestationSigners.empty())
{
m_attestationSigners = newValue;
stateLock.unlock();
auto request = AttestationCommonRequest::CreateRequest(
m_endpoint, HttpMethod::Get, {"certs"}, nullptr);
auto response
= AttestationCommonRequest::SendRequest(*m_pipeline, request, tracingContext.Context);
auto jsonWebKeySet(JsonWebKeySetSerializer::Deserialize(response));
TokenValidationCertificateResult returnValue;
std::vector<AttestationSigner> newValue;
for (const auto& jwk : jsonWebKeySet.Keys)
{
AttestationSignerInternal internalSigner(jwk);
newValue.push_back(internalSigner);
}
stateLock.lock();
if (m_attestationSigners.empty())
{
m_attestationSigners = newValue;
}
tracingContext.Span.SetStatus(SpanStatus::Ok);
}
}
catch (std::runtime_error const& ex)
{
tracingContext.Span.AddEvent(ex);
tracingContext.Span.SetStatus(SpanStatus::Error);
throw;
}
}

/** @brief Construct a new Attestation Client object
Expand Down
2 changes: 1 addition & 1 deletion sdk/attestation/azure-security-attestation/vcpkg.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "azure-security-attestation-cpp",
"version": "1.0.0-beta.1",
"version": "1.0.0-beta.3",
"dependencies": [
{
"name": "azure-core-cpp"
Expand Down
Loading