diff options
| author | Léo Lam <leo@innovatetechnologi.es> | 2018-05-14 22:59:34 +0200 |
|---|---|---|
| committer | Léo Lam <leo@innovatetechnologi.es> | 2018-05-20 20:04:53 +0200 |
| commit | b86f1ea7b3496a2e67659940ec7925d06a68d87a (patch) | |
| tree | 1e4b9ec0a27a1db4b91584026c72afbe379e4d7e | |
| parent | a974c690586d3842297a730865e4ceafa3ac3d75 (diff) | |
ES / IOSC: Add support for ECC certificates
| -rw-r--r-- | Source/Core/Core/IOS/ES/Formats.cpp | 102 | ||||
| -rw-r--r-- | Source/Core/Core/IOS/IOSC.h | 39 |
2 files changed, 84 insertions, 57 deletions
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<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)); } -std::vector<u8> CertReader::GetPublicKey() const +template <typename T, typename It> +std::vector<u8> DetailGetPublicKey(It begin, size_t extra_data = 0) { - 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 key_begin = begin + offsetof(T, public_key); + return {key_begin, key_begin + sizeof(T::public_key) + extra_data}; +} - 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); +std::vector<u8> CertReader::GetPublicKey() const +{ + 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) 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<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>; |
