Skip to content

Commit 293fac8

Browse files
authored
Merge pull request #31 from datachainlab/zkdcap
zkDCAP support Signed-off-by: Jun Kimura <[email protected]>
2 parents ad16a56 + 59851c5 commit 293fac8

30 files changed

+3148
-280
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Test
22
on: [pull_request]
33

44
env:
5-
SOLC_VERSION: 0.8.20
5+
SOLC_VERSION: 0.8.28
66

77
jobs:
88
contract-test:

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "lib/openzeppelin-foundry-upgrades"]
55
path = lib/openzeppelin-foundry-upgrades
66
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
7+
[submodule "lib/risc0-ethereum"]
8+
path = lib/risc0-ethereum
9+
url = https://github.com/risc0/risc0-ethereum

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
SOLC_VERSION=0.8.20
1+
SOLC_VERSION=0.8.28
22
FORGE=forge
33
SLITHER=slither
44
TEST_UPGRADEABLE=false

contracts/AVRValidator.sol

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {Base64} from "base64/base64.sol";
77
import {Asn1Decode, NodePtr} from "./Asn1Decode.sol";
88
import {LCPUtils} from "./LCPUtils.sol";
99
import {ILCPClientErrors} from "./ILCPClientErrors.sol";
10+
import {RemoteAttestation} from "./RemoteAttestation.sol";
1011

1112
/**
1213
* @dev AVRValidator provides the validation functions of Intel's Attestation Verification Report(AVR)
@@ -21,10 +22,6 @@ library AVRValidator {
2122
0x2a864886f70d01010b0000000000000000000000000000000000000000000000;
2223
// OID_RSA_ENCRYPTION is the OID of rsaEncryption(1.2.840.113549.1.1.1)
2324
bytes32 internal constant OID_RSA_ENCRYPTION = 0x2a864886f70d0101010000000000000000000000000000000000000000000000;
24-
// FLAG_DISALLOWED indicates that the advisory or quote status is not allowed.
25-
uint256 internal constant FLAG_DISALLOWED = 0;
26-
// FLAG_ALLOWED indicates that the advisory or quote status is allowed.
27-
uint256 internal constant FLAG_ALLOWED = 1;
2825
// '"'
2926
bytes32 internal constant CHAR_DOUBLE_QUOTE = bytes32(hex"22");
3027
// ','
@@ -50,13 +47,6 @@ library AVRValidator {
5047
uint256 notAfter; // seconds since epoch
5148
}
5249

53-
struct ReportAllowedStatus {
54-
// quote status => flag(0: not allowed, 1: allowed)
55-
mapping(string => uint256) allowedQuoteStatuses;
56-
// advisory id => flag(0: not allowed, 1: allowed)
57-
mapping(string => uint256) allowedAdvisories;
58-
}
59-
6050
// ------------------ Public functions ------------------
6151

6252
struct ReportExtractedElements {
@@ -70,7 +60,7 @@ library AVRValidator {
7060
bool developmentMode,
7161
AVRValidator.RSAParams storage verifiedRootCAParams,
7262
mapping(bytes32 => AVRValidator.RSAParams) storage verifiedSigningRSAParams,
73-
ReportAllowedStatus storage allowedStatuses,
63+
RemoteAttestation.ReportAllowedStatus storage allowedStatuses,
7464
bytes calldata report,
7565
bytes calldata signingCert,
7666
bytes calldata signature
@@ -174,7 +164,7 @@ library AVRValidator {
174164
function validateAndExtractElements(
175165
bool developmentMode,
176166
bytes calldata report,
177-
ReportAllowedStatus storage allowedStatus
167+
RemoteAttestation.ReportAllowedStatus storage allowedStatus
178168
) public view returns (ReportExtractedElements memory) {
179169
// find 'timestamp' key
180170
(uint256 i, bytes memory timestamp) = consumeTimestampReportJSON(report, 0);
@@ -190,7 +180,8 @@ library AVRValidator {
190180
// skip the validation for quote status and advisories if status is "OK"
191181
if (!(status.length == 2 && status[0] == 0x4f && status[1] == 0x4b)) {
192182
require(
193-
allowedStatus.allowedQuoteStatuses[string(status)] == FLAG_ALLOWED, "the quote status is not allowed"
183+
allowedStatus.allowedQuoteStatuses[string(status)] == RemoteAttestation.FLAG_ALLOWED,
184+
"the quote status is not allowed"
194185
);
195186
bytes32 h = keccak256(status);
196187
if (
@@ -263,13 +254,13 @@ library AVRValidator {
263254
}
264255
} else if (chr == CHAR_COMMA) {
265256
require(
266-
allowedAdvisories[string(report[lastStart:offset - 1])] == FLAG_ALLOWED,
257+
allowedAdvisories[string(report[lastStart:offset - 1])] == RemoteAttestation.FLAG_ALLOWED,
267258
"disallowed advisory is included"
268259
);
269260
} else if (chr == CHAR_LIST_END) {
270261
if (offset - lastStart > 0) {
271262
require(
272-
allowedAdvisories[string(report[lastStart:offset - 1])] == FLAG_ALLOWED,
263+
allowedAdvisories[string(report[lastStart:offset - 1])] == RemoteAttestation.FLAG_ALLOWED,
273264
"disallowed advisory is included"
274265
);
275266
}

contracts/DCAPValidator.sol

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.12;
3+
4+
library DCAPValidator {
5+
/// @notice The offset of the SGX quote body in the output bytes
6+
uint256 internal constant SGX_QUOTE_BODY_OFFSET = 67;
7+
/// @notice The offset of the attributes of the SGX quote body in the output bytes
8+
uint256 internal constant ATTRIBUTES_OFFSET = SGX_QUOTE_BODY_OFFSET + 16 + 4 + 28;
9+
/// @notice The offset of the MRENCLAVE of the SGX quote body in the output bytes
10+
uint256 internal constant MRENCLAVE_OFFSET = ATTRIBUTES_OFFSET + 16;
11+
/// @notice The end offset of the MRENCLAVE of the SGX quote body in the output bytes
12+
uint256 internal constant MRENCLAVE_END_OFFSET = MRENCLAVE_OFFSET + 32;
13+
/// @notice The offset of the report data of the SGX quote body in the output bytes
14+
uint256 internal constant REPORT_DATA_OFFSET = SGX_QUOTE_BODY_OFFSET + 320;
15+
/// @notice The offset of the enclave key in the report data of the SGX quote body in the output bytes
16+
uint256 internal constant REPORT_DATA_ENCLAVE_KEY_OFFSET = REPORT_DATA_OFFSET + 1;
17+
/// @notice The offset of the operator in the report data of the SGX quote body in the output bytes
18+
uint256 internal constant REPORT_DATA_OPERATOR_OFFSET = REPORT_DATA_ENCLAVE_KEY_OFFSET + 20;
19+
/// @notice The end offset of the operator in the report data of the SGX quote body in the output bytes
20+
uint256 internal constant REPORT_DATA_OPERATOR_END_OFFSET = REPORT_DATA_OPERATOR_OFFSET + 20;
21+
/// @notice The offset of the advisory IDs in the output bytes
22+
uint256 internal constant ADVISORY_IDS_OFFSET = REPORT_DATA_OFFSET + 64;
23+
24+
/// @notice The TCB status
25+
uint8 internal constant TCB_STATUS_UP_TO_DATE = 0;
26+
uint8 internal constant TCB_STATUS_OUT_OF_DATE = 1;
27+
uint8 internal constant TCB_STATUS_REVOKED = 2;
28+
uint8 internal constant TCB_STATUS_CONFIGURATION_NEEDED = 3;
29+
uint8 internal constant TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED = 4;
30+
uint8 internal constant TCB_STATUS_SW_HARDENING_NEEDED = 5;
31+
uint8 internal constant TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED = 6;
32+
33+
/// @notice The string representation of the TCB status
34+
string internal constant TCB_STATUS_UP_TO_DATE_STRING = "UpToDate";
35+
string internal constant TCB_STATUS_OUT_OF_DATE_STRING = "OutOfDate";
36+
string internal constant TCB_STATUS_REVOKED_STRING = "Revoked";
37+
string internal constant TCB_STATUS_CONFIGURATION_NEEDED_STRING = "ConfigurationNeeded";
38+
string internal constant TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED_STRING = "OutOfDateConfigurationNeeded";
39+
string internal constant TCB_STATUS_SW_HARDENING_NEEDED_STRING = "SWHardeningNeeded";
40+
string internal constant TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED_STRING =
41+
"ConfigurationAndSWHardeningNeeded";
42+
43+
/// @notice The keccak256 hash of the string representation of the TCB status
44+
bytes32 internal constant TCB_STATUS_UP_TO_DATE_KECCAK256_HASH = keccak256(bytes(TCB_STATUS_UP_TO_DATE_STRING));
45+
46+
/**
47+
* @notice The output of the quote verification
48+
* @dev This struct corresponds to `QuoteVerificationOutput` in the dcap-quote-verifier library.
49+
* Note that some fields from the original output are omitted or parsed in greater detail in Solidity for our use case.
50+
* ref. https://github.com/datachainlab/zkdcap/blob/9616d7976a84e97a128fa02175ec994b95e3c137/crates/quote-verifier/src/verifier.rs#L19
51+
*/
52+
struct Output {
53+
string tcbStatus;
54+
uint32 minTcbEvaluationDataNumber;
55+
bytes32 sgxIntelRootCAHash;
56+
uint64 validityNotBefore;
57+
uint64 validityNotAfter;
58+
bool enclaveDebugEnabled;
59+
bytes32 mrenclave;
60+
address enclaveKey;
61+
address operator;
62+
string[] advisoryIDs;
63+
}
64+
65+
/**
66+
* @notice Parse the output bytes from the quote verification
67+
* @param outputBytes The output bytes from the quote verification
68+
* @return output The parsed output
69+
*/
70+
function parseOutput(bytes calldata outputBytes) public pure returns (Output memory) {
71+
require(bytes2(outputBytes[0:2]) == hex"0000", "unexpected version");
72+
require(uint16(bytes2(outputBytes[2:4])) == 3, "unexpected quote version");
73+
require(uint32(bytes4(outputBytes[4:8])) == 0, "unexpected tee type");
74+
75+
Output memory output;
76+
output.tcbStatus = tcbStatusToString(uint8(outputBytes[8]));
77+
output.minTcbEvaluationDataNumber = uint32(bytes4(outputBytes[9:13]));
78+
output.sgxIntelRootCAHash = bytes32(outputBytes[19:51]);
79+
output.validityNotBefore = uint64(bytes8(outputBytes[51:59]));
80+
output.validityNotAfter = uint64(bytes8(outputBytes[59:67]));
81+
output.enclaveDebugEnabled = uint8(outputBytes[ATTRIBUTES_OFFSET]) & uint8(2) != 0;
82+
output.mrenclave = bytes32(outputBytes[MRENCLAVE_OFFSET:MRENCLAVE_END_OFFSET]);
83+
// The initial byte of the report data is the version of the report data
84+
require(outputBytes[REPORT_DATA_OFFSET] == 0x01, "unexpected report data version");
85+
output.enclaveKey = address(bytes20(outputBytes[REPORT_DATA_ENCLAVE_KEY_OFFSET:REPORT_DATA_OPERATOR_OFFSET]));
86+
output.operator = address(bytes20(outputBytes[REPORT_DATA_OPERATOR_OFFSET:REPORT_DATA_OPERATOR_END_OFFSET]));
87+
output.advisoryIDs = abi.decode(outputBytes[ADVISORY_IDS_OFFSET:outputBytes.length], (string[]));
88+
return output;
89+
}
90+
91+
/**
92+
* @notice Convert the TCB status to a string
93+
* @param tcbStatus The TCB status
94+
* @return The string representation of the TCB status
95+
*/
96+
function tcbStatusToString(uint8 tcbStatus) internal pure returns (string memory) {
97+
// The if-else chain is ordered based on the expected frequency of allowed TCB statuses
98+
// (most common statuses first), rather than the order of the enum definition.
99+
// This ordering may result in minor gas savings by reducing the average number of comparisons in common cases.
100+
if (tcbStatus == TCB_STATUS_UP_TO_DATE) {
101+
return TCB_STATUS_UP_TO_DATE_STRING;
102+
} else if (tcbStatus == TCB_STATUS_SW_HARDENING_NEEDED) {
103+
return TCB_STATUS_SW_HARDENING_NEEDED_STRING;
104+
} else if (tcbStatus == TCB_STATUS_CONFIGURATION_NEEDED) {
105+
return TCB_STATUS_CONFIGURATION_NEEDED_STRING;
106+
} else if (tcbStatus == TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED) {
107+
return TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED_STRING;
108+
} else if (tcbStatus == TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED) {
109+
return TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED_STRING;
110+
} else if (tcbStatus == TCB_STATUS_OUT_OF_DATE) {
111+
return TCB_STATUS_OUT_OF_DATE_STRING;
112+
} else if (tcbStatus == TCB_STATUS_REVOKED) {
113+
return TCB_STATUS_REVOKED_STRING;
114+
} else {
115+
revert("unexpected TCB status");
116+
}
117+
}
118+
}

contracts/ILCPClientErrors.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,22 @@ interface ILCPClientErrors {
5858

5959
error LCPClientUpdateOperatorsPermissionless();
6060
error LCPClientUpdateOperatorsSignatureUnexpectedOperator(address actual, address expected);
61+
62+
error LCPClientZKDCAPInvalidConstructorParams();
63+
error LCPClientZKDCAPOutputNotValid();
64+
error LCPClientZKDCAPUnrecognizedTCBStatus();
65+
error LCPClientZKDCAPCurrentTcbEvaluationDataNumberNotSet();
66+
error LCPClientZKDCAPInvalidNextTcbEvaluationDataNumberInfo();
67+
error LCPClientZKDCAPInvalidVerifierInfos();
68+
error LCPClientZKDCAPInvalidVerifierInfoLength();
69+
error LCPClientZKDCAPInvalidVerifierInfoZKVMType();
70+
error LCPClientZKDCAPUnsupportedZKVMType();
71+
error LCPClientZKDCAPRisc0ImageIdNotSet();
72+
error LCPClientZKDCAPUnexpectedIntelRootCAHash();
73+
error LCPClientZKDCAPOutputReportUnexpectedOperator(address actual, address expected);
74+
75+
error LCPClientZKDCAPDisallowedTCBStatus();
76+
error LCPClientZKDCAPDisallowedAdvisoryID();
77+
error LCPClientZKDCAPUnexpectedEnclaveDebugMode();
78+
error LCPClientZKDCAPUnexpectedTcbEvaluationDataNumber(uint64 currentTcbEvaluationDataNumber);
6179
}

0 commit comments

Comments
 (0)