ssl.cpp 19 KB

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