|
| 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 | +} |
0 commit comments