diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index 5c1cac999b..24152773df 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -64,6 +64,7 @@ #define DUMP_FRAMES_DIR "Frames" #define DUMP_AUDIO_DIR "Audio" #define DUMP_DSP_DIR "DSP" +#define DUMP_SSL_DIR "SSL" #define LOGS_DIR "Logs" #define MAIL_LOGS_DIR "Mail" #define SHADERS_DIR "Shaders" diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index dd28aad476..e761f3ade1 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -781,6 +781,7 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[D_DUMPAUDIO_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; s_user_paths[D_DUMPTEXTURES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; + s_user_paths[D_DUMPSSL_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_SSL_DIR DIR_SEP; s_user_paths[D_LOGS_IDX] = s_user_paths[D_USER_IDX] + LOGS_DIR DIR_SEP; s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; s_user_paths[D_THEMES_IDX] = s_user_paths[D_USER_IDX] + THEMES_DIR DIR_SEP; @@ -825,6 +826,7 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[D_DUMPAUDIO_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; s_user_paths[D_DUMPTEXTURES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; + s_user_paths[D_DUMPSSL_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_SSL_DIR DIR_SEP; s_user_paths[F_RAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + RAM_DUMP; s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP; s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP; diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index 7beb4fca2e..f4a20f623d 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -39,6 +39,7 @@ enum D_DUMPAUDIO_IDX, D_DUMPTEXTURES_IDX, D_DUMPDSP_IDX, + D_DUMPSSL_IDX, D_LOAD_IDX, D_LOGS_IDX, D_MAILLOGS_IDX, diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index c0b8ce356d..ec198b2837 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -66,6 +66,7 @@ void SConfig::SaveSettings() SaveInputSettings(ini); SaveFifoPlayerSettings(ini); SaveAnalyticsSettings(ini); + SaveNetworkSettings(ini); ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); m_SYSCONF->Save(); @@ -80,6 +81,7 @@ void CreateDumpPath(const std::string& path) File::SetUserPath(D_DUMP_IDX, path + '/'); File::CreateFullPath(File::GetUserPath(D_DUMPAUDIO_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); + File::CreateFullPath(File::GetUserPath(D_DUMPSSL_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPFRAMES_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); } @@ -300,6 +302,17 @@ void SConfig::SaveFifoPlayerSettings(IniFile& ini) fifoplayer->Set("LoopReplay", bLoopFifoReplay); } +void SConfig::SaveNetworkSettings(IniFile& ini) +{ + IniFile::Section* network = ini.GetOrCreateSection("Network"); + + network->Set("SSLDumpRead", m_SSLDumpRead); + network->Set("SSLDumpWrite", m_SSLDumpWrite); + network->Set("SSLVerifyCert", m_SSLVerifyCert); + network->Set("SSLDumpRootCA", m_SSLDumpRootCA); + network->Set("SSLDumpPeerCert", m_SSLDumpPeerCert); +} + void SConfig::SaveAnalyticsSettings(IniFile& ini) { IniFile::Section* analytics = ini.GetOrCreateSection("Analytics"); @@ -324,6 +337,7 @@ void SConfig::LoadSettings() LoadDSPSettings(ini); LoadInputSettings(ini); LoadFifoPlayerSettings(ini); + LoadNetworkSettings(ini); LoadAnalyticsSettings(ini); m_SYSCONF = new SysConf(); @@ -570,6 +584,17 @@ void SConfig::LoadFifoPlayerSettings(IniFile& ini) fifoplayer->Get("LoopReplay", &bLoopFifoReplay, true); } +void SConfig::LoadNetworkSettings(IniFile& ini) +{ + IniFile::Section* network = ini.GetOrCreateSection("Network"); + + network->Get("SSLDumpRead", &m_SSLDumpRead, false); + network->Get("SSLDumpWrite", &m_SSLDumpWrite, false); + network->Get("SSLVerifyCert", &m_SSLVerifyCert, false); + network->Get("SSLDumpRootCA", &m_SSLDumpRootCA, false); + network->Get("SSLDumpPeerCert", &m_SSLDumpPeerCert, false); +} + void SConfig::LoadAnalyticsSettings(IniFile& ini) { IniFile::Section* analytics = ini.GetOrCreateSection("Analytics"); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 23399a7ba1..001417cb1c 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -290,6 +290,13 @@ struct SConfig : NonCopyable bool m_AdapterRumble[4]; bool m_AdapterKonga[4]; + // Network settings + bool m_SSLDumpRead; + bool m_SSLDumpWrite; + bool m_SSLVerifyCert; + bool m_SSLDumpRootCA; + bool m_SSLDumpPeerCert; + SysConf* m_SYSCONF; // Save settings @@ -316,6 +323,7 @@ private: void SaveInputSettings(IniFile& ini); void SaveMovieSettings(IniFile& ini); void SaveFifoPlayerSettings(IniFile& ini); + void SaveNetworkSettings(IniFile& ini); void SaveAnalyticsSettings(IniFile& ini); void LoadGeneralSettings(IniFile& ini); @@ -327,6 +335,7 @@ private: void LoadInputSettings(IniFile& ini); void LoadMovieSettings(IniFile& ini); void LoadFifoPlayerSettings(IniFile& ini); + void LoadNetworkSettings(IniFile& ini); void LoadAnalyticsSettings(IniFile& ini); static SConfig* m_Instance; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp index 4a4e9823b3..8f29e83ea4 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp @@ -6,12 +6,23 @@ #include "Common/FileUtil.h" #include "Common/NandPaths.h" +#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h" #include "Core/IPC_HLE/WII_Socket.h" WII_SSL CWII_IPC_HLE_Device_net_ssl::_SSL[NET_SSL_MAXINSTANCES]; +static constexpr mbedtls_x509_crt_profile mbedtls_x509_crt_profile_wii = { + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 0, /* No RSA min key size */ +}; + CWII_IPC_HLE_Device_net_ssl::CWII_IPC_HLE_Device_net_ssl(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) @@ -30,13 +41,16 @@ CWII_IPC_HLE_Device_net_ssl::~CWII_IPC_HLE_Device_net_ssl() if (ssl.active) { mbedtls_ssl_close_notify(&ssl.ctx); - mbedtls_ssl_session_free(&ssl.session); - mbedtls_ssl_free(&ssl.ctx); - mbedtls_ssl_config_free(&ssl.config); mbedtls_x509_crt_free(&ssl.cacert); mbedtls_x509_crt_free(&ssl.clicert); + mbedtls_ssl_session_free(&ssl.session); + mbedtls_ssl_free(&ssl.ctx); + mbedtls_ssl_config_free(&ssl.config); + mbedtls_ctr_drbg_free(&ssl.ctr_drbg); + mbedtls_entropy_free(&ssl.entropy); + ssl.hostname.clear(); ssl.active = false; @@ -152,13 +166,14 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress) WII_SSL* ssl = &_SSL[sslID]; mbedtls_ssl_init(&ssl->ctx); mbedtls_entropy_init(&ssl->entropy); - const char* pers = "dolphin-emu"; + static constexpr const char* pers = "dolphin-emu"; mbedtls_ctr_drbg_init(&ssl->ctr_drbg); int ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, (const unsigned char*)pers, strlen(pers)); if (ret) { mbedtls_ssl_free(&ssl->ctx); + mbedtls_ctr_drbg_free(&ssl->ctr_drbg); mbedtls_entropy_free(&ssl->entropy); goto _SSL_NEW_ERROR; } @@ -171,10 +186,13 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress) // For some reason we can't use TLSv1.2, v1.1 and below are fine! mbedtls_ssl_conf_max_version(&ssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); - + mbedtls_ssl_conf_cert_profile(&ssl->config, &mbedtls_x509_crt_profile_wii); mbedtls_ssl_set_session(&ssl->ctx, &ssl->session); - mbedtls_ssl_conf_authmode(&ssl->config, MBEDTLS_SSL_VERIFY_NONE); + if (SConfig::GetInstance().m_SSLVerifyCert && verifyOption) + mbedtls_ssl_conf_authmode(&ssl->config, MBEDTLS_SSL_VERIFY_REQUIRED); + else + mbedtls_ssl_conf_authmode(&ssl->config, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_renegotiation(&ssl->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); ssl->hostname = hostname; @@ -204,16 +222,18 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress) if (SSLID_VALID(sslID)) { WII_SSL* ssl = &_SSL[sslID]; - mbedtls_ssl_close_notify(&ssl->ctx); - mbedtls_ssl_session_free(&ssl->session); - mbedtls_ssl_free(&ssl->ctx); - mbedtls_ssl_config_free(&ssl->config); - mbedtls_entropy_free(&ssl->entropy); + mbedtls_ssl_close_notify(&ssl->ctx); mbedtls_x509_crt_free(&ssl->cacert); mbedtls_x509_crt_free(&ssl->clicert); + mbedtls_ssl_session_free(&ssl->session); + mbedtls_ssl_free(&ssl->ctx); + mbedtls_ssl_config_free(&ssl->config); + mbedtls_ctr_drbg_free(&ssl->ctr_drbg); + mbedtls_entropy_free(&ssl->entropy); + ssl->hostname.clear(); ssl->active = false; @@ -248,6 +268,12 @@ IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress) int ret = mbedtls_x509_crt_parse_der(&ssl->cacert, Memory::GetPointer(BufferOut2), BufferOutSize2); + if (SConfig::GetInstance().m_SSLDumpRootCA) + { + std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + ssl->hostname + "_rootca.der"; + File::IOFile(filename, "wb").WriteBytes(Memory::GetPointer(BufferOut2), BufferOutSize2); + } + if (ret) { Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.cpp b/Source/Core/Core/IPC_HLE/WII_Socket.cpp index 34018f5e14..73d21f8b66 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.cpp +++ b/Source/Core/Core/IPC_HLE/WII_Socket.cpp @@ -3,12 +3,14 @@ // Refer to the license.txt file included. #include +#include #ifndef _WIN32 #include #include #endif #include "Common/FileUtil.h" +#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" @@ -312,7 +314,14 @@ void WiiSocket::Update(bool read, bool write, bool except) { case IOCTLV_NET_SSL_DOHANDSHAKE: { - int ret = mbedtls_ssl_handshake(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx); + mbedtls_ssl_context* ctx = &CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx; + int ret = mbedtls_ssl_handshake(ctx); + if (ret) + { + char error_buffer[256] = ""; + mbedtls_strerror(ret, error_buffer, sizeof(error_buffer)); + ERROR_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE: %s", error_buffer); + } switch (ret) { case 0: @@ -328,11 +337,49 @@ void WiiSocket::Update(bool read, bool write, bool except) if (!nonBlock) ReturnValue = SSL_ERR_WAGAIN; break; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + { + char error_buffer[256] = ""; + int res = mbedtls_ssl_get_verify_result(ctx); + mbedtls_x509_crt_verify_info(error_buffer, sizeof(error_buffer), "", res); + ERROR_LOG(WII_IPC_SSL, "MBEDTLS_ERR_X509_CERT_VERIFY_FAILED (verify_result = %d): %s", + res, error_buffer); + + if (res & MBEDTLS_X509_BADCERT_CN_MISMATCH) + res = SSL_ERR_VCOMMONNAME; + else if (res & MBEDTLS_X509_BADCERT_NOT_TRUSTED) + res = SSL_ERR_VROOTCA; + else if (res & MBEDTLS_X509_BADCERT_REVOKED) + res = SSL_ERR_VCHAIN; + else if (res & MBEDTLS_X509_BADCERT_EXPIRED || res & MBEDTLS_X509_BADCERT_FUTURE) + res = SSL_ERR_VDATE; + else + res = SSL_ERR_FAILED; + + Memory::Write_U32(res, BufferIn); + if (!nonBlock) + ReturnValue = res; + break; + } default: Memory::Write_U32(SSL_ERR_FAILED, BufferIn); break; } + // mbedtls_ssl_get_peer_cert(ctx) seems not to work if handshake failed + // Below is an alternative to dump the peer certificate + if (SConfig::GetInstance().m_SSLDumpPeerCert && ctx->session_negotiate != nullptr) + { + const mbedtls_x509_crt* cert = ctx->session_negotiate->peer_cert; + if (cert != nullptr) + { + std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + + ((ctx->hostname != nullptr) ? ctx->hostname : "") + + "_peercert.der"; + File::IOFile(filename, "wb").WriteBytes(cert->raw.p, cert->raw.len); + } + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) " "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", @@ -345,10 +392,13 @@ void WiiSocket::Update(bool read, bool write, bool except) int ret = mbedtls_ssl_write(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferOut2), BufferOutSize2); -#ifdef DEBUG_SSL - File::IOFile("ssl_write.bin", "ab") - .WriteBytes(Memory::GetPointer(BufferOut2), BufferOutSize2); -#endif + if (SConfig::GetInstance().m_SSLDumpWrite && ret > 0) + { + std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + + SConfig::GetInstance().GetUniqueID() + "_write.bin"; + File::IOFile(filename, "ab").WriteBytes(Memory::GetPointer(BufferOut2), ret); + } + if (ret >= 0) { // Return bytes written or SSL_ERR_ZERO if none @@ -379,12 +429,14 @@ void WiiSocket::Update(bool read, bool write, bool except) { int ret = mbedtls_ssl_read(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferIn2), BufferInSize2); -#ifdef DEBUG_SSL - if (ret > 0) + + if (SConfig::GetInstance().m_SSLDumpRead && ret > 0) { - File::IOFile("ssl_read.bin", "ab").WriteBytes(Memory::GetPointer(BufferIn2), ret); + std::string filename = File::GetUserPath(D_DUMPSSL_IDX) + + SConfig::GetInstance().GetUniqueID() + "_read.bin"; + File::IOFile(filename, "ab").WriteBytes(Memory::GetPointer(BufferIn2), ret); } -#endif + if (ret >= 0) { // Return bytes read or SSL_ERR_ZERO if none diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 7789a11743..4459ec8090 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -51,6 +51,7 @@ void CreateDirectories() File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); + File::CreateFullPath(File::GetUserPath(D_DUMPSSL_IDX)); File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); File::CreateFullPath(File::GetUserPath(D_GAMESETTINGS_IDX)); File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX));