Files
AnyPS5/core/libs/tests/GuestSandboxCertificates.cpp
T

103 lines
4.9 KiB
C++

#include "prx/libc/include/General.hpp"
#include "prx/libkernel/KernelErrors.hpp"
#include "SceTypes.hpp"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <string>
extern "C" {
const char* APS5_VABI sceKernelGetFsSandboxRandomWord();
int APS5_VABI sceKernelOpen(const char*, int, unsigned short);
int APS5_VABI sceKernelClose(int);
std::int64_t APS5_VABI sceKernelRead(int, void*, std::size_t);
int APS5_VABI sceKernelStat(const char*, FileStat*);
void* APS5_VABI fopen_nid_postfix(const char*, const char*);
std::size_t APS5_VABI fread_nid_postfix(void*, std::size_t, std::size_t, void*);
int APS5_VABI fclose_nid_postfix(void*);
}
static void Check(bool value, int line) {
if (!value) {
std::fprintf(stderr, "Sandbox certificates check failed at line %d\n", line);
std::abort();
}
}
#define Require(value) Check((value), __LINE__)
static std::string ReadKernel(const std::string& path) {
const int descriptor = sceKernelOpen(path.c_str(), 0, 0);
Require(descriptor >= 0);
std::string text;
char buffer[4096];
for (std::int64_t count; (count = sceKernelRead(descriptor, buffer, sizeof(buffer))) != 0;) {
Require(count > 0);
text.append(buffer, static_cast<std::size_t>(count));
}
Require(sceKernelClose(descriptor) == 0);
return text;
}
static std::string ReadStream(const std::string& path) {
void* stream = fopen_nid_postfix(path.c_str(), "rb");
Require(stream != nullptr);
std::string text;
char buffer[4096];
for (std::size_t count; (count = fread_nid_postfix(buffer, 1, sizeof(buffer), stream)) != 0;) text.append(buffer, count);
Require(fclose_nid_postfix(stream) == 0);
return text;
}
static void CheckOverrides(const std::string& directory, const std::string& path) {
const auto root = std::filesystem::current_path();
const auto supplied = root / std::filesystem::path(path).relative_path();
std::filesystem::create_directories(supplied.parent_path());
const std::string expected = "explicit guest certificate bundle\n";
{ std::ofstream file(supplied, std::ios::binary | std::ios::trunc); file << expected; Require(static_cast<bool>(file)); }
Require(ReadKernel(path) == expected);
Require(ReadStream(path) == expected);
Require(ResolvePath_nid_no_patch(path.c_str()) == supplied);
Require(std::filesystem::remove(supplied));
for (auto parent = supplied.parent_path(); parent != root; parent = parent.parent_path())
Require(std::filesystem::remove(parent));
const auto alias = root / "sandbox_certificate_override";
std::filesystem::create_directory(alias);
{ std::ofstream file(alias / "CA_LIST.cer", std::ios::binary | std::ios::trunc); file << expected; Require(static_cast<bool>(file)); }
AddPathAlias_nid_no_patch(directory.c_str(), alias.string().c_str());
Require(ReadKernel(path) == expected && ReadStream(path) == expected);
BlockPathAlias_nid_no_patch(directory.c_str());
Require(sceKernelOpen(path.c_str(), 0, 0) == SCE_KERNEL_ERROR_ENOENT);
Require(fopen_nid_postfix(path.c_str(), "rb") == nullptr);
AddPathAlias_nid_no_patch(directory.c_str(), alias.string().c_str());
RemovePathAlias_nid_no_patch(directory.c_str());
Require(std::filesystem::remove(alias / "CA_LIST.cer"));
Require(std::filesystem::remove(alias));
}
int main() {
#ifndef _WIN32
const auto bundle = std::filesystem::absolute("host_bundle.pem");
const std::string expected = "-----BEGIN CERTIFICATE-----\nMIIBAA==\n-----END CERTIFICATE-----\n";
{ std::ofstream file(bundle, std::ios::binary | std::ios::trunc); file << expected; }
Require(setenv("SSL_CERT_FILE", bundle.c_str(), 1) == 0);
#endif
const std::string directory = std::string("/") + sceKernelGetFsSandboxRandomWord() + "/common/cert";
const std::string path = directory + "/CA_LIST.cer";
CheckOverrides(directory, path);
const auto text = ReadKernel(path);
const auto begin = text.find("-----BEGIN CERTIFICATE-----");
Require(begin != std::string::npos);
Require(text.find("-----END CERTIFICATE-----", begin) != std::string::npos);
#ifndef _WIN32
Require(text == expected);
#endif
Require(ReadStream(path) == text);
Require(ReadKernel(directory + "/./ca_list.cer") == text);
FileStat status{};
Require(sceKernelStat(path.c_str(), &status) == 0);
Require(status.st_size == static_cast<std::int64_t>(text.size()));
const auto cached = std::filesystem::current_path() / "cert_cache" / "CA_LIST.cer";
Require(std::filesystem::is_regular_file(cached));
Require((std::filesystem::status(cached).permissions() & std::filesystem::perms::owner_write) == std::filesystem::perms::none);
Require(sceKernelOpen((directory + "/CA_LIST2.cer").c_str(), 0, 0) == SCE_KERNEL_ERROR_ENOENT);
Require(sceKernelOpen((directory + "/CA_LIST.cer.bak").c_str(), 0, 0) == SCE_KERNEL_ERROR_ENOENT);
Require(fopen_nid_postfix((directory + "/CA_LIST2.cer").c_str(), "rb") == nullptr);
return 0;
}