18#include "3rdparty/monocypher/monocypher.h"
19#include "3rdparty/monocypher/monocypher-ed25519.h"
20#include "3rdparty/nlohmann/json.hpp"
27 { 0xed, 0x5d, 0x57, 0x47, 0x21, 0x99, 0x8b, 0x02, 0xdf, 0x6e, 0x3d, 0x69, 0xe1, 0x87, 0xca, 0xd0, 0x0e, 0x88, 0xc3, 0xe2, 0xb2, 0xa6, 0x7b, 0xc0, 0x42, 0xc8, 0xd6, 0x4b, 0x65, 0xe6, 0x48, 0xf7 },
39 if (!f.has_value())
return {};
41 std::array<uint8_t, 32> digest;
42 crypto_blake2b_ctx ctx;
43 crypto_blake2b_init(&ctx, digest.size());
46 std::array<uint8_t, 1024> buf;
47 size_t len = fread(buf.data(), 1, buf.size(), *f);
49 crypto_blake2b_update(&ctx, buf.data(), len);
52 crypto_blake2b_final(&ctx, digest.data());
66 auto pos = checksum.find(
'$');
67 assert(pos != std::string::npos);
68 const std::string version = checksum.substr(0, pos);
69 const std::string hash = checksum.substr(pos + 1);
72 std::string calculated_hash;
76 Debug(misc, 0,
"Failed to validate signature: unknown checksum version: {}", filename);
81 if (calculated_hash.empty()) {
82 Debug(misc, 0,
"Failed to validate signature: couldn't calculate checksum for: {}", filename);
85 if (calculated_hash != hash) {
86 Debug(misc, 0,
"Failed to validate signature: checksum mismatch for: {}", filename);
101static bool ValidateSignature(
const std::string &signature,
const nlohmann::json &files,
const std::string &filename)
104 auto pos = signature.find(
'$');
105 assert(pos != std::string::npos);
106 const std::string version = signature.substr(0, pos);
107 const std::string sig_value = signature.substr(pos + 1);
110 std::string message = files.dump(-1);
113 if (version ==
"1") {
114 std::array<uint8_t, 64> sig;
116 Debug(misc, 0,
"Failed to validate signature: invalid signature: {}", filename);
122 auto res = crypto_ed25519_check(sig.data(), pk_value.data(),
reinterpret_cast<uint8_t *
>(message.data()), message.size());
128 Debug(misc, 0,
"Failed to validate signature: signature validation failed: {}", filename);
131 Debug(misc, 0,
"Failed to validate signature: unknown signature version: {}", filename);
145static bool ValidateSchema(
const nlohmann::json &signatures,
const std::string &filename)
147 if (signatures[
"files"].is_null()) {
148 Debug(misc, 0,
"Failed to validate signature: no files found: {}", filename);
152 if (signatures[
"signature"].is_null()) {
153 Debug(misc, 0,
"Failed to validate signature: no signature found: {}", filename);
157 for (
auto &signature : signatures[
"files"]) {
158 if (signature[
"filename"].is_null() || signature[
"checksum"].is_null()) {
159 Debug(misc, 0,
"Failed to validate signature: invalid entry in files: {}", filename);
163 const std::string sig_filename = signature[
"filename"];
164 const std::string sig_checksum = signature[
"checksum"];
166 if (sig_filename.empty() || sig_checksum.empty()) {
167 Debug(misc, 0,
"Failed to validate signature: invalid entry in files: {}", filename);
171 auto pos = sig_checksum.find(
'$');
172 if (pos == std::string::npos) {
173 Debug(misc, 0,
"Failed to validate signature: invalid checksum format: {}", filename);
178 const std::string signature = signatures[
"signature"];
179 auto pos = signature.find(
'$');
180 if (pos == std::string::npos) {
181 Debug(misc, 0,
"Failed to validate signature: invalid signature format: {}", filename);
198 if (!f.has_value()) {
199 Debug(misc, 0,
"Failed to validate signature: file not found: {}", filename);
203 std::string text(filesize,
'\0');
204 size_t len = fread(text.data(), filesize, 1, *f);
206 Debug(misc, 0,
"Failed to validate signature: failed to read file: {}", filename);
210 nlohmann::json signatures;
212 signatures = nlohmann::json::parse(text);
213 }
catch (nlohmann::json::exception &) {
214 Debug(misc, 0,
"Failed to validate signature: not a valid JSON file: {}", filename);
240 if (!
ValidateSignature(signatures[
"signature"], signatures[
"files"], filename)) {
244 std::string dirname =
FS2OTTD(std::filesystem::path(
OTTD2FS(filename)).parent_path());
246 for (
auto &signature : signatures[
"files"]) {
247 const std::string sig_filename = dirname + PATHSEPCHAR + signature[
"filename"].get<std::string>();
248 const std::string sig_checksum = signature[
"checksum"];
270#if defined(ALLOW_INVALID_SIGNATURE)
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
std::optional< FileHandle > FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Functions for Standard In/Out file operations.
@ NO_DIRECTORY
A path without any base directory.
A number of safeguards to prevent using unsafe methods.
static const std::initializer_list< std::array< uint8_t, 32 > > _public_keys_v1
The public keys used for signature validation.
static std::string CalculateHashV1(const std::string &filename)
Calculate the 32-byte blake2b hash of a file.
static bool ValidateSchema(const nlohmann::json &signatures, const std::string &filename)
Validate the signatures file complies with the JSON schema.
static bool _ValidateSignatureFile(const std::string &filename)
Validate that the signatures mentioned in the signature file are matching the files in question.
bool ValidateSignatureFile(const std::string &filename)
Validate that the signatures mentioned in the signature file are matching the files in question.
static bool ValidateSignature(const std::string &signature, const nlohmann::json &files, const std::string &filename)
Validate whether the signature is valid for this set of files.
static bool ValidateChecksum(const std::string &filename, const std::string &checksum)
Validate whether the checksum of a file is the same.
Routines to validate signature files.
Definition of base types and functions in a cross-platform compatible way.
bool ConvertHexToBytes(std::string_view hex, std::span< uint8_t > bytes)
Convert a hex-string to a byte-array, while validating it was actually hex.
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Functions related to low-level strings.
std::wstring OTTD2FS(const std::string &name)
Convert from OpenTTD's encoding to a wide string.
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.