es.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "core/crypto/key_manager.h"
  5. #include "core/hle/ipc_helpers.h"
  6. #include "core/hle/service/service.h"
  7. namespace Service::ES {
  8. constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::ETicket, 2};
  9. constexpr ResultCode ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3};
  10. class ETicket final : public ServiceFramework<ETicket> {
  11. public:
  12. explicit ETicket() : ServiceFramework{"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::ListCommonTicket, "ListCommonTicket"},
  26. {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicket"},
  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. {503, nullptr, "GetTitleKey"},
  52. };
  53. // clang-format on
  54. RegisterHandlers(functions);
  55. keys.PopulateTickets();
  56. keys.SynthesizeTickets();
  57. }
  58. private:
  59. bool CheckRightsId(Kernel::HLERequestContext& ctx, const u128& rights_id) {
  60. if (rights_id == u128{}) {
  61. LOG_ERROR(Service_ETicket, "The rights ID was invalid!");
  62. IPC::ResponseBuilder rb{ctx, 2};
  63. rb.Push(ERROR_INVALID_RIGHTS_ID);
  64. return false;
  65. }
  66. return true;
  67. }
  68. void ImportTicket(Kernel::HLERequestContext& ctx) {
  69. IPC::RequestParser rp{ctx};
  70. const auto ticket = ctx.ReadBuffer();
  71. const auto cert = ctx.ReadBuffer(1);
  72. if (ticket.size() < sizeof(Core::Crypto::Ticket)) {
  73. LOG_ERROR(Service_ETicket, "The input buffer is not large enough!");
  74. IPC::ResponseBuilder rb{ctx, 2};
  75. rb.Push(ERROR_INVALID_ARGUMENT);
  76. return;
  77. }
  78. Core::Crypto::Ticket raw{};
  79. std::memcpy(&raw, ticket.data(), sizeof(Core::Crypto::Ticket));
  80. if (!keys.AddTicketPersonalized(raw)) {
  81. LOG_ERROR(Service_ETicket, "The ticket could not be imported!");
  82. IPC::ResponseBuilder rb{ctx, 2};
  83. rb.Push(ERROR_INVALID_ARGUMENT);
  84. return;
  85. }
  86. IPC::ResponseBuilder rb{ctx, 2};
  87. rb.Push(RESULT_SUCCESS);
  88. }
  89. void GetTitleKey(Kernel::HLERequestContext& ctx) {
  90. IPC::RequestParser rp{ctx};
  91. const auto rights_id = rp.PopRaw<u128>();
  92. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  93. if (!CheckRightsId(ctx, rights_id))
  94. return;
  95. const auto key =
  96. keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
  97. if (key == Core::Crypto::Key128{}) {
  98. LOG_ERROR(Service_ETicket,
  99. "The titlekey doesn't exist in the KeyManager or the rights ID was invalid!");
  100. IPC::ResponseBuilder rb{ctx, 2};
  101. rb.Push(ERROR_INVALID_RIGHTS_ID);
  102. return;
  103. }
  104. ctx.WriteBuffer(key.data(), key.size());
  105. IPC::ResponseBuilder rb{ctx, 2};
  106. rb.Push(RESULT_SUCCESS);
  107. }
  108. void CountCommonTicket(Kernel::HLERequestContext& ctx) {
  109. LOG_DEBUG(Service_ETicket, "called");
  110. const auto count = keys.GetCommonTickets().size();
  111. IPC::ResponseBuilder rb{ctx, 3};
  112. rb.Push(RESULT_SUCCESS);
  113. rb.Push<u32>(count);
  114. }
  115. void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) {
  116. LOG_DEBUG(Service_ETicket, "called");
  117. const auto count = keys.GetPersonalizedTickets().size();
  118. IPC::ResponseBuilder rb{ctx, 3};
  119. rb.Push(RESULT_SUCCESS);
  120. rb.Push<u32>(count);
  121. }
  122. void ListCommonTicket(Kernel::HLERequestContext& ctx) {
  123. u32 out_entries;
  124. if (keys.GetCommonTickets().empty())
  125. out_entries = 0;
  126. else
  127. out_entries = ctx.GetWriteBufferSize() / sizeof(u128);
  128. LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
  129. keys.PopulateTickets();
  130. const auto tickets = keys.GetCommonTickets();
  131. std::vector<u128> ids;
  132. std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
  133. [](const auto& pair) { return pair.first; });
  134. out_entries = std::min<u32>(ids.size(), out_entries);
  135. ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
  136. IPC::ResponseBuilder rb{ctx, 3};
  137. rb.Push(RESULT_SUCCESS);
  138. rb.Push<u32>(out_entries);
  139. }
  140. void ListPersonalizedTicket(Kernel::HLERequestContext& ctx) {
  141. u32 out_entries;
  142. if (keys.GetPersonalizedTickets().empty())
  143. out_entries = 0;
  144. else
  145. out_entries = ctx.GetWriteBufferSize() / sizeof(u128);
  146. LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
  147. keys.PopulateTickets();
  148. const auto tickets = keys.GetPersonalizedTickets();
  149. std::vector<u128> ids;
  150. std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
  151. [](const auto& pair) { return pair.first; });
  152. out_entries = std::min<u32>(ids.size(), out_entries);
  153. ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
  154. IPC::ResponseBuilder rb{ctx, 3};
  155. rb.Push(RESULT_SUCCESS);
  156. rb.Push<u32>(out_entries);
  157. }
  158. void GetCommonTicketSize(Kernel::HLERequestContext& ctx) {
  159. IPC::RequestParser rp{ctx};
  160. const auto rights_id = rp.PopRaw<u128>();
  161. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  162. if (!CheckRightsId(ctx, rights_id))
  163. return;
  164. const auto ticket = keys.GetCommonTickets().at(rights_id);
  165. IPC::ResponseBuilder rb{ctx, 4};
  166. rb.Push(RESULT_SUCCESS);
  167. rb.Push<u64>(ticket.GetSize());
  168. }
  169. void GetPersonalizedTicketSize(Kernel::HLERequestContext& ctx) {
  170. IPC::RequestParser rp{ctx};
  171. const auto rights_id = rp.PopRaw<u128>();
  172. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  173. if (!CheckRightsId(ctx, rights_id))
  174. return;
  175. const auto ticket = keys.GetPersonalizedTickets().at(rights_id);
  176. IPC::ResponseBuilder rb{ctx, 4};
  177. rb.Push(RESULT_SUCCESS);
  178. rb.Push<u64>(ticket.GetSize());
  179. }
  180. void GetCommonTicketData(Kernel::HLERequestContext& ctx) {
  181. IPC::RequestParser rp{ctx};
  182. const auto rights_id = rp.PopRaw<u128>();
  183. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  184. if (!CheckRightsId(ctx, rights_id))
  185. return;
  186. const auto ticket = keys.GetCommonTickets().at(rights_id);
  187. const auto write_size = std::min(ticket.GetSize(), ctx.GetWriteBufferSize());
  188. ctx.WriteBuffer(&ticket, write_size);
  189. IPC::ResponseBuilder rb{ctx, 4};
  190. rb.Push(RESULT_SUCCESS);
  191. rb.Push<u64>(write_size);
  192. }
  193. void GetPersonalizedTicketData(Kernel::HLERequestContext& ctx) {
  194. IPC::RequestParser rp{ctx};
  195. const auto rights_id = rp.PopRaw<u128>();
  196. LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
  197. if (!CheckRightsId(ctx, rights_id))
  198. return;
  199. const auto ticket = keys.GetPersonalizedTickets().at(rights_id);
  200. const auto write_size = std::min(ticket.GetSize(), ctx.GetWriteBufferSize());
  201. ctx.WriteBuffer(&ticket, write_size);
  202. IPC::ResponseBuilder rb{ctx, 4};
  203. rb.Push(RESULT_SUCCESS);
  204. rb.Push<u64>(write_size);
  205. }
  206. Core::Crypto::KeyManager keys;
  207. };
  208. void InstallInterfaces(SM::ServiceManager& service_manager) {
  209. std::make_shared<ETicket>()->InstallAsService(service_manager);
  210. }
  211. } // namespace Service::ES