ssl.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/string_util.h"
  4. #include "core/core.h"
  5. #include "core/hle/result.h"
  6. #include "core/hle/service/cmif_serialization.h"
  7. #include "core/hle/service/ipc_helpers.h"
  8. #include "core/hle/service/server_manager.h"
  9. #include "core/hle/service/service.h"
  10. #include "core/hle/service/sm/sm.h"
  11. #include "core/hle/service/sockets/bsd.h"
  12. #include "core/hle/service/ssl/cert_store.h"
  13. #include "core/hle/service/ssl/ssl.h"
  14. #include "core/hle/service/ssl/ssl_backend.h"
  15. #include "core/internal_network/network.h"
  16. #include "core/internal_network/sockets.h"
  17. namespace Service::SSL {
  18. // This is nn::ssl::sf::CertificateFormat
  19. enum class CertificateFormat : u32 {
  20. Pem = 1,
  21. Der = 2,
  22. };
  23. // This is nn::ssl::sf::ContextOption
  24. enum class ContextOption : u32 {
  25. None = 0,
  26. CrlImportDateCheckEnable = 1,
  27. };
  28. // This is nn::ssl::Connection::IoMode
  29. enum class IoMode : u32 {
  30. Blocking = 1,
  31. NonBlocking = 2,
  32. };
  33. // This is nn::ssl::sf::OptionType
  34. enum class OptionType : u32 {
  35. DoNotCloseSocket = 0,
  36. GetServerCertChain = 1,
  37. };
  38. // This is nn::ssl::sf::SslVersion
  39. struct SslVersion {
  40. union {
  41. u32 raw{};
  42. BitField<0, 1, u32> tls_auto;
  43. BitField<3, 1, u32> tls_v10;
  44. BitField<4, 1, u32> tls_v11;
  45. BitField<5, 1, u32> tls_v12;
  46. BitField<6, 1, u32> tls_v13;
  47. BitField<24, 7, u32> api_version;
  48. };
  49. };
  50. struct SslContextSharedData {
  51. u32 connection_count = 0;
  52. };
  53. class ISslConnection final : public ServiceFramework<ISslConnection> {
  54. public:
  55. explicit ISslConnection(Core::System& system_in, SslVersion ssl_version_in,
  56. std::shared_ptr<SslContextSharedData>& shared_data_in,
  57. std::unique_ptr<SSLConnectionBackend>&& backend_in)
  58. : ServiceFramework{system_in, "ISslConnection"}, ssl_version{ssl_version_in},
  59. shared_data{shared_data_in}, backend{std::move(backend_in)} {
  60. // clang-format off
  61. static const FunctionInfo functions[] = {
  62. {0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"},
  63. {1, &ISslConnection::SetHostName, "SetHostName"},
  64. {2, &ISslConnection::SetVerifyOption, "SetVerifyOption"},
  65. {3, &ISslConnection::SetIoMode, "SetIoMode"},
  66. {4, nullptr, "GetSocketDescriptor"},
  67. {5, nullptr, "GetHostName"},
  68. {6, nullptr, "GetVerifyOption"},
  69. {7, nullptr, "GetIoMode"},
  70. {8, &ISslConnection::DoHandshake, "DoHandshake"},
  71. {9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
  72. {10, &ISslConnection::Read, "Read"},
  73. {11, &ISslConnection::Write, "Write"},
  74. {12, &ISslConnection::Pending, "Pending"},
  75. {13, nullptr, "Peek"},
  76. {14, nullptr, "Poll"},
  77. {15, nullptr, "GetVerifyCertError"},
  78. {16, nullptr, "GetNeededServerCertBufferSize"},
  79. {17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"},
  80. {18, nullptr, "GetSessionCacheMode"},
  81. {19, nullptr, "FlushSessionCache"},
  82. {20, nullptr, "SetRenegotiationMode"},
  83. {21, nullptr, "GetRenegotiationMode"},
  84. {22, &ISslConnection::SetOption, "SetOption"},
  85. {23, nullptr, "GetOption"},
  86. {24, nullptr, "GetVerifyCertErrors"},
  87. {25, nullptr, "GetCipherInfo"},
  88. {26, nullptr, "SetNextAlpnProto"},
  89. {27, nullptr, "GetNextAlpnProto"},
  90. {28, nullptr, "SetDtlsSocketDescriptor"},
  91. {29, nullptr, "GetDtlsHandshakeTimeout"},
  92. {30, nullptr, "SetPrivateOption"},
  93. {31, nullptr, "SetSrtpCiphers"},
  94. {32, nullptr, "GetSrtpCipher"},
  95. {33, nullptr, "ExportKeyingMaterial"},
  96. {34, nullptr, "SetIoTimeout"},
  97. {35, nullptr, "GetIoTimeout"},
  98. };
  99. // clang-format on
  100. RegisterHandlers(functions);
  101. shared_data->connection_count++;
  102. }
  103. ~ISslConnection() {
  104. shared_data->connection_count--;
  105. if (fd_to_close.has_value()) {
  106. const s32 fd = *fd_to_close;
  107. if (!do_not_close_socket) {
  108. LOG_ERROR(Service_SSL,
  109. "do_not_close_socket was changed after setting socket; is this right?");
  110. } else {
  111. auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
  112. if (bsd) {
  113. auto err = bsd->CloseImpl(fd);
  114. if (err != Service::Sockets::Errno::SUCCESS) {
  115. LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
  116. }
  117. }
  118. }
  119. }
  120. }
  121. private:
  122. SslVersion ssl_version;
  123. std::shared_ptr<SslContextSharedData> shared_data;
  124. std::unique_ptr<SSLConnectionBackend> backend;
  125. std::optional<int> fd_to_close;
  126. bool do_not_close_socket = false;
  127. bool get_server_cert_chain = false;
  128. std::shared_ptr<Network::SocketBase> socket;
  129. bool did_handshake = false;
  130. Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
  131. LOG_DEBUG(Service_SSL, "called, fd={}", fd);
  132. ASSERT(!did_handshake);
  133. auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
  134. ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
  135. // Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
  136. if (do_not_close_socket) {
  137. auto res = bsd->DuplicateSocketImpl(fd);
  138. if (!res.has_value()) {
  139. LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
  140. return ResultInvalidSocket;
  141. }
  142. fd = *res;
  143. fd_to_close = fd;
  144. *out_fd = fd;
  145. } else {
  146. *out_fd = -1;
  147. }
  148. std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
  149. if (!sock.has_value()) {
  150. LOG_ERROR(Service_SSL, "invalid socket fd {}", fd);
  151. return ResultInvalidSocket;
  152. }
  153. socket = std::move(*sock);
  154. backend->SetSocket(socket);
  155. return ResultSuccess;
  156. }
  157. Result SetHostNameImpl(const std::string& hostname) {
  158. LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
  159. ASSERT(!did_handshake);
  160. return backend->SetHostName(hostname);
  161. }
  162. Result SetVerifyOptionImpl(u32 option) {
  163. ASSERT(!did_handshake);
  164. LOG_WARNING(Service_SSL, "(STUBBED) called. option={}", option);
  165. return ResultSuccess;
  166. }
  167. Result SetIoModeImpl(u32 input_mode) {
  168. auto mode = static_cast<IoMode>(input_mode);
  169. ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
  170. ASSERT_OR_EXECUTE(socket, { return ResultNoSocket; });
  171. const bool non_block = mode == IoMode::NonBlocking;
  172. const Network::Errno error = socket->SetNonBlock(non_block);
  173. if (error != Network::Errno::SUCCESS) {
  174. LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
  175. }
  176. return ResultSuccess;
  177. }
  178. Result SetSessionCacheModeImpl(u32 mode) {
  179. ASSERT(!did_handshake);
  180. LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
  181. return ResultSuccess;
  182. }
  183. Result DoHandshakeImpl() {
  184. ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
  185. Result res = backend->DoHandshake();
  186. did_handshake = res.IsSuccess();
  187. return res;
  188. }
  189. std::vector<u8> SerializeServerCerts(const std::vector<std::vector<u8>>& certs) {
  190. struct Header {
  191. u64 magic;
  192. u32 count;
  193. u32 pad;
  194. };
  195. struct EntryHeader {
  196. u32 size;
  197. u32 offset;
  198. };
  199. if (!get_server_cert_chain) {
  200. // Just return the first one, unencoded.
  201. ASSERT_OR_EXECUTE_MSG(
  202. !certs.empty(), { return {}; }, "Should be at least one server cert");
  203. return certs[0];
  204. }
  205. std::vector<u8> ret;
  206. Header header{0x4E4D684374726543, static_cast<u32>(certs.size()), 0};
  207. ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
  208. size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
  209. for (auto& cert : certs) {
  210. EntryHeader entry_header{static_cast<u32>(cert.size()), static_cast<u32>(data_offset)};
  211. data_offset += cert.size();
  212. ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header),
  213. reinterpret_cast<u8*>(&entry_header + 1));
  214. }
  215. for (auto& cert : certs) {
  216. ret.insert(ret.end(), cert.begin(), cert.end());
  217. }
  218. return ret;
  219. }
  220. Result ReadImpl(std::vector<u8>* out_data) {
  221. ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
  222. size_t actual_size{};
  223. Result res = backend->Read(&actual_size, *out_data);
  224. if (res != ResultSuccess) {
  225. return res;
  226. }
  227. out_data->resize(actual_size);
  228. return res;
  229. }
  230. Result WriteImpl(size_t* out_size, std::span<const u8> data) {
  231. ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
  232. return backend->Write(out_size, data);
  233. }
  234. Result PendingImpl(s32* out_pending) {
  235. LOG_WARNING(Service_SSL, "(STUBBED) called.");
  236. *out_pending = 0;
  237. return ResultSuccess;
  238. }
  239. void SetSocketDescriptor(HLERequestContext& ctx) {
  240. IPC::RequestParser rp{ctx};
  241. const s32 in_fd = rp.Pop<s32>();
  242. s32 out_fd{-1};
  243. const Result res = SetSocketDescriptorImpl(&out_fd, in_fd);
  244. IPC::ResponseBuilder rb{ctx, 3};
  245. rb.Push(res);
  246. rb.Push<s32>(out_fd);
  247. }
  248. void SetHostName(HLERequestContext& ctx) {
  249. const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer());
  250. const Result res = SetHostNameImpl(hostname);
  251. IPC::ResponseBuilder rb{ctx, 2};
  252. rb.Push(res);
  253. }
  254. void SetVerifyOption(HLERequestContext& ctx) {
  255. IPC::RequestParser rp{ctx};
  256. const u32 option = rp.Pop<u32>();
  257. const Result res = SetVerifyOptionImpl(option);
  258. IPC::ResponseBuilder rb{ctx, 2};
  259. rb.Push(res);
  260. }
  261. void SetIoMode(HLERequestContext& ctx) {
  262. IPC::RequestParser rp{ctx};
  263. const u32 mode = rp.Pop<u32>();
  264. const Result res = SetIoModeImpl(mode);
  265. IPC::ResponseBuilder rb{ctx, 2};
  266. rb.Push(res);
  267. }
  268. void DoHandshake(HLERequestContext& ctx) {
  269. const Result res = DoHandshakeImpl();
  270. IPC::ResponseBuilder rb{ctx, 2};
  271. rb.Push(res);
  272. }
  273. void DoHandshakeGetServerCert(HLERequestContext& ctx) {
  274. struct OutputParameters {
  275. u32 certs_size;
  276. u32 certs_count;
  277. };
  278. static_assert(sizeof(OutputParameters) == 0x8);
  279. Result res = DoHandshakeImpl();
  280. OutputParameters out{};
  281. if (res == ResultSuccess) {
  282. std::vector<std::vector<u8>> certs;
  283. res = backend->GetServerCerts(&certs);
  284. if (res == ResultSuccess) {
  285. const std::vector<u8> certs_buf = SerializeServerCerts(certs);
  286. ctx.WriteBuffer(certs_buf);
  287. out.certs_count = static_cast<u32>(certs.size());
  288. out.certs_size = static_cast<u32>(certs_buf.size());
  289. }
  290. }
  291. IPC::ResponseBuilder rb{ctx, 4};
  292. rb.Push(res);
  293. rb.PushRaw(out);
  294. }
  295. void Read(HLERequestContext& ctx) {
  296. std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
  297. const Result res = ReadImpl(&output_bytes);
  298. IPC::ResponseBuilder rb{ctx, 3};
  299. rb.Push(res);
  300. if (res == ResultSuccess) {
  301. rb.Push(static_cast<u32>(output_bytes.size()));
  302. ctx.WriteBuffer(output_bytes);
  303. } else {
  304. rb.Push(static_cast<u32>(0));
  305. }
  306. }
  307. void Write(HLERequestContext& ctx) {
  308. size_t write_size{0};
  309. const Result res = WriteImpl(&write_size, ctx.ReadBuffer());
  310. IPC::ResponseBuilder rb{ctx, 3};
  311. rb.Push(res);
  312. rb.Push(static_cast<u32>(write_size));
  313. }
  314. void Pending(HLERequestContext& ctx) {
  315. s32 pending_size{0};
  316. const Result res = PendingImpl(&pending_size);
  317. IPC::ResponseBuilder rb{ctx, 3};
  318. rb.Push(res);
  319. rb.Push<s32>(pending_size);
  320. }
  321. void SetSessionCacheMode(HLERequestContext& ctx) {
  322. IPC::RequestParser rp{ctx};
  323. const u32 mode = rp.Pop<u32>();
  324. const Result res = SetSessionCacheModeImpl(mode);
  325. IPC::ResponseBuilder rb{ctx, 2};
  326. rb.Push(res);
  327. }
  328. void SetOption(HLERequestContext& ctx) {
  329. struct Parameters {
  330. OptionType option;
  331. s32 value;
  332. };
  333. static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
  334. IPC::RequestParser rp{ctx};
  335. const auto parameters = rp.PopRaw<Parameters>();
  336. switch (parameters.option) {
  337. case OptionType::DoNotCloseSocket:
  338. do_not_close_socket = static_cast<bool>(parameters.value);
  339. break;
  340. case OptionType::GetServerCertChain:
  341. get_server_cert_chain = static_cast<bool>(parameters.value);
  342. break;
  343. default:
  344. LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option,
  345. parameters.value);
  346. }
  347. IPC::ResponseBuilder rb{ctx, 2};
  348. rb.Push(ResultSuccess);
  349. }
  350. };
  351. class ISslContext final : public ServiceFramework<ISslContext> {
  352. public:
  353. explicit ISslContext(Core::System& system_, SslVersion version)
  354. : ServiceFramework{system_, "ISslContext"}, ssl_version{version},
  355. shared_data{std::make_shared<SslContextSharedData>()} {
  356. static const FunctionInfo functions[] = {
  357. {0, &ISslContext::SetOption, "SetOption"},
  358. {1, nullptr, "GetOption"},
  359. {2, &ISslContext::CreateConnection, "CreateConnection"},
  360. {3, &ISslContext::GetConnectionCount, "GetConnectionCount"},
  361. {4, &ISslContext::ImportServerPki, "ImportServerPki"},
  362. {5, &ISslContext::ImportClientPki, "ImportClientPki"},
  363. {6, nullptr, "RemoveServerPki"},
  364. {7, nullptr, "RemoveClientPki"},
  365. {8, nullptr, "RegisterInternalPki"},
  366. {9, nullptr, "AddPolicyOid"},
  367. {10, nullptr, "ImportCrl"},
  368. {11, nullptr, "RemoveCrl"},
  369. {12, nullptr, "ImportClientCertKeyPki"},
  370. {13, nullptr, "GeneratePrivateKeyAndCert"},
  371. };
  372. RegisterHandlers(functions);
  373. }
  374. private:
  375. SslVersion ssl_version;
  376. std::shared_ptr<SslContextSharedData> shared_data;
  377. void SetOption(HLERequestContext& ctx) {
  378. struct Parameters {
  379. ContextOption option;
  380. s32 value;
  381. };
  382. static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
  383. IPC::RequestParser rp{ctx};
  384. const auto parameters = rp.PopRaw<Parameters>();
  385. LOG_WARNING(Service_SSL, "(STUBBED) called. option={}, value={}", parameters.option,
  386. parameters.value);
  387. IPC::ResponseBuilder rb{ctx, 2};
  388. rb.Push(ResultSuccess);
  389. }
  390. void CreateConnection(HLERequestContext& ctx) {
  391. LOG_WARNING(Service_SSL, "called");
  392. std::unique_ptr<SSLConnectionBackend> backend;
  393. const Result res = CreateSSLConnectionBackend(&backend);
  394. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  395. rb.Push(res);
  396. if (res == ResultSuccess) {
  397. rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
  398. std::move(backend));
  399. }
  400. }
  401. void GetConnectionCount(HLERequestContext& ctx) {
  402. LOG_DEBUG(Service_SSL, "connection_count={}", shared_data->connection_count);
  403. IPC::ResponseBuilder rb{ctx, 3};
  404. rb.Push(ResultSuccess);
  405. rb.Push(shared_data->connection_count);
  406. }
  407. void ImportServerPki(HLERequestContext& ctx) {
  408. IPC::RequestParser rp{ctx};
  409. const auto certificate_format = rp.PopEnum<CertificateFormat>();
  410. [[maybe_unused]] const auto pkcs_12_certificates = ctx.ReadBuffer(0);
  411. constexpr u64 server_id = 0;
  412. LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format);
  413. IPC::ResponseBuilder rb{ctx, 4};
  414. rb.Push(ResultSuccess);
  415. rb.Push(server_id);
  416. }
  417. void ImportClientPki(HLERequestContext& ctx) {
  418. [[maybe_unused]] const auto pkcs_12_certificate = ctx.ReadBuffer(0);
  419. [[maybe_unused]] const auto ascii_password = [&ctx] {
  420. if (ctx.CanReadBuffer(1)) {
  421. return ctx.ReadBuffer(1);
  422. }
  423. return std::span<const u8>{};
  424. }();
  425. constexpr u64 client_id = 0;
  426. LOG_WARNING(Service_SSL, "(STUBBED) called");
  427. IPC::ResponseBuilder rb{ctx, 4};
  428. rb.Push(ResultSuccess);
  429. rb.Push(client_id);
  430. }
  431. };
  432. class ISslService final : public ServiceFramework<ISslService> {
  433. public:
  434. explicit ISslService(Core::System& system_)
  435. : ServiceFramework{system_, "ssl"}, cert_store{system} {
  436. // clang-format off
  437. static const FunctionInfo functions[] = {
  438. {0, &ISslService::CreateContext, "CreateContext"},
  439. {1, nullptr, "GetContextCount"},
  440. {2, D<&ISslService::GetCertificates>, "GetCertificates"},
  441. {3, D<&ISslService::GetCertificateBufSize>, "GetCertificateBufSize"},
  442. {4, nullptr, "DebugIoctl"},
  443. {5, &ISslService::SetInterfaceVersion, "SetInterfaceVersion"},
  444. {6, nullptr, "FlushSessionCache"},
  445. {7, nullptr, "SetDebugOption"},
  446. {8, nullptr, "GetDebugOption"},
  447. {8, nullptr, "ClearTls12FallbackFlag"},
  448. };
  449. // clang-format on
  450. RegisterHandlers(functions);
  451. }
  452. private:
  453. void CreateContext(HLERequestContext& ctx) {
  454. struct Parameters {
  455. SslVersion ssl_version;
  456. INSERT_PADDING_BYTES(0x4);
  457. u64 pid_placeholder;
  458. };
  459. static_assert(sizeof(Parameters) == 0x10, "Parameters is an invalid size");
  460. IPC::RequestParser rp{ctx};
  461. const auto parameters = rp.PopRaw<Parameters>();
  462. LOG_WARNING(Service_SSL, "(STUBBED) called, api_version={}, pid_placeholder={}",
  463. parameters.ssl_version.api_version, parameters.pid_placeholder);
  464. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  465. rb.Push(ResultSuccess);
  466. rb.PushIpcInterface<ISslContext>(system, parameters.ssl_version);
  467. }
  468. void SetInterfaceVersion(HLERequestContext& ctx) {
  469. IPC::RequestParser rp{ctx};
  470. u32 ssl_version = rp.Pop<u32>();
  471. LOG_DEBUG(Service_SSL, "called, ssl_version={}", ssl_version);
  472. IPC::ResponseBuilder rb{ctx, 2};
  473. rb.Push(ResultSuccess);
  474. }
  475. Result GetCertificateBufSize(
  476. Out<u32> out_size, InArray<CaCertificateId, BufferAttr_HipcMapAlias> certificate_ids) {
  477. LOG_INFO(Service_SSL, "called");
  478. u32 num_entries;
  479. R_RETURN(cert_store.GetCertificateBufSize(out_size, &num_entries, certificate_ids));
  480. }
  481. Result GetCertificates(Out<u32> out_num_entries, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
  482. InArray<CaCertificateId, BufferAttr_HipcMapAlias> certificate_ids) {
  483. LOG_INFO(Service_SSL, "called");
  484. R_RETURN(cert_store.GetCertificates(out_num_entries, out_buffer, certificate_ids));
  485. }
  486. private:
  487. CertStore cert_store;
  488. };
  489. void LoopProcess(Core::System& system) {
  490. auto server_manager = std::make_unique<ServerManager>(system);
  491. server_manager->RegisterNamedService("ssl", std::make_shared<ISslService>(system));
  492. ServerManager::RunServer(std::move(server_manager));
  493. }
  494. } // namespace Service::SSL