es.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/crypto/key_manager.h"
  4. #include "core/hle/ipc_helpers.h"
  5. #include "core/hle/service/es/es.h"
  6. #include "core/hle/service/service.h"
  7. namespace Service::ES {
  8. constexpr Result ERROR_INVALID_ARGUMENT{ErrorModule::ETicket, 2};
  9. constexpr Result ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3};
  10. class ETicket final : public ServiceFramework<ETicket> {
  11. public:
  12. explicit ETicket(Core::System& system_) : ServiceFramework{system_, "es"} {
  13. // clang-format off
  14. static const FunctionInfo functions[] = {
  15. {1, &ETicket::ImportTicket, "ImportTicket"},
  16. {2, nullptr, "ImportTicketCertificateSet"},
  17. {3, nullptr, "DeleteTicket"},
  18. {4, nullptr, "DeletePersonalizedTicket"},
  19. {5, nullptr, "DeleteAllCommonTicket"},
  20. {6, nullptr, "DeleteAllPersonalizedTicket"},
  21. {7, nullptr, "DeleteAllPersonalizedTicketEx"},
  22. {8, &ETicket::GetTitleKey, "GetTitleKey"},
  23. {9, &ETicket::CountCommonTicket, "CountCommonTicket"},
  24. {10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"},
  25. {11, &ETicket::ListCommonTicketRightsIds, "ListCommonTicketRightsIds"},
  26. {12, &ETicket::ListPersonalizedTicketRightsIds, "ListPersonalizedTicketRightsIds"},
  27. {13, nullptr, "ListMissingPersonalizedTicket"},
  28. {14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"},
  29. {15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"},
  30. {16, &ETicket::GetCommonTicketData, "GetCommonTicketData"},
  31. {17, &ETicket::GetPersonalizedTicketData, "GetPersonalizedTicketData"},
  32. {18, nullptr, "OwnTicket"},
  33. {19, nullptr, "GetTicketInfo"},
  34. {20, nullptr, "ListLightTicketInfo"},
  35. {21, nullptr, "SignData"},
  36. {22, nullptr, "GetCommonTicketAndCertificateSize"},
  37. {23, nullptr, "GetCommonTicketAndCertificateData"},
  38. {24, nullptr, "ImportPrepurchaseRecord"},
  39. {25, nullptr, "DeletePrepurchaseRecord"},
  40. {26, nullptr, "DeleteAllPrepurchaseRecord"},
  41. {27, nullptr, "CountPrepurchaseRecord"},
  42. {28, nullptr, "ListPrepurchaseRecordRightsIds"},
  43. {29, nullptr, "ListPrepurchaseRecordInfo"},
  44. {30, nullptr, "CountTicket"},
  45. {31, nullptr, "ListTicketRightsIds"},
  46. {32, nullptr, "CountPrepurchaseRecordEx"},
  47. {33, nullptr, "ListPrepurchaseRecordRightsIdsEx"},
  48. {34, nullptr, "GetEncryptedTicketSize"},
  49. {35, nullptr, "GetEncryptedTicketData"},
  50. {36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"},
  51. {37, nullptr, "OwnTicket2"},
  52. {38, nullptr, "OwnTicket3"},
  53. {39, nullptr, "DeleteAllInactivePersonalizedTicket"},
  54. {40, nullptr, "DeletePrepurchaseRecordByNintendoAccountId"},
  55. {501, nullptr, "Unknown501"},
  56. {502, nullptr, "Unknown502"},
  57. {503, nullptr, "GetTitleKey"},
  58. {504, nullptr, "Unknown504"},
  59. {508, nullptr, "Unknown508"},
  60. {509, nullptr, "Unknown509"},
  61. {510, nullptr, "Unknown510"},
  62. {511, nullptr, "Unknown511"},
  63. {1001, nullptr, "Unknown1001"},
  64. {1002, nullptr, "Unknown1001"},
  65. {1003, nullptr, "Unknown1003"},
  66. {1004, nullptr, "Unknown1004"},
  67. {1005, nullptr, "Unknown1005"},
  68. {1006, nullptr, "Unknown1006"},
  69. {1007, nullptr, "Unknown1007"},
  70. {1009, nullptr, "Unknown1009"},
  71. {1010, nullptr, "Unknown1010"},
  72. {1011, nullptr, "Unknown1011"},
  73. {1012, nullptr, "Unknown1012"},
  74. {1013, nullptr, "Unknown1013"},
  75. {1014, nullptr, "Unknown1014"},
  76. {1015, nullptr, "Unknown1015"},
  77. {1016, nullptr, "Unknown1016"},
  78. {1017, nullptr, "Unknown1017"},
  79. {1018, nullptr, "Unknown1018"},
  80. {1019, nullptr, "Unknown1019"},
  81. {1020, nullptr, "Unknown1020"},
  82. {1021, nullptr, "Unknown1021"},
  83. {1501, nullptr, "Unknown1501"},
  84. {1502, nullptr, "Unknown1502"},
  85. {1503, nullptr, "Unknown1503"},
  86. {1504, nullptr, "Unknown1504"},
  87. {1505, nullptr, "Unknown1505"},
  88. {1506, nullptr, "Unknown1506"},
  89. {2000, nullptr, "Unknown2000"},
  90. {2001, nullptr, "Unknown2001"},
  91. {2002, nullptr, "Unknown2002"},
  92. {2003, nullptr, "Unknown2003"},
  93. {2100, nullptr, "Unknown2100"},
  94. {2501, nullptr, "Unknown2501"},
  95. {2502, nullptr, "Unknown2502"},
  96. {2601, nullptr, "Unknown2601"},
  97. {3001, nullptr, "Unknown3001"},
  98. {3002, nullptr, "Unknown3002"},
  99. };
  100. // clang-format on
  101. RegisterHandlers(functions);
  102. keys.PopulateTickets();
  103. keys.SynthesizeTickets();
  104. }
  105. private:
  106. bool CheckRightsId(Kernel::HLERequestContext& ctx, const u128& rights_id) {
  107. if (rights_id == u128{}) {
  108. LOG_ERROR(Service_ETicket, "The rights ID was invalid!");
  109. IPC::ResponseBuilder rb{ctx, 2};
  110. rb.Push(ERROR_INVALID_RIGHTS_ID);
  111. return false;
  112. }
  113. return true;
  114. }
  115. void ImportTicket(Kernel::HLERequestContext& ctx) {
  116. const auto ticket = ctx.ReadBuffer();
  117. const auto cert = ctx.ReadBuffer(1);
  118. if (ticket.size() < sizeof(Core::Crypto::Ticket)) {
  119. LOG_ERROR(Service_ETicket, "The input buffer is not large enough!");
  120. IPC::ResponseBuilder rb{ctx, 2};
  121. rb.Push(ERROR_INVALID_ARGUMENT);
  122. return;
  123. }
  124. Core::Crypto::Ticket raw{};
  125. std::memcpy(&raw, ticket.data(), sizeof(Core::Crypto::Ticket));
  126. if (!keys.AddTicketPersonalized(raw)) {
  127. LOG_ERROR(Service_ETicket, "The ticket could not be imported!");
  128. IPC::ResponseBuilder rb{ctx, 2};
  129. rb.Push(ERROR_INVALID_ARGUMENT);
  130. return;
  131. }
  132. IPC::ResponseBuilder rb{ctx, 2};
  133. rb.Push(ResultSuccess);
  134. }
  135. void GetTitleKey(Kernel::HLERequestContext& ctx) {
  136. IPC::RequestParser rp{ctx};
  137. const auto rights_id = rp.PopRaw<u128>();
  138. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  139. if (!CheckRightsId(ctx, rights_id))
  140. return;
  141. const auto key =
  142. keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
  143. if (key == Core::Crypto::Key128{}) {
  144. LOG_ERROR(Service_ETicket,
  145. "The titlekey doesn't exist in the KeyManager or the rights ID was invalid!");
  146. IPC::ResponseBuilder rb{ctx, 2};
  147. rb.Push(ERROR_INVALID_RIGHTS_ID);
  148. return;
  149. }
  150. ctx.WriteBuffer(key);
  151. IPC::ResponseBuilder rb{ctx, 2};
  152. rb.Push(ResultSuccess);
  153. }
  154. void CountCommonTicket(Kernel::HLERequestContext& ctx) {
  155. LOG_DEBUG(Service_ETicket, "called");
  156. const u32 count = static_cast<u32>(keys.GetCommonTickets().size());
  157. IPC::ResponseBuilder rb{ctx, 3};
  158. rb.Push(ResultSuccess);
  159. rb.Push<u32>(count);
  160. }
  161. void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) {
  162. LOG_DEBUG(Service_ETicket, "called");
  163. const u32 count = static_cast<u32>(keys.GetPersonalizedTickets().size());
  164. IPC::ResponseBuilder rb{ctx, 3};
  165. rb.Push(ResultSuccess);
  166. rb.Push<u32>(count);
  167. }
  168. void ListCommonTicketRightsIds(Kernel::HLERequestContext& ctx) {
  169. size_t out_entries = 0;
  170. if (!keys.GetCommonTickets().empty()) {
  171. out_entries = ctx.GetWriteBufferNumElements<u128>();
  172. }
  173. LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
  174. keys.PopulateTickets();
  175. const auto tickets = keys.GetCommonTickets();
  176. std::vector<u128> ids;
  177. std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
  178. [](const auto& pair) { return pair.first; });
  179. out_entries = std::min(ids.size(), out_entries);
  180. ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
  181. IPC::ResponseBuilder rb{ctx, 3};
  182. rb.Push(ResultSuccess);
  183. rb.Push<u32>(static_cast<u32>(out_entries));
  184. }
  185. void ListPersonalizedTicketRightsIds(Kernel::HLERequestContext& ctx) {
  186. size_t out_entries = 0;
  187. if (!keys.GetPersonalizedTickets().empty()) {
  188. out_entries = ctx.GetWriteBufferNumElements<u128>();
  189. }
  190. LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
  191. keys.PopulateTickets();
  192. const auto tickets = keys.GetPersonalizedTickets();
  193. std::vector<u128> ids;
  194. std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
  195. [](const auto& pair) { return pair.first; });
  196. out_entries = std::min(ids.size(), out_entries);
  197. ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
  198. IPC::ResponseBuilder rb{ctx, 3};
  199. rb.Push(ResultSuccess);
  200. rb.Push<u32>(static_cast<u32>(out_entries));
  201. }
  202. void GetCommonTicketSize(Kernel::HLERequestContext& ctx) {
  203. IPC::RequestParser rp{ctx};
  204. const auto rights_id = rp.PopRaw<u128>();
  205. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  206. if (!CheckRightsId(ctx, rights_id))
  207. return;
  208. const auto ticket = keys.GetCommonTickets().at(rights_id);
  209. IPC::ResponseBuilder rb{ctx, 4};
  210. rb.Push(ResultSuccess);
  211. rb.Push<u64>(ticket.GetSize());
  212. }
  213. void GetPersonalizedTicketSize(Kernel::HLERequestContext& ctx) {
  214. IPC::RequestParser rp{ctx};
  215. const auto rights_id = rp.PopRaw<u128>();
  216. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  217. if (!CheckRightsId(ctx, rights_id))
  218. return;
  219. const auto ticket = keys.GetPersonalizedTickets().at(rights_id);
  220. IPC::ResponseBuilder rb{ctx, 4};
  221. rb.Push(ResultSuccess);
  222. rb.Push<u64>(ticket.GetSize());
  223. }
  224. void GetCommonTicketData(Kernel::HLERequestContext& ctx) {
  225. IPC::RequestParser rp{ctx};
  226. const auto rights_id = rp.PopRaw<u128>();
  227. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  228. if (!CheckRightsId(ctx, rights_id))
  229. return;
  230. const auto ticket = keys.GetCommonTickets().at(rights_id);
  231. const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize());
  232. ctx.WriteBuffer(&ticket, write_size);
  233. IPC::ResponseBuilder rb{ctx, 4};
  234. rb.Push(ResultSuccess);
  235. rb.Push<u64>(write_size);
  236. }
  237. void GetPersonalizedTicketData(Kernel::HLERequestContext& ctx) {
  238. IPC::RequestParser rp{ctx};
  239. const auto rights_id = rp.PopRaw<u128>();
  240. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  241. if (!CheckRightsId(ctx, rights_id))
  242. return;
  243. const auto ticket = keys.GetPersonalizedTickets().at(rights_id);
  244. const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize());
  245. ctx.WriteBuffer(&ticket, write_size);
  246. IPC::ResponseBuilder rb{ctx, 4};
  247. rb.Push(ResultSuccess);
  248. rb.Push<u64>(write_size);
  249. }
  250. Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
  251. };
  252. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  253. std::make_shared<ETicket>(system)->InstallAsService(service_manager);
  254. }
  255. } // namespace Service::ES