Skip to main content

Remote Attestations

Remote attestation is the process of generating and verifying attestations from the enclave. The goal is to verify the following:

  1. The attestation is valid.
  2. The attestation is recent.
  3. The attestation was generated by a real enclave running on a secure platform.
  4. The enclave is running an enclave image with specific PCRs.

Remote attestations are meant to be used alongside reproducible builds.

Anatomy of attestations

See this AWS doc for the specification and encoding for an attestation document. Important fields include:

  • timestamp - Timestamp when the attestation document was generated, can be used to check recency
  • pcrs - Platform Control Register values, contains measurements of the enclave image that is running and can be matched with PCRs obtained during the image building process
  • certificate - Certificate that is used to sign the attestation document
  • cabundle - Certificate chain that starts from the AWS Nitro Enclaves Root certificate and ends with a certificate that signs the certificate field above
  • public_key - User defined field usually used to advertise the enclave's public key that can be used to then set up secure connections

Generating attestations

Attestations can be generated by sending a request to the AWS Nitro Secure Module (NSM) using aws-nitro-enclaves-nsm-api. The library is primarily written in Rust, but includes a C library as well for interoperability with other languages.

Sample code:

pub fn get_attestation_doc(pub_key: [u8;32]) -> Vec<u8> {
let nsm_fd = nsm_driver::nsm_init();

let public_key = ByteBuf::from(pub_key);

let request = Request::Attestation {
public_key: Some(public_key),
user_data: None,
nonce: None,
};

let response = nsm_driver::nsm_process_request(nsm_fd, request);

nsm_driver::nsm_exit(nsm_fd);

match response {
Response::Attestation { document } => document,
_ => panic!("nsm driver returned invalid response: {:?}", response),
}
}

The attestation request takes three optional parameters - public_key, user_data and nonce - which are included in the attestation document and can be used by verifiers.

Exposing attestations

Attestations can only be generated by a program inside the enclave which necessitates a mechanism to expose them outside the enclave/instance. Oyster exposes attestations using the attestation server that is included in the default enclave image. It accepts requests from outside the enclave, generates attestation documents and returns them as responses.

Some applications require the use of an additional secp256k1 key in order to interact with smart contracts. Such applications can simply run another copy of the attestation server and provide the secp256k1 key as an argument. See the attestation verifier enclave for a concrete example.

Verifying attestations

Attestations first have to be decoded into a readable format for verification, this AWS doc has a description of the format. Once decoded, follow the below checklist:

  • Verify that the timestamp is recent
  • Verify that PCRs match expected values
  • Verify that the attestation document has a valid signature
  • Verify that the certificate chain is valid
  • Verify that the root of the certificate chain is the AWS Nitro Enclaves Root certificate

The Oyster SDK includes functions to get and verify attestations from an endpoint. It also includes a standalone verifier that stores the enclave's public key in a file for later use.

Verifying in solidity

Attestations can be verified on-chain by implementing the above procedure in a Solidity contract. An example contract is available here - https://github.com/marlinprotocol/NitroProver.

Verifying using ZK

Oyster also provides a ZK verifier that can be used to generate a ZK proof of attestation verification. While it requires upfront work (and ~15 min latency) in order to generate the proof, the resulting proof is much cheaper to verify on-chain. It is available here - https://github.com/marlinprotocol/oyster-monorepo/tree/master/attestation/verifier-risczero

Verifying using a chain of trust

Verifying attestations in solidity is expensive, even with a ZK proof. Attestations can also be verified on-chain by using a special attestation verifier enclave as an intermediary to extend the chain of trust.

The attestation verifier enclave accepts attestations, verifies them and creates a verification receipt that is signed using an secp256k1 keypair. Therefore, it converts attestation verification into simple signature verification which is cheap in solidity. Once the attestation verifier enclave itself is verified in solidity, receipts produced by it can be cheaply verified on-chain with the same security guarantees. This includes other attestation verifier enclaves as well, hence multiple verifier enclaves can be bootstrapped using a single enclave (useful for redundancy).

Done correctly, only one enclave per chain should ever need to be verified in solidity directly. All other enclaves of all other applications can use the verifier network to verify themselves.

An example contract is available here - https://github.com/marlinprotocol/oyster-monorepo/blob/master/contracts/contracts/contracts/AttestationVerifier.sol