Skip to content

Commit 8b8c595

Browse files
Clarify how to verify SGX evidence without an Intel SGX-enabled platform (#3158)
This PR encompasses two complementing purposes: A documentation on verifying an Intel SGX evidence as produced by WAMR, including a guide for verification without an Intel SGX-enabled platform. This also contains a small addition to the RA sample to extract specific information, such as whether the enclave is running in debug mode. A C# sample to verify evidence on trusted premises (and without Intel SGX). Evidence is generated on untrusted environments, using Intel SGX.
1 parent b6adec3 commit 8b8c595

File tree

8 files changed

+250
-8
lines changed

8 files changed

+250
-8
lines changed

core/iwasm/libraries/lib-rats/lib_rats_common.h

+16
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@
1515
extern "C" {
1616
#endif
1717

18+
/* Enclave Flags Bit Masks */
19+
/* If set, then the enclave is initialized */
20+
#define SGX_FLAGS_INITTED 0x001ULL
21+
/* If set, then the enclave is debug */
22+
#define SGX_FLAGS_DEBUG 0x002ULL
23+
/* If set, then the enclave is 64 bit */
24+
#define SGX_FLAGS_MODE64BIT 0x004ULL
25+
/* If set, then the enclave has access to provision key */
26+
#define SGX_FLAGS_PROVISION_KEY 0x010ULL
27+
/* If set, then the enclave has access to EINITTOKEN key */
28+
#define SGX_FLAGS_EINITTOKEN_KEY 0x020ULL
29+
/* If set, then the enclave uses KSS */
30+
#define SGX_FLAGS_KSS 0x080ULL
31+
/* If set, then the enclave enables AEX Notify */
32+
#define SGX_FLAGS_AEX_NOTIFY 0x400ULL
33+
1834
#define SGX_QUOTE_MAX_SIZE 8192
1935
#define SGX_USER_DATA_SIZE 64
2036
#define SGX_MEASUREMENT_SIZE 32

samples/sgx-ra/README.md

+72-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The following commands are an example of the SGX environment installation on Ubu
1818
# https://download.01.org/intel-sgx/latest/linux-latest/distro
1919
$ cd $HOME
2020
$ OS_PLATFORM=ubuntu20.04
21+
$ OS_CODE_NAME=`lsb_release -sc`
2122
$ SGX_PLATFORM=$OS_PLATFORM-server
2223
$ SGX_RELEASE_VERSION=1.17
2324
$ SGX_DRIVER_VERSION=1.41
@@ -39,7 +40,7 @@ $ chmod +x sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin
3940
$ sudo ./sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin --prefix /opt/intel
4041

4142
# install SGX DCAP Library
42-
$ echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main' | sudo tee /etc/apt/sources.list.d/intel-sgx.list
43+
$ echo "deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu $OS_CODE_NAME main" | sudo tee /etc/apt/sources.list.d/intel-sgx.list
4344
$ wget -O - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add
4445
$ sudo apt-get update
4546
$ sudo apt-get install -y libsgx-epid libsgx-quote-ex libsgx-dcap-ql libsgx-enclave-common-dev libsgx-dcap-ql-dev libsgx-dcap-default-qpl-dev libsgx-dcap-quote-verify-dev
@@ -86,9 +87,9 @@ Intel provides an implementation of the cache mechanism.
8687
The following commands set up Intel PCCS.
8788
```shell
8889
# install Node.js
90+
$ sudo apt install -y curl cracklib-runtime
8991
$ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs
9092
# install PCCS software
91-
$ sudo apt-get install -y cracklib-runtime
9293
$ sudo apt-get install -y sgx-dcap-pccs
9394
```
9495

@@ -140,7 +141,7 @@ Do you want to generate insecure HTTPS key and cert for PCCS service? [Y] (Y/N)
140141

141142
Answer "Y" to this question.
142143

143-
### Provisioning a system into Intel PCCS
144+
### Provisioning the current system's Intel SGX collateral into the PCCS
144145

145146
Now that the PCCS is up and running, it's time to provision an Intel SGX-enabled platform.
146147
We use the tool `PCKIDRetrievalTool` to get the attestation collateral of the current machine.
@@ -195,8 +196,75 @@ $ ./iwasm wasm-app/test.wasm
195196

196197
The sample will print the evidence in JSON and the message: *Evidence is trusted.*
197198

199+
In case of validation issues expressed as a value of `0xeXXX`, the corresponding error reason is explained in [this header file](https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/master/QuoteGeneration/quote_wrapper/common/inc/sgx_ql_lib_common.h).
200+
201+
## Validate quotes on non-SGX platforms
202+
Quotes created on an Intel SGX platform can also be verified on systems that do not support SGX (e.g., a different CPU architecture).
203+
This scenario typically arises when deploying trusted applications in a cloud environment, which provides confidential computing.
204+
205+
For that purpose, we are required to install a subset of Intel SGX libraries to support quote validation.
206+
The steps below highlight how to set up such an environment.
207+
208+
209+
### Intel SGX dependencies
210+
```shell
211+
$ OS_CODE_NAME=`lsb_release -sc`
212+
# install SGX DCAP Library
213+
$ echo "deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu $OS_CODE_NAME main" | sudo tee /etc/apt/sources.list.d/intel-sgx.list
214+
$ wget -O - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add
215+
$ sudo apt-get update
216+
$ sudo apt-get install -y libsgx-quote-ex libsgx-dcap-ql libsgx-dcap-quote-verify libsgx-dcap-default-qpl
217+
```
218+
219+
### Set up the Intel Provisioning Certification Caching Service (Intel PCCS)
220+
Follow the steps described in the section _Set up the Intel Provisioning Certification Caching Service (Intel PCCS)_.
221+
222+
### Runtime configuration
223+
Follow the steps described in the section _Runtime configuration_.
224+
225+
### Provisioning all the Intel SGX collateral into the PCCS
226+
We must finally fetch and configure the SGX collaterals into the PCCS for all the SGX-enabled CPUs.
227+
228+
```shell
229+
# Set up the Intel PCCS administration tool
230+
$ git clone https://github.com/intel/SGXDataCenterAttestationPrimitives.git
231+
$ cd SGXDataCenterAttestationPrimitives/tools/PccsAdminTool
232+
$ sudo apt-get install -y python3 python3-pip
233+
$ pip3 install -r requirements.txt
234+
235+
# Configuring the Intel PCCS. Input the PCS/PCCS password as requested.
236+
# 1. Get registration data from PCCS service
237+
./pccsadmin.py get
238+
# 2. Fetch platform collateral data from Intel PCS based on the registration data
239+
./pccsadmin.py fetch
240+
# 3. Put platform collateral data or appraisal policy files to PCCS cache db
241+
./pccsadmin.py put
242+
# 4. Request PCCS to refresh certificates or collateral in cache database
243+
./pccsadmin.py refresh
244+
```
245+
246+
### Validation of the quotes
247+
The Wasm application can then be modified to validate precomputed quotes using the exposed function `librats_verify`.
248+
249+
Alternatively, the underlying library `librats` may be directly used if the non-SGX platforms do not execute WebAssembly code (without WAMR).
250+
Examples are provided in the directory [non-sgx-verify/](non-sgx-verify/).
251+
252+
### Claims validation
253+
Once the runtime has validated the signature of the quote, the application must also check the other claims embedded in the quote to ensure they match their expected value.
254+
255+
The documentation _Data Center Attestation Primitives: Library API_ describes in Section _3.8 Enclave Identity Checking_ defines the claims for the user to check.
256+
Here is a summary of them:
257+
258+
- **Enclave Identity Checking**: either check the hash _MRENCLAVE_ (the enclave identity) or _MRSIGNER_ and the _product id_ (the software provider identity).
259+
- **Verify Attributes**: production enclaves should not have the _Debug_ flag set to 1.
260+
- **Verify SSA Frame extended feature set**
261+
- **Verify the ISV_SVN level of the enclave**: whenever there is a security update to an enclave, the ISV_SVN value should be increased to reflect the higher security level.
262+
- **Verify that the ReportData contains the expected value**: This can be used to provide specific data from the enclave or it can be used to hold a hash of a larger block of data which is provided with the quote. Note that the verification of the quote signature confirms the integrity of the report data (and the rest of the REPORT body).
263+
264+
198265
## Further readings
199266

200267
- [Intel SGX Software Installation Guide For Linux OS](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_SW_Installation_Guide_for_Linux.pdf)
201-
- [Intel Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: Library API ](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_ECDSA_QuoteLibReference_DCAP_API.pdf)
268+
- [Intel Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: Library API](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_ECDSA_QuoteLibReference_DCAP_API.pdf)
202269
- [Remote Attestation for Multi-Package Platforms using Intel SGX Datacenter Attestation Primitives (DCAP)](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_DCAP_Multipackage_SW.pdf)
270+
- [Documentation of the PCCS administration tool](https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/master/tools/PccsAdminTool/README.txt)
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Examples of evidence verification without Intel SGX
2+
Intel SGX evidence generated using WAMR can be validated on trusted plaforms without Intel SGX, or an Intel processors.
3+
4+
## Using C#
5+
The sample [csharp/](csharp/) demonstrates such validation using C# as a managed language.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea/
2+
bin/
3+
obj/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation.
3+
* Copyright (C) 2024 University of Neuchatel, Switzerland.
4+
*
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
using System.Diagnostics;
9+
using System.Runtime.InteropServices;
10+
using System.Security.Cryptography;
11+
using System.Text;
12+
using System.Text.Json;
13+
14+
// Set the reference values below
15+
byte[] mrEnclaveReference =
16+
{
17+
0xDA, 0xE0, 0xDA, 0x2F, 0x8A, 0x53, 0xA0, 0xB4, 0x8F, 0x92, 0x6A, 0x3B, 0xC0, 0x48, 0xD6, 0xA9,
18+
0x67, 0xD4, 0x7C, 0x86, 0x19, 0x86, 0x76, 0x6F, 0x8F, 0x5A, 0xB1, 0xC0, 0xA8, 0xD8, 0x8E, 0x44
19+
};
20+
byte[] mrSignerReference =
21+
{
22+
0x83, 0xD7, 0x19, 0xE7, 0x7D, 0xEA, 0xCA, 0x14, 0x70, 0xF6, 0xBA, 0xF6, 0x2A, 0x4D, 0x77, 0x43,
23+
0x03, 0xC8, 0x99, 0xDB, 0x69, 0x02, 0x0F, 0x9C, 0x70, 0xEE, 0x1D, 0xFC, 0x08, 0xC7, 0xCE, 0x9E
24+
};
25+
const ushort securityVersionReference = 0;
26+
const ushort productIdReference = 0;
27+
string nonce = "This is a sample.\0"; // Notice the \0 at the end, which is mandatory as C-strings are terminated with this char
28+
string evidenceAsString = """{"type":"sgx_ecdsa","report_base64":"[..]","report_len":[..]}""";
29+
string wasmFilePath = "../build/wasm-app/test.wasm";
30+
31+
// Parse and compute the claims
32+
EvidenceJson? evidenceAsJson = JsonSerializer.Deserialize<EvidenceJson>(evidenceAsString, new JsonSerializerOptions
33+
{
34+
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
35+
});
36+
Debug.Assert(evidenceAsJson != null, "The evidence cannot be parsed.");
37+
38+
byte[] wasmFileContent = await File.ReadAllBytesAsync(wasmFilePath);
39+
byte[] nonceAsBytes = Encoding.UTF8.GetBytes(nonce);
40+
byte[] computedUserData = await ComputeUserData(wasmFileContent, nonceAsBytes);
41+
byte[] evidenceAsBytes = Convert.FromBase64String(evidenceAsJson.ReportBase64);
42+
Evidence evidence = new(evidenceAsBytes);
43+
int libRatsReturnValue = LibRats.VerifyEvidenceFromJson(evidenceAsString, await ComputeUserData(wasmFileContent, nonceAsBytes));
44+
45+
// Compare and display the results
46+
Console.WriteLine($"User data, evidence: {BitConverter.ToString(evidence.UserData)}");
47+
Console.WriteLine($"User Data, computed: {BitConverter.ToString(computedUserData)}");
48+
Console.WriteLine($"Do the two user data match? {evidence.UserData.SequenceEqual(computedUserData)}");
49+
Console.WriteLine($"MrEnclave: {BitConverter.ToString(evidence.MrEnclave)}");
50+
Console.WriteLine($"Do the MrEnclave match? {mrEnclaveReference.SequenceEqual(evidence.MrEnclave)}");
51+
Console.WriteLine($"MrSigner: {BitConverter.ToString(evidence.MrSigner)}");
52+
Console.WriteLine($"Do the MrSigner match? {mrSignerReference.SequenceEqual(evidence.MrSigner)}");
53+
Console.WriteLine($"Security Version: {evidence.SecurityVersion}, expected: {securityVersionReference}");
54+
Console.WriteLine($"Product ID: {evidence.ProductId}, expected: {productIdReference}");
55+
Console.WriteLine($"VerifyJsonUsingLibrats returned: {libRatsReturnValue:X}");
56+
57+
// Compute the user data as computed by WAMR
58+
static async ValueTask<byte[]> ComputeUserData(byte[] wasmFileContent, byte[] nonce)
59+
{
60+
using var sha256 = SHA256.Create();
61+
var wasmFileContentHash = sha256.ComputeHash(wasmFileContent);
62+
63+
using MemoryStream stream = new();
64+
await stream.WriteAsync(wasmFileContentHash);
65+
await stream.WriteAsync(nonce);
66+
stream.Position = 0;
67+
68+
byte[] computedUserData = await sha256.ComputeHashAsync(stream);
69+
return computedUserData;
70+
}
71+
72+
/// <summary>
73+
/// The layout of the JSON is given by librats.
74+
/// </summary>
75+
class EvidenceJson
76+
{
77+
public required string Type { get; init; }
78+
public required string ReportBase64 { get; init; }
79+
public required int ReportLen { get; init; }
80+
}
81+
82+
/// <summary>
83+
/// The start of the _report_body_t struct from Intel SGX is at offset 0x30.
84+
/// </summary>
85+
/// <remarks>
86+
/// _report_body_t struct: https://github.com/intel/linux-sgx/blob/a1eeccba5a72b3b9b342569d2cc469ece106d3e9/common/inc/sgx_report.h#L93-L111
87+
/// Attestation flow: https://www.intel.com/content/www/us/en/developer/articles/code-sample/software-guard-extensions-remote-attestation-end-to-end-example.html
88+
/// </remarks>
89+
class Evidence(byte[] evidenceAsBytes)
90+
{
91+
public byte[] MrEnclave => evidenceAsBytes[0x70..0x90];
92+
public byte[] MrSigner => evidenceAsBytes[0xB0..0xD0];
93+
public ushort ProductId => BitConverter.ToUInt16(evidenceAsBytes.AsSpan(0x130, 2));
94+
public ushort SecurityVersion => BitConverter.ToUInt16(evidenceAsBytes.AsSpan(0x132, 2));
95+
public byte[] UserData => evidenceAsBytes[0x170..0x190];
96+
}
97+
98+
static class LibRats
99+
{
100+
/// <summary>
101+
/// Verifies the evidence using librats native function.
102+
/// </summary>
103+
/// <remarks>
104+
/// Original signature: int librats_verify_evidence_from_json(const char *json_string, const uint8_t *hash);
105+
/// </remarks>
106+
[DllImport("/usr/local/lib/librats/librats_lib.so", EntryPoint = "librats_verify_evidence_from_json")]
107+
public static extern int VerifyEvidenceFromJson(string json, byte[] hash);
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Examples of evidence verification without Intel SGX using C#
2+
This sample demonstrates how to validate WAMR-generated evidence without using an Intel SGX-enabled platform.
3+
A typical use case is a Web service hosted on trusted premises.
4+
5+
## Prerequisites
6+
- [dotnet-sdk](https://learn.microsoft.com/en-us/dotnet/core/install/linux) (8+)
7+
- [librats](https://github.com/inclavare-containers/librats)
8+
- Intel infrastructure for validating evidence, [see here](../../README.md#validate-quotes-on-non-sgx-platforms)
9+
10+
This sample has been tested on Linux Ubuntu 20.04+.
11+
Any other Linux platforms should be supported.
12+
This sample should also work on other OS, provided librats can be compiled on those other OS.
13+
14+
## How to use
15+
- Supply the reference values to consider trustworthy in [Program.cs](Program.cs#L15-L27).
16+
- Generate a valid JSON evidence using WAMR on an Intel SGX-enabled platform.
17+
- Fill in the JSON evidence in [Program.cs](Program.cs#L28).
18+
- Run the command `dotnet run` in this directory.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

samples/sgx-ra/wasm-app/main.c

+18-4
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,24 @@ main(int argc, char **argv)
9090
hex_dump("User Data", evidence->user_data, SGX_USER_DATA_SIZE, 32);
9191
hex_dump("MRENCLAVE", evidence->mr_enclave, SGX_MEASUREMENT_SIZE, 32);
9292
hex_dump("MRSIGNER", evidence->mr_signer, SGX_MEASUREMENT_SIZE, 32);
93-
printf("\n\tProduct ID:\t\t%u\n", evidence->product_id);
94-
printf("\tSecurity Version:\t%u\n", evidence->security_version);
95-
printf("\tAttributes.flags:\t%llu\n", evidence->att_flags);
96-
printf("\tAttribute.xfrm:\t\t%llu\n", evidence->att_xfrm);
93+
printf("\n\tProduct ID:\t\t\t\t%u\n", evidence->product_id);
94+
printf("\tSecurity Version:\t\t\t%u\n", evidence->security_version);
95+
printf("\tAttributes.flags:\t\t\t%llu\n", evidence->att_flags);
96+
printf("\tAttributes.flags[INITTED]:\t\t%d\n",
97+
(evidence->att_flags & SGX_FLAGS_INITTED) != 0);
98+
printf("\tAttributes.flags[DEBUG]:\t\t%d\n",
99+
(evidence->att_flags & SGX_FLAGS_DEBUG) != 0);
100+
printf("\tAttributes.flags[MODE64BIT]:\t\t%d\n",
101+
(evidence->att_flags & SGX_FLAGS_MODE64BIT) != 0);
102+
printf("\tAttributes.flags[PROVISION_KEY]:\t%d\n",
103+
(evidence->att_flags & SGX_FLAGS_PROVISION_KEY) != 0);
104+
printf("\tAttributes.flags[EINITTOKEN_KEY]:\t%d\n",
105+
(evidence->att_flags & SGX_FLAGS_EINITTOKEN_KEY) != 0);
106+
printf("\tAttributes.flags[KSS]:\t\t\t%d\n",
107+
(evidence->att_flags & SGX_FLAGS_KSS) != 0);
108+
printf("\tAttributes.flags[AEX_NOTIFY]:\t\t%d\n",
109+
(evidence->att_flags & SGX_FLAGS_AEX_NOTIFY) != 0);
110+
printf("\tAttribute.xfrm:\t\t\t\t%llu\n", evidence->att_xfrm);
97111

98112
rats_err = librats_verify((const char *)evidence_json, evidence->user_data);
99113
if (rats_err != 0) {

0 commit comments

Comments
 (0)