Verifying the root of trust - AWS Nitro Enclaves

Verifying the root of trust

This topic is intended for users who are using a third-party key management service, and need to build their own attestation document validation processes.

It provides a detailed overview of the entire Nitro Enclaves 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.

Attestation in the Nitro Enclaves world

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

The root of trust component for the attestation is the Nitro Hypervisor, which contains information about the enclave, such as its platform configuration registers (PCRs). The Nitro Hypervisor is able to produce an attestation document that contains details of the enclave, including the enclave signing key, a hash of the enclave image, a hash of the parent instance ID, and a hash of the ARN of the attached IAM role.

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

An enclave can request an attestation document from the Nitro hypervisor that it can use to verify its identify with an external service. The attestation document that is generated by the Nitro system is encoded in Concise Binary Object Representation (CBOR), and it is signed using CBOR Object Signing and Encryption (COSE).

Attestation document specification

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 pcrs: { + index => pcr }, ; map of all locked PCRs at the moment the ; attestation document was generated certificate: cert, ; the infrastucture certificate used to sign this ; document, DER encoded 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 enclave and the service that wants to attest the enclave first need to agree on a common protocol to follow. The optional parameters in the attestation document (public_key, user_data, and nonce) allow the enclave and the entity to set up a variety of protocols depending on the security properties that the service and the enclave want to guarantee. Services that rely on attestation need to define a protocol that can meet those guarantees, and the enclave software needs to agree to and follow these protocols.

An enclave wishing to attest to a specific service first has to open a TLS connection to that service and verify that the service's certificates are valid. These certificates must then be included in the enclave during the enclave image file build.


A TLS session is not absolutely required, but it does provide integrity of data between the enclave and the third-party service.

For more information about the optional fields in the attestation document, see the Nitro Enclaves Attestation Process.

Attestation document validation

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_Sign1 signature structure) object. The overall validation process includes the following steps:

  1. Decode the CBOR object and map it to a COSE_Sign1 structure.

  2. Extract the attestation document from the COSE_Sign1 structure.

  3. Verify the certificate's chain.

  4. 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, and it can be verified using the following SHA256 checksum.


The root certificate is based on an AWS Certificate Manager Private Certificate Authority (ACM PCA) 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


Usually, the COSE_Sign1 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_Sign. The structure can be encoded as either tagged or untagged, depending on the context it will be used in. A tagged COSE_Sign1 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_Sign1 structure. The COSE_Sign1 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 */ )

Semantical validity

An attestation document will always have its 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, 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.


For more information about the optional fields in the attestation document, see the Nitro Enclaves Attestation Process.

Certificate validity

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

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.


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); }