fs: add gc validation wrappers for hac2l

This commit is contained in:
Michael Scire 2022-03-14 04:42:55 -07:00 committed by SciresM
parent 32d443977e
commit 2d984822c6
15 changed files with 939 additions and 6 deletions

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/gc/impl/gc_gc_crypto.hpp>
namespace ams::gc::impl {
class EmbeddedDataHolder {
NON_COPYABLE(EmbeddedDataHolder);
NON_MOVEABLE(EmbeddedDataHolder);
friend class GcCrypto;
private:
struct ConcatenatedGcLibraryEmbeddedKeys {
u8 enc_hmac_key_for_cv[GcCrypto::GcHmacKeyLength];
u8 enc_hmac_key_for_key_and_iv[GcCrypto::GcHmacKeyLength];
u8 enc_cv_constant_value[GcCrypto::GcCvConstLength];
u8 enc_rsa_oaep_label_hash[GcCrypto::GcSha256HashLength];
};
static_assert(util::is_pod<ConcatenatedGcLibraryEmbeddedKeys>::value);
static_assert(sizeof(ConcatenatedGcLibraryEmbeddedKeys) == 0x70);
private:
static bool s_is_dev;
static const void *s_ca_public_exponent;
static const void *s_ca1_modulus;
static const void *s_ca9_modulus;
static const void *s_ca10_modulus;
static const void *s_ca10_certificate_modulus;
static const void *s_card_header_key;
public:
static Result SetLibraryEmbeddedKeys(bool is_dev = GcCrypto::CheckDevelopmentSpl());
private:
static Result DecryptoEmbeddedKeys(ConcatenatedGcLibraryEmbeddedKeys *out, size_t out_size, bool is_dev = GcCrypto::CheckDevelopmentSpl());
};
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/gc/impl/gc_types.hpp>
namespace ams::gc::impl {
class GcCrypto {
NON_COPYABLE(GcCrypto);
NON_MOVEABLE(GcCrypto);
public:
static constexpr size_t GcRsaKeyLength = crypto::Rsa2048PssSha256Verifier::ModulusSize;
static constexpr size_t GcRsaPublicExponentLength = 3;
static constexpr size_t GcAesKeyLength = crypto::AesEncryptor128::KeySize;
static constexpr size_t GcAesCbcIvLength = crypto::Aes128CbcEncryptor::IvSize;
static constexpr size_t GcHmacKeyLength = 0x20;
static constexpr size_t GcCvConstLength = 0x10;
static constexpr size_t GcSha256HashLength = crypto::Sha256Generator::HashSize;
public:
static bool CheckDevelopmentSpl();
static Result DecryptAesKeySpl(void *dst, size_t dst_size, const void *src, size_t src_size, s32 generation, u32 option);
static Result VerifyCardHeader(const void *header_buffer, size_t header_size, const void *modulus, size_t modulus_size);
static Result EncryptCardHeader(void *header, size_t header_size);
static Result DecryptCardHeader(void *header, size_t header_size);
static Result VerifyT1CardCertificate(const void *cert_buffer, size_t cert_size);
static Result VerifyCa10Certificate(const void *cert_buffer, size_t cert_size);
};
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::gc::impl {
struct CardInitialDataPayload {
u8 package_id[8];
u8 reserved_8[8];
u8 auth_data[0x10];
u8 auth_mac[0x10];
u8 auth_nonce[0xC];
};
static_assert(util::is_pod<CardInitialDataPayload>::value);
static_assert(sizeof(CardInitialDataPayload) == 0x3C);
struct CardInitialData {
CardInitialDataPayload payload;
u8 padding[0x200 - sizeof(CardInitialDataPayload)];
};
static_assert(util::is_pod<CardInitialData>::value);
static_assert(sizeof(CardInitialData) == 0x200);
struct CardHeaderKeyIndex {
using KekIndex = util::BitPack8::Field<0, 4, u8>;
using TitleKeyDecIndex = util::BitPack8::Field<KekIndex::Next, 4, u8>;
static_assert(TitleKeyDecIndex::Next == BITSIZEOF(u8));
};
struct CardHeaderEncryptedData {
u32 fw_version[2];
u32 acc_ctrl_1;
u32 wait_1_time_read;
u32 wait_2_time_read;
u32 wait_1_time_write;
u32 wait_2_time_write;
u32 fw_mode;
u32 cup_version;
u8 compatibility_type;
u8 reserved_25;
u8 reserved_26;
u8 reserved_27;
u8 upp_hash[8];
u64 cup_id;
u8 reserved_38[0x38];
};
static_assert(util::is_pod<CardHeaderEncryptedData>::value);
static_assert(sizeof(CardHeaderEncryptedData) == 0x70);
enum MemoryCapacity : u8 {
MemoryCapacity_1GB = 0xFA,
MemoryCapacity_2GB = 0xF8,
MemoryCapacity_4GB = 0xF0,
MemoryCapacity_8GB = 0xE0,
MemoryCapacity_16GB = 0xE1,
MemoryCapacity_32GB = 0xE2,
};
enum AccessControl1ClockRate : u32 {
AccessControl1ClockRate_25MHz = 0x00A10011,
AccessControl1ClockRate_50MHz = 0x00A10010,
};
struct CardHeader {
static constexpr u32 Magic = util::FourCC<'H','E','A','D'>::Code;
u32 magic;
u32 rom_area_start_page;
u32 backup_area_start_page;
util::BitPack8 key_index;
u8 rom_size;
u8 version;
u8 flags;
u8 package_id[8];
u32 valid_data_end_page;
u8 reserved_11C[4];
u8 iv[crypto::Aes128CbcDecryptor::IvSize];
u64 partition_fs_header_address;
u64 partition_fs_header_size;
u8 partition_fs_header_hash[crypto::Sha256Generator::HashSize];
u8 initial_data_hash[crypto::Sha256Generator::HashSize];
u32 sel_sec;
u32 sel_t1_key;
u32 sel_key;
u32 lim_area_page;
union {
u8 raw_encrypted_data[sizeof(CardHeaderEncryptedData)];
CardHeaderEncryptedData encrypted_data;
};
};
static_assert(util::is_pod<CardHeader>::value);
static_assert(sizeof(CardHeader) == 0x100);
struct CardHeaderWithSignature {
u8 signature[crypto::Rsa2048Pkcs1Sha256Verifier::SignatureSize];
CardHeader data;
};
static_assert(util::is_pod<CardHeaderWithSignature>::value);
static_assert(sizeof(CardHeaderWithSignature) == 0x200);
static constexpr size_t CardDeviceIdLength = 0x10;
struct T1CardCertificate {
static constexpr u32 Magic = util::FourCC<'C','E','R','T'>::Code;
u8 signature[crypto::Rsa2048Pkcs1Sha256Verifier::SignatureSize];
u32 magic;
u32 version;
u8 kek_index;
u8 flags[7];
u8 t1_card_device_id[CardDeviceIdLength];
u8 iv[crypto::Aes128CtrEncryptor::IvSize];
u8 hw_key[crypto::Aes128CtrEncryptor::KeySize];
u8 reserved[0xC0];
u8 padding[0x200];
};
static_assert(util::is_pod<T1CardCertificate>::value);
static_assert(sizeof(T1CardCertificate) == 0x400);
struct Ca10Certificate {
u8 signature[crypto::Rsa2048Pkcs1Sha256Verifier::SignatureSize];
u8 unk_100[0x200];
u8 modulus[crypto::Rsa2048Pkcs1Sha256Verifier::ModulusSize];
};
static_assert(util::is_pod<Ca10Certificate>::value);
static_assert(sizeof(Ca10Certificate) == 0x400);
}