Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Test
on: [pull_request]

env:
SOLC_VERSION: 0.8.20
SOLC_VERSION: 0.8.28

jobs:
contract-test:
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "lib/openzeppelin-foundry-upgrades"]
path = lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
[submodule "lib/risc0-ethereum"]
path = lib/risc0-ethereum
url = https://github.com/risc0/risc0-ethereum
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SOLC_VERSION=0.8.20
SOLC_VERSION=0.8.28
FORGE=forge
SLITHER=slither
TEST_UPGRADEABLE=false
Expand Down
23 changes: 7 additions & 16 deletions contracts/AVRValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Base64} from "base64/base64.sol";
import {Asn1Decode, NodePtr} from "./Asn1Decode.sol";
import {LCPUtils} from "./LCPUtils.sol";
import {ILCPClientErrors} from "./ILCPClientErrors.sol";
import {RemoteAttestation} from "./RemoteAttestation.sol";

/**
* @dev AVRValidator provides the validation functions of Intel's Attestation Verification Report(AVR)
Expand All @@ -21,10 +22,6 @@ library AVRValidator {
0x2a864886f70d01010b0000000000000000000000000000000000000000000000;
// OID_RSA_ENCRYPTION is the OID of rsaEncryption(1.2.840.113549.1.1.1)
bytes32 internal constant OID_RSA_ENCRYPTION = 0x2a864886f70d0101010000000000000000000000000000000000000000000000;
// FLAG_DISALLOWED indicates that the advisory or quote status is not allowed.
uint256 internal constant FLAG_DISALLOWED = 0;
// FLAG_ALLOWED indicates that the advisory or quote status is allowed.
uint256 internal constant FLAG_ALLOWED = 1;
// '"'
bytes32 internal constant CHAR_DOUBLE_QUOTE = bytes32(hex"22");
// ','
Expand All @@ -50,13 +47,6 @@ library AVRValidator {
uint256 notAfter; // seconds since epoch
}

struct ReportAllowedStatus {
// quote status => flag(0: not allowed, 1: allowed)
mapping(string => uint256) allowedQuoteStatuses;
// advisory id => flag(0: not allowed, 1: allowed)
mapping(string => uint256) allowedAdvisories;
}

// ------------------ Public functions ------------------

struct ReportExtractedElements {
Expand All @@ -70,7 +60,7 @@ library AVRValidator {
bool developmentMode,
AVRValidator.RSAParams storage verifiedRootCAParams,
mapping(bytes32 => AVRValidator.RSAParams) storage verifiedSigningRSAParams,
ReportAllowedStatus storage allowedStatuses,
RemoteAttestation.ReportAllowedStatus storage allowedStatuses,
bytes calldata report,
bytes calldata signingCert,
bytes calldata signature
Expand Down Expand Up @@ -174,7 +164,7 @@ library AVRValidator {
function validateAndExtractElements(
bool developmentMode,
bytes calldata report,
ReportAllowedStatus storage allowedStatus
RemoteAttestation.ReportAllowedStatus storage allowedStatus
) public view returns (ReportExtractedElements memory) {
// find 'timestamp' key
(uint256 i, bytes memory timestamp) = consumeTimestampReportJSON(report, 0);
Expand All @@ -190,7 +180,8 @@ library AVRValidator {
// skip the validation for quote status and advisories if status is "OK"
if (!(status.length == 2 && status[0] == 0x4f && status[1] == 0x4b)) {
require(
allowedStatus.allowedQuoteStatuses[string(status)] == FLAG_ALLOWED, "the quote status is not allowed"
allowedStatus.allowedQuoteStatuses[string(status)] == RemoteAttestation.FLAG_ALLOWED,
"the quote status is not allowed"
);
bytes32 h = keccak256(status);
if (
Expand Down Expand Up @@ -263,13 +254,13 @@ library AVRValidator {
}
} else if (chr == CHAR_COMMA) {
require(
allowedAdvisories[string(report[lastStart:offset - 1])] == FLAG_ALLOWED,
allowedAdvisories[string(report[lastStart:offset - 1])] == RemoteAttestation.FLAG_ALLOWED,
"disallowed advisory is included"
);
} else if (chr == CHAR_LIST_END) {
if (offset - lastStart > 0) {
require(
allowedAdvisories[string(report[lastStart:offset - 1])] == FLAG_ALLOWED,
allowedAdvisories[string(report[lastStart:offset - 1])] == RemoteAttestation.FLAG_ALLOWED,
"disallowed advisory is included"
);
}
Expand Down
118 changes: 118 additions & 0 deletions contracts/DCAPValidator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.12;

library DCAPValidator {
/// @notice The offset of the SGX quote body in the output bytes
uint256 internal constant SGX_QUOTE_BODY_OFFSET = 67;
/// @notice The offset of the attributes of the SGX quote body in the output bytes
uint256 internal constant ATTRIBUTES_OFFSET = SGX_QUOTE_BODY_OFFSET + 16 + 4 + 28;
/// @notice The offset of the MRENCLAVE of the SGX quote body in the output bytes
uint256 internal constant MRENCLAVE_OFFSET = ATTRIBUTES_OFFSET + 16;
/// @notice The end offset of the MRENCLAVE of the SGX quote body in the output bytes
uint256 internal constant MRENCLAVE_END_OFFSET = MRENCLAVE_OFFSET + 32;
/// @notice The offset of the report data of the SGX quote body in the output bytes
uint256 internal constant REPORT_DATA_OFFSET = SGX_QUOTE_BODY_OFFSET + 320;
/// @notice The offset of the enclave key in the report data of the SGX quote body in the output bytes
uint256 internal constant REPORT_DATA_ENCLAVE_KEY_OFFSET = REPORT_DATA_OFFSET + 1;
/// @notice The offset of the operator in the report data of the SGX quote body in the output bytes
uint256 internal constant REPORT_DATA_OPERATOR_OFFSET = REPORT_DATA_ENCLAVE_KEY_OFFSET + 20;
/// @notice The end offset of the operator in the report data of the SGX quote body in the output bytes
uint256 internal constant REPORT_DATA_OPERATOR_END_OFFSET = REPORT_DATA_OPERATOR_OFFSET + 20;
/// @notice The offset of the advisory IDs in the output bytes
uint256 internal constant ADVISORY_IDS_OFFSET = REPORT_DATA_OFFSET + 64;

/// @notice The TCB status
uint8 internal constant TCB_STATUS_UP_TO_DATE = 0;
uint8 internal constant TCB_STATUS_OUT_OF_DATE = 1;
uint8 internal constant TCB_STATUS_REVOKED = 2;
uint8 internal constant TCB_STATUS_CONFIGURATION_NEEDED = 3;
uint8 internal constant TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED = 4;
uint8 internal constant TCB_STATUS_SW_HARDENING_NEEDED = 5;
uint8 internal constant TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED = 6;

/// @notice The string representation of the TCB status
string internal constant TCB_STATUS_UP_TO_DATE_STRING = "UpToDate";
string internal constant TCB_STATUS_OUT_OF_DATE_STRING = "OutOfDate";
string internal constant TCB_STATUS_REVOKED_STRING = "Revoked";
string internal constant TCB_STATUS_CONFIGURATION_NEEDED_STRING = "ConfigurationNeeded";
string internal constant TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED_STRING = "OutOfDateConfigurationNeeded";
string internal constant TCB_STATUS_SW_HARDENING_NEEDED_STRING = "SWHardeningNeeded";
string internal constant TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED_STRING =
"ConfigurationAndSWHardeningNeeded";

/// @notice The keccak256 hash of the string representation of the TCB status
bytes32 internal constant TCB_STATUS_UP_TO_DATE_KECCAK256_HASH = keccak256(bytes(TCB_STATUS_UP_TO_DATE_STRING));

/**
* @notice The output of the quote verification
* @dev This struct corresponds to `QuoteVerificationOutput` in the dcap-quote-verifier library.
* Note that some fields from the original output are omitted or parsed in greater detail in Solidity for our use case.
* ref. https://github.com/datachainlab/zkdcap/blob/9616d7976a84e97a128fa02175ec994b95e3c137/crates/quote-verifier/src/verifier.rs#L19
*/
struct Output {
string tcbStatus;
uint32 minTcbEvaluationDataNumber;
bytes32 sgxIntelRootCAHash;
uint64 validityNotBefore;
uint64 validityNotAfter;
bool enclaveDebugEnabled;
bytes32 mrenclave;
address enclaveKey;
address operator;
string[] advisoryIDs;
}

/**
* @notice Parse the output bytes from the quote verification
* @param outputBytes The output bytes from the quote verification
* @return output The parsed output
*/
function parseOutput(bytes calldata outputBytes) public pure returns (Output memory) {
require(bytes2(outputBytes[0:2]) == hex"0000", "unexpected version");
require(uint16(bytes2(outputBytes[2:4])) == 3, "unexpected quote version");
require(uint32(bytes4(outputBytes[4:8])) == 0, "unexpected tee type");

Output memory output;
output.tcbStatus = tcbStatusToString(uint8(outputBytes[8]));
output.minTcbEvaluationDataNumber = uint32(bytes4(outputBytes[9:13]));
output.sgxIntelRootCAHash = bytes32(outputBytes[19:51]);
output.validityNotBefore = uint64(bytes8(outputBytes[51:59]));
output.validityNotAfter = uint64(bytes8(outputBytes[59:67]));
output.enclaveDebugEnabled = uint8(outputBytes[ATTRIBUTES_OFFSET]) & uint8(2) != 0;
output.mrenclave = bytes32(outputBytes[MRENCLAVE_OFFSET:MRENCLAVE_END_OFFSET]);
// The initial byte of the report data is the version of the report data
require(outputBytes[REPORT_DATA_OFFSET] == 0x01, "unexpected report data version");
output.enclaveKey = address(bytes20(outputBytes[REPORT_DATA_ENCLAVE_KEY_OFFSET:REPORT_DATA_OPERATOR_OFFSET]));
output.operator = address(bytes20(outputBytes[REPORT_DATA_OPERATOR_OFFSET:REPORT_DATA_OPERATOR_END_OFFSET]));
output.advisoryIDs = abi.decode(outputBytes[ADVISORY_IDS_OFFSET:outputBytes.length], (string[]));
return output;
}

/**
* @notice Convert the TCB status to a string
* @param tcbStatus The TCB status
* @return The string representation of the TCB status
*/
function tcbStatusToString(uint8 tcbStatus) internal pure returns (string memory) {
// The if-else chain is ordered based on the expected frequency of allowed TCB statuses
// (most common statuses first), rather than the order of the enum definition.
// This ordering may result in minor gas savings by reducing the average number of comparisons in common cases.
if (tcbStatus == TCB_STATUS_UP_TO_DATE) {
return TCB_STATUS_UP_TO_DATE_STRING;
} else if (tcbStatus == TCB_STATUS_SW_HARDENING_NEEDED) {
return TCB_STATUS_SW_HARDENING_NEEDED_STRING;
} else if (tcbStatus == TCB_STATUS_CONFIGURATION_NEEDED) {
return TCB_STATUS_CONFIGURATION_NEEDED_STRING;
} else if (tcbStatus == TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED) {
return TCB_STATUS_CONFIGURATION_AND_SW_HARDENING_NEEDED_STRING;
} else if (tcbStatus == TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED) {
return TCB_STATUS_OUT_OF_DATE_CONFIGURATION_NEEDED_STRING;
} else if (tcbStatus == TCB_STATUS_OUT_OF_DATE) {
return TCB_STATUS_OUT_OF_DATE_STRING;
} else if (tcbStatus == TCB_STATUS_REVOKED) {
return TCB_STATUS_REVOKED_STRING;
} else {
revert("unexpected TCB status");
}
}
}
18 changes: 18 additions & 0 deletions contracts/ILCPClientErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,22 @@ interface ILCPClientErrors {

error LCPClientUpdateOperatorsPermissionless();
error LCPClientUpdateOperatorsSignatureUnexpectedOperator(address actual, address expected);

error LCPClientZKDCAPInvalidConstructorParams();
error LCPClientZKDCAPOutputNotValid();
error LCPClientZKDCAPUnrecognizedTCBStatus();
error LCPClientZKDCAPCurrentTcbEvaluationDataNumberNotSet();
error LCPClientZKDCAPInvalidNextTcbEvaluationDataNumberInfo();
error LCPClientZKDCAPInvalidVerifierInfos();
error LCPClientZKDCAPInvalidVerifierInfoLength();
error LCPClientZKDCAPInvalidVerifierInfoZKVMType();
error LCPClientZKDCAPUnsupportedZKVMType();
error LCPClientZKDCAPRisc0ImageIdNotSet();
error LCPClientZKDCAPUnexpectedIntelRootCAHash();
error LCPClientZKDCAPOutputReportUnexpectedOperator(address actual, address expected);

error LCPClientZKDCAPDisallowedTCBStatus();
error LCPClientZKDCAPDisallowedAdvisoryID();
error LCPClientZKDCAPUnexpectedEnclaveDebugMode();
error LCPClientZKDCAPUnexpectedTcbEvaluationDataNumber(uint64 currentTcbEvaluationDataNumber);
}
Loading
Loading