Skip to content

Commit

Permalink
Updated and add samples for Attestation service. (#3448)
Browse files Browse the repository at this point in the history
* Moved samples around to meet new recommendations; added a couple of additional tests.
* Reworked attestation to include RetrieveAttestationValidationCollateral
* Attestation sample readme updates
* TPM doesn't need to retrieve response validation collateral
* Added cautionary warning about the dangers of overriding the TearDown method from inside a test case
* Added attestation team members to codeowners for attestation SDK
* Remove CODEOWNERS from cspell checks
* Don't hold a lock across retrieving the signers over the network
* Updated snippets in readme; clang-format
  • Loading branch information
LarryOsterman authored Mar 22, 2022
1 parent d7536a2 commit af7281e
Show file tree
Hide file tree
Showing 108 changed files with 3,754 additions and 1,151 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
###########

# PRLabel: %Attestation
/sdk/attestation/ @LarryOsterman
/sdk/attestation/ @LarryOsterman @gkostal @anilba06 @kroshkina-ms

# PRLabel: %KeyVault
/sdk/keyvault/ @vhvb1989 @gearama @antkmsft @rickwinter
Expand Down
1 change: 1 addition & 0 deletions .vscode/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"*.exe",
"*.a",
"*.lib",
".github/CODEOWNERS",
".gitignore",
".vscode/cspell.json",
"eng/common/**/*",
Expand Down
15 changes: 15 additions & 0 deletions samples/helpers/get-env/inc/get_env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,18 @@ char* getenv(const char* name);
#endif

#endif
#include <stdexcept>
#include <string>

struct GetEnvHelper
{
static std::string GetEnv(char const* env)
{
auto const val = std::getenv(env);
if (val == nullptr)
{
throw std::runtime_error("Could not find required environment variable: " + std::string(env));
}
return std::string(val);
}
};
3 changes: 2 additions & 1 deletion sdk/attestation/azure-security-attestation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ add_library(Azure::azure-security-attestation ALIAS azure-security-attestation)
# coverage. Has no effect if BUILD_CODE_COVERAGE is OFF
create_code_coverage(attestation azure-security-attestation azure-security-attestation-test "tests?/*;samples?/*")


get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp")
generate_documentation(azure-security-attestation ${AZ_LIBRARY_VERSION})

Expand All @@ -104,5 +105,5 @@ if(BUILD_TESTING)
endif()

if(BUILD_SAMPLES)
add_subdirectory(test/samples)
add_subdirectory(samples)
endif()
216 changes: 155 additions & 61 deletions sdk/attestation/azure-security-attestation/README.md

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions sdk/attestation/azure-security-attestation/cspell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": "0.2",
"language": "en",
"languageId": "cpp",
"dictionaries": [
"powershell",
"cpp"
],
"ignorePaths": [
"**/test/ut/recordings/*.json"
],
"words": [
"ECDS",
"jwks",
"jwk",
"mrenclave",
"mrsigner",
"shareduks",
"attestsgxenclave",
"attestsgxenclavewithruntimejson",
"attestsgxenclavewithruntimebinary",
"getopenidmetadata"

]
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,30 @@ namespace Azure { namespace Security { namespace Attestation {
m_pipeline(attestationClient.m_pipeline),
m_tokenValidationOptions(attestationClient.m_tokenValidationOptions){};

/**
* @brief Retrieves the information needed to validate the response returned from the
* attestation service.
*
* @details Validating the response returned by the attestation service requires a set of
* possible signers for the attestation token.
*
* @param context Client context for the request to the service.
*/
void RetrieveResponseValidationCollateral(
Azure::Core::Context const& context = Azure::Core::Context{}) const;

/**
* @brief Retrieves an Attestation Policy from the service.
*
* @param attestationType Attestation type to be used when retrieving the policy.
* @param options Options to be used when retrieving the policy.
* @param context User defined context for the operation.
* @return Response<Models::AttestationToken<std::string>> The returned policy from the service.
* @return Response<Models::AttestationToken<std::string>> The returned policy from the
* service.
*
* @note \b Note: The RetrieveResponseValidationCollateral API \b MUST be called before the
* GetAttestationPolicy API is called to retrieve the information needed to validate the
* result returned by the service.
*/
Response<Models::AttestationToken<std::string>> GetAttestationPolicy(
Models::AttestationType const& attestationType,
Expand Down Expand Up @@ -123,6 +140,10 @@ namespace Azure { namespace Security { namespace Attestation {
* @param context User defined context for the operation.
* @return Response<Models::AttestationToken<Models::PolicyResult>> The result of the set policy
* operation.
*
* @note \b Note: The RetrieveResponseValidationCollateral API \b MUST be called before the
* SetAttestationPolicy API is called to retrieve the information needed to validate the
* result returned by the service.
*/
Response<Models::AttestationToken<Models::PolicyResult>> SetAttestationPolicy(
Models::AttestationType const& attestationType,
Expand All @@ -138,6 +159,10 @@ namespace Azure { namespace Security { namespace Attestation {
* @param context User defined context for the operation.
* @return Response<Models::AttestationToken<Models::PolicyResult>> The result of the reset
* policy operation.
*
* @note \b Note: The RetrieveResponseValidationCollateral API \b MUST be called before the
* ResetAttestationPolicy API is called to retrieve the information needed to validate the
* result returned by the service.
*/
Response<Models::AttestationToken<Models::PolicyResult>> ResetAttestationPolicy(
Models::AttestationType const& attestationType,
Expand Down Expand Up @@ -165,6 +190,10 @@ namespace Azure { namespace Security { namespace Attestation {
* attestation service based on this signing key.
*
* @note: If policyToSet is null, then this generates a policy reset token.
*
* @note \b Note: The RetrieveResponseValidationCollateral API \b MUST be called before the
* ResetAttestationPolicy API is called to retrieve the information needed to validate the
* result returned by the service.
*/
Models::AttestationToken<> CreateSetAttestationPolicyToken(
Azure::Nullable<std::string> const& policyToSet,
Expand Down Expand Up @@ -255,18 +284,20 @@ namespace Azure { namespace Security { namespace Attestation {

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

std::vector<Models::AttestationSigner> const& GetAttestationSigners(
Azure::Core::Context const& context) const;

std::string CreatePolicyCertificateModificationToken(
std::string const& pemEncodedX509CertificateToAdd,
AttestationSigningKey const& existingSigningKey) const;

Models::AttestationToken<Models::PolicyCertificateModificationResult>
ProcessPolicyCertModificationResult(
std::unique_ptr<Azure::Core::Http::RawResponse> const& serverResponse,
AttestationTokenValidationOptions const& tokenValidationOptions,
Azure::Core::Context const& context) const;
AttestationTokenValidationOptions const& tokenValidationOptions) const;

/**
* @brief Check the m_AttestationSigners to ensure that RetrieveResponseValidationCollateral has
* been called.
*/
void CheckAttestationSigners() const;
};

}}} // namespace Azure::Security::Attestation
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,15 @@ namespace Azure { namespace Security { namespace Attestation {
Response<Models::AttestationSigningCertificateResult> GetAttestationSigningCertificates(
Azure::Core::Context const& context = Azure::Core::Context{}) const;

/**
* @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{}) const;

/**
* @brief Attest an SGX enclave, returning an attestation token representing the result
* of the attestation operation.
Expand All @@ -193,8 +202,8 @@ namespace Azure { namespace Security { namespace Attestation {
* @returns Response<AttestationToken<AttestationResult>> - The result of the
* attestation operation.
*
* @note \b Note: The GetAttestationSigningCertificates API API \b MUST be called before the
* AttestSgxEnclave API is called to retrieve the signing certificates used to validate the
* @note \b Note: The RetrieveResponseValidationCollateral API \b MUST be called before the
* AttestSgxEnclave API is called to retrieve the information needed to validate the
* result returned by the service.
*/
Response<Models::AttestationToken<Models::AttestationResult>> AttestSgxEnclave(
Expand All @@ -213,6 +222,10 @@ namespace Azure { namespace Security { namespace Attestation {
*
* @returns Response<AttestationToken<AttestationResult>> - The result of the attestation
* operation
* @note \b Note: The RetrieveResponseValidationCollateral API \b MUST be called before the
* AttestOpenEnclave API is called to retrieve information needed to used to validate the
* result returned by the service.
*/
Response<Models::AttestationToken<Models::AttestationResult>> AttestOpenEnclave(
std::vector<uint8_t> const& openEnclaveReportToAttest,
Expand Down Expand Up @@ -251,8 +264,11 @@ namespace Azure { namespace Security { namespace Attestation {

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

std::vector<Models::AttestationSigner> const& GetAttestationSigners(
Azure::Core::Context const& context) const;
/**
* @brief Check the m_AttestationSigners to ensure that RetrieveResponseValidationCollateral has
* been called.
*/
void CheckAttestationSigners() const;
};

}}} // namespace Azure::Security::Attestation
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <unordered_map>
#include <vector>

// cspell: words MRSIGNER MRENCLAVE
namespace Azure { namespace Security { namespace Attestation { namespace Models {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ namespace Azure { namespace Security { namespace Attestation {
}
};

/** @brief Attestation Validation Collateral
*
* This structure contains all the information needed to validate the response from the
* attestation service.
*
*/
class AttestationValidationCollateral final {
std::vector<Models::AttestationSigner> m_attestationSigners;
};

/** @brief The AttestationDataType represents how the attestation service should interpret the
* {@link AttestOptions::RuntimeData} and {@link AttestOptions::InittimeData} fields.
*/
Expand Down Expand Up @@ -302,7 +312,7 @@ namespace Azure { namespace Security { namespace Attestation {
* @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{};
Azure::Nullable<AttestationTokenValidationOptions> TokenValidationOptions;
};

/** @brief Parameters sent to the attestation service when setting an attestation policy.
Expand All @@ -318,7 +328,7 @@ namespace Azure { namespace Security { namespace Attestation {
* @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{};
Azure::Nullable<AttestationTokenValidationOptions> TokenValidationOptions;
};

/** @brief Parameters sent to the attestation service when retrieving the list of policy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ cmake_minimum_required (VERSION 3.13)
add_subdirectory(basic-operations)
add_subdirectory(attestation)
add_subdirectory(policy)
add_subdirectory(policy-certificates)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ products:
- azure-attestation
urlFragment: attestation-samples

#cspell: words mrsigner mrenclave shareduks
---

# Samples for the Microsoft Azure Attestation client library for C++
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT

cmake_minimum_required (VERSION 3.13)

project (attestation-attestation LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)

macro (define_sample samplename)
add_executable (
attestation-${samplename}
${samplename}.cpp
attestation_collateral.cpp
attestation_collateral.hpp)

CREATE_PER_SERVICE_TARGET_BUILD_FOR_SAMPLE(attestation attestation-${samplename})

target_link_libraries(attestation-${samplename} PRIVATE azure-security-attestation get-env-helper)

endmacro()


define_sample(attestsgxenclave)
define_sample(attestsgxenclavewithruntimejson)
define_sample(attestsgxenclavewithruntimebinary)
define_sample(attestopenenclavewithdraftpolicy)
define_sample(attestopenenclaveshared)

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
page_type: sample
languages:
- C++
products:
- azure
- azure-attestation
urlFragment: attestation-samples

---

# Attestation Samples for the Microsoft Azure Attestation client library for C++

These code samples show common scenario operations for the Attestation APIs within the Azure Attestation client library.

## Sample Requirements

These samples are written with the assumption that the following environment
variables have been set by the user:

* ATTESTATION_AAD_URL - the base URL for an attestation service instance in AAD mode.
* ATTESTATION_ISOLATED_URL - the base URL for an attestation service instance in Isolated mode.
* ATTESTATION_LOCATION_SHORT_NAME - the short name for the region in which the
sample should be run - used to interact with the shared endpoint for that
region.

## Samples descriptions

The samples are structured as separate source files, one per scenario. The are:
Sample | What it tests | Notes
-----|-----|-----
AttestSgxEnclave | The simplest usage of the AttestSgxEnclave API |
AttestOpenEnclaveShared | Attest an OpenEnclave report using the shared attestation instance |
AttestSgxEnclaveWithRuntimeBinary | Calling AttestSgxEnclave with RuntimeData sent to the service which should be interpreted as binary data |
AttestSgxEnclaveWithRuntimeJson | Calling AttestSgxEnclave with RuntimeData sent to the service which should be interpreted as JSON data |
AttestOpenEnclaveWithDraftPolicy | Calling AttestOpenEnclave with a draft attestation policy which can be used to test attestation policies to determine their effect |

## Additional Information

### Attestation Policy

An attestation policy is a document which defines authorization and claim generation
rules for attestation operations.

The following is an example of an attestation policy document for an SGX enclave:

```text
version= 1.0;
authorizationrules
{
[ type=="x-ms-sgx-is-debuggable", value==false ] &&
[ type=="x-ms-sgx-product-id", value==<product-id> ] &&
[ type=="x-ms-sgx-svn", value>= 0 ] &&
[ type=="x-ms-sgx-mrsigner", value=="<mrsigner>"]
=> permit();
};
issuancerules {
c:[type=="x-ms-sgx-mrsigner"] => issue(type="<custom-name>", value=c.value);
};
```

There are two sections to the document: `authorizationrules` and `issuancerules`.
`authorizationrules` are rules which control whether an attestation token
should be issued. `issuancerules` are rules which cause claims to be issued in an
attestation token.

In the example, the attestation service will issue an attestation token if and only if
the SGX enclave is configured as follows:

* Not-Debuggable
* Enclave product ID: `<product-id>`.
* Enclave SVN: `<svn value>` greater or equal to zero.
* Enclave signer: matches `<mrsigner>`.

Assuming a token is issued, this policy will cause a claim named `<custom-name>`
to be issued with a value which matches the `x-ms-sgx-mrsigner` claim.

For more information on authoring attestation policy documents, see: [Authoring an attestation policy](https://docs.microsoft.com/azure/attestation/author-sign-policy)

## Next Steps

For more information about the Microsoft Azure Attestation service, please see our [documentation page](https://docs.microsoft.com/azure/attestation/) .

<!-- LINKS -->
<!-- links are known to be broken, they will be fixed after this initial pull
request completes. -->
[readme_md]: https://github.com/Azure/azure-sdk-for-cpp/blob/main/sdk/attestation/azure-security-attestation/README.md
Loading

0 comments on commit af7281e

Please sign in to comment.