diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 6039cacb8c..2af15c0c70 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -130,7 +130,7 @@ std::array 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(Common::swap32(m_bytes.data())); } +template +static std::vector DetailGetSignatureData(It begin) +{ + const auto signature_begin = begin + offsetof(T, sig); + return std::vector(signature_begin, signature_begin + sizeof(T::sig)); +} + std::vector SignedBlobReader::GetSignatureData() const { switch (GetSignatureType()) { case SignatureType::RSA4096: - { - const auto signature_begin = m_bytes.begin() + offsetof(SignatureRSA4096, sig); - return std::vector(signature_begin, signature_begin + sizeof(SignatureRSA4096::sig)); - } + return DetailGetSignatureData(m_bytes.cbegin()); case SignatureType::RSA2048: - { - const auto signature_begin = m_bytes.begin() + offsetof(SignatureRSA2048, sig); - return std::vector(signature_begin, signature_begin + sizeof(SignatureRSA2048::sig)); - } + return DetailGetSignatureData(m_bytes.cbegin()); + case SignatureType::ECC: + return DetailGetSignatureData(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 +static std::string DetailGetIssuer(const u8* bytes) +{ + const char* issuer = reinterpret_cast(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(m_bytes.data() + offsetof(SignatureRSA4096, issuer)); - return std::string(issuer, strnlen(issuer, sizeof(SignatureRSA4096::issuer))); - } + return DetailGetIssuer(m_bytes.data()); case SignatureType::RSA2048: - { - const char* issuer = - reinterpret_cast(m_bytes.data() + offsetof(SignatureRSA2048, issuer)); - return std::string(issuer, strnlen(issuer, sizeof(SignatureRSA2048::issuer))); - } + return DetailGetIssuer(m_bytes.data()); + case SignatureType::ECC: + return DetailGetIssuer(m_bytes.data()); default: return ""; } @@ -677,24 +683,22 @@ CertReader::CertReader(std::vector&& 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, 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(Common::swap32(m_bytes.data() + offset)); } +template +std::vector 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 CertReader::GetPublicKey() const { - static const std::map> 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(key_begin, key_begin + info.second); + switch (GetSignatureType()) + { + case SignatureType::RSA4096: + return DetailGetPublicKey(m_bytes.begin(), 4); + case SignatureType::RSA2048: + if (GetPublicKeyType() == PublicKeyType::RSA2048) + return DetailGetPublicKey(m_bytes.begin(), 4); + return DetailGetPublicKey(m_bytes.begin()); + case SignatureType::ECC: + return DetailGetPublicKey(m_bytes.begin()); + default: + return {}; + } } std::map ParseCertChain(const std::vector& chain) diff --git a/Source/Core/Core/IOS/IOSC.h b/Source/Core/Core/IOS/IOSC.h index c397b85a5c..5207f4c9f0 100644 --- a/Source/Core/Core/IOS/IOSC.h +++ b/Source/Core/Core/IOS/IOSC.h @@ -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; +using ECCPublicKey = std::array; + +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 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 padding; +}; +static_assert(sizeof(CertECC) == 0x180, "Wrong size for CertECC"); #pragma pack(pop) using ECCSignature = std::array;