diff --git a/common/platform/config.c b/common/platform/config.c index adc6451..7461430 100644 --- a/common/platform/config.c +++ b/common/platform/config.c @@ -23,6 +23,8 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/openssl.h" + void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { @@ -41,6 +43,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) nusec_config_load(&cfg->nusec, filename); vfs_config_load(&cfg->vfs, filename); system_config_load(&cfg->system, filename); + openssl_config_load(&cfg->openssl, filename); } void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename) @@ -362,3 +365,12 @@ void epay_config_load(struct epay_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename); cfg->hook = GetPrivateProfileIntW(L"epay", L"hook", 1, filename); } + +void openssl_config_load(struct openssl_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"openssl", L"enable", 1, filename); + cfg->override = GetPrivateProfileIntW(L"openssl", L"override", 0, filename); +} diff --git a/common/platform/config.h b/common/platform/config.h index e945378..efad5a3 100644 --- a/common/platform/config.h +++ b/common/platform/config.h @@ -19,6 +19,7 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/openssl.h" void platform_config_load( struct platform_config *cfg, @@ -36,3 +37,4 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename); void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename); void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename); void system_config_load(struct system_config *cfg, const wchar_t *filename); +void openssl_config_load(struct openssl_config *cfg, const wchar_t *filename); diff --git a/common/platform/meson.build b/common/platform/meson.build index 0e54b6c..0e51ddd 100644 --- a/common/platform/meson.build +++ b/common/platform/meson.build @@ -38,5 +38,7 @@ platform_lib = static_library( 'vfs.h', 'system.c', 'system.h', + 'openssl.c', + 'openssl.h' ], ) diff --git a/common/platform/openssl.c b/common/platform/openssl.c new file mode 100644 index 0000000..e10843e --- /dev/null +++ b/common/platform/openssl.c @@ -0,0 +1,106 @@ +#include + +#include +#include +#include +#include +#include + +#include "hook/table.h" + +#include "hooklib/config.h" + +#include "platform/openssl.h" + +#include "util/dprintf.h" + +/* API hooks */ + +static char * __cdecl hook_getenv(const char *name); + +/* Link pointers */ + +static char * (__cdecl *next_getenv)(const char *name); + +static bool openssl_hook_initted; +static struct openssl_config openssl_config; + +static const struct hook_symbol openssl_hooks[] = { + { + .name = "getenv", + .patch = hook_getenv, + .link = (void **) &next_getenv + }, +}; + +int check_intel_sha_extension() { + int cpui[4] = {0}; + + __cpuid(cpui, 0); + int nIds_ = cpui[0]; + + char vendor[0x20] = {0}; + *((int*)vendor) = cpui[1]; + *((int*)(vendor + 4)) = cpui[3]; + *((int*)(vendor + 8)) = cpui[2]; + + // Intel CPU + int isIntel = (strcmp(vendor, "GenuineIntel") == 0); + + if (isIntel && nIds_ >= 7) { + __cpuidex(cpui, 7, 0); + // SHA extension + return (cpui[1] & (1 << 29)) != 0; + } + + return 0; +} + +HRESULT openssl_hook_init(const struct openssl_config *cfg) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return S_FALSE; + } + + if (openssl_hook_initted) { + return S_FALSE; + } + + if (cfg->override) { + dprintf("OpenSSL: hook enabled.\n"); + } else if (check_intel_sha_extension()) { + dprintf("OpenSSL: Intel CPU SHA extension detected, hook enabled.\n"); + } else { + return S_FALSE; + } + + openssl_hook_initted = true; + + memcpy(&openssl_config, cfg, sizeof(*cfg)); + hook_table_apply( + NULL, + "msvcr110.dll", + openssl_hooks, + _countof(openssl_hooks) + ); + + return S_OK; +} + +static char * __cdecl hook_getenv(const char *name) +{ + /* Intercept OpenSSL CPU-cap override */ + if (name && strcmp(name, "OPENSSL_ia32cap") == 0) { + static char override[] = "~0x20000000"; + + dprintf("OpenSSL: Overriding OPENSSL_ia32cap -> %s\n", override); + + return override; + } + + char *real_val = next_getenv(name); + + return real_val; +} diff --git a/common/platform/openssl.h b/common/platform/openssl.h new file mode 100644 index 0000000..ebb2e46 --- /dev/null +++ b/common/platform/openssl.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include + +struct openssl_config { + bool enable; + bool override; +}; + +HRESULT openssl_hook_init(const struct openssl_config *cfg); diff --git a/common/platform/platform.c b/common/platform/platform.c index c882760..d1f380d 100644 --- a/common/platform/platform.c +++ b/common/platform/platform.c @@ -14,6 +14,7 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/openssl.h" HRESULT platform_hook_init( const struct platform_config *cfg, @@ -94,5 +95,11 @@ HRESULT platform_hook_init( return hr; } + hr = openssl_hook_init(&cfg->openssl); + + if (FAILED(hr)) { + return hr; + } + return S_OK; } diff --git a/common/platform/platform.h b/common/platform/platform.h index 0b69f12..dc8dfc2 100644 --- a/common/platform/platform.h +++ b/common/platform/platform.h @@ -14,6 +14,7 @@ #include "platform/pcbid.h" #include "platform/vfs.h" #include "platform/system.h" +#include "platform/openssl.h" struct platform_config { struct amvideo_config amvideo; @@ -28,6 +29,7 @@ struct platform_config { struct nusec_config nusec; struct vfs_config vfs; struct system_config system; + struct openssl_config openssl; }; HRESULT platform_hook_init( diff --git a/doc/config/common.md b/doc/config/common.md index 68adfc4..d2eb385 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -663,4 +663,21 @@ Enables the Thinca emulation. This will allow you to enable E-Money on compatibl Default: `1` -Enables hooking of respective Thinca DLL functions to emulate the existence of E-Money. This cannot be used with a real E-Money server. \ No newline at end of file +Enables hooking of respective Thinca DLL functions to emulate the existence of E-Money. This cannot be used with a real E-Money server. + +## `[openssl]` + +Configure the OpenSSL SHA extension bug hook. + +### `enable` + +Default: `1` + +Enables the OpenSSL hook to fix the SHA extension bug on Intel CPUs. + +### `override` + +Default: `0` + +Enables the override to always hook the OpenSSL env variable. By default the +hook is only applied to Intel CPUs with the SHA extension present.