From fdf9a88dd7fbc209ad56d2d22d934f5121a239d2 Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 10 Mar 2020 20:22:36 +0800 Subject: [PATCH] Add support for specifying Acid/Nca/Nrr signature key generations in the keyfile. --- SWITCH_KEYS.md | 49 +++++++++++++++--------- src/KeyConfiguration.cpp | 82 +++++++++++++++++++++++----------------- src/KeyConfiguration.h | 16 ++++++-- src/UserSettings.cpp | 19 +++++++--- 4 files changed, 105 insertions(+), 61 deletions(-) diff --git a/SWITCH_KEYS.md b/SWITCH_KEYS.md index 038dd1e..29a9856 100644 --- a/SWITCH_KEYS.md +++ b/SWITCH_KEYS.md @@ -29,36 +29,49 @@ nca_body_keak_ocean_source : Used with master_key_##, aes_kek_generation_s nca_body_keak_system_source : Used with master_key_##, aes_kek_generation_source and aes_key_generation_source to generate nca_body_keak_system_##. (0x10 bytes) ; Package1 keys -package1_key_## : AES128 Key (0x10 bytes) +package1_key_## : AES128 Key (0x10 bytes) ; Package2 Keys -package2_key_## : AES128 Key (0x10 bytes) -package2_sign_key_modulus : RSA2048 Modulus (0x100 bytes) -package2_sign_key_private : RSA2048 Private Exponent (0x100 bytes) +package2_key_## : AES128 Key (0x10 bytes) +package2_sign_key_modulus : RSA2048 Modulus (0x100 bytes) +package2_sign_key_private : RSA2048 Private Exponent (0x100 bytes) ; Ticket Keys -ticket_commonkey_## : AES128 Key (0x10 bytes) +ticket_commonkey_## : AES128 Key (0x10 bytes) ; PKI Root Signing Key -pki_root_sign_key_modulus : RSA4096 Modulus (0x200 bytes) -pki_root_sign_key_private : RSA4096 Private Exponent (0x200 bytes) +pki_root_sign_key_modulus : RSA4096 Modulus (0x200 bytes) +pki_root_sign_key_private : RSA4096 Private Exponent (0x200 bytes) ; NCA Keys -nca_header_key : AES128-XTS Key (0x20 bytes) -nca_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes) -nca_header_sign_key_private : RSA2048 Private Exponent (0x100 bytes) -nca_body_keak_application_## : AES128 Key (0x10 bytes) -nca_body_keak_ocean_## : AES128 Key (0x10 bytes) -nca_body_keak_system_## : AES128 Key (0x10 bytes) +nca_header_key : AES128-XTS Key (0x20 bytes) +nca_header_sign_key_##_modulus : RSA2048 Modulus (0x100 bytes) +nca_header_sign_key_##_private : RSA2048 Private Exponent (0x100 bytes) +nca_body_keak_application_## : AES128 Key (0x10 bytes) +nca_body_keak_ocean_## : AES128 Key (0x10 bytes) +nca_body_keak_system_## : AES128 Key (0x10 bytes) + +; NRR Keys +nrr_certificate_sign_key_##_modulus : RSA2048 Modulus (0x100 bytes) +nrr_certificate_sign_key_##_private : RSA2048 Private Exponent (0x100 bytes) ; XCI Keys -xci_header_key : AES128 Key (0x10 bytes) -xci_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes) -xci_header_sign_key_private : RSA2048 Private Exponent (0x100 bytes) +xci_header_key : AES128 Key (0x10 bytes) +xci_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes) +xci_header_sign_key_private : RSA2048 Private Exponent (0x100 bytes) ; ACID Keys -acid_sign_key_modulus : RSA2048 Modulus (0x100 bytes) -acid_sign_key_private : RSA2048 Private Exponent (0x100 bytes) +acid_sign_key_##_modulus : RSA2048 Modulus (0x100 bytes) +acid_sign_key_##_private : RSA2048 Private Exponent (0x100 bytes) +``` + +## Legacy Keynames +Since firmware `9.0.0+` support for signature key generations was retroactively added for RSA-PSS signatures in NRR, ACID and NCA. The old names for these keys are still valid: +``` +nca_header_sign_key_modulus : alias for nca_header_sign_key_00_modulus +nca_header_sign_key_private : alias nca_header_sign_key_00_private +acid_sign_key_modulus : alias for acid_sign_key_00_modulus +acid_sign_key_private : alias for acid_sign_key_00_private ``` ## Compatibility with hactool keyset files diff --git a/src/KeyConfiguration.cpp b/src/KeyConfiguration.cpp index 5a2edf8..897554c 100644 --- a/src/KeyConfiguration.cpp +++ b/src/KeyConfiguration.cpp @@ -16,9 +16,7 @@ KeyConfiguration::KeyConfiguration(const KeyConfiguration& other) void KeyConfiguration::operator=(const KeyConfiguration& other) { - mAcidSignKey = other.mAcidSignKey; mPkg2SignKey = other.mPkg2SignKey; - mContentArchiveHeader0SignKey = other.mContentArchiveHeader0SignKey; mXciHeaderSignKey = other.mXciHeaderSignKey; mContentArchiveHeaderKey = other.mContentArchiveHeaderKey; @@ -26,6 +24,9 @@ void KeyConfiguration::operator=(const KeyConfiguration& other) for (size_t i = 0; i < kMasterKeyNum; i++) { + mAcidSignKey[i] = other.mAcidSignKey[i]; + mContentArchiveHeader0SignKey[i] = other.mContentArchiveHeader0SignKey[i]; + mNrrCertificateSignKey[i] = other.mNrrCertificateSignKey[i]; mPkg2Key[i] = other.mPkg2Key[i]; mPkg1Key[i] = other.mPkg1Key[i]; mNcaKeyAreaEncryptionKey[0][i] = other.mNcaKeyAreaEncryptionKey[0][i]; @@ -69,6 +70,7 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) #define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2)) #define _CONCAT_3_STRINGS(str1, str2, str3) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3) +#define _CONCAT_4_STRINGS(str1, str2, str3, str4) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3), str4) std::string key,val; fnd::Vec dec_array; @@ -110,6 +112,13 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[0][mkeyidx].key, 0x10); _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[1][mkeyidx].key, 0x10); _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[2][mkeyidx].key, 0x10); + + _SAVE_KEYDATA(_CONCAT_4_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mContentArchiveHeader0SignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_4_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mContentArchiveHeader0SignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_4_STRINGS(kAcidBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mAcidSignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_4_STRINGS(kAcidBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mAcidSignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_4_STRINGS(kNrrCertBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kPrivateStr), mNrrCertificateSignKey[mkeyidx].priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_4_STRINGS(kNrrCertBase[nameidx], kSignKey, kKeyIndex[mkeyidx], kModulusStr), mNrrCertificateSignKey[mkeyidx].modulus, fnd::rsa::kRsa2048Size); } // store nca header key @@ -119,20 +128,23 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kKeyStr), mXciHeaderKey.key, 0x10); // store rsa keys - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kContentArchiveHeaderBase[nameidx], kRsaKeyPrivate), mContentArchiveHeader0SignKey.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kContentArchiveHeaderBase[nameidx], kRsaKeyModulus), mContentArchiveHeader0SignKey.modulus, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyPrivate), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyModulus), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size); + // legacy header nca key name + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kPrivateStr), mContentArchiveHeader0SignKey[0].priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kContentArchiveHeaderBase[nameidx], kSignKey, kModulusStr), mContentArchiveHeader0SignKey[0].modulus, fnd::rsa::kRsa2048Size); + + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kSignKey, kPrivateStr), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kSignKey, kModulusStr), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyPrivate), mAcidSignKey.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyModulus), mAcidSignKey.modulus, fnd::rsa::kRsa2048Size); + // legacy acid header key name + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kAcidBase[nameidx], kSignKey, kPrivateStr), mAcidSignKey[0].priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kAcidBase[nameidx], kSignKey, kModulusStr), mAcidSignKey[0].modulus, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyPrivate), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyModulus), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kSignKey, kPrivateStr), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kSignKey, kModulusStr), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyPrivate), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyModulus), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkiRootBase[nameidx], kSignKey, kPrivateStr), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkiRootBase[nameidx], kSignKey, kModulusStr), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size); } #undef _SAVE_KEYDATA @@ -193,9 +205,9 @@ void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) void KeyConfiguration::clearGeneralKeyConfiguration() { - mAcidSignKey = kNullRsa2048Key; + mPkg2SignKey = kNullRsa2048Key; - mContentArchiveHeader0SignKey = kNullRsa2048Key; + mXciHeaderSignKey = kNullRsa2048Key; mPkiRootKeyList.clear(); @@ -204,6 +216,9 @@ void KeyConfiguration::clearGeneralKeyConfiguration() for (size_t i = 0; i < kMasterKeyNum; i++) { + mAcidSignKey[i] = kNullRsa2048Key; + mContentArchiveHeader0SignKey[i] = kNullRsa2048Key; + mNrrCertificateSignKey[i] = kNullRsa2048Key; mPkg1Key[i] = kNullAesKey; mPkg2Key[i] = kNullAesKey; mETicketCommonKey[i] = kNullAesKey; @@ -228,35 +243,23 @@ bool KeyConfiguration::getContentArchiveHeaderKey(fnd::aes::sAesXts128Key& key) bool KeyConfiguration::getContentArchiveHeader0SignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const { // TODO: This needs to be changed to support multiple keys - - bool keyIsFound = false; - switch (key_generation) + if (key_generation >= kMasterKeyNum) { - case (0x00): - keyIsFound = copyOutKeyResourceIfExists(mContentArchiveHeader0SignKey, key, kNullRsa2048Key); - break; - default: - keyIsFound = false; - } + return false; + } - return keyIsFound; + return copyOutKeyResourceIfExists(mContentArchiveHeader0SignKey[key_generation], key, kNullRsa2048Key); } bool KeyConfiguration::getAcidSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const { // TODO: This needs to be changed to support multiple keys - - bool keyIsFound = false; - switch (key_generation) + if (key_generation >= kMasterKeyNum) { - case (0x00): - keyIsFound = copyOutKeyResourceIfExists(mAcidSignKey, key, kNullRsa2048Key); - break; - default: - keyIsFound = false; - } + return false; + } - return keyIsFound; + return copyOutKeyResourceIfExists(mAcidSignKey[key_generation], key, kNullRsa2048Key); } bool KeyConfiguration::getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const @@ -308,6 +311,17 @@ bool KeyConfiguration::getNcaExternalContentKey(const byte_t rights_id[nn::hac:: return res_exists; } +bool KeyConfiguration::getNrrCertificateSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const +{ + // TODO: This needs to be changed to support multiple keys + if (key_generation >= kMasterKeyNum) + { + return false; + } + + return copyOutKeyResourceIfExists(mNrrCertificateSignKey[key_generation], key, kNullRsa2048Key); +} + bool KeyConfiguration::getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const { if (masterkey_index >= kMasterKeyNum) diff --git a/src/KeyConfiguration.h b/src/KeyConfiguration.h index 58245b6..4a112c6 100644 --- a/src/KeyConfiguration.h +++ b/src/KeyConfiguration.h @@ -34,6 +34,9 @@ public: void addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key); bool getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const; + // nrr key + bool getNrrCertificateSignKey(fnd::rsa::sRsa2048Key& key, byte_t key_generation) const; + // pkg1/pkg2 bool getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; bool getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; @@ -73,6 +76,7 @@ private: const std::string kXciHeaderBase[kNameVariantNum] = { "xci_header", "xci_header", "xci_header" }; const std::string kContentArchiveHeaderBase[kNameVariantNum] = { "nca_header", "header", "nca_header" }; const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" }; + const std::string kNrrCertBase[kNameVariantNum] = { "nrr_certificate", "nrr_certificate", "nrr_certificate" }; const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" }; const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" }; const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_key_area_key", "key_area_key", "nca_body_keak" }; @@ -84,8 +88,9 @@ private: const std::string kKeyStr = "key"; const std::string kKekStr = "kek"; const std::string kSourceStr = "source"; - const std::string kRsaKeyModulus = "sign_key_modulus"; - const std::string kRsaKeyPrivate = "sign_key_private"; + const std::string kSignKey = "sign_key"; + const std::string kModulusStr = "modulus"; + const std::string kPrivateStr = "private"; const std::string kNcaKeyAreaKeyIndexStr[kNcaKeakNum] = { "application", "ocean", "system" }; const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"}; @@ -167,7 +172,7 @@ private: /* general key config */ // acid - fnd::rsa::sRsa2048Key mAcidSignKey; + fnd::rsa::sRsa2048Key mAcidSignKey[kMasterKeyNum]; // pkg1 and pkg2 fnd::aes::sAes128Key mPkg1Key[kMasterKeyNum]; @@ -175,11 +180,14 @@ private: fnd::aes::sAes128Key mPkg2Key[kMasterKeyNum]; // nca - fnd::rsa::sRsa2048Key mContentArchiveHeader0SignKey; + fnd::rsa::sRsa2048Key mContentArchiveHeader0SignKey[kMasterKeyNum]; fnd::aes::sAesXts128Key mContentArchiveHeaderKey; fnd::aes::sAes128Key mNcaKeyAreaEncryptionKey[kNcaKeakNum][kMasterKeyNum]; fnd::aes::sAes128Key mNcaKeyAreaEncryptionKeyHw[kNcaKeakNum][kMasterKeyNum]; + // nrr + fnd::rsa::sRsa2048Key mNrrCertificateSignKey[kMasterKeyNum]; + // xci fnd::rsa::sRsa2048Key mXciHeaderSignKey; fnd::aes::sAes128Key mXciHeaderKey; diff --git a/src/UserSettings.cpp b/src/UserSettings.cpp index 9ad678a..348cc51 100644 --- a/src/UserSettings.cpp +++ b/src/UserSettings.cpp @@ -917,6 +917,11 @@ void UserSettings::dumpKeyConfig() const if (mKeyCfg.getContentArchiveHeader0SignKey(rsa2048_key, i) == true) dumpRsa2048Key(rsa2048_key, "Header0-SignatureKey-" + kKeyIndex[i], 2); } + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getAcidSignKey(rsa2048_key, i) == true) + dumpRsa2048Key(rsa2048_key, "Acid-SignatureKey-" + kKeyIndex[i], 2); + } if (mKeyCfg.getContentArchiveHeaderKey(aesxts_key) == true) dumpAesXtsKey(aesxts_key, "Header-EncryptionKey", 2); @@ -941,17 +946,21 @@ void UserSettings::dumpKeyConfig() const dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-System-" + kKeyIndex[i], 2); } + std::cout << " NRR Keys:" << std::endl; + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getNrrCertificateSignKey(rsa2048_key, i) == true) + dumpRsa2048Key(rsa2048_key, "Certificate-SignatureKey-" + kKeyIndex[i], 2); + } + std::cout << " XCI Keys:" << std::endl; if (mKeyCfg.getXciHeaderSignKey(rsa2048_key) == true) dumpRsa2048Key(rsa2048_key, "Header-SignatureKey", 2); if (mKeyCfg.getXciHeaderKey(aes_key) == true) dumpAesKey(aes_key, "ExtendedHeader-EncryptionKey", 2); - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (mKeyCfg.getAcidSignKey(rsa2048_key, i) == true) - dumpRsa2048Key(rsa2048_key, "ACID-SignatureKey-" + kKeyIndex[i], 1); - } + + std::cout << " Package1 Keys:" << std::endl; for (size_t i = 0; i < kMasterKeyNum; i++)