@inco/lightning 0.2.16 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/manifest.yaml +29 -0
  2. package/package.json +5 -1
  3. package/src/DeployTEE.sol +153 -0
  4. package/src/DeployUtils.sol +17 -9
  5. package/src/Errors.sol +4 -0
  6. package/src/IncoLightning.gen.sol +1 -1
  7. package/src/IncoLightning.sol +2 -1
  8. package/src/Types.sol +45 -3
  9. package/src/lightning-parts/EncryptedInput.gen.sol +1 -0
  10. package/src/lightning-parts/EncryptedInput.sol +1 -1
  11. package/src/lightning-parts/EncryptedOperations.gen.sol +1 -1
  12. package/src/lightning-parts/EncryptedOperations.sol +8 -6
  13. package/src/lightning-parts/TEELifecycle.gen.sol +58 -0
  14. package/src/lightning-parts/TEELifecycle.sol +255 -0
  15. package/src/lightning-parts/TEELifecycle.types.sol +21 -0
  16. package/src/lightning-parts/primitives/SignatureVerifier.gen.sol +1 -0
  17. package/src/lightning-parts/primitives/SignatureVerifier.sol +11 -0
  18. package/src/lightning-parts/test/HandleMetadata.t.sol +1 -1
  19. package/src/test/FakeIncoInfra/FakeQuoteVerifier.sol +29 -0
  20. package/src/test/FakeIncoInfra/MockRemoteAttestation.sol +37 -0
  21. package/src/test/FibonacciDecrypt.sol +1 -0
  22. package/src/test/IncoTest.sol +5 -1
  23. package/src/test/TEELifecycle/README.md +53 -0
  24. package/src/test/TEELifecycle/TEELifecycleHWTest.t.sol +119 -0
  25. package/src/test/TEELifecycle/TEELifecycleMockTest.t.sol +145 -0
  26. package/src/test/TEELifecycle/addnode_data/eoa.txt +1 -0
  27. package/src/test/TEELifecycle/addnode_data/quote.bin +0 -0
  28. package/src/test/TEELifecycle/bootstrap_data/ecies_pubkey.bin +1 -0
  29. package/src/test/TEELifecycle/bootstrap_data/eip712_signature.bin +1 -0
  30. package/src/test/TEELifecycle/bootstrap_data/eoa.txt +1 -0
  31. package/src/test/TEELifecycle/bootstrap_data/qe_identity +1 -0
  32. package/src/test/TEELifecycle/bootstrap_data/qe_identity_signature.bin +1 -0
  33. package/src/test/TEELifecycle/bootstrap_data/quote.bin +0 -0
  34. package/src/test/TEELifecycle/bootstrap_data/tcb_info +1 -0
  35. package/src/test/TEELifecycle/bootstrap_data/tcb_info_signature.bin +1 -0
  36. package/src/test/TEELifecycle/test_cert/AttestationReportSigningCA.crl +0 -0
  37. package/src/test/TEELifecycle/test_cert/Intel_SGX_Attestation_RootCA.cer +0 -0
  38. package/src/test/TEELifecycle/test_cert/Intel_SGX_PCK_CRL.crl +0 -0
  39. package/src/test/TEELifecycle/test_cert/Intel_SGX_PCK_PlatformCA.cer +0 -0
  40. package/src/test/TEELifecycle/test_cert/Intel_SGX_TCB_Signing.cer +0 -0
  41. package/src/test/TestFakeInfra.t.sol +18 -1
  42. package/src/test/TestUpgrade.t.sol +314 -0
@@ -0,0 +1,255 @@
1
+ /// SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8.19;
3
+
4
+ import "./TEELifecycle.types.sol";
5
+
6
+ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
7
+ import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
8
+ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
9
+ import {IQuoteVerifier} from "automata-dcap-attestation/interfaces/IQuoteVerifier.sol";
10
+ import {BELE} from "automata-dcap-attestation/utils/BELE.sol";
11
+ import {HEADER_LENGTH} from "automata-dcap-attestation/types/Constants.sol";
12
+ import {TD10ReportBody, Header} from "automata-dcap-attestation/types/V4Structs.sol";
13
+ import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
14
+ import {EnclaveIdentityJsonObj, IdentityObj} from "@automata-network/on-chain-pccs/helpers/EnclaveIdentityHelper.sol";
15
+ import {TcbInfoJsonObj} from "@automata-network/on-chain-pccs/helpers/FmspcTcbHelper.sol";
16
+ import {AutomataFmspcTcbDao} from "@automata-network/on-chain-pccs/automata_pccs/AutomataFmspcTcbDao.sol";
17
+ import {AutomataEnclaveIdentityDao} from "@automata-network/on-chain-pccs/automata_pccs/AutomataEnclaveIdentityDao.sol";
18
+
19
+ // @todo: Make this contract UUPSUpgradeable: https://github.com/Inco-fhevm/inco-monorepo/issues/875
20
+ contract TEELifecycle is OwnableUpgradeable, EIP712Upgradeable {
21
+
22
+ event QuoteVerifierUpdated(uint16 indexed version);
23
+
24
+ event BootstrapStageComplete(
25
+ address indexed newEOASigner,
26
+ BootstrapResult bootstrapResult
27
+ );
28
+
29
+ event TEEVersionUpdated(
30
+ TEEVersion teeVersion
31
+ );
32
+
33
+ event NewCovalidatorAdded(
34
+ address covalidatorAddress,
35
+ bytes quote
36
+ );
37
+
38
+ bytes32 public constant BootstrapResultStructHash =
39
+ keccak256(bytes(
40
+ "BootstrapResult(bytes ecies_pubkey)"
41
+ ));
42
+
43
+ uint16 public constant QUOTE_VERIFIER_VERSION = 4;
44
+
45
+ IQuoteVerifier quoteVerifier;
46
+
47
+ BootstrapResult public VerifiedBootstrapResult;
48
+
49
+ TEEVersion[] public TEEVersionHistory;
50
+ bytes public ECIESPubkey;
51
+ mapping(address => bool) public EOASigners;
52
+
53
+ function initialize(address owner, string memory eip712Name, string memory eip712Version, address quoteVerifierAddress) public initializer {
54
+ __Ownable_init(owner);
55
+ __EIP712_init(eip712Name, eip712Version);
56
+ quoteVerifier = IQuoteVerifier(quoteVerifierAddress);
57
+ require(quoteVerifier.quoteVersion() == QUOTE_VERIFIER_VERSION, "Invalid quote verifier version");
58
+ }
59
+
60
+ /**
61
+ * @notice Uploads the collateral to the contract
62
+ * @param tcbInfo - The TCB info to upload
63
+ * @param identity - The identity to upload
64
+ */
65
+ function uploadCollateral(TcbInfoJsonObj memory tcbInfo, EnclaveIdentityJsonObj memory identity) public onlyOwner {
66
+ require(bytes(tcbInfo.tcbInfoStr).length != 0, "tcbInfo.tcbInfoStr must not be empty");
67
+ require(bytes(identity.identityStr).length != 0, "identity.identityStr must not be empty");
68
+
69
+ AutomataFmspcTcbDao fmspcTcbDao = AutomataFmspcTcbDao(quoteVerifier.pccsRouter().fmspcTcbDaoAddr());
70
+ fmspcTcbDao.upsertFmspcTcb(tcbInfo);
71
+ AutomataEnclaveIdentityDao enclaveIdDao = AutomataEnclaveIdentityDao(quoteVerifier.pccsRouter().qeIdDaoAddr());
72
+ (IdentityObj memory identityObj,) = enclaveIdDao.EnclaveIdentityLib().parseIdentityString(identity.identityStr);
73
+ enclaveIdDao.upsertEnclaveIdentity(uint256(identityObj.id), 4, identity);
74
+ }
75
+
76
+ /**
77
+ * @notice Verifies the bootstrap data against the provided quote and signature
78
+ * @param bootstrapResult - The bootstrap data to verify
79
+ * @param quote - The quote to verify against
80
+ * @param signature - The signature to verify against
81
+ */
82
+ function verifyBootstrapResult(BootstrapResult calldata bootstrapResult, bytes calldata quote, bytes calldata signature) public onlyOwner {
83
+ // Make sure the bootstrap is not already complete, and that the contract owner
84
+ // has already submitted the pending TEE MRTD.
85
+ require(!isBootstrapComplete(), "Bootstrap already completed");
86
+ require(TEEVersionHistory.length == 1, "TEEVersionHistory must have exactly one version, please call approveNewTEEVersion first");
87
+ require(TEEVersionHistory[0].status == TEEVersionStatus.PENDING, "TEEVersionHistory must still be pending");
88
+
89
+ bytes32 _bootstrapResultDigest = bootstrapResultDigest(bootstrapResult);
90
+ (bool success, bytes memory output) = _verifyAndAttestOnChain(quote);
91
+ require(success, string(output));
92
+
93
+ bytes memory v0MRTD = TEEVersionHistory[0].mrtd;
94
+
95
+ TD10ReportBody memory tdReport = parseTD10ReportBody(quote);
96
+ (address reportDataSigner, bytes memory reportMRTD) = parseReport(tdReport);
97
+ require(keccak256(reportMRTD) == keccak256(v0MRTD), "Invalid report MRTD");
98
+ address recoveredAddress = ECDSA.recover(_bootstrapResultDigest, signature);
99
+ require(recoveredAddress == reportDataSigner, "Invalid signature for bootstrap data");
100
+
101
+ VerifiedBootstrapResult = bootstrapResult;
102
+ TEEVersionHistory[0].status = TEEVersionStatus.ACTIVE;
103
+ emit BootstrapStageComplete(reportDataSigner, bootstrapResult);
104
+ ECIESPubkey = bootstrapResult.ecies_pubkey;
105
+ EOASigners[reportDataSigner] = true;
106
+ //TODO: update ECIES public key to ?? contract state and EOA addresses signers to the Signers contract state
107
+ }
108
+
109
+ /**
110
+ * @notice Approves a new TEE version and updates the TEEVersionHistory
111
+ * @param newMRTD - The MRTD bytes of the new TEE version
112
+ * @dev This function increments the version number automatically based on the current history
113
+ */
114
+ function approveNewTEEVersion(bytes calldata newMRTD) public onlyOwner {
115
+ require(newMRTD.length == 48, "MRTD must be 48 bytes");
116
+
117
+ TEEVersionHistory.push(TEEVersion({
118
+ mrtd: newMRTD,
119
+ status: TEEVersionStatus.PENDING
120
+ }));
121
+
122
+ emit TEEVersionUpdated(TEEVersionHistory[TEEVersionHistory.length - 1]);
123
+ }
124
+
125
+ /**
126
+ * @notice Adds a new covalidator to the contract state
127
+ * @param quote - The quote from the new covalidator that contains the current MRTD and the eoa address of the new party in the report data
128
+ */
129
+ function addNewCovalidator(bytes calldata quote) public onlyOwner {
130
+ require(isBootstrapComplete(), "Bootstrap not complete");
131
+
132
+ (bool success, bytes memory output) = _verifyAndAttestOnChain(quote);
133
+ require(success, string(output));
134
+ TD10ReportBody memory tdReport = parseTD10ReportBody(quote);
135
+ (address reportDataSigner, bytes memory reportMRTD) = parseReport(tdReport);
136
+ require(!EOASigners[reportDataSigner], "EOA signer already initialized");
137
+
138
+ require(keccak256(reportMRTD) == keccak256(TEEVersionHistory[TEEVersionHistory.length - 1].mrtd), "Invalid report MRTD");
139
+ require(reportDataSigner != address(0), "Invalid report data signer");
140
+ emit NewCovalidatorAdded(reportDataSigner, quote);
141
+ EOASigners[reportDataSigner] = true;
142
+ //TODO: Add the new covalidator signers to the Signers contract state
143
+ }
144
+
145
+ /**
146
+ * @notice Checks if the bootstrap is complete, meaning that there is an active TEE version.
147
+ * @return true if the bootstrap is complete, false otherwise
148
+ */
149
+ function isBootstrapComplete() public view returns (bool) {
150
+ return TEEVersionHistory.length >= 1 && TEEVersionHistory[0].status == TEEVersionStatus.ACTIVE;
151
+ }
152
+
153
+ /**
154
+ * @notice From https://github.com/automata-network/automata-dcap-attestation/blob/evm-v1.0.0/evm/contracts/AttestationEntrypointBase.sol#L103
155
+ * @notice full on-chain verification for an attestation
156
+ * @param rawQuote - Intel DCAP Quote serialized in raw bytes
157
+ * @return success - whether the quote has been successfully verified or not
158
+ * @return output - the output upon completion of verification. The output data may require post-processing by the consumer.
159
+ * For verification failures, the output is simply a UTF-8 encoded string, describing the reason for failure.
160
+ * @dev can directly type-cast the failed output as a string
161
+ */
162
+ function _verifyAndAttestOnChain(bytes calldata rawQuote) internal view returns (bool success, bytes memory output) {
163
+ // Parse the header
164
+ Header memory header;
165
+ (success, header) = _parseQuoteHeader(rawQuote);
166
+ if (!success) {
167
+ return (false, bytes("Could not parse quote header"));
168
+ }
169
+
170
+ if (QUOTE_VERIFIER_VERSION != header.version) {
171
+ return (false, bytes("Unsupported quote version"));
172
+ }
173
+
174
+ // We found a supported version, begin verifying the quote
175
+ // Note: The quote header cannot be trusted yet, it will be validated by the Verifier library
176
+ (success, output) = quoteVerifier.verifyQuote(header, rawQuote);
177
+ }
178
+
179
+ /**
180
+ * @notice From https://github.com/automata-network/automata-dcap-attestation/blob/evm-v1.0.0/evm/contracts/AttestationEntrypointBase.sol#L168
181
+ * @notice Parses the header to get basic information about the quote, such as the version, TEE types etc.
182
+ */
183
+ function _parseQuoteHeader(bytes calldata rawQuote) private pure returns (bool success, Header memory header) {
184
+ success = rawQuote.length >= HEADER_LENGTH;
185
+ if (success) {
186
+ uint16 version = uint16(BELE.leBytesToBeUint(rawQuote[0:2]));
187
+ bytes4 teeType = bytes4(rawQuote[4:8]);
188
+ bytes2 attestationKeyType = bytes2(rawQuote[2:4]);
189
+ bytes2 qeSvn = bytes2(rawQuote[8:10]);
190
+ bytes2 pceSvn = bytes2(rawQuote[10:12]);
191
+ bytes16 qeVendorId = bytes16(rawQuote[12:28]);
192
+ bytes20 userData = bytes20(rawQuote[28:48]);
193
+
194
+ header = Header({
195
+ version: version,
196
+ attestationKeyType: attestationKeyType,
197
+ teeType: teeType,
198
+ qeSvn: qeSvn,
199
+ pceSvn: pceSvn,
200
+ qeVendorId: qeVendorId,
201
+ userData: userData
202
+ });
203
+ }
204
+ }
205
+
206
+ /**
207
+ * @notice From https://github.com/automata-network/automata-dcap-attestation/blob/evm-v1.0.0/evm/contracts/verifiers/V4QuoteVerifier.sol#L309
208
+ * @notice Parses the TD10 report body from the raw quote
209
+ * @param rawQuote - The raw quote bytes
210
+ * @return report - The parsed TD10 report body
211
+ */
212
+ function parseTD10ReportBody(bytes calldata rawQuote) public pure returns (TD10ReportBody memory report) {
213
+ report = TD10ReportBody({
214
+ teeTcbSvn: bytes16(rawQuote[HEADER_LENGTH:HEADER_LENGTH+16]),
215
+ mrSeam: bytes(rawQuote[HEADER_LENGTH+16:HEADER_LENGTH+64]),
216
+ mrsignerSeam: bytes(rawQuote[HEADER_LENGTH+64:HEADER_LENGTH+112]),
217
+ seamAttributes: bytes8(uint64(BELE.leBytesToBeUint(rawQuote[HEADER_LENGTH+112:HEADER_LENGTH+120]))),
218
+ tdAttributes: bytes8(uint64(BELE.leBytesToBeUint(rawQuote[HEADER_LENGTH+120:HEADER_LENGTH+128]))),
219
+ xFAM: bytes8(uint64(BELE.leBytesToBeUint(rawQuote[HEADER_LENGTH+128:HEADER_LENGTH+136]))),
220
+ mrTd: bytes(rawQuote[HEADER_LENGTH+136:HEADER_LENGTH+184]),
221
+ mrConfigId: bytes(rawQuote[HEADER_LENGTH+184:HEADER_LENGTH+232]),
222
+ mrOwner: bytes(rawQuote[HEADER_LENGTH+232:HEADER_LENGTH+280]),
223
+ mrOwnerConfig: bytes(rawQuote[HEADER_LENGTH+280:HEADER_LENGTH+328]),
224
+ rtMr0: bytes(rawQuote[HEADER_LENGTH+328:HEADER_LENGTH+376]),
225
+ rtMr1: bytes(rawQuote[HEADER_LENGTH+376:HEADER_LENGTH+424]),
226
+ rtMr2: bytes(rawQuote[HEADER_LENGTH+424:HEADER_LENGTH+472]),
227
+ rtMr3: bytes(rawQuote[HEADER_LENGTH+472:HEADER_LENGTH+520]),
228
+ reportData: bytes(rawQuote[HEADER_LENGTH+520:HEADER_LENGTH+584])
229
+ });
230
+ }
231
+
232
+ /**
233
+ * @notice Parses the TD10 report to extract the report data and MRTD
234
+ * @param tdReport - The TD10 report body
235
+ * @return reportDataSigner - The signing address of the report data signer
236
+ * @return reportMRTD - The MRTD bytes from the report
237
+ */
238
+ function parseReport(TD10ReportBody memory tdReport) public pure returns (address, bytes memory) {
239
+ return (address(bytes20(tdReport.reportData)), tdReport.mrTd);
240
+ }
241
+
242
+ function bootstrapResultDigest(
243
+ BootstrapResult memory bootstrapResult
244
+ ) public view returns (bytes32) {
245
+ return
246
+ _hashTypedDataV4(
247
+ keccak256(
248
+ abi.encode(
249
+ BootstrapResultStructHash,
250
+ keccak256(bootstrapResult.ecies_pubkey)
251
+ )
252
+ )
253
+ );
254
+ }
255
+ }
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8.19;
3
+
4
+ struct BootstrapResult {
5
+ bytes ecies_pubkey;
6
+ }
7
+
8
+ enum TEEVersionStatus {
9
+ PENDING,
10
+ ACTIVE
11
+ }
12
+
13
+ /**
14
+ * @notice A struct representing a TEE version. The actual version number is the index in the TEEVersionHistory array.
15
+ * @param mrtd - The MRTD of the TEE version
16
+ * @param status - The status of the TEE version
17
+ */
18
+ struct TEEVersion {
19
+ bytes mrtd;
20
+ TEEVersionStatus status;
21
+ }
@@ -3,6 +3,7 @@ pragma solidity ^0.8;
3
3
 
4
4
  import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
5
5
  import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
6
+ import { TEELifecycle } from "../TEELifecycle.sol";
6
7
 
7
8
  interface ISignatureVerifierGen {
8
9
  function addSigner(address signerAddress) external;
@@ -4,6 +4,7 @@ pragma solidity ^0.8;
4
4
  import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
5
5
  import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
6
6
  import {ISignatureVerifierGen} from "./SignatureVerifier.gen.sol";
7
+ import {TEELifecycle} from "../TEELifecycle.sol";
7
8
 
8
9
  contract SignatureVerifierStorage {
9
10
  struct StorageForSigVerifier {
@@ -35,11 +36,20 @@ contract SignatureVerifier is ISignatureVerifierGen, OwnableUpgradeable, Signatu
35
36
  event AddedSignatureVerifier(address signerAddress);
36
37
  event RemovedSignatureVerifier(address signerAddress);
37
38
 
39
+ // Reference to the TEELifecycle contract, to get the list of EOA signers
40
+ TEELifecycle teeLifecycle;
41
+
42
+ function __SignatureVerifier_init(address _teeLifecycleAddress) internal {
43
+ teeLifecycle = TEELifecycle(_teeLifecycleAddress);
44
+ }
45
+
46
+ // @todo: This function should be removed once we have a way to read the signers from the TEELifecycle contract
38
47
  function addSigner(address signerAddress) external onlyOwner {
39
48
  getSigVerifierStorage().isSigner[signerAddress] = true;
40
49
  emit AddedSignatureVerifier(signerAddress);
41
50
  }
42
51
 
52
+ // @todo: This function should be removed once we have a way to read the signers from the TEELifecycle contract
43
53
  function removeSigner(address signerAddress) external onlyOwner {
44
54
  require(
45
55
  getSigVerifierStorage().isSigner[signerAddress],
@@ -49,6 +59,7 @@ contract SignatureVerifier is ISignatureVerifierGen, OwnableUpgradeable, Signatu
49
59
  emit AddedSignatureVerifier(signerAddress);
50
60
  }
51
61
 
62
+ // @todo: This function should read from the TEELifecycle contract instead of the storage
52
63
  function isSigner(address signerAddress) public view returns (bool) {
53
64
  return getSigVerifierStorage().isSigner[signerAddress];
54
65
  }
@@ -7,7 +7,7 @@ import {TrivialEncryption} from "../TrivialEncryption.sol";
7
7
  import {EncryptedOperations} from "../EncryptedOperations.sol";
8
8
  import {EncryptedInput} from "../EncryptedInput.sol";
9
9
  import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
10
- import {ETypes, ebool, euint256, eaddress} from "../../Types.sol";
10
+ import {ETypes, ebool, euint256, eaddress, typeToBitMask} from "../../Types.sol";
11
11
 
12
12
  contract TestHandleMetadata is
13
13
  EIP712,
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {IPCCSRouter} from "@automata-network/dcap-attestation/interfaces/IPCCSRouter.sol";
5
+ import {Header} from "@automata-network/dcap-attestation/types/CommonStruct.sol";
6
+ import {IQuoteVerifier} from "automata-dcap-attestation/interfaces/IQuoteVerifier.sol";
7
+
8
+ // This contract is used to test the IncoLightning contract. It is a simple implementation of the QuoteVerifier interface.
9
+ // It is used to test the IncoLightning contract without relying on the real QuoteVerifier contract.
10
+ contract FakeQuoteVerifier is IQuoteVerifier {
11
+ /// @dev immutable
12
+ function pccsRouter() external pure returns (IPCCSRouter) {
13
+ return IPCCSRouter(address(0));
14
+ }
15
+
16
+ /// @dev immutable
17
+ function quoteVersion() external pure returns (uint16) {
18
+ return 4;
19
+ }
20
+
21
+ function verifyQuote(Header calldata, bytes calldata quote) external pure returns (bool, bytes memory) {
22
+ return (true, quote);
23
+ }
24
+
25
+ function verifyZkOutput(bytes calldata quote) external pure returns (bool, bytes memory) {
26
+ return (true, quote);
27
+ }
28
+
29
+ }
@@ -0,0 +1,37 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import {TestUtils} from "@inco/shared/src/TestUtils.sol";
5
+ import {TEELifecycle} from "@inco/lightning/src/lightning-parts/TEELifecycle.sol";
6
+
7
+ import {HEADER_LENGTH, MINIMUM_QUOTE_LENGTH, TDX_TEE} from "@automata-network/dcap-attestation/types/Constants.sol";
8
+ import {BootstrapResult} from "@inco/lightning/src/lightning-parts/TEELifecycle.types.sol";
9
+
10
+ contract MockRemoteAttestation is TestUtils {
11
+ function createQuote(
12
+ bytes memory mrtd,
13
+ address signer
14
+ ) public pure returns (bytes memory quote) {
15
+ // Mock implementation of quote creation
16
+ require(mrtd.length == 48, "MRTD should be 48 bytes");
17
+ /* Quote structure:
18
+ - version ([0:4], 4 bytes long)
19
+ - teeType ([4:8], 4 bytes long)
20
+ - prefix ([8:HEADER_LENGTH+136], HEADER_LENGTH+136 - 8 bytes long)
21
+ - mrtd ([HEADER_LENGTH+136:HEADER_LENGTH+184], 48 bytes long)
22
+ - middle ([HEADER_LENGTH+184:HEADER_LENGTH+520], 336 bytes long)
23
+ - reportData ([HEADER_LENGTH+520:HEADER_LENGTH+584], 64 bytes long)
24
+ - signer ([HEADER_LENGTH+520:HEADER_LENGTH+540], 20 bytes long)
25
+ - reportDataSuffix ([HEADER_LENGTH+540:HEADER_LENGTH+584], 44 bytes long)
26
+ - suffix ([HEADER_LENGTH+584:MINIMUM_QUOTE_LENGTH], remaining bytes to reach MINIMUM_QUOTE_LENGTH)
27
+
28
+ */
29
+ bytes4 version = 0x04000000; // Version 4
30
+ bytes4 tdxTEEType = TDX_TEE; // TDX TEETYPE
31
+ bytes memory prefix = new bytes(HEADER_LENGTH + 136 - 8);
32
+ bytes memory middle = new bytes(520 - 184);
33
+ bytes memory reportDataSuffix = new bytes(44);
34
+ bytes memory suffix = new bytes(MINIMUM_QUOTE_LENGTH - HEADER_LENGTH - 584);
35
+ quote = abi.encodePacked(version, tdxTEEType, prefix, mrtd, middle, abi.encodePacked(signer), reportDataSuffix, suffix);
36
+ }
37
+ }
@@ -17,6 +17,7 @@ contract FibonacciDecrypt {
17
17
  function fib(
18
18
  uint256 n
19
19
  ) external returns (uint256 lastRequestId, euint256 nthTerm) {
20
+ require(address(inco) != address(0), "IncoLightning not set");
20
21
  euint256 prev = inco.asEuint256(0);
21
22
  lastRequestId = emitTerm(prev);
22
23
  nthTerm = inco.asEuint256(1);
@@ -7,6 +7,7 @@ import {inco} from "../Lib.sol";
7
7
  import {DeployUtils} from "../DeployUtils.sol";
8
8
  import {deployedBy} from "../Lib.sol";
9
9
  import {console} from "forge-std/console.sol";
10
+ import {FakeQuoteVerifier} from "./FakeIncoInfra/FakeQuoteVerifier.sol";
10
11
 
11
12
  contract IncoTest is MockOpHandler, DeployUtils {
12
13
  address immutable owner;
@@ -25,12 +26,15 @@ contract IncoTest is MockOpHandler, DeployUtils {
25
26
  function setUp() public virtual {
26
27
  deployCreateX();
27
28
  vm.startPrank(testDeployer);
29
+ vm.setEnv("USE_TDX_HW", "false"); // results in the test deployment using the FakeQuoteVerifier
28
30
  IncoLightning proxy = deployIncoLightningUsingConfig({
29
31
  deployer: testDeployer,
30
32
  // The highest precedent deployment
31
33
  pepper: "testnet",
32
34
  minorVersionForSalt: 1,
33
- patchVersionForSalt: 29
35
+ patchVersionForSalt: 29,
36
+ includePreviewFeatures: false,
37
+ teeLifecycleAddress: address(0)
34
38
  });
35
39
  proxy.transferOwnership(owner);
36
40
  vm.stopPrank();
@@ -0,0 +1,53 @@
1
+ # TEE Lifecycle Test
2
+
3
+ ## TEELifecycle HW Test
4
+
5
+ This test data was generated using Adrian's V0 TDX VM running in GCP. The data
6
+ was returned collected using the `agent-lib` tool.
7
+
8
+ * To generate new test data: for `test_LifecycleBootstrap`
9
+
10
+ ```bash
11
+ cd agent-lib
12
+
13
+ cargo run --features hw -- start-bootstrap \
14
+ --expected-mrtd 0x409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99 \
15
+ --tee-lifecycle-grpc-url http://34.91.236.235:4321 \
16
+ --output-dir ../contracts/lightning/src/test/TEELifecycle/bootstrap_data
17
+ ```
18
+
19
+ * To generate new test data for `test_LifecycleNewEOA`
20
+
21
+ ```bash
22
+ cd agent-lib
23
+
24
+ # TODO: change this to add-node endpoint after https://github.com/Inco-fhevm/inco-monorepo/issues/889
25
+ cargo run --features hw -- start-bootstrap \
26
+ --expected-mrtd 0x409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99 \
27
+ --tee-lifecycle-grpc-url http://34.91.236.235:4321 \
28
+ --output-dir ../contracts/lightning/src/test/TEELifecycle/addnode_data
29
+
30
+ # Delete the unused output data since it is not used
31
+ # to add a node
32
+ rm ../contracts/lightning/src/test/TEELifecycle/addnode_data/ecies_pubkey.bin
33
+ rm ../contracts/lightning/src/test/TEELifecycle/addnode_data/eip712_signature.bin
34
+ rm ../contracts/lightning/src/test/TEELifecycle/addnode_data/qe_identity
35
+ rm ../contracts/lightning/src/test/TEELifecycle/addnode_data/qe_identity_signature.bin
36
+ rm ../contracts/lightning/src/test/TEELifecycle/addnode_data/tcb_info
37
+ rm ../contracts/lightning/src/test/TEELifecycle/addnode_data/tcb_info_signature.bin
38
+ ```
39
+
40
+ * To generate the Intel root certificates
41
+
42
+ ```bash
43
+ cd contracts/lightning/src/test/TEELifecycle/test_cert
44
+ python3 -m pip install -r ../../../../../lightning-deployment/script/tee/requirements.txt
45
+ python3 ../../../../../lightning-deployment/script/tee/get_ca_certs.py
46
+ ```
47
+
48
+ * Hard code the block timestamp to the current time to ensure that there is no certificate out of date errors
49
+ by setting `uint256 collateral_timestamp =` in [TEELifecycleHWTest.t](TEELifecycleHWTest.t.sol#24) to the output of:
50
+
51
+ ```bash
52
+ echo $(date +%s)
53
+ ```
@@ -0,0 +1,119 @@
1
+ // SPDX-License-Identifier: No License
2
+ pragma solidity ^0.8;
3
+
4
+ import "forge-std/Test.sol";
5
+
6
+ import "../../lightning-parts/TEELifecycle.types.sol";
7
+ import "../../lightning-parts/TEELifecycle.sol";
8
+ import "../../DeployUtils.sol";
9
+ import "../../DeployTEE.sol";
10
+ import {TestUtils} from "@inco/shared/src/TestUtils.sol";
11
+
12
+ import {EnclaveIdentityJsonObj} from "@automata-network/on-chain-pccs/helpers/EnclaveIdentityHelper.sol";
13
+ import {TcbInfoJsonObj} from "@automata-network/on-chain-pccs/helpers/FmspcTcbHelper.sol";
14
+ import {IQuoteVerifier} from "automata-dcap-attestation/interfaces/IQuoteVerifier.sol";
15
+
16
+ contract TEELifecycleHWTest is DeployUtils , TestUtils, DeployTEE {
17
+ using stdStorage for StdStorage;
18
+
19
+ // This is the MRTD from Adrian's v0 TDX VM running on GCP that was used to generate the test data.
20
+ bytes public v0mrtd = hex"409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99";
21
+
22
+ // This is the address that is used as the lifecycle contract address in Adrian's v0 TDX VM.
23
+ address lifecycleAddress = 0x63D8135aF4D393B1dB43B649010c8D3EE19FC9fd;
24
+
25
+ // Avoid expired collateral and certificate errors by setting time to
26
+ // the date when the test data was generated.
27
+ uint256 collateral_timestamp = 1754498833;
28
+
29
+ // This is the location of the bootstrap and add node and test data files
30
+ string bootstrapDir;
31
+ string addNodeDir;
32
+
33
+ TEELifecycle lifecycle;
34
+
35
+ address immutable owner;
36
+
37
+ constructor() {
38
+ owner = getLabeledAddress("owner");
39
+ }
40
+
41
+ function setUp() public {
42
+ // This test data was generate by running the TEELifecycle binary in a real TDX environment
43
+ // to generate the quote and other files.
44
+ bootstrapDir = string.concat(vm.projectRoot(), "/src/test/TEELifecycle/bootstrap_data/");
45
+ addNodeDir = string.concat(vm.projectRoot(), "/src/test/TEELifecycle/addnode_data/");
46
+ string memory certDir = string.concat(vm.projectRoot(), "/src/test/TEELifecycle/test_cert/");
47
+
48
+ vm.warp(collateral_timestamp);
49
+ vm.startPrank(owner);
50
+
51
+ // PCCS Setup
52
+ deployP256();
53
+ deployPCCS(owner, certDir);
54
+ IQuoteVerifier quoteVerifier = deployQuoteVerifier();
55
+
56
+ bytes memory lifecycleCode = address(deployTEELifecycle(owner, address(quoteVerifier))).code;
57
+ // Make sure the verifyingContract for the EIP217 domain matches the one in the test data
58
+ // By using vm.etch to deploy the TEELifecycle contract at a specific address
59
+ vm.etch(lifecycleAddress, lifecycleCode);
60
+ lifecycle = TEELifecycle(lifecycleAddress);
61
+
62
+ // Make sure the name and version for the EIP712 domain matches the one in the test data
63
+ lifecycle.initialize(owner, "IncoTeeLifecycleBootstrap", "1.0.0", address(quoteVerifier));
64
+
65
+ vm.stopPrank();
66
+ }
67
+
68
+ function test_LifecycleBootstrap() public {
69
+ _uploadCollateral(bootstrapDir);
70
+ string memory expected_address_string = vm.readFile(string.concat(bootstrapDir, "eoa.txt"));
71
+ address expected_address = vm.parseAddress(expected_address_string);
72
+
73
+ vm.startPrank(owner);
74
+ bytes memory pubkey = vm.readFileBinary(string.concat(bootstrapDir, "ecies_pubkey.bin"));
75
+ BootstrapResult memory bootstrapResult = BootstrapResult({ecies_pubkey: pubkey});
76
+ bytes memory quote = vm.readFileBinary(string.concat(bootstrapDir, "quote.bin"));
77
+ bytes memory sig = vm.readFileBinary(string.concat(bootstrapDir, "eip712_signature.bin"));
78
+ lifecycle.approveNewTEEVersion(v0mrtd);
79
+ lifecycle.verifyBootstrapResult(bootstrapResult, quote, sig);
80
+
81
+ (bytes memory mrtd,) = lifecycle.TEEVersionHistory(0);
82
+ assert(keccak256(mrtd) == keccak256(v0mrtd));
83
+ assert(lifecycle.isBootstrapComplete() == true);
84
+ assert(keccak256(lifecycle.ECIESPubkey()) == keccak256(pubkey));
85
+ assert(lifecycle.EOASigners(expected_address));
86
+ vm.stopPrank();
87
+ }
88
+
89
+ function test_LifecycleNewEOA() public {
90
+ // This test assumes that the lifecycle bootstrap is already completed
91
+ test_LifecycleBootstrap();
92
+
93
+ string memory expected_address_string = vm.readFile(string.concat(addNodeDir, "eoa.txt"));
94
+ address expected_address = vm.parseAddress(expected_address_string);
95
+
96
+ vm.startPrank(owner);
97
+ bytes memory quote2 = vm.readFileBinary(string.concat(addNodeDir, "quote.bin"));
98
+ lifecycle.addNewCovalidator(quote2);
99
+ vm.stopPrank();
100
+
101
+ assert(lifecycle.EOASigners(expected_address));
102
+ }
103
+
104
+ function _uploadCollateral(string memory collateralDir) private {
105
+ vm.startPrank(owner);
106
+ // upload collateral
107
+ string memory tcbInfoStr = vm.readFile(string.concat(collateralDir, "tcb_info"));
108
+ bytes memory tcbInfoSig = vm.readFileBinary(string.concat(collateralDir, "tcb_info_signature.bin"));
109
+ TcbInfoJsonObj memory tcbInfo = TcbInfoJsonObj(tcbInfoStr, tcbInfoSig);
110
+
111
+ string memory qeIdStr = vm.readFile(string.concat(collateralDir, "qe_identity"));
112
+ bytes memory qeIdSig = vm.readFileBinary(string.concat(collateralDir, "qe_identity_signature.bin"));
113
+ EnclaveIdentityJsonObj memory identityJson = EnclaveIdentityJsonObj(qeIdStr, qeIdSig);
114
+
115
+ lifecycle.uploadCollateral(tcbInfo, identityJson);
116
+
117
+ vm.stopPrank();
118
+ }
119
+ }