Remote attestation is a fundamental concept when designing secure protocols using TEEs. One of the best ways to make it clear how this works is with an on-chain demo.
This demo is mainly possible through recent projects like Puffer Finance “RAVE”, which are Solidity smart contract implementations of verifiers for SGX remote attestation. We’ll walk through an end to end example, starting from the verifier and working backward.
To follow along with the post:
- [Live instance of the smart contract on Sepolia](https://sepolia.etherscan.io/address/0x290ca2ccf25b63521d3297d48b4ea2aaca2cbebb#readContract
- Forge environment for this smart contract GitHub - amiller/gramine-forge
- A Gramine project for the enclave used in this post GitHub - amiller/gramine-dummy-attester
Verification of SGX Remote attestations using Solidity.
Let’s start with the on-chain instance of the attestation checker based on RAVE. This happens to be on Sepolia testnet, and is a verification contract written in Solidity.
The contract comes with a utility that decodes an encoded attestation. Essentially this is the Solidity equivalent of the “gramine-sgx-quote-view” utility from Gramine. You can use the “Read Contract” tab of Etherscan to query it. Here’s an example response from decodeAttestation
.
[ decodeAttestation(bytes) method Response ]
id string : 3342293282022782940082890185166001797
timestamp string : 2023-11-14T18:22:53.362222
version string : 4
epidPseudonym string : +CUyIi74LPqS6M0NF7YrSxLqPdX3...WiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=
advisoryURL string : https://security-center.intel.com
advisoryIDs string : ["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"]
isvEnclaveQuoteStatus string : CONFIGURATION_AND_SW_HARDENING_NEEDED
platformInfoBlob string : 15020065000008000014140204018...58D2D8F75EAA
isvEnclaveQuoteBody string : 0200010...40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000
userReportData string : 9113b0be77ed5d0...00000000
For a sample attestation you can copy and paste into the decodeAttestation
field on Etherscan , copy the following:
0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000076000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000002732343231393434323133303637383236343035353330363132313539353131343739323932383600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a323032332d31312d31315431383a33383a34362e3832373430370000000000000000000000000000000000000000000000000000000000000000000000000001340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ac2b435579496937344c507153364d304e4637597253784c71506458334d4b733644364c49507152472f5a454234576d785a567678414a776477672f306d3963596e55555167754c6e4a6f747468583634356c416f67664a674f385867352f39316c5365677779554b76486d4b67746a4f48582f59546256652f776d6757694264614c2b4b6d617259304a6534353950782f4671474c574c73414637656750414a526431586e38385a6e72733d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002168747470733a2f2f73656375726974792d63656e7465722e696e74656c2e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000565b22494e54454c2d53412d3030313631222c22494e54454c2d53412d3030323139222c22494e54454c2d53412d3030323839222c22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030363135225d000000000000000000000000000000000000000000000000000000000000000000000000000000000025434f4e46494755524154494f4e5f414e445f53575f48415244454e494e475f4e454544454400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d2313530323030363530303030303830303030313431343032303430313830303730303030303030303030303030303030303030443030303030433030303030303032303030303030303030303030304342304137454441433943463241433845453330453438354246453242344134384430423242323546333334454432373241334234433832304635383846463242303634414133363534354445444236394143374333374241444637433644423546393344453141313639313130413442383239414244353243413745303944434636000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b002000100b00c00000f000f000000000051caf5a48b450d624aefe3286d3148940000000000000000000000000000000014140207018001000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000700000000000000e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb00000000000000000000000000000000000000000000000000000000000000001cf2e52911410fbf3f199056a98d58795a559a2e800933f7fcd13d048462271c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a68200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001006aa5d776471423ccc1ee3a09366f98bb48b4b3ab8466b1e3cd28ae019dd5a48443cc1f44b0797761de4ef9c4935854b9eeece0cb2eeb2c31066900c6c1ddc6858883996217f09392d03d87b7a68107a93b1c5b08259b7beee6e14541348eaf247f6fb582826a3c2645c36d4f8c5e4af8c94993e0bf9023e40ba25c36cddcf0b4a8414b34a628aaf4faab450d1e01c53b46b7c19de2cc20c76078bc55b7ad02a12b31b9fe56cfa11339d13567e58fdc614a51df89bd88fd915a9973e3e03e32b4489d22c30bf66aac56673db38e45eaefc5a0e89a3457df070b4e7e1801b26e1a8448c0f67f8f0b0ce2b1e8c866441e584db371d1697ca2778ab2f5d117282cc4
The “verify_epid” function is the main function in this demonstration.
function verify_epid(string memory userReportData, bytes memory attestation) public view returns(bool);
It can be found here: https://github.com/amiller/gramine-forge/blob/master/src/MyRave.sol#L40
The high level pseudocode is this:
- The root public key from Intel is hardcoded (but can be independently found from many other places, i.e. gramine source code, web archive snapshot)
- The attestation is parsed into a report and signature from abi encoded bytes.
- The signature is verified against the root public key, as a signature over the report data.
- The MRENCLAVE value from the report, which is a hash over the enclave program, is matched to a reference we pass in
- The “userReportData”, which is set by the enclave when running, is also matched against a reference.
Note that the root of trust here starts with the manufacturer, and getting around that is out of scope for this article (although hopefully you can see how smart contracts would be useful for coordinating multiple enclaves).
The MRENCLAVE is the hash of the enclave program binary, analogous to how the address is a codehash over the contract bytecode. In this case the MRENCLAVE refers to the dummy attestation enclave explained in a moment, which is e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb.
Checking the signatures relies primarily on verifying an RSA signature. These have already been implemented in solidity, so these are through imports from dnssec-oracle.
Dummy Attestation service in SGX/Gramine/Python:
Let’s look at the enclave that generated these attestations. I defined a dummy enclave that generates remote attestations for any userReportData chosen by the user. It attests to anything! But it has to run on a valid SGX machine.
To make it as conceptually simple as possible, the dummy attester enclave is implemented in python using Gramine:
- It reads a 64 byte string from stdin.
- Writes this to the attestation interface /dev/attestation/user_report_data
- It reads a result from the interface /dev/attestation/quote.
- Return this quote.
Note that you can try reproducing the enclave binary, without having to have an SGX machine at all. The main limitation of this python/gramine approach is that it seems more likely to suffer reproducibility rot, as the particular python libraries packaged here may not remain identical when package maintainers update them. But maybe this can be mitigated. The README does list a particular mrenclave, so you can see if it remains reproducible using docker.
As a best effort service: for a little while following this post, I’ll provide this service that generates fresh attestations to play with on demand: http://dummyattest.ln.soc1024.com/9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000
(If the service goes down, it will remain possible to run your own enclave using the docker compose instructions)
Conclusion
This on-chain Solidity attestation checker in this example is just a starting point. It’s necessary but not sufficient. Any application or framework using remote attestation would need to add some more constraints to the verification. Most enclaves don’t get a straightforward “OK” but come with warnings - which configurations should we tolerate? Do we only care about a single program or a range of acceptable programs? The structure of the userReportData itself is also up to the application to define. And what about DCAP, as this demo appears to be EPID specific?
Answering any of these questions requires deeper understanding of SGX to solve… but, it may only require writing more Solidity code. The main takeaway from this demonstration is that verifying remote attestations is a naturally on-chain activity. The availability of Solidity libraries for verifying remote attestations now makes Solidity a very plausible way to define remote attestation policies.