// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * @brief This sample provides the code implementation to use the Key Vault Certificates SDK client * for C++ to create, get, update, delete and purge a certificate. * * @remark The following environment variables must be set before running the sample. * - ATTESTATION_AAD_URL: Points to an Attestation Service Instance in AAD mode. * - ATTESTATION_ISOLATED_URL: Points to an Attestation Service Instance in Isolated mode. * - LOCATION_SHORT_NAME: Specifies the short name of an Azure region to use for shared mode * operations. * - AZURE_TENANT_ID: Tenant ID for the Azure account. * - AZURE_CLIENT_ID: The Client ID to authenticate the request. * - AZURE_CLIENT_SECRET: The client secret. * */ #include #include #include #include #include #include #include #include #include #include #include // cspell:: words mrsigner mrenclave mitm using namespace Azure::Security::Attestation; using namespace Azure::Security::Attestation::Models; using namespace std::chrono_literals; using namespace Azure::Core; using namespace Azure::Core::Cryptography::_internal; int main() { try { std::string const endpoint(GetEnvHelper::GetEnv("ATTESTATION_AAD_URL")); // Attestation tokens returned by the service should be issued by the // attestation service instance. Update the token validation logic to ensure that // the right instance issued the token we received (this protects against a MITM responding // with a token issued by a different attestation service instance). AttestationAdministrationClientOptions clientOptions; clientOptions.TokenValidationOptions.ExpectedIssuer = endpoint; clientOptions.TokenValidationOptions.ValidateIssuer = true; // Ten seconds of clock drift are allowed between this machine and the attestation service. clientOptions.TokenValidationOptions.TimeValidationSlack = 10s; // create client auto const credential = std::make_shared( GetEnvHelper::GetEnv("AZURE_TENANT_ID"), GetEnvHelper::GetEnv("AZURE_CLIENT_ID"), GetEnvHelper::GetEnv("AZURE_CLIENT_SECRET")); AttestationAdministrationClient const adminClient( AttestationAdministrationClient::Create(endpoint, credential, clientOptions)); // Set the attestation policy on this attestation instance. // Note that because this is an AAD mode instance, the caller does not need to sign the policy // being set. std::string const policyToSet(R"(version= 1.0; authorizationrules { [ type=="x-ms-sgx-is-debuggable", value==true ]&& [ type=="x-ms-sgx-mrsigner", value=="mrsigner1"] => permit(); [ type=="x-ms-sgx-is-debuggable", value==true ]&& [ type=="x-ms-sgx-mrsigner", value=="mrsigner2"] => permit(); };)"); Azure::Response> const setResult = adminClient.SetAttestationPolicy(AttestationType::SgxEnclave, policyToSet); if (setResult.Value.Body.PolicyResolution == PolicyModification::Updated) { std::cout << "Attestation policy was updated." << std::endl; } // To verify that the attestation service received the attestation policy, the service returns // the SHA256 hash of the policy token which was sent ot the service. To simplify the customer // experience of interacting with the SetPolicy APIs, CreateAttestationPolicyToken API will // generate the same token that would be send to the service. // // To ensure that the token which was sent from the client matches the token which was received // by the attestation service, the customer can call CreateAttestationPolicyToken and then // generate the SHA256 of that token and compare it with the value returned by the service - the // two hash values should be identical. auto const setPolicyToken = adminClient.CreateAttestationPolicyToken(policyToSet); Sha256Hash shaHasher; std::vector policyTokenHash = shaHasher.Final( reinterpret_cast(setPolicyToken.RawToken.data()), setPolicyToken.RawToken.size()); std::cout << "Expected token hash: " << Convert::Base64Encode(policyTokenHash) << std::endl; std::cout << "Actual token hash: " << Convert::Base64Encode(setResult.Value.Body.PolicyTokenHash) << std::endl; } catch (Azure::Core::Credentials::AuthenticationException const& e) { std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl; return 1; } catch (Azure::Core::RequestFailedException const& e) { std::cout << "Request Failed Exception happened:" << std::endl << e.what() << std::endl; if (e.RawResponse) { std::cout << "Error Code: " << e.ErrorCode << std::endl; std::cout << "Error Message: " << e.Message << std::endl; } return 1; } return 0; }