forked from metin-server/m2dev-client-src
Add key id based m2p rotation support
This commit is contained in:
@@ -40,12 +40,6 @@ bool ReadPod(const uint8_t* bytes, std::size_t size, std::size_t& offset, T& out
|
|||||||
|
|
||||||
bool CM2Pack::Load(const std::string& path)
|
bool CM2Pack::Load(const std::string& path)
|
||||||
{
|
{
|
||||||
if (!HasM2PackRuntimeKeysForArchiveLoad())
|
|
||||||
{
|
|
||||||
TraceError("CM2Pack::Load: runtime master key required for '%s'", path.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
m_file.map(path, ec);
|
m_file.map(path, ec);
|
||||||
|
|
||||||
@@ -75,6 +69,15 @@ bool CM2Pack::Load(const std::string& path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!HasM2PackRuntimeKeysForArchiveLoad(m_header.key_id))
|
||||||
|
{
|
||||||
|
TraceError("CM2Pack::Load: runtime master key with key_id=%u required for '%s' (active key_id=%u)",
|
||||||
|
m_header.key_id,
|
||||||
|
path.c_str(),
|
||||||
|
GetM2PackActiveMasterKeyId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_header.manifest_offset + m_header.manifest_size > m_file.size())
|
if (m_header.manifest_offset + m_header.manifest_size > m_file.size())
|
||||||
{
|
{
|
||||||
TraceError("CM2Pack::Load: manifest out of bounds in '%s'", path.c_str());
|
TraceError("CM2Pack::Load: manifest out of bounds in '%s'", path.c_str());
|
||||||
@@ -111,11 +114,18 @@ bool CM2Pack::ValidateManifest()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto* publicKey = GetM2PackPublicKeyForKeyId(m_header.key_id);
|
||||||
|
if (!publicKey)
|
||||||
|
{
|
||||||
|
TraceError("CM2Pack::ValidateManifest: no public key configured for key_id=%u", m_header.key_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (crypto_sign_verify_detached(
|
if (crypto_sign_verify_detached(
|
||||||
m_header.manifest_signature,
|
m_header.manifest_signature,
|
||||||
m_manifest_bytes.data(),
|
m_manifest_bytes.data(),
|
||||||
m_manifest_bytes.size(),
|
m_manifest_bytes.size(),
|
||||||
GetM2PackActivePublicKey().data()) != 0)
|
publicKey->data()) != 0)
|
||||||
{
|
{
|
||||||
TraceError("CM2Pack::ValidateManifest: manifest signature mismatch");
|
TraceError("CM2Pack::ValidateManifest: manifest signature mismatch");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -26,11 +26,12 @@ struct TM2PackHeader
|
|||||||
char magic[M2PACK_MAGIC_SIZE];
|
char magic[M2PACK_MAGIC_SIZE];
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
uint32_t key_id;
|
||||||
uint64_t manifest_offset;
|
uint64_t manifest_offset;
|
||||||
uint64_t manifest_size;
|
uint64_t manifest_size;
|
||||||
uint8_t manifest_hash[M2PACK_HASH_SIZE];
|
uint8_t manifest_hash[M2PACK_HASH_SIZE];
|
||||||
uint8_t manifest_signature[M2PACK_SIGNATURE_SIZE];
|
uint8_t manifest_signature[M2PACK_SIGNATURE_SIZE];
|
||||||
uint8_t reserved[64];
|
uint8_t reserved[60];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TM2PackManifestHeader
|
struct TM2PackManifestHeader
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
constexpr bool M2PACK_RUNTIME_MASTER_KEY_REQUIRED = true;
|
constexpr bool M2PACK_RUNTIME_MASTER_KEY_REQUIRED = true;
|
||||||
|
|
||||||
|
constexpr uint32_t M2PACK_KEY_SLOT_COUNT = 1;
|
||||||
|
constexpr std::array<uint32_t, M2PACK_KEY_SLOT_COUNT> M2PACK_SIGN_KEY_IDS = { 1 };
|
||||||
|
|
||||||
constexpr std::array<uint8_t, M2PACK_KEY_SIZE> M2PACK_MASTER_KEY = {
|
constexpr std::array<uint8_t, M2PACK_KEY_SIZE> M2PACK_MASTER_KEY = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
@@ -16,9 +19,11 @@ constexpr std::array<uint8_t, M2PACK_KEY_SIZE> M2PACK_MASTER_KEY = {
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE> M2PACK_SIGN_PUBLIC_KEY = {
|
constexpr std::array<std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>, M2PACK_KEY_SLOT_COUNT> M2PACK_SIGN_PUBLIC_KEYS = {{
|
||||||
|
{
|
||||||
0x22, 0x69, 0x26, 0xd0, 0xa9, 0xa5, 0x53, 0x4c,
|
0x22, 0x69, 0x26, 0xd0, 0xa9, 0xa5, 0x53, 0x4c,
|
||||||
0x95, 0x45, 0xec, 0xba, 0xe9, 0x32, 0x46, 0xc9,
|
0x95, 0x45, 0xec, 0xba, 0xe9, 0x32, 0x46, 0xc9,
|
||||||
0x43, 0x80, 0x5c, 0x1a, 0x2c, 0x57, 0xc0, 0x03,
|
0x43, 0x80, 0x5c, 0x1a, 0x2c, 0x57, 0xc0, 0x03,
|
||||||
0xd9, 0x72, 0x41, 0x19, 0xea, 0x0b, 0xc6, 0xa4
|
0xd9, 0x72, 0x41, 0x19, 0xea, 0x0b, 0xc6, 0xa4
|
||||||
};
|
}
|
||||||
|
}};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ constexpr const char* M2PACK_DEFAULT_MAP_NAME = "Local\\M2PackSharedKeys";
|
|||||||
constexpr const char* M2PACK_ENV_MASTER_KEY = "M2PACK_MASTER_KEY_HEX";
|
constexpr const char* M2PACK_ENV_MASTER_KEY = "M2PACK_MASTER_KEY_HEX";
|
||||||
constexpr const char* M2PACK_ENV_PUBLIC_KEY = "M2PACK_SIGN_PUBKEY_HEX";
|
constexpr const char* M2PACK_ENV_PUBLIC_KEY = "M2PACK_SIGN_PUBKEY_HEX";
|
||||||
constexpr const char* M2PACK_ENV_MAP_NAME = "M2PACK_KEY_MAP";
|
constexpr const char* M2PACK_ENV_MAP_NAME = "M2PACK_KEY_MAP";
|
||||||
|
constexpr const char* M2PACK_ENV_KEY_ID = "M2PACK_KEY_ID";
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct M2PackSharedKeys
|
struct M2PackSharedKeys
|
||||||
@@ -24,6 +25,7 @@ struct M2PackSharedKeys
|
|||||||
char magic[8];
|
char magic[8];
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
uint32_t key_id;
|
||||||
uint8_t master_key[M2PACK_KEY_SIZE];
|
uint8_t master_key[M2PACK_KEY_SIZE];
|
||||||
uint8_t sign_public_key[M2PACK_PUBLIC_KEY_SIZE];
|
uint8_t sign_public_key[M2PACK_PUBLIC_KEY_SIZE];
|
||||||
};
|
};
|
||||||
@@ -31,8 +33,9 @@ struct M2PackSharedKeys
|
|||||||
|
|
||||||
struct RuntimeKeyState
|
struct RuntimeKeyState
|
||||||
{
|
{
|
||||||
|
uint32_t master_key_id = 0;
|
||||||
std::array<uint8_t, M2PACK_KEY_SIZE> master_key {};
|
std::array<uint8_t, M2PACK_KEY_SIZE> master_key {};
|
||||||
std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE> public_key = M2PACK_SIGN_PUBLIC_KEY;
|
std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE> public_key {};
|
||||||
bool runtime_master_key = false;
|
bool runtime_master_key = false;
|
||||||
bool runtime_public_key = false;
|
bool runtime_public_key = false;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
@@ -82,6 +85,32 @@ std::string GetEnvString(const char* name)
|
|||||||
return std::string(buffer, buffer + len);
|
return std::string(buffer, buffer + len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ParseUInt32(const std::string& value)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return static_cast<uint32_t>(std::stoul(value));
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>* FindCompiledPublicKey(uint32_t keyId)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < M2PACK_SIGN_KEY_IDS.size(); ++i)
|
||||||
|
{
|
||||||
|
if (M2PACK_SIGN_KEY_IDS[i] == keyId)
|
||||||
|
return &M2PACK_SIGN_PUBLIC_KEYS[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool LoadFromSharedMapping(const std::string& mappingName)
|
bool LoadFromSharedMapping(const std::string& mappingName)
|
||||||
{
|
{
|
||||||
const HANDLE mapping = OpenFileMappingA(FILE_MAP_READ, FALSE, mappingName.c_str());
|
const HANDLE mapping = OpenFileMappingA(FILE_MAP_READ, FALSE, mappingName.c_str());
|
||||||
@@ -108,6 +137,7 @@ bool LoadFromSharedMapping(const std::string& mappingName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memcpy(g_state.master_key.data(), blob.master_key, g_state.master_key.size());
|
memcpy(g_state.master_key.data(), blob.master_key, g_state.master_key.size());
|
||||||
|
g_state.master_key_id = blob.key_id;
|
||||||
memcpy(g_state.public_key.data(), blob.sign_public_key, g_state.public_key.size());
|
memcpy(g_state.public_key.data(), blob.sign_public_key, g_state.public_key.size());
|
||||||
g_state.runtime_master_key = true;
|
g_state.runtime_master_key = true;
|
||||||
g_state.runtime_public_key = true;
|
g_state.runtime_public_key = true;
|
||||||
@@ -129,6 +159,20 @@ void ApplyCommandLineOption(const std::string& key, const std::string& value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key == "--m2pack-key-id")
|
||||||
|
{
|
||||||
|
const auto parsed = ParseUInt32(value);
|
||||||
|
if (parsed != 0)
|
||||||
|
{
|
||||||
|
g_state.master_key_id = parsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TraceError("Invalid value for --m2pack-key-id");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (key == "--m2pack-pubkey-hex")
|
if (key == "--m2pack-pubkey-hex")
|
||||||
{
|
{
|
||||||
if (ParseHexInto(value, g_state.public_key))
|
if (ParseHexInto(value, g_state.public_key))
|
||||||
@@ -177,6 +221,16 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
|
|||||||
TraceError("Invalid M2PACK_MASTER_KEY_HEX value");
|
TraceError("Invalid M2PACK_MASTER_KEY_HEX value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string envKeyId = GetEnvString(M2PACK_ENV_KEY_ID);
|
||||||
|
if (!envKeyId.empty())
|
||||||
|
{
|
||||||
|
const auto parsed = ParseUInt32(envKeyId);
|
||||||
|
if (parsed != 0)
|
||||||
|
g_state.master_key_id = parsed;
|
||||||
|
else
|
||||||
|
TraceError("Invalid M2PACK_KEY_ID value");
|
||||||
|
}
|
||||||
|
|
||||||
const std::string envPublic = GetEnvString(M2PACK_ENV_PUBLIC_KEY);
|
const std::string envPublic = GetEnvString(M2PACK_ENV_PUBLIC_KEY);
|
||||||
if (!envPublic.empty())
|
if (!envPublic.empty())
|
||||||
{
|
{
|
||||||
@@ -193,7 +247,7 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
|
|||||||
for (int i = 0; i < argc; ++i)
|
for (int i = 0; i < argc; ++i)
|
||||||
{
|
{
|
||||||
const std::string key = argv[i];
|
const std::string key = argv[i];
|
||||||
if ((key == "--m2pack-key-hex" || key == "--m2pack-pubkey-hex" || key == "--m2pack-key-map") && i + 1 < argc)
|
if ((key == "--m2pack-key-hex" || key == "--m2pack-pubkey-hex" || key == "--m2pack-key-map" || key == "--m2pack-key-id") && i + 1 < argc)
|
||||||
{
|
{
|
||||||
ApplyCommandLineOption(key, argv[i + 1]);
|
ApplyCommandLineOption(key, argv[i + 1]);
|
||||||
++i;
|
++i;
|
||||||
@@ -223,9 +277,19 @@ const std::array<uint8_t, M2PACK_KEY_SIZE>& GetM2PackActiveMasterKey()
|
|||||||
return g_state.master_key;
|
return g_state.master_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>& GetM2PackActivePublicKey()
|
const std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>* GetM2PackPublicKeyForKeyId(uint32_t keyId)
|
||||||
{
|
{
|
||||||
return g_state.public_key;
|
if (g_state.runtime_public_key && g_state.master_key_id == keyId)
|
||||||
|
{
|
||||||
|
return &g_state.public_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FindCompiledPublicKey(keyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetM2PackActiveMasterKeyId()
|
||||||
|
{
|
||||||
|
return g_state.master_key_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasM2PackRuntimeMasterKey()
|
bool HasM2PackRuntimeMasterKey()
|
||||||
@@ -233,9 +297,9 @@ bool HasM2PackRuntimeMasterKey()
|
|||||||
return g_state.runtime_master_key;
|
return g_state.runtime_master_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasM2PackRuntimeKeysForArchiveLoad()
|
bool HasM2PackRuntimeKeysForArchiveLoad(uint32_t keyId)
|
||||||
{
|
{
|
||||||
return g_state.runtime_master_key;
|
return g_state.runtime_master_key && g_state.master_key_id == keyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsM2PackUsingRuntimeMasterKey()
|
bool IsM2PackUsingRuntimeMasterKey()
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
bool InitializeM2PackRuntimeKeyProvider(const char* commandLine);
|
bool InitializeM2PackRuntimeKeyProvider(const char* commandLine);
|
||||||
const std::array<uint8_t, M2PACK_KEY_SIZE>& GetM2PackActiveMasterKey();
|
const std::array<uint8_t, M2PACK_KEY_SIZE>& GetM2PackActiveMasterKey();
|
||||||
const std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>& GetM2PackActivePublicKey();
|
const std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>* GetM2PackPublicKeyForKeyId(uint32_t keyId);
|
||||||
|
uint32_t GetM2PackActiveMasterKeyId();
|
||||||
bool HasM2PackRuntimeMasterKey();
|
bool HasM2PackRuntimeMasterKey();
|
||||||
bool HasM2PackRuntimeKeysForArchiveLoad();
|
bool HasM2PackRuntimeKeysForArchiveLoad(uint32_t keyId);
|
||||||
bool IsM2PackUsingRuntimeMasterKey();
|
bool IsM2PackUsingRuntimeMasterKey();
|
||||||
bool IsM2PackUsingRuntimePublicKey();
|
bool IsM2PackUsingRuntimePublicKey();
|
||||||
|
|||||||
Reference in New Issue
Block a user