@super-protocol/addons-tee 0.8.16 → 0.8.17-beta.2

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 (94) hide show
  1. package/README.md +1 -1
  2. package/bindings/amd-sev-snp-napi-rs/amd-sev-snp-napi-rs.linux-x64-gnu.node +0 -0
  3. package/bindings/amd-sev-snp-napi-rs/index.d.ts +24 -0
  4. package/bindings/amd-sev-snp-napi-rs/index.js +328 -0
  5. package/bindings/amd-sev-snp-napi-rs/package-lock.json +40 -0
  6. package/bindings/amd-sev-snp-napi-rs/package.json +31 -0
  7. package/bindings/sgx-native/build/Release/sgx_native.node +0 -0
  8. package/bindings/sp-sev/.github/auto_assign-issues.yml +5 -0
  9. package/bindings/sp-sev/.github/auto_assign.yml +21 -0
  10. package/bindings/sp-sev/.github/dependabot.yml +6 -0
  11. package/bindings/sp-sev/.github/workflows/dco.yml +10 -0
  12. package/bindings/sp-sev/.github/workflows/lint.yml +56 -0
  13. package/bindings/sp-sev/.github/workflows/test.yml +54 -0
  14. package/bindings/sp-sev/.rustfmt.toml +2 -0
  15. package/bindings/sp-sev/CODEOWNERS +1 -0
  16. package/bindings/sp-sev/Cargo.lock +2221 -0
  17. package/bindings/sp-sev/Cargo.toml +80 -0
  18. package/bindings/sp-sev/LICENSE +201 -0
  19. package/bindings/sp-sev/README.md +82 -0
  20. package/bindings/sp-sev/build.rs +17 -0
  21. package/bindings/sp-sev/docs/attestation/README.md +239 -0
  22. package/bindings/sp-sev/docs/attestation/certchain.dot +14 -0
  23. package/bindings/sp-sev/docs/attestation/certchain.dot.png +0 -0
  24. package/bindings/sp-sev/docs/attestation/prerequisites.md +6 -0
  25. package/bindings/sp-sev/docs/attestation/process.msc +60 -0
  26. package/bindings/sp-sev/docs/attestation/process.msc.png +0 -0
  27. package/bindings/sp-sev/docs/attestation/protections.md +53 -0
  28. package/bindings/sp-sev/package-version.py +11 -0
  29. package/bindings/sp-sev/tests/api.rs +191 -0
  30. package/bindings/sp-sev/tests/certs.rs +143 -0
  31. package/bindings/sp-sev/tests/certs_data/cert_chain_milan +74 -0
  32. package/bindings/sp-sev/tests/certs_data/cert_chain_turin +74 -0
  33. package/bindings/sp-sev/tests/certs_data/report_milan.hex +1 -0
  34. package/bindings/sp-sev/tests/certs_data/vcek_milan.der +0 -0
  35. package/bindings/sp-sev/tests/certs_data/vcek_turin.der +0 -0
  36. package/bindings/sp-sev/tests/guest.rs +56 -0
  37. package/bindings/sp-sev/tests/id-block.rs +168 -0
  38. package/bindings/sp-sev/tests/measurement/ovmf_AmdSev_suffix.bin +0 -0
  39. package/bindings/sp-sev/tests/measurement/ovmf_OvmfX64_suffix.bin +0 -0
  40. package/bindings/sp-sev/tests/measurement/test_auth_block.bin +0 -0
  41. package/bindings/sp-sev/tests/measurement/test_auth_key.pem +6 -0
  42. package/bindings/sp-sev/tests/measurement/test_auth_sig.bin +0 -0
  43. package/bindings/sp-sev/tests/measurement/test_id_key.pem +6 -0
  44. package/bindings/sp-sev/tests/measurement/test_id_sig.bin +0 -0
  45. package/bindings/sp-sev/tests/measurement.rs +510 -0
  46. package/bindings/sp-sev/tests/naples/ark.cert.bad +0 -0
  47. package/bindings/sp-sev/tests/naples/ark.cert.sig +0 -0
  48. package/bindings/sp-sev/tests/naples/ark.rs +38 -0
  49. package/bindings/sp-sev/tests/naples/ask.rs +29 -0
  50. package/bindings/sp-sev/tests/naples/cek.cert +0 -0
  51. package/bindings/sp-sev/tests/naples/cek.rs +30 -0
  52. package/bindings/sp-sev/tests/naples/mod.rs +20 -0
  53. package/bindings/sp-sev/tests/naples/oca.cert +0 -0
  54. package/bindings/sp-sev/tests/naples/oca.rs +45 -0
  55. package/bindings/sp-sev/tests/naples/pdh.cert +0 -0
  56. package/bindings/sp-sev/tests/naples/pdh.rs +28 -0
  57. package/bindings/sp-sev/tests/naples/pek.cert +0 -0
  58. package/bindings/sp-sev/tests/naples/pek.rs +32 -0
  59. package/bindings/sp-sev/tests/rome/ark.rs +33 -0
  60. package/bindings/sp-sev/tests/rome/ask.rs +29 -0
  61. package/bindings/sp-sev/tests/rome/cek.cert +0 -0
  62. package/bindings/sp-sev/tests/rome/cek.rs +29 -0
  63. package/bindings/sp-sev/tests/rome/mod.rs +16 -0
  64. package/bindings/sp-sev/tests/rome/oca.cert +0 -0
  65. package/bindings/sp-sev/tests/rome/oca.rs +45 -0
  66. package/bindings/sp-sev/tests/rome/pdh.cert +0 -0
  67. package/bindings/sp-sev/tests/rome/pdh.rs +28 -0
  68. package/bindings/sp-sev/tests/rome/pek.cert +0 -0
  69. package/bindings/sp-sev/tests/rome/pek.rs +32 -0
  70. package/bindings/sp-sev/tests/session.rs +39 -0
  71. package/bindings/sp-sev/tests/sev_launch.rs +120 -0
  72. package/bindings/sp-sev/tests/snp_launch.rs +108 -0
  73. package/bindings/utils/virtee/LICENSE +201 -0
  74. package/bindings/utils/virtee/libsev.so +0 -0
  75. package/bindings/utils/virtee/snpguest +0 -0
  76. package/dist/sgx-native-module/consts.d.ts +1 -1
  77. package/dist/sgx-native-module/consts.js +4 -4
  78. package/dist/sgx-native-module/dcap-quote-verify.service.js +1 -1
  79. package/dist/sgx-native-module/enclave.service.d.ts +5 -4
  80. package/dist/sgx-native-module/enclave.service.js +1 -1
  81. package/dist/sgx-native-module/errors.js +1 -1
  82. package/dist/sgx-native-module/index.d.ts +2 -0
  83. package/dist/sgx-native-module/index.js +3 -1
  84. package/dist/sgx-native-module/pki.service.d.ts +2 -2
  85. package/dist/sgx-native-module/pki.service.js +4 -4
  86. package/dist/sgx-native-module/sev-snp-mrenclave.d.ts +63 -0
  87. package/dist/sgx-native-module/sev-snp-mrenclave.js +290 -0
  88. package/dist/sgx-native-module/sev-snp.d.ts +134 -0
  89. package/dist/sgx-native-module/sev-snp.js +534 -0
  90. package/package.json +21 -14
  91. package/dist/sgx-native-module/sgx-tests.d.ts +0 -1
  92. package/dist/sgx-native-module/sgx-tests.js +0 -114
  93. package/dist/sgx-native-module/tdx-tests.d.ts +0 -1
  94. package/dist/sgx-native-module/tdx-tests.js +0 -64
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.SNPMrEnclaveCalculator = void 0;
30
+ const fs = __importStar(require("fs"));
31
+ const fsAsync = __importStar(require("fs/promises"));
32
+ const path = __importStar(require("path"));
33
+ const os = __importStar(require("os"));
34
+ const sev_snp_1 = require("./sev-snp");
35
+ const axios_1 = __importDefault(require("axios"));
36
+ const sdk_js_1 = require("@super-protocol/sdk-js");
37
+ const dto_js_1 = require("@super-protocol/dto-js");
38
+ const crypto_1 = require("crypto");
39
+ const stream_1 = require("stream");
40
+ class VMConfigCache {
41
+ constructor(ttl = 5 * 60 * 1000) {
42
+ this.cache = {};
43
+ this.ttl = ttl;
44
+ }
45
+ set(key, value) {
46
+ const timestamp = Date.now();
47
+ this.cache[key] = {
48
+ value,
49
+ timestamp,
50
+ };
51
+ }
52
+ get(key, force = false) {
53
+ const record = this.cache[key];
54
+ if (record) {
55
+ if (force === false) {
56
+ const now = Date.now();
57
+ if (now - record.timestamp > this.ttl) {
58
+ return null;
59
+ }
60
+ }
61
+ return record.value;
62
+ }
63
+ return null;
64
+ }
65
+ clear() {
66
+ this.cache = {};
67
+ }
68
+ }
69
+ class SNPMrEnclaveCalculator {
70
+ constructor(config) {
71
+ this.axiosInstance = axios_1.default.create();
72
+ this.defaultCredentials = {
73
+ token: "1UXqNMwov41q9TgHmyopNg5q2giQ8aTdh1gjKWKjfbWPFrcrnhenp6QZfd5ukyVnYXDx9Cok6RtnQMMnXmoZPrSUMNGZGF9KuLCzvRNmQYHowX14C2xAxtJeH6VCuNX39ist4bRE9L5VT3k41frDVh3cG1gZvsqh4EaDeaJyV6U4xVaqXqULnSb9PozqU97VVLWhfwdnj6XgUM59Wzq7yo7vn8RxwSyn8H74TEiLNGUPPA3frsYZuoqWQkNzbiYev5ByWeLro1TXo7DogD4WALCKfEmpwHs9j9rsX5WZvvZ13ourTiuZp5vTTZkByB2ibxUJqkSoZSpCNVtmDToNVKkMREVySe",
74
+ };
75
+ this.cacheFolder = config.cacheFolder || fs.mkdtempSync(path.join(os.tmpdir(), "snp-mrenclave-cache-"));
76
+ const rmPrevCache = config.rmPrevCache ?? false;
77
+ this.vmRepoOwner = config.vmRepoOwner || "Super-Protocol";
78
+ this.vmRepo = config.vmRepo || "sp-vm";
79
+ this.releaseAsset = config.releaseAsset || "vm.json";
80
+ this.retryInterval = config.downloadAssetRetryInterval ?? 1000;
81
+ this.retryMax = config.downloadAssetRetryMax ?? 3;
82
+ if ((config.storageCredentials && !config.storageType) || (!config.storageCredentials && config.storageType)) {
83
+ throw new Error("Both the StorageCredentials and StorageType parameters must either be passed or not passed");
84
+ }
85
+ this.storageCredentials = config.storageCredentials ?? this.defaultCredentials;
86
+ this.storageType = config.storageType ?? dto_js_1.StorageType.StorJ;
87
+ const cacheRecordsTTL = config.cacheRecordsTTL ?? 5 * 60 * 1000;
88
+ if (rmPrevCache && fs.existsSync(this.cacheFolder)) {
89
+ this.clearFileCache();
90
+ }
91
+ if (!fs.existsSync(this.cacheFolder)) {
92
+ fs.mkdirSync(this.cacheFolder, { recursive: true });
93
+ }
94
+ this.vmInfoCache = new VMConfigCache(cacheRecordsTTL);
95
+ }
96
+ clearFileCache() {
97
+ fs.rmSync(this.cacheFolder, {
98
+ recursive: true,
99
+ force: true,
100
+ });
101
+ }
102
+ /**
103
+ * The method allows to obtain expected mrenclave if the virtual machine for which the report is
104
+ * submitted was running on one core and a Milan processor
105
+ * @param report - @see CalcSnpMrEnclaveParams
106
+ */
107
+ async getSingleCoreMrEnclave(report) {
108
+ const mrEnclave = await sev_snp_1.SevSNP.getMrEnclave(report.report);
109
+ const vmMeasure = await this.downloadVM(report.build);
110
+ const expectedMrEnclave = await sev_snp_1.SevSNP.calcSnpMrEnclave({
111
+ ovmfPath: vmMeasure.ovmfFilePath,
112
+ kernelHash: vmMeasure.kernelHash,
113
+ initrdHash: vmMeasure.initrdHash,
114
+ cmdLineHash: report.cmdLineHash,
115
+ vcpuSig: report.cpuSig,
116
+ vcpuCount: report.cores,
117
+ });
118
+ if (!mrEnclave.equals(expectedMrEnclave))
119
+ throw new Error("Expected mrEnclave does not match the calculated one");
120
+ const singleCoreMrEnclave = await sev_snp_1.SevSNP.calcSnpMrEnclave({
121
+ ovmfPath: vmMeasure.ovmfFilePath,
122
+ kernelHash: vmMeasure.kernelHash,
123
+ initrdHash: vmMeasure.initrdHash,
124
+ cmdLineHash: report.cmdLineHash,
125
+ vcpuSig: sev_snp_1.SevSNP.getCpuSig(sev_snp_1.AMD_EPYC_MILAN_CPUINFO),
126
+ vcpuCount: 1,
127
+ });
128
+ return singleCoreMrEnclave;
129
+ }
130
+ async downloadAsset(assetUrl) {
131
+ const { retryInterval, retryMax } = this;
132
+ const response = await sdk_js_1.helpers.tryWithInterval({
133
+ checkResult(response) {
134
+ return { isResultOk: response.status === 200 };
135
+ },
136
+ handler: async () => {
137
+ return this.axiosInstance.get(assetUrl, {
138
+ responseType: "arraybuffer",
139
+ });
140
+ },
141
+ checkError(err) {
142
+ if (axios_1.default.isAxiosError(err) && err.response) {
143
+ const status = err.response.status;
144
+ return { retryable: status < 400 || status >= 500 || status === 429 };
145
+ }
146
+ return { retryable: axios_1.default.isAxiosError(err) };
147
+ },
148
+ retryInterval,
149
+ retryMax,
150
+ });
151
+ return response.data;
152
+ }
153
+ extractVMData(data) {
154
+ const vm = JSON.parse(data.toString("utf-8"));
155
+ const kernelHash = vm.kernel?.sha256;
156
+ if (!kernelHash) {
157
+ throw new Error("kernel hash is missing");
158
+ }
159
+ const initrdHash = vm.initrd?.sha256;
160
+ const OVMF = vm.bios_amd || vm.bios;
161
+ if (!OVMF) {
162
+ throw new Error("Neither bios_amd nor bios is available");
163
+ }
164
+ const { sha256, bucket, prefix, filename } = OVMF;
165
+ if (!sha256 || !bucket || !prefix || !filename) {
166
+ throw new Error("Missing one or more required fields in OVMF");
167
+ }
168
+ return {
169
+ kernelHash: Buffer.from(kernelHash, "hex"),
170
+ initrdHash: initrdHash ? Buffer.from(initrdHash, "hex") : undefined,
171
+ ovmfHash: Buffer.from(sha256, "hex"),
172
+ ovmfBucket: bucket,
173
+ ovmfPrefix: prefix,
174
+ ovmfFilename: filename,
175
+ };
176
+ }
177
+ static calcHashStream(alg = "sha256") {
178
+ const hash = (0, crypto_1.createHash)(alg);
179
+ return {
180
+ process: new stream_1.Transform({
181
+ transform: (data, encoding, done) => {
182
+ hash.update(data);
183
+ done(null, data);
184
+ },
185
+ }),
186
+ get: () => hash.digest(),
187
+ };
188
+ }
189
+ static async fileExist(filePath) {
190
+ try {
191
+ await fsAsync.access(filePath);
192
+ return true;
193
+ }
194
+ catch (err) {
195
+ return false;
196
+ }
197
+ }
198
+ async getAssetUrl(build) {
199
+ const { retryInterval, retryMax } = this;
200
+ const response = await sdk_js_1.helpers.tryWithInterval({
201
+ checkResult(response) {
202
+ return { isResultOk: response.status === 200 };
203
+ },
204
+ handler: async () => {
205
+ return this.axiosInstance.get(`https://api.github.com/repos/${this.vmRepoOwner}/${this.vmRepo}/releases/tags/${build}`);
206
+ },
207
+ checkError(err) {
208
+ if (axios_1.default.isAxiosError(err) && err.response) {
209
+ const status = err.response.status;
210
+ return { retryable: status < 400 || status >= 500 || status === 429 };
211
+ }
212
+ return { retryable: axios_1.default.isAxiosError(err) };
213
+ },
214
+ retryInterval,
215
+ retryMax,
216
+ });
217
+ const { data } = response;
218
+ const asset = data.assets.find((asset) => asset.name === this.releaseAsset);
219
+ return asset.browser_download_url;
220
+ }
221
+ async downloadVM(build) {
222
+ let fromCache = false;
223
+ let vmFiles;
224
+ const vmInfo = this.vmInfoCache.get(build);
225
+ if (vmInfo) {
226
+ fromCache = true;
227
+ vmFiles = vmInfo;
228
+ }
229
+ else {
230
+ try {
231
+ const assetUrl = await this.getAssetUrl(build);
232
+ const vm = await this.downloadAsset(assetUrl);
233
+ vmFiles = this.extractVMData(vm);
234
+ }
235
+ catch (error) {
236
+ const vmInfo = this.vmInfoCache.get(build, true);
237
+ if (vmInfo) {
238
+ fromCache = true;
239
+ vmFiles = vmInfo;
240
+ }
241
+ else {
242
+ throw error;
243
+ }
244
+ }
245
+ }
246
+ const ovmfPath = path.join(this.cacheFolder, `${vmFiles.ovmfHash.toString("hex")}_OVMF.fd`);
247
+ let fileExistAndCorrect = false;
248
+ if (await SNPMrEnclaveCalculator.fileExist(ovmfPath)) {
249
+ const fileStream = fs.createReadStream(ovmfPath);
250
+ const hash = await sdk_js_1.Crypto.createHash(fileStream, {
251
+ algo: dto_js_1.HashAlgorithm.SHA256,
252
+ encoding: dto_js_1.Encoding.hex,
253
+ });
254
+ if (vmFiles.ovmfHash.toString("hex") === hash.hash) {
255
+ fileExistAndCorrect = true;
256
+ }
257
+ }
258
+ if (fileExistAndCorrect !== true) {
259
+ await this.downloadOvmf(vmFiles, ovmfPath);
260
+ }
261
+ if (fromCache !== true) {
262
+ this.vmInfoCache.set(build, vmFiles);
263
+ }
264
+ return {
265
+ initrdHash: vmFiles.initrdHash,
266
+ kernelHash: vmFiles.kernelHash,
267
+ ovmfFilePath: ovmfPath,
268
+ };
269
+ }
270
+ async downloadOvmf(vmFiles, ovmfPath) {
271
+ const credentials = {
272
+ ...this.storageCredentials,
273
+ bucket: vmFiles.ovmfBucket,
274
+ prefix: vmFiles.ovmfPrefix.endsWith("/") ? vmFiles.ovmfPrefix : `${vmFiles.ovmfPrefix}/`,
275
+ };
276
+ const access = {
277
+ storageType: this.storageType,
278
+ credentials,
279
+ };
280
+ const storageProvider = (0, sdk_js_1.getStorageProvider)(access);
281
+ const downloaderStream = await storageProvider.downloadFile(vmFiles.ovmfFilename, {});
282
+ const { process: hashStream, get: getStreamHash } = SNPMrEnclaveCalculator.calcHashStream("sha256");
283
+ await stream_1.promises.pipeline(downloaderStream, hashStream, fs.createWriteStream(ovmfPath));
284
+ if (!vmFiles.ovmfHash.equals(getStreamHash())) {
285
+ throw new Error("The downloaded OVMF-file does not match the expected checksum");
286
+ }
287
+ }
288
+ }
289
+ exports.SNPMrEnclaveCalculator = SNPMrEnclaveCalculator;
290
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V2LXNucC1tcmVuY2xhdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2d4LW5hdGl2ZS1tb2R1bGUvc2V2LXNucC1tcmVuY2xhdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBeUI7QUFDekIscURBQXVDO0FBQ3ZDLDJDQUE2QjtBQUM3Qix1Q0FBeUI7QUFDekIsdUNBQXNFO0FBQ3RFLGtEQUE2QztBQUM3QyxtREFBMEc7QUFDMUcsbURBTWdDO0FBQ2hDLG1DQUFvQztBQUNwQyxtQ0FBNkM7QUFrQzdDLE1BQU0sYUFBYTtJQUlmLFlBQVksTUFBYyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUk7UUFIL0IsVUFBSyxHQUE4RCxFQUFFLENBQUM7UUFJMUUsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDbkIsQ0FBQztJQUVELEdBQUcsQ0FBQyxHQUFXLEVBQUUsS0FBZTtRQUM1QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRztZQUNkLEtBQUs7WUFDTCxTQUFTO1NBQ1osQ0FBQztJQUNOLENBQUM7SUFFRCxHQUFHLENBQUMsR0FBVyxFQUFFLFFBQWlCLEtBQUs7UUFDbkMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUUvQixJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1QsSUFBSSxLQUFLLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQ2xCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxHQUFHLEdBQUcsTUFBTSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7b0JBQ3BDLE9BQU8sSUFBSSxDQUFDO2dCQUNoQixDQUFDO1lBQ0wsQ0FB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
@@ -0,0 +1,134 @@
1
+ /// <reference types="node" />
2
+ import { CpuInfo } from "../../bindings/amd-sev-snp-napi-rs/";
3
+ import { CertificateFormat } from "./pki.service";
4
+ export declare enum SupportedAmdSevSnpGenerations {
5
+ Milan = "Milan",
6
+ Genoa = "Genoa"
7
+ }
8
+ export declare enum SevSNPCertType {
9
+ ARK = "ARK",
10
+ ASK = "ASK",
11
+ VCEK = "VCEK"
12
+ }
13
+ export interface SnpCert {
14
+ type: SevSNPCertType;
15
+ cert: Buffer | string;
16
+ format: CertificateFormat;
17
+ }
18
+ export interface SNPReport {
19
+ report: Buffer;
20
+ cpuSig: number;
21
+ cores: number;
22
+ cmdLineHash: Buffer;
23
+ build: string;
24
+ }
25
+ export interface SNPReportWithChain extends SNPReport {
26
+ certs: SnpCert[];
27
+ }
28
+ export interface CalcSnpMrEnclaveParams {
29
+ ovmfPath: string;
30
+ kernelHash: Buffer;
31
+ initrdHash?: Buffer;
32
+ cmdLineHash: Buffer;
33
+ vcpuSig: number;
34
+ vcpuCount: number;
35
+ vmpl?: number;
36
+ policy?: bigint;
37
+ }
38
+ export declare const AMD_EPYC_MILAN_CPUINFO: CpuInfo;
39
+ export declare const EMPTY_INITRD_SHA256_HASH: Buffer;
40
+ export type ArkHashes = {
41
+ [key: string]: Buffer;
42
+ };
43
+ export declare const ARK_MILAN = "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----";
44
+ export declare const ARK_GENOA = "-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAgAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstR2Vub2EwHhcNMjIwMTI2MTUzNDM3WhcNNDcwMTI2\nMTUzNDM3WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLUdlbm9hMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA3Cd95S/uFOuRIskW9vz9VDBF69NDQF79oRhL\n/L2PVQGhK3YdfEBgpF/JiwWFBsT/fXDhzA01p3LkcT/7LdjcRfKXjHl+0Qq/M4dZ\nkh6QDoUeKzNBLDcBKDDGWo3v35NyrxbA1DnkYwUKU5AAk4P94tKXLp80oxt84ahy\nHoLmc/LqsGsp+oq1Bz4PPsYLwTG4iMKVaaT90/oZ4I8oibSru92vJhlqWO27d/Rx\nc3iUMyhNeGToOvgx/iUo4gGpG61NDpkEUvIzuKcaMx8IdTpWg2DF6SwF0IgVMffn\nvtJmA68BwJNWo1E4PLJdaPfBifcJpuBFwNVQIPQEVX3aP89HJSp8YbY9lySS6PlV\nEqTBBtaQmi4ATGmMR+n2K/e+JAhU2Gj7jIpJhOkdH9firQDnmlA2SFfJ/Cc0mGNz\nW9RmIhyOUnNFoclmkRhl3/AQU5Ys9Qsan1jT/EiyT+pCpmnA+y9edvhDCbOG8F2o\nxHGRdTBkylungrkXJGYiwGrR8kaiqv7NN8QhOBMqYjcbrkEr0f8QMKklIS5ruOfq\nlLMCBw8JLB3LkjpWgtD7OpxkzSsohN47Uom86RY6lp72g8eXHP1qYrnvhzaG1S70\nvw6OkbaaC9EjiH/uHgAJQGxon7u0Q7xgoREWA/e7JcBQwLg80Hq/sbRuqesxz7wB\nWSY254cCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSfXfn+Ddjz\nWtAzGiXvgSlPvjGoWzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvR2Vub2EvY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQAdIlPBC7DQmvH7kjlOznFx3i21SzOPDs5L\n7SgFjMC9rR07292GQCA7Z7Ulq97JQaWeD2ofGGse5swj4OQfKfVv/zaJUFjvosZO\nnfZ63epu8MjWgBSXJg5QE/Al0zRsZsp53DBTdA+Uv/s33fexdenT1mpKYzhIg/cK\ntz4oMxq8JKWJ8Po1CXLzKcfrTphjlbkh8AVKMXeBd2SpM33B1YP4g1BOdk013kqb\n7bRHZ1iB2JHG5cMKKbwRCSAAGHLTzASgDcXr9Fp7Z3liDhGu/ci1opGmkp12QNiJ\nuBbkTU+xDZHm5X8Jm99BX7NEpzlOwIVR8ClgBDyuBkBC2ljtr3ZSaUIYj2xuyWN9\n5KFY49nWxcz90CFa3Hzmy4zMQmBe9dVyls5eL5p9bkXcgRMDTbgmVZiAf4afe8DL\ndmQcYcMFQbHhgVzMiyZHGJgcCrQmA7MkTwEIds1wx/HzMcwU4qqNBAoZV7oeIIPx\ndqFXfPqHqiRlEbRDfX1TG5NFVaeByX0GyH6jzYVuezETzruaky6fp2bl2bczxPE8\nHdS38ijiJmm9vl50RGUeOAXjSuInGR4bsRufeGPB9peTa9BcBOeTWzstqTUB/F/q\naZCIZKr4X6TyfUuSDz/1JDAGl+lxdM0P9+lLaP9NahQjHCVf0zf1c1salVuGFk2w\n/wMz1R1BHg==\n-----END CERTIFICATE-----";
45
+ export declare function getDefaultArkHashes(): ArkHashes;
46
+ export declare class SevSNP {
47
+ static serializeSNPReport(report: SNPReportWithChain): Buffer;
48
+ static deserializeSNPReport(serialized: Buffer): SNPReportWithChain;
49
+ protected static convertCertToPem(cert: Buffer): string;
50
+ protected static convertPemToDer(cert: string): Buffer;
51
+ protected static splitCerts(certsPem: string): string[];
52
+ protected static readCmdLine(): Promise<string>;
53
+ /**
54
+ * Method for generation AMD SEV-SNP Report
55
+ * @param userData - The data that will be included in the report and will be signed
56
+ */
57
+ static generateSNPReport(userData: Buffer): Promise<SNPReport>;
58
+ /**
59
+ * Method for fetch certificates from AMD KDS
60
+ * @param report - report generated by the `generateSNPReport` method
61
+ * @param options - options for working with HTTP, allows you to configure repetitions and the interval between them,
62
+ * as well as the format of the returned certificates
63
+ */
64
+ static getReportChain(report: SNPReport, options?: {
65
+ retryMax?: number;
66
+ retryInterval?: number;
67
+ certFormat?: CertificateFormat;
68
+ }): Promise<SnpCert[]>;
69
+ /**
70
+ * Method for generation AMD SEV-SNP Report and fetching certificates
71
+ * @param userData - @see generateSNPReport
72
+ * @param options - @see getReportChain
73
+ */
74
+ static generateSNPReportWithChain(userData: Buffer, options?: {
75
+ retryMax?: number;
76
+ retryInterval?: number;
77
+ certFormat?: CertificateFormat;
78
+ }): Promise<SNPReportWithChain>;
79
+ protected static runSubProcess(binaryPath: string, args?: string[], options?: {
80
+ cwd?: string;
81
+ timeoutMs?: number;
82
+ }): Promise<{
83
+ exitCode: number;
84
+ stdout: string;
85
+ stderr: string;
86
+ }>;
87
+ static getCertHash(cert: SnpCert): Buffer;
88
+ protected static isValidArk(ARK: SnpCert, trustedHashes: ArkHashes): boolean;
89
+ /**
90
+ * AMD SEV-SNP verification method
91
+ * @param report - report with full certificate chain
92
+ * @param options - trustedHashes - map of trusted AMD ARK Certificates (CommonName as Key, Sha256 Hash of Der Certificate as Value) - optional
93
+ * timeoutMs - timeout of the utility snpnost in ms
94
+ * snpGuestBinaryPath - path for snpguest util
95
+ */
96
+ static verifyReport(report: SNPReportWithChain, options?: {
97
+ trustedHashes?: ArkHashes;
98
+ timeoutMs?: number;
99
+ snpGuestBinaryPath?: string;
100
+ tmpDir?: string;
101
+ }): Promise<void>;
102
+ protected static calcMrEnclave(measure: Buffer, vmpl: number, policy: bigint): Buffer;
103
+ /**
104
+ * Method for obtaining mrEnclave from report. MrEnclave includes report measure, report vmpl and report policy
105
+ * @param report - report without certificates
106
+ */
107
+ static getMrEnclave(report: Buffer): Buffer;
108
+ /**
109
+ * Method for obtaining reportData. This data was passed when generating the report
110
+ * @param report - report without certificates
111
+ */
112
+ static getReportData(report: Buffer): Promise<Buffer>;
113
+ /**
114
+ * Method for obtaining measure. Please do not confuse with mrenclave. Report measure is part of mrEnclave.
115
+ * @param report - report without certificates
116
+ */
117
+ static getReportMeasure(report: Buffer): Promise<Buffer>;
118
+ protected static calculateFileSha256(filePath: string): Promise<Buffer>;
119
+ protected static calculateCmdlineHash(cmdLine: string): Buffer;
120
+ /**
121
+ * The method allows to get the expected mrEnclave without generating a report
122
+ * @param params - @see CalcSnpMrEnclaveParams
123
+ */
124
+ static calcSnpMrEnclave(params: CalcSnpMrEnclaveParams): Promise<Buffer>;
125
+ protected static extractBuildFromCmdline(cmdLine: string, paramName?: string): string;
126
+ /**
127
+ * Compute the 32-bit CPUID signature from family, model, and stepping.
128
+ * This computation is described in AMD's CPUID Specification, publication #25481
129
+ * https://www.amd.com/system/files/TechDocs/25481.pdf
130
+ * See section: CPUID Fn0000_0001_EAX Family, Model, Stepping Identifiers
131
+ * @param cpuInfo - Structure containing family, model and stepping @see CpuInfo
132
+ */
133
+ static getCpuSig(cpuInfo: CpuInfo): number;
134
+ }