From 1d16785590987d5e077ad0f62172fee7549a2bd5 Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Mon, 27 Feb 2012 23:20:29 +1300 Subject: [PATCH] Implement ES_Sign and GetDeviceCert and others --- .../Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 199 +++++++++++++++--- .../Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h | 18 +- 2 files changed, 190 insertions(+), 27 deletions(-) diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp index 83c7544734..b214db804a 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -58,13 +58,40 @@ #include "CommonPaths.h" #include "IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include +#include +#include +#include +#include + CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) , m_pContentLoader(NULL) , m_TitleID(-1) , AccessIdentID(0x6000000) , m_ContentFile() -{} +{ +} + +static u8 key_sd [0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d}; +static u8 key_ecc [0x1e] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +static u8 key_empty[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static u8 key_ecc_r[0x1e] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + +// default key table +u8* CWII_IPC_HLE_Device_es::keyTable[11] = { + key_ecc, // ECC Private Key + key_empty, // Console ID + key_empty, // NAND AES Key + key_empty, // NAND HMAC + key_empty, // Common Key + key_empty, // PRNG seed + key_sd, // SD Key + key_empty, // Unknown + key_empty, // Unknown + key_empty, // Unknown + key_empty, // Unknown +}; CWII_IPC_HLE_Device_es::~CWII_IPC_HLE_Device_es() {} @@ -141,21 +168,6 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) Buffer.PayloadBuffer[i].m_Size); } - // Uhh just put this here for now - u8 keyTable[11][16] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // ECC Private Key - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Console ID - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // NAND AES Key - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // NAND HMAC - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Common Key - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // PRNG seed - {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d,}, // SD Key - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}, // Unknown - }; - switch (Buffer.Parameter) { case IOCTL_ES_GETDEVICEID: @@ -164,7 +176,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICEID"); // Return arbitrary device ID - TODO allow user to set value? - Memory::Write_U32(0x31337f11, Buffer.PayloadBuffer[0].m_Address); + Memory::Write_U32(0x21FFFFF, Buffer.PayloadBuffer[0].m_Address); Memory::Write_U32(0, _CommandAddress + 0x4); return true; } @@ -390,7 +402,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) case IOCTL_ES_SETUID: { _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_SETUID no in buffer"); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0, "IOCTL_ES_SETUID has a payload, it shouldn't"); // TODO: fs permissions based on this u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); INFO_LOG(WII_IPC_ES, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID>>32), (u32)TitleID); @@ -820,17 +832,152 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT , _CommandAddress + 0x4); return true; + case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes) + { + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICECERT"); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); + + std::string path = File::GetUserPath(D_WIIUSER_IDX) + "clientcert.bin"; + + u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + u32 size = Buffer.PayloadBuffer[0].m_Size; + + if (File::Exists(path)) + { + File::IOFile(path, "rb").ReadBytes(destination, size); + } + + Memory::Write_U32(0, _CommandAddress + 0x4); + break; + } + case IOCTL_ES_SIGN: + { + + WARN_LOG(WII_IPC_ES, "IOCTL_ES_SIGN"); + + ecc_cert_t device_cert; + memset(&device_cert, 0, sizeof(ecc_cert_t)); + + std::string path = File::GetUserPath(D_WIIUSER_IDX) + "clientcert.bin"; + if (File::Exists(path)) + { + File::IOFile(path, "rb").ReadBytes((u8*)&device_cert, 0x180); + }else{ + WARN_LOG(WII_IPC_ES, "IOCTL_ES_SIGN: clientcert.bin not found."); + break; + } + + ecc_cert_t * ap_cert = (ecc_cert_t *)Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); + + ap_cert->sig_type = Common::swap32(0x00010002); + ap_cert->key_type = Common::swap32(0x00000002); + ap_cert->ng_key_id = 0; + + snprintf((char*)ap_cert->issuer, + 0x40, + "%s-%s", + device_cert.issuer, + device_cert.key_name); + + snprintf((char*)ap_cert->key_name, + 0x40, + "AP%08x%08x", + (u32)(m_TitleID>>32), + (u32)(m_TitleID & 0xFFFFFFFF)); + + + u8 hash[SHA_DIGEST_LENGTH]; + SHA1(Memory::GetPointer(Buffer.InBuffer[0].m_Address), Buffer.InBuffer[0].m_Size, hash); + + BIGNUM *bn = BN_bin2bn(key_ecc_r, 0x1e, NULL); + EC_KEY *rand_key = EC_KEY_new_by_curve_name(NID_sect233r1); + EC_KEY_set_private_key(rand_key, bn); + + const EC_GROUP *group = EC_KEY_get0_group(rand_key); + + EC_POINT *pubkey = EC_POINT_new(group); + EC_POINT_mul(group, pubkey, bn, NULL, NULL, NULL); + + BIGNUM *x = BN_new(); + BIGNUM *y = BN_new(); + EC_POINT_get_affine_coordinates_GF2m(group, pubkey, x, y, NULL); + + int len = BN_num_bits(x); + BN_bn2bin(x, &ap_cert->ecc_pubkey[(240-len)/8]); + len = BN_num_bits(y); + BN_bn2bin(y, &ap_cert->ecc_pubkey[0x1e + (240-len)/8]); + + //BN_clear_free(x); + //BN_clear_free(y); + + EC_KEY_set_public_key(rand_key, pubkey); + + //EC_POINT_free(pubkey); + //BN_clear_free(bn); + + unsigned int buf_len = ECDSA_size(rand_key); + + unsigned char * sign_me = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + + ECDSA_SIG *rand_sig = ECDSA_do_sign(hash, SHA_DIGEST_LENGTH, rand_key); + + len = BN_num_bits(rand_sig->r); + BN_bn2bin(rand_sig->r, &sign_me[(240-len)/8]); + len = BN_num_bits(rand_sig->s); + BN_bn2bin(rand_sig->s, &sign_me[0x1e + (240-len)/8]); + + + SHA1(&ap_cert->issuer[0], 0x180 - 0x80, hash); + + bn = BN_bin2bn(key_ecc, 0x1e, NULL); + EC_KEY *ecc_key = EC_KEY_new_by_curve_name(NID_sect233r1); + EC_KEY_set_private_key(ecc_key, bn); + + group = EC_KEY_get0_group(ecc_key); + pubkey = EC_POINT_new(group); + + EC_POINT_mul(group, pubkey, bn, NULL, NULL, NULL); + + EC_KEY_set_public_key(ecc_key, pubkey); + + //BN_clear_free(bn); + //EC_POINT_free(pubkey); + + + ECDSA_SIG *ecc_sig = ECDSA_do_sign(hash, SHA_DIGEST_LENGTH, ecc_key); + + len = BN_num_bits(ecc_sig->r); + BN_bn2bin(ecc_sig->r, &ap_cert->sig[(240-len)/8]); + len = BN_num_bits(ecc_sig->s); + BN_bn2bin(ecc_sig->s, &ap_cert->sig[0x1e + (240-len)/8]); + + //ECDSA_SIG_free(ecc_sig); + + //OPENSSL_free(r); + //OPENSSL_free(s); + + //EC_KEY_free(ecc_key); + + break; + } + case IOCTL_ES_GETBOOT2VERSION: + { + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETBOOT2VERSION"); + + Memory::Write_U32(4, Buffer.PayloadBuffer[0].m_Address); // as of 26/02/2012, this was latest bootmii version + break; + } // =============================================================================================== // unsupported functions // =============================================================================================== - case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D - WARN_LOG(WII_IPC_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); - break; - - case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes) - WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICECERT: this looks really wrong..."); - break; - + case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D + WARN_LOG(WII_IPC_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); + break; + case IOCTL_ES_GETOWNEDTITLECNT: + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETOWNEDTITLECNT"); + + Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); + break; default: WARN_LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h index 6c31e7be31..69916110f0 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -105,7 +105,7 @@ private: { ES_INVALID_TMD = -106, // or access denied ES_READ_LESS_DATA_THAN_EXPECTED = -1009, - ES_UNK_1 = -1010, + ES_WRITE_FAILURE = -1010, ES_PARAMTER_SIZE_OR_ALIGNMENT = -1017, ES_HASH_DOESNT_MATCH = -1022, ES_MEM_ALLOC_FAILED = -1024, @@ -137,11 +137,27 @@ private: // This should only be cleared on power reset std::string m_ContentFile; + static u8 *keyTable[11]; + u64 GetCurrentTitleID() const; const DiscIO::INANDContentLoader& AccessContentDevice(u64 _TitleID); bool IsValid(u64 _TitleID) const; + + + typedef struct ecc_cert_t + { + u32 sig_type ; + u8 sig [0x3c] ; + u8 pad [0x40] ; + u8 issuer [0x40] ; + u32 key_type ; + u8 key_name [0x40] ; + u32 ng_key_id ; + u8 ecc_pubkey [0x3c] ; + u8 padding [0x3c] ; + } ecc_cert_t; }; #endif