Attestation
An attestation document is a feature that allows the enclave to prove its identity. This document can be used by external services to give the enclave access to data. For more information about the attestation document specification visit Attestation Document Specification .
Verify attestation document
Document retrieval
When you request an attestation document it is signed as a CBOR Object Signing and Encryption (COSE) message. The COSE object sent by the enclave it's an array with 4 elements:
- The set of protected header parameters wrapped in a bstr.
- The set of unprotected header parameters as a map.
- The content of the message, in this case, is the attestation document.
- The signature generated by the enclave.
The attestation document is encoded in Concise Binary Object Representation (CBOR) so we have to set up a codification to access the document data.
# Decode the attestation document
document_data = cbor2.loads(attestation_doc)
# Load and decode document payload
att_doc_encoded = data[2]
att_doc = cbor2.loads(doc)PCR verification
The first step to verify an attestation document is to check that the platform configuration registers (PCRs) that are unique to the enclave correspond to the one we expect.
# Get PCRs from attestation document
document_pcrs_arr = att_doc['pcrs']
for index, pcr in enumerate(expected_pcrs):
# Check that the index exist in the document pcr
if index not in document_pcrs_arr or document_pcrs_arr[index] is None:
raise Exception("PCR not found at index {}".format(index))
# Get PCR hexcode
doc_pcr = document_pcrs_arr[index].hex()
# Check if the PCR matches with the expected one
if pcr != doc_pcr:
raise Excepetion("Wrong pcr {}".format(index))Validate signature
Now we need to validate the attestation document signature, for this, we need to build an elliptic curve key and then validate it using the headers.
# Get certificate from attestation document
cert = crypto.load_certificate(crypto.FILETYPE_ASN1, att_doc['certificate'])
# Get parameters from the certificate public key
cert_public_numbers = cert.get_pubkey().to_cryptography_key().public_numbers()
x = long_to_bytes(cert_public_numbers.x)
y = long_to_bytes(cert_public_numbers.y)
curve = cert_public_numbers.curve
x = long_to_bytes(x)
y = long_to_bytes(y)
# Create the EC2 key from public key parameters
key = EC2(alg = CoseAlgorithms.ES384, x = x, y = y, crv = CoseEllipticCurves.P_384)
# Get the protected header from attestation document
protected_header = cbor2.loads(document_data[0])
unprotected_header = document_data[1]
doc_signature = document_data[3]
# Construct the Sign1 message
msg = cose.Sign1Message(
phdr = protected_header, uhdr = unprotected_header,
payload = att_doc)
msg.signature = doc_signature
# Verify the signature using the EC2 key
if not msg.verify_signature(key):
raise Exception("Could not verify signature")Validate certificate
Lastly, we want to validate the certificate of the attestation document. To do this we want to verify that the certificate is signed by the root certificate of the AWS Nitro Attestation Public Key Infrastructure (PKI). This root certificate can be found in Attestation Document Validation.
root_cert_pem = None
# Load the root certificate
with open('root.pem', 'r') as file:
root_cert_pem = file.read()
# Get signing certificate from attestation document
cert = crypto.load_certificate(crypto.FILETYPE_ASN1, doc_obj['certificate'])
# Create an X509Store object for the CA bundles
store = crypto.X509Store()
# Create the CA cert object from PEM string, and store into X509Store
_cert = crypto.load_certificate(crypto.FILETYPE_PEM, root_cert_pem)
store.add_cert(_cert)
# Get the CA bundle from attestation document and store into X509Store
# Except the first certificate, which is the root certificate
for _cert_binary in doc_obj['cabundle'][1:]:
_cert = crypto.load_certificate(crypto.FILETYPE_ASN1, _cert_binary)
store.add_cert(_cert)
# Get the X509Store context
store_ctx = crypto.X509StoreContext(store, cert)
# Validate the certificate
# If the cert is invalid, it will raise exception
try:
store_ctx.verify_certificate()
except Exception as e:
print(e)