ES / IOSC: Add support for ECC certificates
This commit is contained in:
parent
a974c69058
commit
b86f1ea7b3
|
@ -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)
|
||||
|
|
|
@ -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>;
|
||||
|
|
Loading…
Reference in New Issue