Merge pull request #6914 from leoetlino/verifysign
ES: Implement VerifySign (last remaining unimplemented, actually used ioctlv)
This commit is contained in:
commit
3d8e63fffd
|
@ -278,8 +278,10 @@ std::array<u8, 60> Sign(const u8* key, const u8* hash)
|
|||
return signature;
|
||||
}
|
||||
|
||||
UNUSED static int check_ecdsa(u8* Q, u8* R, u8* S, const u8* hash)
|
||||
bool VerifySignature(const u8* public_key, const u8* signature, const u8* hash)
|
||||
{
|
||||
const u8* R = signature;
|
||||
const u8* S = signature + 30;
|
||||
u8 Sinv[30];
|
||||
|
||||
bn_inv(Sinv, S, ec_N, 30);
|
||||
|
@ -290,7 +292,7 @@ UNUSED static int check_ecdsa(u8* Q, u8* R, u8* S, const u8* hash)
|
|||
bn_mul(w1, e, Sinv, ec_N, 30);
|
||||
bn_mul(w2, R, Sinv, ec_N, 30);
|
||||
|
||||
Point r1 = w1 * ec_G + w2 * Point{Q};
|
||||
Point r1 = w1 * ec_G + w2 * Point{public_key};
|
||||
auto& rx = r1.X().data;
|
||||
if (bn_compare(rx.data(), ec_N, 30) >= 0)
|
||||
bn_sub_modulus(rx.data(), ec_N, 30);
|
||||
|
|
|
@ -13,6 +13,13 @@ namespace Common::ec
|
|||
/// Generate a signature using ECDSA.
|
||||
std::array<u8, 60> Sign(const u8* key, const u8* hash);
|
||||
|
||||
/// Check a signature using ECDSA.
|
||||
///
|
||||
/// @param public_key 30 byte ECC public key
|
||||
/// @param signature 60 byte signature
|
||||
/// @param hash Message hash
|
||||
bool VerifySignature(const u8* public_key, const u8* signature, const u8* hash);
|
||||
|
||||
/// Compute a shared secret from a private key (30 bytes) and public key (60 bytes).
|
||||
std::array<u8, 60> ComputeSharedSecret(const u8* private_key, const u8* public_key);
|
||||
|
||||
|
|
|
@ -524,6 +524,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
return GetDeviceCertificate(request);
|
||||
case IOCTL_ES_SIGN:
|
||||
return Sign(request);
|
||||
case IOCTL_ES_VERIFYSIGN:
|
||||
return VerifySign(request);
|
||||
case IOCTL_ES_GETBOOT2VERSION:
|
||||
return GetBoot2Version(request);
|
||||
|
||||
|
@ -539,7 +541,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
case IOCTL_ES_DELETE_STREAM_KEY:
|
||||
return DeleteStreamKey(request);
|
||||
|
||||
case IOCTL_ES_VERIFYSIGN:
|
||||
case IOCTL_ES_UNKNOWN_41:
|
||||
case IOCTL_ES_UNKNOWN_42:
|
||||
PanicAlert("IOS-ES: Unimplemented ioctlv 0x%x (%zu in vectors, %zu io vectors)",
|
||||
|
|
|
@ -132,6 +132,9 @@ public:
|
|||
ReturnCode GetDeviceId(u32* device_id) const;
|
||||
ReturnCode GetTitleId(u64* device_id) const;
|
||||
|
||||
ReturnCode VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
|
||||
const std::vector<u8>& certs);
|
||||
|
||||
// Views
|
||||
ReturnCode GetV0TicketFromView(const u8* ticket_view, u8* ticket) const;
|
||||
ReturnCode GetTicketFromView(const u8* ticket_view, u8* ticket, u32* ticket_size) const;
|
||||
|
@ -243,6 +246,7 @@ private:
|
|||
IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request);
|
||||
IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request);
|
||||
IPCCommandResult Sign(const IOCtlVRequest& request);
|
||||
IPCCommandResult VerifySign(const IOCtlVRequest& request);
|
||||
IPCCommandResult Encrypt(u32 uid, const IOCtlVRequest& request);
|
||||
IPCCommandResult Decrypt(u32 uid, const IOCtlVRequest& request);
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ std::array<u8, 20> SignedBlobReader::GetSha1() const
|
|||
bool SignedBlobReader::IsSignatureValid() const
|
||||
{
|
||||
// Too small for the certificate type.
|
||||
if (m_bytes.size() < sizeof(Cert::type))
|
||||
if (m_bytes.size() < sizeof(SignatureType))
|
||||
return false;
|
||||
|
||||
// Too small to contain the whole signature data.
|
||||
|
@ -146,20 +146,23 @@ SignatureType SignedBlobReader::GetSignatureType() const
|
|||
return static_cast<SignatureType>(Common::swap32(m_bytes.data()));
|
||||
}
|
||||
|
||||
template <typename T, typename It>
|
||||
static std::vector<u8> DetailGetSignatureData(It begin)
|
||||
{
|
||||
const auto signature_begin = begin + offsetof(T, sig);
|
||||
return std::vector<u8>(signature_begin, signature_begin + sizeof(T::sig));
|
||||
}
|
||||
|
||||
std::vector<u8> SignedBlobReader::GetSignatureData() const
|
||||
{
|
||||
switch (GetSignatureType())
|
||||
{
|
||||
case SignatureType::RSA4096:
|
||||
{
|
||||
const auto signature_begin = m_bytes.begin() + offsetof(SignatureRSA4096, sig);
|
||||
return std::vector<u8>(signature_begin, signature_begin + sizeof(SignatureRSA4096::sig));
|
||||
}
|
||||
return DetailGetSignatureData<SignatureRSA4096>(m_bytes.cbegin());
|
||||
case SignatureType::RSA2048:
|
||||
{
|
||||
const auto signature_begin = m_bytes.begin() + offsetof(SignatureRSA2048, sig);
|
||||
return std::vector<u8>(signature_begin, signature_begin + sizeof(SignatureRSA2048::sig));
|
||||
}
|
||||
return DetailGetSignatureData<SignatureRSA2048>(m_bytes.cbegin());
|
||||
case SignatureType::ECC:
|
||||
return DetailGetSignatureData<SignatureECC>(m_bytes.cbegin());
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
@ -173,27 +176,30 @@ size_t SignedBlobReader::GetSignatureSize() const
|
|||
return sizeof(SignatureRSA4096);
|
||||
case SignatureType::RSA2048:
|
||||
return sizeof(SignatureRSA2048);
|
||||
case SignatureType::ECC:
|
||||
return sizeof(SignatureECC);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::string DetailGetIssuer(const u8* bytes)
|
||||
{
|
||||
const char* issuer = reinterpret_cast<const char*>(bytes + offsetof(T, issuer));
|
||||
return {issuer, strnlen(issuer, sizeof(T::issuer))};
|
||||
}
|
||||
|
||||
std::string SignedBlobReader::GetIssuer() const
|
||||
{
|
||||
switch (GetSignatureType())
|
||||
{
|
||||
case SignatureType::RSA4096:
|
||||
{
|
||||
const char* issuer =
|
||||
reinterpret_cast<const char*>(m_bytes.data() + offsetof(SignatureRSA4096, issuer));
|
||||
return std::string(issuer, strnlen(issuer, sizeof(SignatureRSA4096::issuer)));
|
||||
}
|
||||
return DetailGetIssuer<SignatureRSA4096>(m_bytes.data());
|
||||
case SignatureType::RSA2048:
|
||||
{
|
||||
const char* issuer =
|
||||
reinterpret_cast<const char*>(m_bytes.data() + offsetof(SignatureRSA2048, issuer));
|
||||
return std::string(issuer, strnlen(issuer, sizeof(SignatureRSA2048::issuer)));
|
||||
}
|
||||
return DetailGetIssuer<SignatureRSA2048>(m_bytes.data());
|
||||
case SignatureType::ECC:
|
||||
return DetailGetIssuer<SignatureECC>(m_bytes.data());
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
@ -677,24 +683,22 @@ CertReader::CertReader(std::vector<u8>&& bytes) : SignedBlobReader(std::move(byt
|
|||
if (!IsSignatureValid())
|
||||
return;
|
||||
|
||||
switch (GetSignatureType())
|
||||
{
|
||||
case SignatureType::RSA4096:
|
||||
if (m_bytes.size() < sizeof(CertRSA4096))
|
||||
return;
|
||||
m_bytes.resize(sizeof(CertRSA4096));
|
||||
break;
|
||||
static constexpr std::array<std::tuple<SignatureType, PublicKeyType, size_t>, 4> types{{
|
||||
{SignatureType::RSA4096, PublicKeyType::RSA2048, sizeof(CertRSA4096RSA2048)},
|
||||
{SignatureType::RSA2048, PublicKeyType::RSA2048, sizeof(CertRSA2048RSA2048)},
|
||||
{SignatureType::RSA2048, PublicKeyType::ECC, sizeof(CertRSA2048ECC)},
|
||||
{SignatureType::ECC, PublicKeyType::ECC, sizeof(CertECC)},
|
||||
}};
|
||||
|
||||
case SignatureType::RSA2048:
|
||||
if (m_bytes.size() < sizeof(CertRSA2048))
|
||||
return;
|
||||
m_bytes.resize(sizeof(CertRSA2048));
|
||||
break;
|
||||
const auto info = std::find_if(types.cbegin(), types.cend(), [this](const auto& entry) {
|
||||
return m_bytes.size() >= std::get<2>(entry) && std::get<0>(entry) == GetSignatureType() &&
|
||||
std::get<1>(entry) == GetPublicKeyType();
|
||||
});
|
||||
|
||||
default:
|
||||
if (info == types.cend())
|
||||
return;
|
||||
}
|
||||
|
||||
m_bytes.resize(std::get<2>(*info));
|
||||
m_is_valid = true;
|
||||
}
|
||||
|
||||
|
@ -722,20 +726,28 @@ PublicKeyType CertReader::GetPublicKeyType() const
|
|||
return static_cast<PublicKeyType>(Common::swap32(m_bytes.data() + offset));
|
||||
}
|
||||
|
||||
template <typename T, typename It>
|
||||
std::vector<u8> DetailGetPublicKey(It begin, size_t extra_data = 0)
|
||||
{
|
||||
const auto key_begin = begin + offsetof(T, public_key);
|
||||
return {key_begin, key_begin + sizeof(T::public_key) + extra_data};
|
||||
}
|
||||
|
||||
std::vector<u8> CertReader::GetPublicKey() const
|
||||
{
|
||||
static const std::map<SignatureType, std::pair<size_t, size_t>> type_to_key_info = {{
|
||||
{SignatureType::RSA4096,
|
||||
{offsetof(CertRSA4096, public_key),
|
||||
sizeof(CertRSA4096::public_key) + sizeof(CertRSA4096::exponent)}},
|
||||
{SignatureType::RSA2048,
|
||||
{offsetof(CertRSA2048, public_key),
|
||||
sizeof(CertRSA2048::public_key) + sizeof(CertRSA2048::exponent)}},
|
||||
}};
|
||||
|
||||
const auto info = type_to_key_info.at(GetSignatureType());
|
||||
const auto key_begin = m_bytes.begin() + info.first;
|
||||
return std::vector<u8>(key_begin, key_begin + info.second);
|
||||
switch (GetSignatureType())
|
||||
{
|
||||
case SignatureType::RSA4096:
|
||||
return DetailGetPublicKey<CertRSA4096RSA2048>(m_bytes.begin(), 4);
|
||||
case SignatureType::RSA2048:
|
||||
if (GetPublicKeyType() == PublicKeyType::RSA2048)
|
||||
return DetailGetPublicKey<CertRSA2048RSA2048>(m_bytes.begin(), 4);
|
||||
return DetailGetPublicKey<CertRSA2048ECC>(m_bytes.begin());
|
||||
case SignatureType::ECC:
|
||||
return DetailGetPublicKey<CertECC>(m_bytes.begin());
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, CertReader> ParseCertChain(const std::vector<u8>& chain)
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
#include "Core/IOS/ES/ES.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <mbedtls/sha1.h>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "Core/IOS/Uids.h"
|
||||
|
@ -114,6 +118,99 @@ IPCCommandResult ES::Sign(const IOCtlVRequest& request)
|
|||
m_ios.GetIOSC().Sign(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size);
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
|
||||
ReturnCode ES::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
|
||||
const std::vector<u8>& certs_bytes)
|
||||
{
|
||||
if (!SConfig::GetInstance().m_enable_signature_checks)
|
||||
{
|
||||
WARN_LOG(IOS_ES, "VerifySign: signature checks are disabled. Skipping.");
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
const std::map<std::string, IOS::ES::CertReader> certs = IOS::ES::ParseCertChain(certs_bytes);
|
||||
if (certs.empty())
|
||||
return ES_EINVAL;
|
||||
|
||||
const auto ap_iterator = std::find_if(certs.begin(), certs.end(), [](const auto& entry) {
|
||||
return entry.first.length() > 2 && entry.first.compare(0, 2, "AP") == 0;
|
||||
});
|
||||
if (ap_iterator == certs.end())
|
||||
return ES_UNKNOWN_ISSUER;
|
||||
const IOS::ES::CertReader& ap = ap_iterator->second;
|
||||
|
||||
const auto ap_issuers = SplitString(ap.GetIssuer(), '-');
|
||||
const auto ng_iterator = ap_issuers.size() > 1 ? certs.find(*ap_issuers.rbegin()) : certs.end();
|
||||
if (ng_iterator == certs.end())
|
||||
return ES_UNKNOWN_ISSUER;
|
||||
const IOS::ES::CertReader& ng = ng_iterator->second;
|
||||
|
||||
IOSC& iosc = m_ios.GetIOSC();
|
||||
IOSC::Handle ng_cert;
|
||||
ReturnCode ret = iosc.CreateObject(&ng_cert, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
return ret;
|
||||
Common::ScopeGuard handle_guard{[&] { iosc.DeleteObject(ng_cert, PID_ES); }};
|
||||
|
||||
ret = VerifyContainer(VerifyContainerType::Device, VerifyMode::DoNotUpdateCertStore, ng,
|
||||
certs_bytes, ng_cert);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: VerifyContainer(ng) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iosc.VerifyPublicKeySign(ap.GetSha1(), ng_cert, ap.GetSignatureData(), PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: IOSC_VerifyPublicKeySign(ap) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IOSC::Handle ap_cert;
|
||||
ret = iosc.CreateObject(&ap_cert, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
return ret;
|
||||
Common::ScopeGuard handle2_guard{[&] { iosc.DeleteObject(ap_cert, PID_ES); }};
|
||||
|
||||
ret = iosc.ImportPublicKey(ap_cert, ap.GetPublicKey().data(), nullptr, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: IOSC_ImportPublicKey(ap) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::array<u8, 20> sha1;
|
||||
mbedtls_sha1(hash.data(), hash.size(), sha1.data());
|
||||
ret = iosc.VerifyPublicKeySign(sha1, ap_cert, ecc_signature, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: IOSC_VerifyPublicKeySign(data) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INFO_LOG(IOS_ES, "VerifySign: all checks passed");
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
IPCCommandResult ES::VerifySign(const IOCtlVRequest& request)
|
||||
{
|
||||
if (!request.HasNumberOfValidVectors(3, 0))
|
||||
return GetDefaultReply(ES_EINVAL);
|
||||
if (request.in_vectors[1].size != sizeof(IOS::ECCSignature))
|
||||
return GetDefaultReply(ES_EINVAL);
|
||||
|
||||
std::vector<u8> hash(request.in_vectors[0].size);
|
||||
Memory::CopyFromEmu(hash.data(), request.in_vectors[0].address, hash.size());
|
||||
|
||||
std::vector<u8> ecc_signature(request.in_vectors[1].size);
|
||||
Memory::CopyFromEmu(ecc_signature.data(), request.in_vectors[1].address, ecc_signature.size());
|
||||
|
||||
std::vector<u8> certs(request.in_vectors[2].size);
|
||||
Memory::CopyFromEmu(certs.data(), request.in_vectors[2].address, certs.size());
|
||||
|
||||
return GetDefaultReply(VerifySign(hash, ecc_signature, certs));
|
||||
}
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
||||
|
|
|
@ -337,8 +337,12 @@ ReturnCode IOSC::VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle sign
|
|||
return IPC_SUCCESS;
|
||||
}
|
||||
case SUBTYPE_ECC233:
|
||||
ERROR_LOG(IOS, "VerifyPublicKeySign: SUBTYPE_ECC233 is unimplemented");
|
||||
// [[fallthrough]]
|
||||
{
|
||||
ASSERT(entry->data.size() == sizeof(CertECC::public_key));
|
||||
|
||||
const bool ok = Common::ec::VerifySignature(entry->data.data(), signature.data(), sha1.data());
|
||||
return ok ? IPC_SUCCESS : IOSC_FAIL_CHECKVALUE;
|
||||
}
|
||||
default:
|
||||
return IOSC_INVALID_OBJTYPE;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ enum class PublicKeyType : u32
|
|||
{
|
||||
RSA4096 = 0,
|
||||
RSA2048 = 1,
|
||||
ECC = 2,
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
@ -72,34 +73,48 @@ struct CertHeader
|
|||
u32 id;
|
||||
};
|
||||
|
||||
struct CertRSA4096
|
||||
using RSA2048PublicKey = std::array<u8, 0x100>;
|
||||
using ECCPublicKey = std::array<u8, 60>;
|
||||
|
||||
struct CertRSA4096RSA2048
|
||||
{
|
||||
SignatureRSA4096 signature;
|
||||
CertHeader header;
|
||||
// The signature is RSA4096, but the key is a RSA2048 public key,
|
||||
// so its size is 0x100, not 0x200, as one would expect from the name.
|
||||
u8 public_key[0x100];
|
||||
RSA2048PublicKey public_key;
|
||||
u8 exponent[0x4];
|
||||
u8 pad[0x34];
|
||||
};
|
||||
static_assert(sizeof(CertRSA4096) == 0x400, "Wrong size for CertRSA4096");
|
||||
static_assert(sizeof(CertRSA4096RSA2048) == 0x400, "Wrong size for CertRSA4096RSA2048");
|
||||
|
||||
struct CertRSA2048
|
||||
struct CertRSA2048RSA2048
|
||||
{
|
||||
SignatureRSA2048 signature;
|
||||
CertHeader header;
|
||||
u8 public_key[0x100];
|
||||
RSA2048PublicKey public_key;
|
||||
u8 exponent[0x4];
|
||||
u8 pad[0x34];
|
||||
};
|
||||
static_assert(sizeof(CertRSA2048) == 0x300, "Wrong size for CertRSA2048");
|
||||
static_assert(sizeof(CertRSA2048RSA2048) == 0x300, "Wrong size for CertRSA2048RSA2048");
|
||||
|
||||
union Cert
|
||||
/// Used for device certificates
|
||||
struct CertRSA2048ECC
|
||||
{
|
||||
SignatureType type;
|
||||
CertRSA4096 rsa4096;
|
||||
CertRSA2048 rsa2048;
|
||||
SignatureRSA2048 signature;
|
||||
CertHeader header;
|
||||
ECCPublicKey public_key;
|
||||
std::array<u8, 60> padding;
|
||||
};
|
||||
static_assert(sizeof(CertRSA2048ECC) == 0x240, "Wrong size for CertRSA2048ECC");
|
||||
|
||||
/// Used for device signed certificates
|
||||
struct CertECC
|
||||
{
|
||||
SignatureECC signature;
|
||||
CertHeader header;
|
||||
ECCPublicKey public_key;
|
||||
std::array<u8, 60> padding;
|
||||
};
|
||||
static_assert(sizeof(CertECC) == 0x180, "Wrong size for CertECC");
|
||||
#pragma pack(pop)
|
||||
|
||||
using ECCSignature = std::array<u8, 60>;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Common/Crypto/ec.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
|
||||
constexpr std::array<u8, 30> PRIVATE_KEY{{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
|
||||
|
@ -43,3 +44,55 @@ TEST(ec, GenerateSharedSecret)
|
|||
|
||||
EXPECT_EQ(Common::ec::ComputeSharedSecret(PRIVATE_KEY.data(), PUBLIC_KEY.data()), SECRET);
|
||||
}
|
||||
|
||||
TEST(ec, SignAndVerify)
|
||||
{
|
||||
static constexpr std::array<u8, 20> HASH = {{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}};
|
||||
|
||||
auto signature = Common::ec::Sign(PRIVATE_KEY.data(), HASH.data());
|
||||
EXPECT_TRUE(Common::ec::VerifySignature(PUBLIC_KEY.data(), signature.data(), HASH.data()));
|
||||
signature.fill(0xff);
|
||||
EXPECT_FALSE(Common::ec::VerifySignature(PUBLIC_KEY.data(), signature.data(), HASH.data()));
|
||||
}
|
||||
|
||||
TEST(ec, VerifyRealWorldSignature)
|
||||
{
|
||||
static constexpr std::array<u8, 60> MS_PUBKEY = {
|
||||
{0x00, 0xfd, 0x56, 0x04, 0x18, 0x2c, 0xf1, 0x75, 0x09, 0x21, 0x00, 0xc3, 0x08, 0xae, 0x48,
|
||||
0x39, 0x91, 0x1b, 0x6f, 0x9f, 0xa1, 0xd5, 0x3a, 0x95, 0xaf, 0x08, 0x33, 0x49, 0x47, 0x2b,
|
||||
0x00, 0x01, 0x71, 0x31, 0x69, 0xb5, 0x91, 0xff, 0xd3, 0x0c, 0xbf, 0x73, 0xda, 0x76, 0x64,
|
||||
0xba, 0x8d, 0x0d, 0xf9, 0x5b, 0x4d, 0x11, 0x04, 0x44, 0x64, 0x35, 0xc0, 0xed, 0xa4, 0x2f}};
|
||||
|
||||
static constexpr std::array<u8, 0x180> DEVICE_CERT = {
|
||||
{0x00, 0x01, 0x00, 0x02, 0x00, 0x54, 0xe3, 0x9a, 0x0f, 0xe6, 0xe1, 0x61, 0xb6, 0x2f, 0x9d,
|
||||
0x0c, 0xaa, 0x1e, 0xc5, 0x58, 0x85, 0xa1, 0xeb, 0x93, 0xa5, 0x1e, 0xf4, 0x06, 0x99, 0x77,
|
||||
0x9a, 0x46, 0x76, 0x01, 0x00, 0xb7, 0xe4, 0x72, 0x10, 0x6e, 0xa2, 0x21, 0x57, 0xe0, 0xe3,
|
||||
0xbe, 0x48, 0x9d, 0x7b, 0xa5, 0x2d, 0x46, 0x2f, 0x33, 0x93, 0xae, 0xb0, 0x4b, 0x53, 0xcb,
|
||||
0xb9, 0xef, 0x16, 0x70, 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, 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, 0x52, 0x6f, 0x6f, 0x74, 0x2d, 0x43, 0x41,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x2d, 0x4d, 0x53, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x32, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x4e, 0x47, 0x30, 0x34, 0x65, 0x35, 0x34, 0x32, 0x31, 0x64, 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, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x5f, 0x58, 0x01, 0xa8, 0x1a, 0x89, 0x8d, 0x04,
|
||||
0xe4, 0x0e, 0x44, 0x6c, 0x99, 0x52, 0xef, 0xe8, 0xe9, 0x8a, 0xec, 0x2b, 0x73, 0xea, 0x13,
|
||||
0x56, 0x93, 0xf5, 0x1a, 0xd8, 0x53, 0xa8, 0xc5, 0xf2, 0x00, 0x41, 0xe9, 0x5e, 0x0a, 0x5d,
|
||||
0x0c, 0xdf, 0xf0, 0xc6, 0x96, 0x2c, 0x98, 0x96, 0xa9, 0x0f, 0xf0, 0x2e, 0x1f, 0x0d, 0x1a,
|
||||
0xcf, 0xa8, 0x35, 0x52, 0x74, 0x36, 0x13, 0x88, 0x02, 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, 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}};
|
||||
|
||||
const auto device_cert = IOS::ES::CertReader{{std::cbegin(DEVICE_CERT), std::cend(DEVICE_CERT)}};
|
||||
EXPECT_TRUE(Common::ec::VerifySignature(MS_PUBKEY.data(), device_cert.GetSignatureData().data(),
|
||||
device_cert.GetSha1().data()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue