CCF
Loading...
Searching...
No Matches
enclave.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/ds/logger.h"
6#include "ccf/version.h"
7#include "enclave/interface.h"
8
9#include <dlfcn.h>
10#include <filesystem>
11
12#ifdef PLATFORM_SGX
13# include <ccf_u.h>
14# include <openenclave/bits/result.h>
15# include <openenclave/host.h>
16# include <openenclave/trace.h>
17#endif
18
19#if defined(PLATFORM_VIRTUAL) || defined(PLATFORM_SNP)
20// Include order matters. virtual_enclave.h uses the OE definitions if
21// available, else creates its own stubs
23#endif
24
25namespace host
26{
28 const std::string& file,
29 char const* expected_suffix,
31 {
32 if (!file.ends_with(expected_suffix))
33 {
34 // Remove possible suffixes to try and get root of filename, to build
35 // suggested filename
36 auto basename = file;
37 for (const char* suffix :
38 {".signed", ".debuggable", ".so", ".enclave", ".virtual", ".snp"})
39 {
40 if (basename.ends_with(suffix))
41 {
42 basename = basename.substr(0, basename.size() - strlen(suffix));
43 }
44 }
45 const auto suggested = fmt::format("{}{}", basename, expected_suffix);
46 throw std::logic_error(fmt::format(
47 "Given enclave file '{}' does not have suffix expected for enclave "
48 "type "
49 "{}. Did you mean '{}'?",
50 file,
51 nlohmann::json(type).dump(),
52 suggested));
53 }
54 }
55
56 static std::pair<uint8_t*, size_t> allocate_8_aligned(size_t size)
57 {
58 const auto aligned_size = (size + 7) & ~(7ull);
59 auto data = static_cast<uint8_t*>(std::aligned_alloc(8u, aligned_size));
60 if (data == nullptr)
61 {
62 throw std::runtime_error(fmt::format(
63 "Unable to allocate {} bytes for aligned data", aligned_size));
64 }
65 return std::make_pair(data, aligned_size);
66 }
67
73 class Enclave
74 {
75 private:
76#ifdef PLATFORM_SGX
77 oe_enclave_t* sgx_handle = nullptr;
78#endif
79#if defined(PLATFORM_VIRTUAL) || defined(PLATFORM_SNP)
80 void* virtual_handle = nullptr;
81#endif
82
83 public:
92 Enclave(const std::string& path, EnclaveType type, EnclavePlatform platform)
93 {
94 if (!std::filesystem::exists(path))
95 {
96 throw std::logic_error(
97 fmt::format("No enclave file found at {}", path));
98 }
99
100 switch (platform)
101 {
103 {
104#ifdef PLATFORM_SGX
105 uint32_t oe_flags = 0;
106 if (type == host::EnclaveType::DEBUG)
107 {
108 expect_enclave_file_suffix(path, ".enclave.so.debuggable", type);
109 oe_flags |= OE_ENCLAVE_FLAG_DEBUG;
110 }
111 else
112 {
113 expect_enclave_file_suffix(path, ".enclave.so.signed", type);
114 }
115
116 auto err = oe_create_ccf_enclave(
117 path.c_str(),
119 oe_flags,
120 nullptr,
121 0,
122 &sgx_handle);
123
124 if (err != OE_OK)
125 {
126 throw std::logic_error(
127 fmt::format("Could not create enclave: {}", oe_result_str(err)));
128 }
129#else
130 throw std::logic_error(fmt::format(
131 "SGX enclaves are not supported in current build - cannot launch "
132 "{}",
133 path));
134#endif // defined(PLATFORM_SGX)
135 break;
136 }
137
139 {
140#if defined(PLATFORM_SNP)
141 expect_enclave_file_suffix(path, ".snp.so", type);
142 virtual_handle = load_virtual_enclave(path.c_str());
143#else
144 throw std::logic_error(fmt::format(
145 "SNP enclaves are not supported in current build - cannot launch "
146 "{}",
147 path));
148#endif // defined(PLATFORM_SNP)
149 break;
150 }
151
153 {
154#if defined(PLATFORM_VIRTUAL)
155 expect_enclave_file_suffix(path, ".virtual.so", type);
156 virtual_handle = load_virtual_enclave(path.c_str());
157#else
158 throw std::logic_error(fmt::format(
159 "Virtual enclaves are not supported in current build - cannot "
160 "launch {}",
161 path));
162#endif // defined(PLATFORM_VIRTUAL)
163 break;
164 }
165
166 default:
167 {
168 throw std::logic_error(fmt::format(
169 "Unsupported enclave type: {}", nlohmann::json(type).dump()));
170 }
171 }
172 }
173
175 {
176#ifdef PLATFORM_SGX
177 if (sgx_handle != nullptr)
178 {
179 auto err = oe_terminate_enclave(sgx_handle);
180
181 if (err != OE_OK)
182 {
184 "Error while terminating enclave: {}", oe_result_str(err));
185 }
186 }
187#endif
188
189#if defined(PLATFORM_SNP) || defined(PLATFORM_VIRTUAL)
190 if (virtual_handle != nullptr)
191 {
192 terminate_virtual_enclave(virtual_handle);
193 }
194#endif
195 }
196
198 const EnclaveConfig& enclave_config,
199 const StartupConfig& ccf_config,
200 std::vector<uint8_t>&& startup_snapshot,
201 std::vector<uint8_t>& node_cert,
202 std::vector<uint8_t>& service_cert,
203 StartType start_type,
204 LoggerLevel enclave_log_level,
205 size_t num_worker_thread,
206 void* time_location)
207 {
209 constexpr size_t enclave_version_size = 256;
210 std::vector<uint8_t> enclave_version_buf(enclave_version_size);
211
212 size_t node_cert_len = 0;
213 size_t service_cert_len = 0;
214 size_t enclave_version_len = 0;
215
216 // Pad config and startup snapshot with NULLs to a multiple of 8, in an
217 // 8-byte aligned allocation
218 auto config_s = nlohmann::json(ccf_config).dump();
219 auto [config, config_aligned_size] = allocate_8_aligned(config_s.size());
221 "Padding config of size {} to {} bytes",
222 config_s.size(),
223 config_aligned_size);
224 auto copy_end = std::copy(config_s.begin(), config_s.end(), config);
225 std::fill(copy_end, config + config_aligned_size, 0);
226
227 auto [snapshot, snapshot_aligned_size] =
228 allocate_8_aligned(startup_snapshot.size());
230 "Padding startup snapshot of size {} to {} bytes",
231 startup_snapshot.size(),
232 snapshot_aligned_size);
233
234 auto snapshot_copy_end =
235 std::copy(startup_snapshot.begin(), startup_snapshot.end(), snapshot);
236 std::fill(snapshot_copy_end, snapshot + snapshot_aligned_size, 0);
237
238#define CREATE_NODE_ARGS \
239 &status, (void*)&enclave_config, config, config_aligned_size, snapshot, \
240 snapshot_aligned_size, node_cert.data(), node_cert.size(), &node_cert_len, \
241 service_cert.data(), service_cert.size(), &service_cert_len, \
242 enclave_version_buf.data(), enclave_version_buf.size(), \
243 &enclave_version_len, start_type, enclave_log_level, num_worker_thread, \
244 time_location
245
247
248// Assume that constructor correctly set the appropriate field, and call
249// appropriate function
250#if defined(PLATFORM_VIRTUAL) || defined(PLATFORM_SNP)
251 if (virtual_handle != nullptr)
252 {
253 err = virtual_create_node(virtual_handle, CREATE_NODE_ARGS);
254 }
255#endif
256#ifdef PLATFORM_SGX
257 if (sgx_handle != nullptr)
258 {
259 err = enclave_create_node(sgx_handle, CREATE_NODE_ARGS);
260 }
261#endif
262
263 std::free(config);
264 std::free(snapshot);
265
266 if (err != OE_OK || status != CreateNodeStatus::OK)
267 {
268 // Logs have described the errors already, we just need to allow the
269 // host to read them (via read_all()).
270 return status;
271 }
272
273 // Host and enclave versions must match. Otherwise the node may crash much
274 // later (e.g. unhandled ring buffer message on either end)
275 auto enclave_version = std::string(
276 enclave_version_buf.begin(),
277 enclave_version_buf.begin() + enclave_version_len);
278 if (ccf::ccf_version != enclave_version)
279 {
281 "Host/Enclave versions mismatch: {} != {}",
282 ccf::ccf_version,
283 enclave_version);
285 }
286
287 node_cert.resize(node_cert_len);
288 service_cert.resize(service_cert_len);
289
291 }
292
293 // Run a processor over this circuit inside the enclave - should be called
294 // from a thread
295 bool run()
296 {
297 bool ret = true;
299
300#if defined(PLATFORM_VIRTUAL) || defined(PLATFORM_SNP)
301 if (virtual_handle != nullptr)
302 {
303 err = virtual_run(virtual_handle, &ret);
304 }
305#endif
306#ifdef PLATFORM_SGX
307 if (sgx_handle != nullptr)
308 {
309 err = enclave_run(sgx_handle, &ret);
310 }
311#endif
312
313 if (err != OE_OK)
314 {
315 throw std::logic_error(
316 fmt::format("Failed to call in enclave_run: {}", oe_result_str(err)));
317 }
318
319 return ret;
320 }
321 };
322}
Definition enclave.h:74
Enclave(const std::string &path, EnclaveType type, EnclavePlatform platform)
Definition enclave.h:92
CreateNodeStatus create_node(const EnclaveConfig &enclave_config, const StartupConfig &ccf_config, std::vector< uint8_t > &&startup_snapshot, std::vector< uint8_t > &node_cert, std::vector< uint8_t > &service_cert, StartType start_type, LoggerLevel enclave_log_level, size_t num_worker_thread, void *time_location)
Definition enclave.h:197
bool run()
Definition enclave.h:295
~Enclave()
Definition enclave.h:174
bool enclave_run()
Definition main.cpp:338
CreateNodeStatus enclave_create_node(void *enclave_config, uint8_t *ccf_config, size_t ccf_config_size, uint8_t *startup_snapshot_data, size_t startup_snapshot_size, uint8_t *node_cert, size_t node_cert_size, size_t *node_cert_len, uint8_t *service_cert, size_t service_cert_size, size_t *service_cert_len, uint8_t *enclave_version, size_t enclave_version_size, size_t *enclave_version_len, StartType start_type, LoggerLevel enclave_log_level, size_t num_worker_threads, void *time_location)
Definition main.cpp:59
CreateNodeStatus
Definition enclave_interface_types.h:8
@ OK
Definition enclave_interface_types.h:10
@ VersionMismatch
Definition enclave_interface_types.h:43
@ InternalError
Definition enclave_interface_types.h:13
StartType
Definition enclave_interface_types.h:113
#define LOG_DEBUG_FMT
Definition logger.h:380
#define LOG_FAIL_FMT
Definition logger.h:396
LoggerLevel
Definition logger_level.h:6
Definition configuration.h:13
EnclaveType
Definition configuration.h:15
EnclavePlatform
Definition configuration.h:27
void expect_enclave_file_suffix(const std::string &file, char const *expected_suffix, host::EnclaveType type)
Definition enclave.h:27
#define CREATE_NODE_ARGS
Definition configuration.h:41
Definition startup_config.h:79
void terminate_virtual_enclave(void *handle)
Definition virtual_enclave.h:91
void * load_virtual_enclave(const char *path)
Definition virtual_enclave.h:70
void oe_enclave_t
Definition virtual_enclave.h:44
oe_result_t virtual_run(void *virtual_enclave_handle, bool *_retval)
Definition virtual_enclave.h:179
@ OE_ENCLAVE_TYPE_SGX
Definition virtual_enclave.h:49
oe_result_t virtual_create_node(void *virtual_enclave_handle, CreateNodeStatus *status, void *enclave_config, uint8_t *ccf_config, size_t ccf_config_size, uint8_t *startup_snapshot, size_t startup_snapshot_size, uint8_t *node_cert, size_t node_cert_size, size_t *node_cert_len, uint8_t *service_cert, size_t service_cert_size, size_t *service_cert_len, uint8_t *enclave_version, size_t enclave_version_size, size_t *enclave_version_len, StartType start_type, LoggerLevel enclave_log_level, size_t num_worker_thread, void *time_location)
Definition virtual_enclave.h:100
#define oe_result_str(x)
Definition virtual_enclave.h:52
constexpr oe_result_t OE_OK
Definition virtual_enclave.h:41
int oe_result_t
Definition virtual_enclave.h:40
constexpr oe_result_t OE_FAILURE
Definition virtual_enclave.h:42