Browse Source
Merge pull request #13159 from liamwhite/web-error
Merge pull request #13159 from liamwhite/web-error
core: enable error applet, add stubs for web appletpull/15/merge
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 494 additions and 45 deletions
-
2src/common/settings.h
-
3src/core/CMakeLists.txt
-
23src/core/hle/service/acc/acc.cpp
-
2src/core/hle/service/acc/acc_u1.cpp
-
5src/core/hle/service/am/am_types.h
-
4src/core/hle/service/am/service/common_state_getter.cpp
-
3src/core/hle/service/am/service/common_state_getter.h
-
40src/core/hle/service/erpt/erpt.cpp
-
72src/core/hle/service/filesystem/fsp/fsp_srv.cpp
-
16src/core/hle/service/filesystem/fsp/fsp_srv.h
-
13src/core/hle/service/ldn/monitor_service.cpp
-
1src/core/hle/service/ldn/monitor_service.h
-
5src/core/hle/service/set/settings_types.h
-
16src/core/hle/service/set/system_settings_server.cpp
-
2src/core/hle/service/set/system_settings_server.h
-
156src/core/hle/service/ssl/cert_store.cpp
-
42src/core/hle/service/ssl/cert_store.h
-
25src/core/hle/service/ssl/ssl.cpp
-
107src/core/hle/service/ssl/ssl_types.h
-
2src/yuzu/configuration/configure_applets.cpp
@ -0,0 +1,156 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/alignment.h"
|
|||
#include "core/core.h"
|
|||
#include "core/file_sys/content_archive.h"
|
|||
#include "core/file_sys/nca_metadata.h"
|
|||
#include "core/file_sys/registered_cache.h"
|
|||
#include "core/file_sys/romfs.h"
|
|||
#include "core/hle/service/filesystem/filesystem.h"
|
|||
#include "core/hle/service/ssl/cert_store.h"
|
|||
|
|||
namespace Service::SSL { |
|||
|
|||
// https://switchbrew.org/wiki/SSL_services#CertStore
|
|||
|
|||
CertStore::CertStore(Core::System& system) { |
|||
constexpr u64 CertStoreDataId = 0x0100000000000800ULL; |
|||
|
|||
auto& fsc = system.GetFileSystemController(); |
|||
|
|||
// Attempt to load certificate data from storage
|
|||
const auto nca = |
|||
fsc.GetSystemNANDContents()->GetEntry(CertStoreDataId, FileSys::ContentRecordType::Data); |
|||
if (!nca) { |
|||
return; |
|||
} |
|||
const auto romfs = nca->GetRomFS(); |
|||
if (!romfs) { |
|||
return; |
|||
} |
|||
const auto extracted = FileSys::ExtractRomFS(romfs); |
|||
if (!extracted) { |
|||
LOG_ERROR(Service_SSL, "CertStore could not be extracted, corrupt RomFS?"); |
|||
return; |
|||
} |
|||
const auto cert_store_file = extracted->GetFile("ssl_TrustedCerts.bdf"); |
|||
if (!cert_store_file) { |
|||
LOG_ERROR(Service_SSL, "Failed to find trusted certificates in CertStore"); |
|||
return; |
|||
} |
|||
|
|||
// Read and verify the header.
|
|||
CertStoreHeader header; |
|||
cert_store_file->ReadObject(std::addressof(header)); |
|||
|
|||
if (header.magic != Common::MakeMagic('s', 's', 'l', 'T')) { |
|||
LOG_ERROR(Service_SSL, "Invalid certificate store magic"); |
|||
return; |
|||
} |
|||
|
|||
// Ensure the file can contains the number of entries it says it does.
|
|||
const u64 expected_size = sizeof(header) + sizeof(CertStoreEntry) * header.num_entries; |
|||
const u64 actual_size = cert_store_file->GetSize(); |
|||
if (actual_size < expected_size) { |
|||
LOG_ERROR(Service_SSL, "Size mismatch, expected at least {} bytes, got {}", expected_size, |
|||
actual_size); |
|||
return; |
|||
} |
|||
|
|||
// Read entries.
|
|||
std::vector<CertStoreEntry> entries(header.num_entries); |
|||
cert_store_file->ReadArray(entries.data(), header.num_entries, sizeof(header)); |
|||
|
|||
// Insert into memory store.
|
|||
for (const auto& entry : entries) { |
|||
m_certs.emplace(entry.certificate_id, |
|||
Certificate{ |
|||
.status = entry.certificate_status, |
|||
.der_data = cert_store_file->ReadBytes( |
|||
entry.der_size, entry.der_offset + sizeof(header)), |
|||
}); |
|||
} |
|||
} |
|||
|
|||
CertStore::~CertStore() = default; |
|||
|
|||
template <typename F> |
|||
void CertStore::ForEachCertificate(std::span<const CaCertificateId> certificate_ids, F&& f) { |
|||
if (certificate_ids.size() == 1 && certificate_ids.front() == CaCertificateId::All) { |
|||
for (const auto& entry : m_certs) { |
|||
f(entry); |
|||
} |
|||
} else { |
|||
for (const auto certificate_id : certificate_ids) { |
|||
const auto entry = m_certs.find(certificate_id); |
|||
if (entry == m_certs.end()) { |
|||
continue; |
|||
} |
|||
f(*entry); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Result CertStore::GetCertificates(u32* out_num_entries, std::span<u8> out_data, |
|||
std::span<const CaCertificateId> certificate_ids) { |
|||
// Ensure the buffer is large enough to hold the output.
|
|||
u32 required_size; |
|||
R_TRY(this->GetCertificateBufSize(std::addressof(required_size), out_num_entries, |
|||
certificate_ids)); |
|||
R_UNLESS(out_data.size_bytes() >= required_size, ResultUnknown); |
|||
|
|||
// Make parallel arrays.
|
|||
std::vector<BuiltInCertificateInfo> cert_infos; |
|||
std::vector<u8> der_datas; |
|||
|
|||
const u32 der_data_offset = (*out_num_entries + 1) * sizeof(BuiltInCertificateInfo); |
|||
u32 cur_der_offset = der_data_offset; |
|||
|
|||
// Fill output.
|
|||
this->ForEachCertificate(certificate_ids, [&](auto& entry) { |
|||
const auto& [status, cur_der_data] = entry.second; |
|||
BuiltInCertificateInfo cert_info{ |
|||
.cert_id = entry.first, |
|||
.status = status, |
|||
.der_size = cur_der_data.size(), |
|||
.der_offset = cur_der_offset, |
|||
}; |
|||
|
|||
cert_infos.push_back(cert_info); |
|||
der_datas.insert(der_datas.end(), cur_der_data.begin(), cur_der_data.end()); |
|||
cur_der_offset += static_cast<u32>(cur_der_data.size()); |
|||
}); |
|||
|
|||
// Append terminator entry.
|
|||
cert_infos.push_back(BuiltInCertificateInfo{ |
|||
.cert_id = CaCertificateId::All, |
|||
.status = TrustedCertStatus::Invalid, |
|||
.der_size = 0, |
|||
.der_offset = 0, |
|||
}); |
|||
|
|||
// Write to output span.
|
|||
std::memcpy(out_data.data(), cert_infos.data(), |
|||
cert_infos.size() * sizeof(BuiltInCertificateInfo)); |
|||
std::memcpy(out_data.data() + der_data_offset, der_datas.data(), der_datas.size()); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result CertStore::GetCertificateBufSize(u32* out_size, u32* out_num_entries, |
|||
std::span<const CaCertificateId> certificate_ids) { |
|||
// Output size is at least the size of the terminator entry.
|
|||
*out_size = sizeof(BuiltInCertificateInfo); |
|||
*out_num_entries = 0; |
|||
|
|||
this->ForEachCertificate(certificate_ids, [&](auto& entry) { |
|||
*out_size += sizeof(BuiltInCertificateInfo); |
|||
*out_size += Common::AlignUp(static_cast<u32>(entry.second.der_data.size()), 4); |
|||
(*out_num_entries)++; |
|||
}); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::SSL
|
|||
@ -0,0 +1,42 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include <span> |
|||
#include <vector> |
|||
|
|||
#include "core/hle/result.h" |
|||
#include "core/hle/service/ssl/ssl_types.h" |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace Service::SSL { |
|||
|
|||
class CertStore { |
|||
public: |
|||
explicit CertStore(Core::System& system); |
|||
~CertStore(); |
|||
|
|||
Result GetCertificates(u32* out_num_entries, std::span<u8> out_data, |
|||
std::span<const CaCertificateId> certificate_ids); |
|||
Result GetCertificateBufSize(u32* out_size, u32* out_num_entries, |
|||
std::span<const CaCertificateId> certificate_ids); |
|||
|
|||
private: |
|||
template <typename F> |
|||
void ForEachCertificate(std::span<const CaCertificateId> certs, F&& f); |
|||
|
|||
private: |
|||
struct Certificate { |
|||
TrustedCertStatus status; |
|||
std::vector<u8> der_data; |
|||
}; |
|||
|
|||
std::map<CaCertificateId, Certificate> m_certs; |
|||
}; |
|||
|
|||
} // namespace Service::SSL |
|||
@ -0,0 +1,107 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
|
|||
namespace Service::SSL { |
|||
|
|||
enum class CaCertificateId : s32 { |
|||
All = -1, |
|||
NintendoCAG3 = 1, |
|||
NintendoClass2CAG3 = 2, |
|||
NintendoRootCAG4 = 3, |
|||
AmazonRootCA1 = 1000, |
|||
StarfieldServicesRootCertificateAuthorityG2 = 1001, |
|||
AddTrustExternalCARoot = 1002, |
|||
COMODOCertificationAuthority = 1003, |
|||
UTNDATACorpSGC = 1004, |
|||
UTNUSERFirstHardware = 1005, |
|||
BaltimoreCyberTrustRoot = 1006, |
|||
CybertrustGlobalRoot = 1007, |
|||
VerizonGlobalRootCA = 1008, |
|||
DigiCertAssuredIDRootCA = 1009, |
|||
DigiCertAssuredIDRootG2 = 1010, |
|||
DigiCertGlobalRootCA = 1011, |
|||
DigiCertGlobalRootG2 = 1012, |
|||
DigiCertHighAssuranceEVRootCA = 1013, |
|||
EntrustnetCertificationAuthority2048 = 1014, |
|||
EntrustRootCertificationAuthority = 1015, |
|||
EntrustRootCertificationAuthorityG2 = 1016, |
|||
GeoTrustGlobalCA2 = 1017, |
|||
GeoTrustGlobalCA = 1018, |
|||
GeoTrustPrimaryCertificationAuthorityG3 = 1019, |
|||
GeoTrustPrimaryCertificationAuthority = 1020, |
|||
GlobalSignRootCA = 1021, |
|||
GlobalSignRootCAR2 = 1022, |
|||
GlobalSignRootCAR3 = 1023, |
|||
GoDaddyClass2CertificationAuthority = 1024, |
|||
GoDaddyRootCertificateAuthorityG2 = 1025, |
|||
StarfieldClass2CertificationAuthority = 1026, |
|||
StarfieldRootCertificateAuthorityG2 = 1027, |
|||
thawtePrimaryRootCAG3 = 1028, |
|||
thawtePrimaryRootCA = 1029, |
|||
VeriSignClass3PublicPrimaryCertificationAuthorityG3 = 1030, |
|||
VeriSignClass3PublicPrimaryCertificationAuthorityG5 = 1031, |
|||
VeriSignUniversalRootCertificationAuthority = 1032, |
|||
DSTRootCAX3 = 1033, |
|||
USERTrustRsaCertificationAuthority = 1034, |
|||
ISRGRootX10 = 1035, |
|||
USERTrustEccCertificationAuthority = 1036, |
|||
COMODORsaCertificationAuthority = 1037, |
|||
COMODOEccCertificationAuthority = 1038, |
|||
AmazonRootCA2 = 1039, |
|||
AmazonRootCA3 = 1040, |
|||
AmazonRootCA4 = 1041, |
|||
DigiCertAssuredIDRootG3 = 1042, |
|||
DigiCertGlobalRootG3 = 1043, |
|||
DigiCertTrustedRootG4 = 1044, |
|||
EntrustRootCertificationAuthorityEC1 = 1045, |
|||
EntrustRootCertificationAuthorityG4 = 1046, |
|||
GlobalSignECCRootCAR4 = 1047, |
|||
GlobalSignECCRootCAR5 = 1048, |
|||
GlobalSignECCRootCAR6 = 1049, |
|||
GTSRootR1 = 1050, |
|||
GTSRootR2 = 1051, |
|||
GTSRootR3 = 1052, |
|||
GTSRootR4 = 1053, |
|||
SecurityCommunicationRootCA = 1054, |
|||
GlobalSignRootE4 = 1055, |
|||
GlobalSignRootR4 = 1056, |
|||
TTeleSecGlobalRootClass2 = 1057, |
|||
DigiCertTLSECCP384RootG5 = 1058, |
|||
DigiCertTLSRSA4096RootG5 = 1059, |
|||
}; |
|||
|
|||
enum class TrustedCertStatus : s32 { |
|||
Invalid = -1, |
|||
Removed = 0, |
|||
EnabledTrusted = 1, |
|||
EnabledNotTrusted = 2, |
|||
Revoked = 3, |
|||
}; |
|||
|
|||
struct BuiltInCertificateInfo { |
|||
CaCertificateId cert_id; |
|||
TrustedCertStatus status; |
|||
u64 der_size; |
|||
u64 der_offset; |
|||
}; |
|||
static_assert(sizeof(BuiltInCertificateInfo) == 0x18, "BuiltInCertificateInfo has incorrect size."); |
|||
|
|||
struct CertStoreHeader { |
|||
u32 magic; |
|||
u32 num_entries; |
|||
}; |
|||
static_assert(sizeof(CertStoreHeader) == 0x8, "CertStoreHeader has incorrect size."); |
|||
|
|||
struct CertStoreEntry { |
|||
CaCertificateId certificate_id; |
|||
TrustedCertStatus certificate_status; |
|||
u32 der_size; |
|||
u32 der_offset; |
|||
}; |
|||
static_assert(sizeof(CertStoreEntry) == 0x10, "CertStoreEntry has incorrect size."); |
|||
|
|||
} // namespace Service::SSL |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue