

# Get the NitroTPM Attestation Document
<a name="attestation-get-doc"></a>

The Attestation Document is a key component of the NitroTPM attestation process. It contains a series of cryptographic measurements that can be used to verify the identity of the instance and to prove that it is running only trusted software. You can use the Attestation Document with AWS KMS, which provides built-in support for NitroTPM attestation, or to build your own cryptographic attestation mechanisms.

The `nitro-tpm-attest` utility enables you to retrieve a signed NitroTPM Attestation Document for an Amazon EC2 instance during runtime.

The sample Amazon Linux 2023 image description automatically installs the utility in the built image in the `/usr/bin/` directory. This ensures that the utility is preinstalled on instances launched using the AMI. You don't need to manually install the utility. For more information, see [Build the sample Amazon Linux 2023 image description](build-sample-ami.md).

**Topics**
+ [Install the `nitro-tpm-attest` utility](#nitro-tpm-attest-install)
+ [Use the `nitro-tpm-attest` utility](#nitro-tpm-attest-use)
+ [NitroTPM Attestation Document](nitrotpm-attestation-document-content.md)
+ [Validate Attestation Document](nitrotpm-attestation-document-validate.md)

## Install the `nitro-tpm-attest` utility
<a name="nitro-tpm-attest-install"></a>

If you are using Amazon Linux 2023, you can install the `nitro-tpm-attest` utility from the Amazon Linux repository as follows.

```
sudo yum install aws-nitro-tpm-tools
```

## Use the `nitro-tpm-attest` utility
<a name="nitro-tpm-attest-use"></a>

The utility provides a single command, `nitro-tpm-attest`, for retrieving the Attestation Document. The command returns the Attestation Document encoded in Concise Binary Object Representation (CBOR) and signed using CBOR Object Signing and Encryption (COSE).

When you run the command, you can specify the following optional parameters:
+ `public-key` — A public key that can be used by AWS KMS or an external service to encrypt response data before it is returned. This ensures that only the intended recipient, that has possession of the private key, can decrypt the data. For example, if you are attesting with AWS KMS, the service encrypts the plaintext data with the public key in the Attestation Document, and returns the resulting ciphertext in the `CiphertextForRecipient` field in the response. Only RSA keys are supported.
+ `user-data` — The user data can be used to deliver any additional signed data to an external service. This user data can be used to complete an agreed protocol between the requesting instance and the external service. Not used for attestation with AWS KMS.
+ `nonce` — The nonce can be used to set up challenge-response authentication between the instance and the external service to help prevent impersonation attacks. Using a nonce enables the external service to verify that it is interacting with a live instance and not an impersonator that is reusing an old Attestation Document. Not used for attestation with AWS KMS.

**To retrieve the Attestation Document**  
Use the following command and optional parameters:

```
/usr/bin/nitro-tpm-attest \
--public-key rsa_public_key \
--user-data user_data \
--nonce nonce
```

For a complete example that shows how to generate an RSA key pair, and how to request an attestation with the public key, see the [nitro-tpm-attest GitHub repo](https://github.com/aws/NitroTPM-Tools/).

# NitroTPM Attestation Document contents
<a name="nitrotpm-attestation-document-content"></a>

An Attestation Document is generated by the NitroTPM and it is signed by the Nitro Hypervisor. It includes a series of platform configuration registers (PCR) values related to an Amazon EC2 instance. The following PCRs are included in the Attestation Document:

**Important**  
PCR0 and PCR1 are generally used to measure the initial boot code, which is controlled by AWS. To allow safe updates of early boot code, these PCRs will always contain constant values.
+ `PCR0` — Core System Firmware Executable Code
+ `PCR1` — Core System Firmware Data
+ `PCR2` — Extended or pluggable executable code
+ `PCR3` — Extended or pluggable Firmware Data
+ `PCR4` — Boot Manager Code
+ `PCR5` — Boot Manager Code Configuration and Data and GPT Partition Table
+ `PCR6` — Host Platform Manufacturer Specifics
+ `PCR7` — Secure Boot Policy
+ `PCR8 - 15` — Defined for use by the Static Operating System
+ `PCR16` — Debug
+ `PCR23` — Application Support

**PCR4**, **PCR7**, and **PCR12** specifically are used to validate that an instance was launched using an Attestable AMI. PCR4 and PCR12 can be used to validate with standard boot, and PCR7 can be used to validate with Secure Boot.
+ **PCR4 (Boot Manager Code)** — When an instance starts, the NitroTPM creates cryptographic hashes of all the binaries executed by its UEFI environment. With Attestable AMIs, these boot binaries embed hashes that prevent future loading of binaries that do not have matching hashes. This way, the single boot binary hash can describe exactly what code an instance will execute.
+ **PCR7 (Secure Boot Policy)** — UEFI boot binaries can be signed with a UEFI Secure Boot signing key. When UEFI Secure Boot is enabled, UEFI will prevent execution of UEFI boot binaries that do not match the configured policy. PCR7 contains a hash of the instance’s UEFI Secure Boot policy.

  If you need to maintain a single KMS policy that persists across instance updates, you can create a policy that validates against PCR7 to validate a UEFI Secure Boot certificate. During creation of an Attestable AMI, you can then sign the boot binary with your certificate and install it as the only permitted certificate in the AMI’s UEFI-data. Keep in mind that this model requires you to still generate a new certificate, install it in your policy and update AMIs if you want to prevent instances launched from old (untrusted) AMIs from passing your KMS policy.
+ **PCR12** — Contains the hash of the command line passed to the UEFI boot binary. Required in conjunction with PCR4 for standard boot to validate the command line was not modified.

# Validate a NitroTPM Attestation Document
<a name="nitrotpm-attestation-document-validate"></a>

**Note**  
This topic is intended for users who are using a third-party key management service, and need to build their own Attestation Document validation mechanisms.

This topic provides a detailed overview of the entire NitroTPM attestation flow. It also discusses what is generated by the AWS Nitro system when an Attestation Document is requested, and explains how a key management service should process an Attestation Document.

**Topics**
+ [The Attestation Document](#doc-def)
+ [Attestation Document validation](#validation-process)

The purpose of attestation is to prove that an instance is a trustworthy entity, based on the code and configuration that it is running. The root of trust for the instance resides within the AWS Nitro system, which provides Attestation Documents. 

Attestation Documents are signed by the AWS Nitro Attestation Public Key Infrastructure (PKI), which includes a published certificate authority that can be incorporated into any service. 

## The Attestation Document
<a name="doc-def"></a>

Attestation Documents are encoded in Concise Binary Object Representation (CBOR), and signed using CBOR Object Signing and Encryption (COSE).

For more information about CBOR, see [RFC 8949: Concise Binary Object Representation (CBOR)](https://www.rfc-editor.org/rfc/rfc8949.html).

### Attestation Document specification
<a name="doc-spec"></a>

The following shows the structure of an Attestation Document.

```
AttestationDocument = {
    module_id: text,                     ; issuing Nitro hypervisor module ID
    timestamp: uint .size 8,             ; UTC time when document was created, in
                                         ; milliseconds since UNIX epoch
    digest: digest,                      ; the digest function used for calculating the
                                         ; register values
    nitrotpm_pcrs: { + index => pcr },   ; map of PCRs at the moment the Attestation Document was generated
    certificate: cert,                   ; the public key certificate for the public key 
                                         ; that was used to sign the Attestation Document
    cabundle: [* cert],                  ; issuing CA bundle for infrastructure certificate
    ? public_key: user_data,             ; an optional DER-encoded key the attestation
                                         ; consumer can use to encrypt data with
    ? user_data: user_data,              ; additional signed user data, defined by protocol
    ? nonce: user_data,                  ; an optional cryptographic nonce provided by the
                                         ; attestation consumer as a proof of authenticity
}

cert = bytes .size (1..1024)       ; DER encoded certificate
user_data = bytes .size (0..1024)
pcr = bytes .size (32/48/64)       ; PCR content
index = 0..31
digest = "SHA384"
```

The optional parameters in the Attestation Document (`public_key`, `user_data`, and `nonce`) can be used to establish a custom validation protocol between an attesting instance and the external service.

## Attestation Document validation
<a name="validation-process"></a>

When you request an Attestation Document from the Nitro Hypervisor, you receive a binary blob that contains the signed Attestation Document. The signed Attestation Document is a CBOR-encoded, COSE-signed (using the COSE\$1Sign1 signature structure) object. The overall validation process includes the following steps:

1. Decode the CBOR object and map it to a COSE\$1Sign1 structure.

1. Extract the Attestation Document from the COSE\$1Sign1 structure.

1. Verify the certificate's chain.

1. Ensure that the Attestation Document is properly signed.

Attestation Documents are signed by the AWS Nitro Attestation PKI, which includes a root certificate for the commercial AWS partitions. The root certificate can be downloaded from [https://aws-nitro-enclaves.amazonaws.com/AWS\$1NitroEnclaves\$1Root-G1.zip](https://aws-nitro-enclaves.amazonaws.com/AWS_NitroEnclaves_Root-G1.zip), and it can be verified using the following fingerprint.

```
64:1A:03:21:A3:E2:44:EF:E4:56:46:31:95:D6:06:31:7E:D7:CD:CC:3C:17:56:E0:98:93:F3:C6:8F:79:BB:5B
```

The root certificate is based on an AWS Certificate Manager Private Certificate Authority (AWS Private CA) private key and it has a lifetime of 30 years. The subject of the PCA has the following format.

```
CN=aws.nitro-enclaves, C=US, O=Amazon, OU=AWS
```

**Topics**
+ [COSE and CBOR](#COSE-CBOR)
+ [Semantic validity](#semantic-validation)
+ [Certificate validity](#cert-validity)
+ [Certificate chain validity](#chain)

### COSE and CBOR
<a name="COSE-CBOR"></a>

Usually, the COSE\$1Sign1 signature structure is used when only one signature is going to be placed on a message. The parameters dealing with the content and the signature are placed in the protected header rather than having the separation of COSE\$1Sign. The structure can be encoded as either tagged or untagged, depending on the context it will be used in. A tagged COSE\$1Sign1 structure is identified by the CBOR tag 18. 

The CBOR object that carries the body, the signature, and the information about the body and signature is called the COSE\$1Sign1 structure. The COSE\$1Sign1 structure is a CBOR array. The array includes the following fields.

```
[
  protected:   Header,
  unprotected: Header,
  payload:     This field contains the serialized content to be signed,
  signature:   This field contains the computed signature value.
]
```

In the context of an Attestation Document, the array includes the following.

```
18(/* COSE_Sign1 CBOR tag is 18 */
    {1: -35}, /* This is equivalent with {algorithm: ECDS 384} */
    {}, /* We have nothing in unprotected */
    $ATTESTATION_DOCUMENT_CONTENT /* Attestation Document */,
    signature /* This is the signature */
)
```

For more information about CBOR, see [RFC 8949: Concise Binary Object Representation (CBOR)](https://www.rfc-editor.org/rfc/rfc8949.html).

### Semantic validity
<a name="semantic-validation"></a>

An Attestation Document will always have their CA bundle in the following order.

```
[ ROOT_CERT - INTERM_1 - INTERM_2 .... - INTERM_N]
      0          1          2             N - 1
```

Keep this ordering in mind, as some existing tools, such as Java’s CertPath from [ Java PKI API Programmer’s Guide](https://docs.oracle.com/javase/8/docs/technotes/guides/security/certpath/CertPathProgGuide.html), might require them to be ordered differently.

To validate the certificates, start from the Attestation Document CA bundle and generate the required chain, Where `TARGET_CERT` is the certificate in the Attestation Document.

```
[TARGET_CERT, INTERM_N, ..... , INTERM_2, INTERM_1, ROOT_CERT]
```

### Certificate validity
<a name="cert-validity"></a>

For all of the certificates in the chain, you must ensure that the current date falls within the validity period specified in the certificate.

### Certificate chain validity
<a name="chain"></a>

In general, a chain of multiple certificates might be needed, comprising a certificate of the public key owner signed by one CA, and zero or more additional certificates of CAs signed by other CAs. Such chains, called certification paths, are required because a public key user is only initialized with a limited number of assured CA public keys. Certification path validation procedures for the internet PKI are based on the algorithm supplied in X.509. Certification path processing verifies the binding between the subject distinguished name and/or subject alternative name and subject public key. The binding is limited by constraints that are specified in the certificates that comprise the path and inputs that are specified by the relying party. The basic constraints and policy constraint extensions allow the certification path processing logic to automate the decision making process.

**Note**  
CRL must be disabled when doing the validation.

Using Java, starting from the root path and the generated certificate chain, the chain validation is as follows.

```
validateCertsPath(certChain, rootCertficate) {
    /* The trust anchor is the root CA to trust */
    trustAnchors.add(rootCertificate);

    /* We need PKIX parameters to specify the trust anchors
     * and disable the CRL validation
     */
    validationParameters = new PKIXParameters(trustAnchors);
    certPathValidator = CertPathValidator.getInstance(PKIX);
    validationParameters.setRevocationEnabled(false);

    /* We are ensuring that certificates are chained correctly */
    certPathValidator.validate(certPath, validationParameters);
}
```