2017-09-20 11:27:13 +00:00
|
|
|
#include "quakedef.h"
|
|
|
|
#if defined(HAVE_WINSSPI)
|
|
|
|
|
|
|
|
/*regarding HAVE_DTLS
|
|
|
|
DTLS1.0 is supported from win8 onwards
|
|
|
|
Its also meant to be supported from some RDP server patch on win7, but I can't get it to work.
|
|
|
|
I've given up for now.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "winquake.h"
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
#include "netinc.h"
|
2017-09-20 11:27:13 +00:00
|
|
|
#define SECURITY_WIN32
|
|
|
|
#include <security.h>
|
|
|
|
#include <sspi.h>
|
|
|
|
#include <schannel.h>
|
|
|
|
|
|
|
|
#define SP_PROT_TLS1_1_SERVER 0x00000100
|
|
|
|
#define SP_PROT_TLS1_1_CLIENT 0x00000200
|
|
|
|
|
|
|
|
#define SP_PROT_TLS1_2_SERVER 0x00000400
|
|
|
|
#define SP_PROT_TLS1_2_CLIENT 0x00000800
|
|
|
|
|
|
|
|
#define SP_PROT_DTLS_SERVER 0x00010000
|
|
|
|
#define SP_PROT_DTLS_CLIENT 0x00020000
|
|
|
|
|
|
|
|
//avoid the use of outdated/insecure protocols
|
|
|
|
//so no ssl2/ssl3
|
|
|
|
#define USE_PROT_SERVER (SP_PROT_TLS1_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER)
|
|
|
|
#define USE_PROT_CLIENT (SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT)
|
|
|
|
|
|
|
|
#define USE_PROT_DGRAM_SERVER (SP_PROT_DTLS_SERVER)
|
|
|
|
#define USE_PROT_DGRAM_CLIENT (SP_PROT_DTLS_CLIENT)
|
|
|
|
|
|
|
|
#ifndef szOID_RSA_SHA512RSA
|
|
|
|
#define szOID_RSA_SHA512RSA "1.2.840.113549.1.1.13"
|
|
|
|
#endif
|
|
|
|
#ifndef SCH_CRED_SNI_CREDENTIAL
|
|
|
|
#define SCH_CRED_SNI_CREDENTIAL 0x00080000
|
|
|
|
#endif
|
|
|
|
|
2019-02-16 19:09:07 +00:00
|
|
|
#ifndef SEC_I_MESSAGE_FRAGMENT
|
2017-09-20 11:27:13 +00:00
|
|
|
#define SEC_I_MESSAGE_FRAGMENT 0x00090364L
|
2019-02-16 19:09:07 +00:00
|
|
|
#endif
|
|
|
|
#ifndef SEC_E_INVALID_PARAMETER
|
2017-09-20 11:27:13 +00:00
|
|
|
#define SEC_E_INVALID_PARAMETER 0x8009035DL
|
2019-02-16 19:09:07 +00:00
|
|
|
#endif
|
2017-09-20 11:27:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
//hungarian ensures we hit no macros.
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
dllhandle_t *lib;
|
|
|
|
SECURITY_STATUS (WINAPI *pDecryptMessage) (PCtxtHandle,PSecBufferDesc,ULONG,PULONG);
|
|
|
|
SECURITY_STATUS (WINAPI *pEncryptMessage) (PCtxtHandle,ULONG,PSecBufferDesc,ULONG);
|
|
|
|
SECURITY_STATUS (WINAPI *pAcquireCredentialsHandleA) (SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp);
|
|
|
|
// SECURITY_STATUS (WINAPI *pInitializeSecurityContextA) (PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp);
|
|
|
|
SECURITY_STATUS (WINAPI *pInitializeSecurityContextW) (PCredHandle,PCtxtHandle,SEC_WCHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp);
|
|
|
|
SECURITY_STATUS (WINAPI *pAcceptSecurityContext) (PCredHandle,PCtxtHandle,PSecBufferDesc,unsigned long,unsigned long,PCtxtHandle,PSecBufferDesc,unsigned long SEC_FAR *,PTimeStamp);
|
|
|
|
SECURITY_STATUS (WINAPI *pCompleteAuthToken) (PCtxtHandle,PSecBufferDesc);
|
|
|
|
SECURITY_STATUS (WINAPI *pQueryContextAttributesA) (PCtxtHandle,ULONG,PVOID);
|
|
|
|
SECURITY_STATUS (WINAPI *pFreeCredentialsHandle) (PCredHandle);
|
|
|
|
SECURITY_STATUS (WINAPI *pDeleteSecurityContext) (PCtxtHandle);
|
|
|
|
} secur;
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
dllhandle_t *lib;
|
|
|
|
BOOL (WINAPI *pCertGetCertificateChain) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*);
|
|
|
|
BOOL (WINAPI *pCertVerifyCertificateChainPolicy) (LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS);
|
|
|
|
void (WINAPI *pCertFreeCertificateChain) (PCCERT_CHAIN_CONTEXT);
|
|
|
|
DWORD (WINAPI *pCertNameToStrA) (DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, DWORD dwStrType, LPCSTR psz, DWORD csz);
|
|
|
|
|
|
|
|
PCCERT_CONTEXT (WINAPI *pCertCreateSelfSignCertificate) (HCRYPTPROV,PCERT_NAME_BLOB,DWORD,PCRYPT_KEY_PROV_INFO,PCRYPT_ALGORITHM_IDENTIFIER,PSYSTEMTIME,PSYSTEMTIME,PCERT_EXTENSIONS);
|
|
|
|
BOOL (WINAPI *pCertStrToNameA) (DWORD,LPCSTR,DWORD,void *,BYTE *,DWORD *,LPCSTR *);
|
|
|
|
} crypt;
|
|
|
|
void SSL_Init(void)
|
|
|
|
{
|
|
|
|
dllfunction_t secur_functable[] =
|
|
|
|
{
|
|
|
|
{(void**)&secur.pDecryptMessage, "DecryptMessage"},
|
|
|
|
{(void**)&secur.pEncryptMessage, "EncryptMessage"},
|
|
|
|
{(void**)&secur.pAcquireCredentialsHandleA, "AcquireCredentialsHandleA"},
|
|
|
|
// {(void**)&secur.pInitializeSecurityContextA, "InitializeSecurityContextA"},
|
|
|
|
{(void**)&secur.pInitializeSecurityContextW, "InitializeSecurityContextW"},
|
|
|
|
{(void**)&secur.pAcceptSecurityContext, "AcceptSecurityContext"},
|
|
|
|
{(void**)&secur.pCompleteAuthToken, "CompleteAuthToken"},
|
|
|
|
{(void**)&secur.pQueryContextAttributesA, "QueryContextAttributesA"},
|
|
|
|
{(void**)&secur.pFreeCredentialsHandle, "FreeCredentialsHandle"},
|
|
|
|
{(void**)&secur.pDeleteSecurityContext, "DeleteSecurityContext"},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
dllfunction_t crypt_functable[] =
|
|
|
|
{
|
|
|
|
{(void**)&crypt.pCertGetCertificateChain, "CertGetCertificateChain"},
|
|
|
|
{(void**)&crypt.pCertVerifyCertificateChainPolicy, "CertVerifyCertificateChainPolicy"},
|
|
|
|
{(void**)&crypt.pCertFreeCertificateChain, "CertFreeCertificateChain"},
|
|
|
|
{(void**)&crypt.pCertNameToStrA, "CertNameToStrA"},
|
|
|
|
{(void**)&crypt.pCertCreateSelfSignCertificate, "CertCreateSelfSignCertificate"},
|
|
|
|
{(void**)&crypt.pCertStrToNameA, "CertStrToNameA"},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!secur.lib)
|
|
|
|
secur.lib = Sys_LoadLibrary("secur32.dll", secur_functable);
|
|
|
|
if (!crypt.lib)
|
|
|
|
crypt.lib = Sys_LoadLibrary("crypt32.dll", crypt_functable);
|
|
|
|
}
|
|
|
|
qboolean SSL_Inited(void)
|
|
|
|
{
|
|
|
|
return !!secur.lib && !!crypt.lib;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MessageAttribute (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MANUAL_CRED_VALIDATION)
|
|
|
|
|
|
|
|
struct sslbuf
|
|
|
|
{
|
|
|
|
size_t datasize;
|
|
|
|
char *data;
|
|
|
|
size_t avail;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
vfsfile_t funcs;
|
|
|
|
vfsfile_t *stream;
|
|
|
|
|
|
|
|
wchar_t wpeername[256];
|
|
|
|
qboolean datagram;
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
HS_ESTABLISHED,
|
|
|
|
|
|
|
|
HS_ERROR,
|
|
|
|
|
|
|
|
HS_STARTCLIENT,
|
|
|
|
HS_CLIENT,
|
|
|
|
|
|
|
|
HS_STARTSERVER,
|
|
|
|
HS_SERVER
|
|
|
|
} handshaking;
|
|
|
|
|
|
|
|
struct sslbuf outraw;
|
|
|
|
struct sslbuf outcrypt;
|
|
|
|
struct sslbuf inraw;
|
|
|
|
struct sslbuf incrypt;
|
|
|
|
|
|
|
|
|
|
|
|
CredHandle cred;
|
|
|
|
SecHandle sechnd;
|
|
|
|
int headersize, footersize;
|
|
|
|
char headerdata[1024], footerdata[1024];
|
|
|
|
|
|
|
|
#ifdef HAVE_DTLS
|
|
|
|
void *cbctx;
|
|
|
|
neterr_t (*transmit)(void *cbctx, const qbyte *data, size_t datasize);
|
|
|
|
#endif
|
|
|
|
} sslfile_t;
|
|
|
|
|
|
|
|
static int SSPI_ExpandBuffer(struct sslbuf *buf, size_t bytes)
|
|
|
|
{
|
|
|
|
if (bytes < buf->datasize)
|
|
|
|
return buf->datasize;
|
|
|
|
Z_ReallocElements((void**)&buf->data, &buf->datasize, bytes, 1);
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes, qboolean expand)
|
|
|
|
{
|
|
|
|
if (bytes > buf->datasize - buf->avail)
|
|
|
|
{
|
|
|
|
if (!expand || SSPI_ExpandBuffer(buf, buf->avail + bytes + 1024) < buf->avail + bytes)
|
|
|
|
bytes = buf->datasize - buf->avail;
|
|
|
|
}
|
|
|
|
memcpy(buf->data + buf->avail, data, bytes);
|
|
|
|
buf->avail += bytes;
|
|
|
|
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
2020-08-13 10:09:39 +00:00
|
|
|
static void SSPI_Error(sslfile_t *f, const char *error, ...)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char string[1024];
|
|
|
|
va_start (argptr, error);
|
|
|
|
vsnprintf (string,sizeof(string)-1, error,argptr);
|
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
f->handshaking = HS_ERROR;
|
|
|
|
if (*string)
|
2020-08-13 10:09:39 +00:00
|
|
|
{
|
|
|
|
if (f->datagram)
|
|
|
|
Con_Printf(CON_ERROR "%s", string);
|
|
|
|
else
|
|
|
|
Sys_Printf(CON_ERROR "%s", string);
|
|
|
|
}
|
2017-09-20 11:27:13 +00:00
|
|
|
if (f->stream)
|
|
|
|
VFS_CLOSE(f->stream);
|
|
|
|
|
|
|
|
secur.pDeleteSecurityContext(&f->sechnd);
|
|
|
|
secur.pFreeCredentialsHandle(&f->cred);
|
|
|
|
f->stream = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SSPI_TryFlushCryptOut(sslfile_t *f)
|
|
|
|
{
|
|
|
|
int sent;
|
|
|
|
if (f->outcrypt.avail)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_DTLS
|
|
|
|
if (f->transmit)
|
|
|
|
{
|
|
|
|
f->transmit(f->cbctx, f->outcrypt.data, f->outcrypt.avail);
|
|
|
|
f->outcrypt.avail = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
sent = VFS_WRITE(f->stream, f->outcrypt.data, f->outcrypt.avail);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sent > 0)
|
|
|
|
{
|
|
|
|
memmove(f->outcrypt.data, f->outcrypt.data + sent, f->outcrypt.avail - sent);
|
|
|
|
f->outcrypt.avail -= sent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int SSPI_CheckNewInCrypt(sslfile_t *f)
|
|
|
|
{
|
|
|
|
int newd;
|
|
|
|
if (!f->stream)
|
2020-10-06 03:17:28 +00:00
|
|
|
return VFS_ERROR_EOF;
|
2017-09-20 11:27:13 +00:00
|
|
|
newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, f->incrypt.datasize - f->incrypt.avail);
|
|
|
|
if (newd < 0)
|
|
|
|
return newd;
|
|
|
|
else
|
|
|
|
f->incrypt.avail += newd;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert inbound crypt->data
|
|
|
|
static void SSPI_Decode(sslfile_t *f)
|
|
|
|
{
|
|
|
|
SECURITY_STATUS ss;
|
|
|
|
SecBufferDesc BuffDesc;
|
|
|
|
SecBuffer SecBuff[4];
|
|
|
|
ULONG ulQop = 0;
|
|
|
|
SecBuffer *extra = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!f->incrypt.avail)
|
|
|
|
return;
|
|
|
|
|
|
|
|
BuffDesc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
BuffDesc.cBuffers = countof(SecBuff);
|
|
|
|
BuffDesc.pBuffers = SecBuff;
|
|
|
|
|
|
|
|
SecBuff[0].BufferType = SECBUFFER_DATA;
|
|
|
|
SecBuff[0].cbBuffer = f->incrypt.avail;
|
|
|
|
SecBuff[0].pvBuffer = f->incrypt.data;
|
|
|
|
|
|
|
|
SecBuff[1].BufferType = SECBUFFER_EMPTY; //space for header
|
|
|
|
SecBuff[2].BufferType = SECBUFFER_EMPTY; //space for footer
|
|
|
|
SecBuff[3].BufferType = SECBUFFER_EMPTY; //space for extra marker
|
|
|
|
|
|
|
|
ss = secur.pDecryptMessage(&f->sechnd, &BuffDesc, 0, &ulQop);
|
|
|
|
|
|
|
|
if (ss < 0)
|
|
|
|
{
|
|
|
|
if (ss == SEC_E_INCOMPLETE_MESSAGE)
|
|
|
|
{
|
|
|
|
if (f->incrypt.avail == f->incrypt.datasize)
|
|
|
|
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
|
|
|
|
return; //no error if its incomplete, we can just get more data later on.
|
|
|
|
}
|
|
|
|
switch(ss)
|
|
|
|
{
|
|
|
|
case SEC_E_DECRYPT_FAILURE: SSPI_Error(f, "DecryptMessage failed: SEC_E_DECRYPT_FAILURE\n", ss); break;
|
|
|
|
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "DecryptMessage failed: SEC_E_INVALID_HANDLE\n"); break;
|
|
|
|
default: SSPI_Error(f, "DecryptMessage failed: %0#lx\n", ss); break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < BuffDesc.cBuffers; i++)
|
|
|
|
{
|
|
|
|
switch(SecBuff[i].BufferType)
|
|
|
|
{
|
|
|
|
case SECBUFFER_DATA:
|
|
|
|
if (SSPI_CopyIntoBuffer(&f->inraw, SecBuff[i].pvBuffer, SecBuff[i].cbBuffer, true) != SecBuff[i].cbBuffer)
|
|
|
|
SSPI_Error(f, "outraw buffer overflowed\n");
|
|
|
|
break;
|
|
|
|
case SECBUFFER_EXTRA:
|
|
|
|
if (extra)
|
|
|
|
SSPI_Error(f, "multiple extra buffers\n");
|
|
|
|
extra = &SecBuff[i];
|
|
|
|
break;
|
|
|
|
case SECBUFFER_EMPTY:
|
|
|
|
case SECBUFFER_MISSING:
|
|
|
|
case SECBUFFER_STREAM_TRAILER:
|
|
|
|
case SECBUFFER_STREAM_HEADER:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SSPI_Error(f, "got unexpected buffer type\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//retain the extra. if there's no extra then mark it so.
|
|
|
|
if (extra)
|
|
|
|
{
|
|
|
|
memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - extra->cbBuffer), extra->cbBuffer);
|
|
|
|
f->incrypt.avail = extra->cbBuffer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
f->incrypt.avail = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert outgoing data->crypt
|
|
|
|
static void SSPI_Encode(sslfile_t *f)
|
|
|
|
{
|
|
|
|
SECURITY_STATUS ss;
|
|
|
|
SecBufferDesc BuffDesc;
|
|
|
|
SecBuffer SecBuff[4];
|
|
|
|
ULONG ulQop = 0;
|
|
|
|
|
|
|
|
if (f->outcrypt.avail)
|
|
|
|
{
|
|
|
|
SSPI_TryFlushCryptOut(f);
|
|
|
|
if (f->outcrypt.avail)
|
|
|
|
return; //don't flood too much
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//don't corrupt the handshake data.
|
|
|
|
if (f->handshaking)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!f->outraw.avail)
|
|
|
|
return;
|
|
|
|
|
|
|
|
BuffDesc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
BuffDesc.cBuffers = 4;
|
|
|
|
BuffDesc.pBuffers = SecBuff;
|
|
|
|
|
|
|
|
SecBuff[0].BufferType = SECBUFFER_STREAM_HEADER;
|
|
|
|
SecBuff[0].cbBuffer = f->headersize;
|
|
|
|
SecBuff[0].pvBuffer = f->headerdata;
|
|
|
|
|
|
|
|
SecBuff[1].BufferType = SECBUFFER_DATA;
|
|
|
|
SecBuff[1].cbBuffer = f->outraw.avail;
|
|
|
|
SecBuff[1].pvBuffer = f->outraw.data;
|
|
|
|
|
|
|
|
SecBuff[2].BufferType = SECBUFFER_STREAM_TRAILER;
|
|
|
|
SecBuff[2].cbBuffer = f->footersize;
|
|
|
|
SecBuff[2].pvBuffer = f->footerdata;
|
|
|
|
|
|
|
|
SecBuff[3].BufferType = SECBUFFER_EMPTY;
|
|
|
|
SecBuff[3].cbBuffer = 0;
|
|
|
|
SecBuff[3].pvBuffer = NULL;
|
|
|
|
|
|
|
|
ss = secur.pEncryptMessage(&f->sechnd, ulQop, &BuffDesc, 0);
|
|
|
|
|
|
|
|
if (ss < 0)
|
|
|
|
{
|
|
|
|
SSPI_Error(f, "EncryptMessage failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
f->outraw.avail = 0;
|
|
|
|
|
|
|
|
//fixme: these should be made non-fatal.
|
|
|
|
if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer, true) < SecBuff[0].cbBuffer)
|
|
|
|
{
|
|
|
|
SSPI_Error(f, "crypt buffer overflowed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer, true) < SecBuff[1].cbBuffer)
|
|
|
|
{
|
|
|
|
SSPI_Error(f, "crypt buffer overflowed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer, true) < SecBuff[2].cbBuffer)
|
|
|
|
{
|
|
|
|
SSPI_Error(f, "crypt buffer overflowed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SSPI_TryFlushCryptOut(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *narrowen(char *out, size_t outlen, wchar_t *wide);
|
|
|
|
static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data, size_t datasize, qboolean datagram)
|
|
|
|
{
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
size_t knownsize;
|
|
|
|
void *knowncert;
|
2017-10-12 12:02:25 +00:00
|
|
|
char realdomain[256];
|
2020-08-13 10:09:39 +00:00
|
|
|
unsigned int probs = 0;
|
2017-09-20 11:27:13 +00:00
|
|
|
if (datagram)
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
if (status == CERT_E_UNTRUSTEDROOT || status == CERT_E_UNTRUSTEDTESTROOT)
|
|
|
|
probs |= CERTLOG_MISSINGCA;
|
|
|
|
if (status == CERT_E_EXPIRED)
|
|
|
|
probs |= CERTLOG_EXPIRED;
|
|
|
|
if (status == SEC_E_WRONG_PRINCIPAL)
|
|
|
|
probs |= CERTLOG_WRONGHOST;
|
2017-09-20 11:27:13 +00:00
|
|
|
if (status == CERT_E_UNTRUSTEDROOT || SUCCEEDED(status))
|
|
|
|
{
|
|
|
|
#ifndef SERVERONLY
|
2020-08-13 10:09:39 +00:00
|
|
|
if (CertLog_ConnectOkay(narrowen(realdomain, sizeof(realdomain), domain), data, datasize, probs))
|
2017-09-20 11:27:13 +00:00
|
|
|
status = SEC_E_OK;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
status = TRUST_E_FAIL;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
|
|
|
|
narrowen(realdomain, sizeof(realdomain), domain);
|
|
|
|
knowncert = TLS_GetKnownCertificate(realdomain, &knownsize);
|
|
|
|
if (knowncert)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
if (knownsize == datasize && !memcmp(data, knowncert, datasize))
|
|
|
|
{ //what we know about matched
|
|
|
|
if (status == CERT_E_UNTRUSTEDROOT || status == CERT_E_EXPIRED)
|
|
|
|
status = SEC_E_OK;
|
|
|
|
}
|
|
|
|
else
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
if (status != CERT_E_EXPIRED)
|
|
|
|
Con_Printf("%ls has an unexpected certificate\n", domain);
|
|
|
|
if (status == SEC_E_OK) //we (think) we know better.
|
|
|
|
status = TRUST_E_FAIL;
|
2017-09-20 11:27:13 +00:00
|
|
|
}
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
BZ_Free(knowncert);
|
2017-09-20 11:27:13 +00:00
|
|
|
}
|
2017-10-12 12:02:25 +00:00
|
|
|
|
|
|
|
#ifndef SERVERONLY
|
|
|
|
//self-signed and expired certs are understandable in many situations.
|
|
|
|
//prompt and cache (although this connection attempt will fail).
|
2020-08-13 10:09:39 +00:00
|
|
|
if (status == CERT_E_UNTRUSTEDROOT || status == CERT_E_UNTRUSTEDTESTROOT)
|
|
|
|
probs |= CERTLOG_MISSINGCA;
|
|
|
|
else if (status == CERT_E_EXPIRED)
|
|
|
|
probs |= CERTLOG_EXPIRED;
|
|
|
|
else if (status == SEC_E_WRONG_PRINCIPAL)
|
|
|
|
probs |= CERTLOG_WRONGHOST;
|
|
|
|
else if (status != SEC_E_OK)
|
|
|
|
probs |= CERTLOG_UNKNOWN;
|
2017-10-12 12:02:25 +00:00
|
|
|
if (status == CERT_E_UNTRUSTEDROOT || status == CERT_E_UNTRUSTEDTESTROOT || status == CERT_E_EXPIRED)
|
2020-08-13 10:09:39 +00:00
|
|
|
if (CertLog_ConnectOkay(realdomain, data, datasize, probs))
|
2017-10-12 12:02:25 +00:00
|
|
|
return SEC_E_OK;
|
|
|
|
#endif
|
|
|
|
|
2017-09-20 11:27:13 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServerName, DWORD dwCertFlags, qboolean datagram)
|
|
|
|
{
|
|
|
|
HTTPSPolicyCallbackData polHttps;
|
|
|
|
CERT_CHAIN_POLICY_PARA PolicyPara;
|
|
|
|
CERT_CHAIN_POLICY_STATUS PolicyStatus;
|
|
|
|
CERT_CHAIN_PARA ChainPara;
|
|
|
|
PCCERT_CHAIN_CONTEXT pChainContext;
|
|
|
|
DWORD Status;
|
|
|
|
LPSTR rgszUsages[] =
|
|
|
|
{
|
|
|
|
szOID_PKIX_KP_SERVER_AUTH,
|
|
|
|
szOID_SERVER_GATED_CRYPTO,
|
|
|
|
szOID_SGC_NETSCAPE
|
|
|
|
};
|
|
|
|
DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
|
|
|
|
|
|
|
|
if(pServerCert == NULL)
|
|
|
|
return SEC_E_WRONG_PRINCIPAL;
|
|
|
|
if(!*pwszServerName)
|
|
|
|
return SEC_E_WRONG_PRINCIPAL;
|
|
|
|
|
|
|
|
// Build certificate chain.
|
|
|
|
memset(&ChainPara, 0, sizeof(ChainPara));
|
|
|
|
ChainPara.cbSize = sizeof(ChainPara);
|
|
|
|
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
|
|
|
|
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
|
|
|
|
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
|
|
|
|
|
|
|
|
if (!crypt.pCertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext))
|
|
|
|
{
|
|
|
|
Status = GetLastError();
|
|
|
|
Sys_Printf("Error %#lx returned by CertGetCertificateChain!\n", Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Validate certificate chain.
|
|
|
|
memset(&polHttps, 0, sizeof(HTTPSPolicyCallbackData));
|
|
|
|
polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
|
|
|
|
polHttps.dwAuthType = AUTHTYPE_SERVER;
|
|
|
|
polHttps.fdwChecks = dwCertFlags;
|
|
|
|
polHttps.pwszServerName = pwszServerName;
|
|
|
|
|
|
|
|
memset(&PolicyPara, 0, sizeof(PolicyPara));
|
|
|
|
PolicyPara.cbSize = sizeof(PolicyPara);
|
|
|
|
PolicyPara.pvExtraPolicyPara = &polHttps;
|
|
|
|
|
|
|
|
memset(&PolicyStatus, 0, sizeof(PolicyStatus));
|
|
|
|
PolicyStatus.cbSize = sizeof(PolicyStatus);
|
|
|
|
|
|
|
|
if (!crypt.pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus))
|
|
|
|
{
|
|
|
|
Status = GetLastError();
|
|
|
|
Sys_Printf("Error %#lx returned by CertVerifyCertificateChainPolicy!\n", Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = VerifyKnownCertificates(PolicyStatus.dwError, pwszServerName, pServerCert->pbCertEncoded, pServerCert->cbCertEncoded, datagram);
|
|
|
|
if (Status)
|
|
|
|
{
|
|
|
|
char fmsg[512];
|
|
|
|
char *err;
|
|
|
|
switch (Status)
|
|
|
|
{
|
|
|
|
case CERT_E_EXPIRED: err = "CERT_E_EXPIRED"; break;
|
|
|
|
case CERT_E_VALIDITYPERIODNESTING: err = "CERT_E_VALIDITYPERIODNESTING"; break;
|
|
|
|
case CERT_E_ROLE: err = "CERT_E_ROLE"; break;
|
|
|
|
case CERT_E_PATHLENCONST: err = "CERT_E_PATHLENCONST"; break;
|
|
|
|
case CERT_E_CRITICAL: err = "CERT_E_CRITICAL"; break;
|
|
|
|
case CERT_E_PURPOSE: err = "CERT_E_PURPOSE"; break;
|
|
|
|
case CERT_E_ISSUERCHAINING: err = "CERT_E_ISSUERCHAINING"; break;
|
|
|
|
case CERT_E_MALFORMED: err = "CERT_E_MALFORMED"; break;
|
|
|
|
case CERT_E_UNTRUSTEDROOT: err = "CERT_E_UNTRUSTEDROOT"; break;
|
|
|
|
case CERT_E_CHAINING: err = "CERT_E_CHAINING"; break;
|
|
|
|
case TRUST_E_FAIL: err = "TRUST_E_FAIL"; break;
|
|
|
|
case CERT_E_REVOKED: err = "CERT_E_REVOKED"; break;
|
|
|
|
case CERT_E_UNTRUSTEDTESTROOT: err = "CERT_E_UNTRUSTEDTESTROOT"; break;
|
|
|
|
case CERT_E_REVOCATION_FAILURE: err = "CERT_E_REVOCATION_FAILURE"; break;
|
|
|
|
case CERT_E_CN_NO_MATCH:
|
|
|
|
err = fmsg;
|
|
|
|
Q_strncpyz(fmsg, "Certificate is for ", sizeof(fmsg));
|
|
|
|
crypt.pCertNameToStrA(X509_ASN_ENCODING, &pServerCert->pCertInfo->Subject, 0, fmsg+strlen(fmsg), sizeof(fmsg)-strlen(fmsg));
|
|
|
|
break;
|
|
|
|
case CERT_E_WRONG_USAGE: err = "CERT_E_WRONG_USAGE"; break;
|
|
|
|
default: err = "(unknown)"; break;
|
|
|
|
}
|
2019-06-05 20:48:06 +00:00
|
|
|
Con_Printf(CON_ERROR "Error verifying certificate for '%ls': %s\n", pwszServerName, err);
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2019-06-05 20:48:06 +00:00
|
|
|
if (tls_ignorecertificateerrors.ival)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
2019-06-05 20:48:06 +00:00
|
|
|
Con_Printf(CON_WARNING "pretending it didn't happen... (tls_ignorecertificateerrors is set)\n");
|
2017-09-20 11:27:13 +00:00
|
|
|
Status = SEC_E_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Status = SEC_E_OK;
|
|
|
|
}
|
|
|
|
crypt.pCertFreeCertificateChain(pChainContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
static PCCERT_CONTEXT SSPI_GetServerCertificate(void)
|
|
|
|
{
|
|
|
|
static PCCERT_CONTEXT ret;
|
|
|
|
char *issuertext = "CN=127.0.0.1, O=\"FTE QuakeWorld\", OU=Testing, C=TR";
|
|
|
|
CERT_NAME_BLOB issuerblob;
|
|
|
|
|
2014-03-30 08:55:06 +00:00
|
|
|
CRYPT_ALGORITHM_IDENTIFIER sigalg;
|
|
|
|
SYSTEMTIME expiredate;
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2017-09-20 11:27:13 +00:00
|
|
|
memset(&sigalg, 0, sizeof(sigalg));
|
|
|
|
sigalg.pszObjId = szOID_RSA_SHA512RSA;
|
2014-03-30 08:55:06 +00:00
|
|
|
|
|
|
|
GetSystemTime(&expiredate);
|
2017-09-20 11:27:13 +00:00
|
|
|
expiredate.wYear += 2; //2 years hence. woo
|
|
|
|
|
|
|
|
|
|
|
|
memset(&issuerblob, 0, sizeof(issuerblob));
|
2014-03-30 08:55:06 +00:00
|
|
|
crypt.pCertStrToNameA(X509_ASN_ENCODING, issuertext, CERT_X500_NAME_STR, NULL, issuerblob.pbData, &issuerblob.cbData, NULL);
|
|
|
|
issuerblob.pbData = Z_Malloc(issuerblob.cbData);
|
2017-09-20 11:27:13 +00:00
|
|
|
crypt.pCertStrToNameA(X509_ASN_ENCODING, issuertext, CERT_X500_NAME_STR, NULL, issuerblob.pbData, &issuerblob.cbData, NULL);
|
|
|
|
|
2014-03-30 08:55:06 +00:00
|
|
|
ret = crypt.pCertCreateSelfSignCertificate(
|
|
|
|
0,
|
|
|
|
&issuerblob,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
&sigalg,
|
|
|
|
NULL,
|
|
|
|
&expiredate,
|
|
|
|
NULL
|
2017-09-20 11:27:13 +00:00
|
|
|
);
|
|
|
|
if (!ret)
|
|
|
|
{ //try and downgrade the signature algo if it failed.
|
|
|
|
sigalg.pszObjId = szOID_RSA_SHA1RSA;
|
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
|
|
|
ret = crypt.pCertCreateSelfSignCertificate(
|
|
|
|
0,
|
|
|
|
&issuerblob,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
&sigalg,
|
|
|
|
NULL,
|
|
|
|
&expiredate,
|
|
|
|
NULL
|
2017-09-20 11:27:13 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Z_Free(issuerblob.pbData);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SSPI_GenServerCredentials(sslfile_t *f)
|
|
|
|
{
|
|
|
|
SECURITY_STATUS ss;
|
|
|
|
TimeStamp Lifetime;
|
|
|
|
SCHANNEL_CRED SchannelCred;
|
|
|
|
PCCERT_CONTEXT cred;
|
|
|
|
|
|
|
|
memset(&SchannelCred, 0, sizeof(SchannelCred));
|
|
|
|
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
|
|
|
|
SchannelCred.grbitEnabledProtocols = f->datagram?USE_PROT_DGRAM_SERVER:USE_PROT_SERVER;
|
|
|
|
SchannelCred.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER|SCH_CRED_DISABLE_RECONNECTS; /*don't use windows login info or anything*/
|
|
|
|
|
|
|
|
cred = SSPI_GetServerCertificate();
|
|
|
|
SchannelCred.cCreds = 1;
|
|
|
|
SchannelCred.paCred = &cred;
|
|
|
|
|
|
|
|
if (!cred)
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
SSPI_Error(f, localtext("Unable to load/generate certificate\n"));
|
2017-09-20 11:27:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss = secur.pAcquireCredentialsHandleA (NULL, UNISP_NAME_A, SECPKG_CRED_INBOUND, NULL, &SchannelCred, NULL, NULL, &f->cred, &Lifetime);
|
|
|
|
if (ss < 0)
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
SSPI_Error(f, localtext("WinSSPI: AcquireCredentialsHandle failed\n"));
|
2017-09-20 11:27:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SSPI_Handshake (sslfile_t *f)
|
|
|
|
{
|
|
|
|
SECURITY_STATUS ss;
|
|
|
|
TimeStamp Lifetime;
|
|
|
|
SecBufferDesc OutBuffDesc;
|
|
|
|
SecBuffer OutSecBuff[8];
|
|
|
|
SecBufferDesc InBuffDesc;
|
|
|
|
SecBuffer InSecBuff[8];
|
|
|
|
ULONG ContextAttributes;
|
|
|
|
SCHANNEL_CRED SchannelCred;
|
|
|
|
int i;
|
|
|
|
qboolean retries = 5;
|
|
|
|
|
|
|
|
// char buf1[128];
|
|
|
|
// char buf2[128];
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
if (f->outcrypt.avail)
|
|
|
|
{
|
|
|
|
//don't let things build up too much
|
|
|
|
SSPI_TryFlushCryptOut(f);
|
|
|
|
if (f->outcrypt.avail)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//FIXME: skip this if we've had no new data since last time
|
|
|
|
|
|
|
|
OutBuffDesc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
OutBuffDesc.cBuffers = countof(OutSecBuff);
|
|
|
|
OutBuffDesc.pBuffers = OutSecBuff;
|
|
|
|
|
|
|
|
OutSecBuff[0].BufferType = SECBUFFER_TOKEN;
|
|
|
|
OutSecBuff[0].cbBuffer = f->outcrypt.datasize - f->outcrypt.avail;
|
|
|
|
OutSecBuff[0].pvBuffer = f->outcrypt.data + f->outcrypt.avail;
|
|
|
|
|
|
|
|
for (i = 0; i < OutBuffDesc.cBuffers; i++)
|
|
|
|
{
|
|
|
|
OutSecBuff[i].BufferType = SECBUFFER_EMPTY;
|
|
|
|
OutSecBuff[i].pvBuffer = NULL;
|
|
|
|
OutSecBuff[i].cbBuffer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f->handshaking == HS_ERROR)
|
|
|
|
return; //gave up.
|
|
|
|
else if (f->handshaking == HS_STARTCLIENT)
|
|
|
|
{
|
|
|
|
//no input data yet.
|
|
|
|
f->handshaking = HS_CLIENT;
|
|
|
|
|
|
|
|
memset(&SchannelCred, 0, sizeof(SchannelCred));
|
|
|
|
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
|
|
|
|
SchannelCred.grbitEnabledProtocols = f->datagram?USE_PROT_DGRAM_CLIENT:USE_PROT_CLIENT;
|
|
|
|
SchannelCred.dwFlags |= SCH_CRED_SNI_CREDENTIAL | SCH_CRED_NO_DEFAULT_CREDS; /*don't use windows login info or anything*/
|
|
|
|
|
|
|
|
ss = secur.pAcquireCredentialsHandleA (NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &f->cred, &Lifetime);
|
|
|
|
if (ss < 0)
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
SSPI_Error(f, localtext("WINSSPI: AcquireCredentialsHandle failed\n"));
|
2017-09-20 11:27:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss = secur.pInitializeSecurityContextW (&f->cred, NULL, f->wpeername, MessageAttribute|(f->datagram?ISC_REQ_DATAGRAM:ISC_REQ_STREAM), 0, SECURITY_NATIVE_DREP, NULL, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
|
|
|
|
}
|
|
|
|
else if (f->handshaking == HS_CLIENT)
|
|
|
|
{
|
|
|
|
//only if we actually have data.
|
|
|
|
if (!f->incrypt.avail && !f->datagram)
|
|
|
|
return;
|
|
|
|
|
|
|
|
InBuffDesc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
InBuffDesc.cBuffers = 4;
|
|
|
|
InBuffDesc.pBuffers = InSecBuff;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
if (f->incrypt.avail)
|
|
|
|
{
|
|
|
|
InSecBuff[i].BufferType = SECBUFFER_TOKEN;
|
|
|
|
InSecBuff[i].cbBuffer = f->incrypt.avail;
|
|
|
|
InSecBuff[i].pvBuffer = f->incrypt.data;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i < InBuffDesc.cBuffers; i++)
|
|
|
|
{
|
|
|
|
InSecBuff[i].BufferType = SECBUFFER_EMPTY;
|
|
|
|
InSecBuff[i].pvBuffer = NULL;
|
|
|
|
InSecBuff[i].cbBuffer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss = secur.pInitializeSecurityContextW (&f->cred, &f->sechnd, NULL, MessageAttribute|(f->datagram?ISC_REQ_DATAGRAM:ISC_REQ_STREAM), 0, SECURITY_NETWORK_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
|
|
|
|
|
|
|
|
if (ss == SEC_E_INCOMPLETE_MESSAGE)
|
|
|
|
{
|
|
|
|
// Con_Printf("SEC_E_INCOMPLETE_MESSAGE\n");
|
|
|
|
if (!f->datagram && f->incrypt.avail == f->incrypt.datasize)
|
|
|
|
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (ss == SEC_E_INVALID_TOKEN)
|
|
|
|
{
|
|
|
|
// Con_Printf("SEC_E_INVALID_TOKEN\n");
|
|
|
|
if (f->datagram)
|
|
|
|
return; //our udp protocol may have non-dtls packets mixed in. besides, we don't want to die from spoofed packets.
|
|
|
|
}
|
|
|
|
// else if (ss == SEC_I_MESSAGE_FRAGMENT)
|
|
|
|
// Con_Printf("SEC_I_MESSAGE_FRAGMENT\n");
|
|
|
|
// else if (ss == SEC_I_CONTINUE_NEEDED)
|
|
|
|
// Con_Printf("SEC_I_CONTINUE_NEEDED\n");
|
|
|
|
// else
|
|
|
|
// Con_Printf("InitializeSecurityContextA %x\n", ss);
|
|
|
|
|
|
|
|
|
|
|
|
//any extra data should still remain for the next time around. this might be more handshake data or payload data.
|
|
|
|
if (InSecBuff[1].BufferType == SECBUFFER_EXTRA)
|
|
|
|
{
|
|
|
|
memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - InSecBuff[1].cbBuffer), InSecBuff[1].cbBuffer);
|
|
|
|
f->incrypt.avail = InSecBuff[1].cbBuffer;
|
|
|
|
}
|
|
|
|
else f->incrypt.avail = 0;
|
|
|
|
}
|
|
|
|
else if (f->handshaking == HS_STARTSERVER || f->handshaking == HS_SERVER)
|
|
|
|
{
|
|
|
|
//only if we actually have data.
|
|
|
|
if (!f->incrypt.avail)
|
|
|
|
return;
|
|
|
|
|
|
|
|
InBuffDesc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
InBuffDesc.cBuffers = countof(InSecBuff);
|
|
|
|
InBuffDesc.pBuffers = InSecBuff;
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
if (f->incrypt.avail)
|
|
|
|
{
|
|
|
|
InSecBuff[i].BufferType = SECBUFFER_TOKEN;
|
|
|
|
InSecBuff[i].cbBuffer = f->incrypt.avail;
|
|
|
|
InSecBuff[i].pvBuffer = f->incrypt.data;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i < InBuffDesc.cBuffers; i++)
|
|
|
|
{
|
|
|
|
InSecBuff[i].BufferType = SECBUFFER_EMPTY;
|
|
|
|
InSecBuff[i].pvBuffer = NULL;
|
|
|
|
InSecBuff[i].cbBuffer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
OutSecBuff[i++].BufferType = SECBUFFER_EXTRA;
|
|
|
|
OutSecBuff[i++].BufferType = 17/*SECBUFFER_ALERT*/;
|
|
|
|
|
|
|
|
#define ServerMessageAttribute (ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | ASC_REQ_CONFIDENTIALITY /*| ASC_REQ_EXTENDED_ERROR*/ | ASC_REQ_ALLOCATE_MEMORY)
|
|
|
|
|
|
|
|
ss = secur.pAcceptSecurityContext(&f->cred, (f->handshaking==HS_SERVER)?&f->sechnd:NULL, &InBuffDesc,
|
|
|
|
ServerMessageAttribute|(f->datagram?ASC_REQ_DATAGRAM:ASC_REQ_STREAM), SECURITY_NETWORK_DREP, &f->sechnd,
|
|
|
|
&OutBuffDesc, &ContextAttributes, NULL);
|
|
|
|
if (ss == SEC_E_INVALID_TOKEN)
|
|
|
|
{
|
|
|
|
// Con_Printf("SEC_E_INVALID_TOKEN\n");
|
|
|
|
if (f->datagram)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (ss == SEC_E_INCOMPLETE_MESSAGE)
|
|
|
|
{
|
|
|
|
// Con_Printf("SEC_E_INCOMPLETE_MESSAGE\n");
|
|
|
|
if (!f->datagram && f->incrypt.avail == f->incrypt.datasize)
|
|
|
|
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
// Con_Printf("InitializeSecurityContextA %x\n", ss);
|
|
|
|
f->handshaking = HS_SERVER;
|
|
|
|
|
|
|
|
//any extra data should still remain for the next time around. this might be more handshake data or payload data.
|
|
|
|
if (InSecBuff[1].BufferType == SECBUFFER_EXTRA)
|
|
|
|
{
|
|
|
|
memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - InSecBuff[1].cbBuffer), InSecBuff[1].cbBuffer);
|
|
|
|
f->incrypt.avail = InSecBuff[1].cbBuffer;
|
|
|
|
}
|
|
|
|
else f->incrypt.avail = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
2020-08-13 10:09:39 +00:00
|
|
|
|
2017-09-20 11:27:13 +00:00
|
|
|
|
|
|
|
if (ss == SEC_I_INCOMPLETE_CREDENTIALS)
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
SSPI_Error(f, localtext("server requires credentials\n"));
|
2017-09-20 11:27:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ss < 0)
|
|
|
|
{
|
|
|
|
switch(ss)
|
|
|
|
{
|
|
|
|
case SEC_E_ALGORITHM_MISMATCH: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_ALGORITHM_MISMATCH\n"); break;
|
|
|
|
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_HANDLE\n"); break;
|
|
|
|
case SEC_E_ILLEGAL_MESSAGE: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE\n"); break;
|
|
|
|
case SEC_E_INVALID_TOKEN: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_TOKEN\n"); break;
|
|
|
|
case SEC_E_INVALID_PARAMETER: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_PARAMETER\n"); break;
|
|
|
|
default: SSPI_Error(f, "InitializeSecurityContext failed: %lx\n", (long)ss); break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((SEC_I_COMPLETE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss))
|
|
|
|
{
|
|
|
|
ss = secur.pCompleteAuthToken (&f->sechnd, &OutBuffDesc);
|
|
|
|
if (ss < 0)
|
|
|
|
{
|
|
|
|
SSPI_Error(f, "CompleteAuthToken failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//its all okay and established if we get this far.
|
|
|
|
if (ss == SEC_E_OK)
|
|
|
|
{
|
|
|
|
SecPkgContext_StreamSizes strsizes;
|
|
|
|
CERT_CONTEXT *remotecert;
|
|
|
|
|
|
|
|
secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_STREAM_SIZES, &strsizes);
|
|
|
|
f->headersize = strsizes.cbHeader;
|
|
|
|
f->footersize = strsizes.cbTrailer;
|
|
|
|
if (f->handshaking != HS_SERVER)
|
|
|
|
{ //server takes an annonymous client. client expects a proper certificate.
|
|
|
|
if (*f->wpeername)
|
|
|
|
{
|
|
|
|
ss = secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &remotecert);
|
|
|
|
if (ss != SEC_E_OK)
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
SSPI_Error(f, localtext("unable to read server's certificate\n"));
|
2017-09-20 11:27:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (VerifyServerCertificate(remotecert, f->wpeername, 0, f->datagram))
|
|
|
|
{
|
2020-08-13 10:09:39 +00:00
|
|
|
SSPI_Error(f, localtext("Error validating certificante\n"));
|
2017-09-20 11:27:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Sys_Printf("SSL/TLS Server name not specified, skipping verification\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
f->handshaking = HS_ESTABLISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//send early, send often.
|
|
|
|
#ifdef HAVE_DTLS
|
|
|
|
if (f->transmit)
|
|
|
|
{
|
|
|
|
for (i = 0; i < OutBuffDesc.cBuffers; i++)
|
|
|
|
if (OutSecBuff[i].BufferType == SECBUFFER_TOKEN && OutSecBuff[i].cbBuffer)
|
|
|
|
f->transmit(f->cbctx, OutSecBuff[i].pvBuffer, OutSecBuff[i].cbBuffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
i = 0;
|
|
|
|
if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff[i].pvBuffer, OutSecBuff[i].cbBuffer, true) < OutSecBuff[i].cbBuffer)
|
|
|
|
{
|
|
|
|
SSPI_Error(f, "crypt overflow\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SSPI_TryFlushCryptOut(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f->handshaking == HS_ESTABLISHED)
|
|
|
|
SSPI_Encode(f);
|
|
|
|
else if (ss == SEC_I_MESSAGE_FRAGMENT) //looks like we can connect faster if we loop when we get this result.
|
|
|
|
if (retries --> 0)
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int QDECL SSPI_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
|
|
|
|
{
|
|
|
|
sslfile_t *f = (sslfile_t *)file;
|
|
|
|
int err = SSPI_CheckNewInCrypt(f);
|
|
|
|
|
|
|
|
if (f->handshaking)
|
|
|
|
{
|
|
|
|
SSPI_Handshake(f);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
SSPI_Encode(f);
|
|
|
|
|
|
|
|
SSPI_Decode(f);
|
|
|
|
|
|
|
|
bytestoread = min(bytestoread, f->inraw.avail);
|
|
|
|
if (bytestoread)
|
|
|
|
{
|
|
|
|
memcpy(buffer, f->inraw.data, bytestoread);
|
|
|
|
f->inraw.avail -= bytestoread;
|
|
|
|
memmove(f->inraw.data, f->inraw.data + bytestoread, f->inraw.avail);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return bytestoread;
|
|
|
|
}
|
|
|
|
static int QDECL SSPI_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
|
|
|
{
|
|
|
|
sslfile_t *f = (sslfile_t *)file;
|
|
|
|
|
|
|
|
//don't endlessly accept data faster than we can push it out.
|
|
|
|
//we'll buffer a little, but don't go overboard
|
|
|
|
if (f->outcrypt.avail > 8192)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bytestowrite = SSPI_CopyIntoBuffer(&f->outraw, buffer, bytestowrite, false);
|
|
|
|
|
|
|
|
if (f->handshaking)
|
|
|
|
{
|
|
|
|
SSPI_CheckNewInCrypt(f); //make sure its ticking over
|
|
|
|
SSPI_Handshake(f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SSPI_Encode(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytestowrite;
|
|
|
|
}
|
|
|
|
static qboolean QDECL SSPI_Seek (struct vfsfile_s *file, qofs_t pos)
|
|
|
|
{
|
|
|
|
SSPI_Error((sslfile_t*)file, "unable to seek on streams\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
static qofs_t QDECL SSPI_Tell (struct vfsfile_s *file)
|
|
|
|
{
|
|
|
|
SSPI_Error((sslfile_t*)file, "unable to seek on streams\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static qofs_t QDECL SSPI_GetLen (struct vfsfile_s *file)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static qboolean QDECL SSPI_Close (struct vfsfile_s *file)
|
|
|
|
{
|
|
|
|
sslfile_t *f = (sslfile_t *)file;
|
|
|
|
qboolean success = f->stream != NULL;
|
|
|
|
SSPI_Error(f, "");
|
|
|
|
|
|
|
|
Z_Free(f->outraw.data);
|
|
|
|
Z_Free(f->outcrypt.data);
|
|
|
|
Z_Free(f->inraw.data);
|
|
|
|
Z_Free(f->incrypt.data);
|
|
|
|
|
|
|
|
Z_Free(f);
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <wchar.h>
|
2021-06-21 13:43:57 +00:00
|
|
|
static vfsfile_t *SSPI_OpenVFS(const char *servername, vfsfile_t *source, qboolean server)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
|
|
|
sslfile_t *newf;
|
|
|
|
int i = 0;
|
|
|
|
int err;
|
|
|
|
unsigned int c;
|
|
|
|
// const char *localname;
|
|
|
|
const char *peername;
|
|
|
|
|
|
|
|
if (!source || !SSL_Inited())
|
|
|
|
return NULL;
|
|
|
|
if (server)
|
|
|
|
{
|
|
|
|
// localname = servername;
|
|
|
|
peername = "";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// localname = "";
|
|
|
|
peername = servername;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (server) //unsupported
|
|
|
|
return NULL;
|
|
|
|
*/
|
|
|
|
|
|
|
|
newf = Z_Malloc(sizeof(*newf));
|
|
|
|
while(*peername)
|
|
|
|
{
|
|
|
|
c = utf8_decode(&err, peername, (void*)&peername);
|
|
|
|
if (c > WCHAR_MAX)
|
|
|
|
err = true; //no 16bit surrogates. they're evil.
|
|
|
|
else if (i == sizeof(newf->wpeername)/sizeof(newf->wpeername[0]) - 1)
|
|
|
|
err = true; //no space to store it
|
|
|
|
else
|
|
|
|
newf->wpeername[i++] = c;
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
Z_Free(newf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newf->wpeername[i] = 0;
|
|
|
|
|
|
|
|
newf->handshaking = server?HS_STARTSERVER:HS_STARTCLIENT;
|
|
|
|
newf->stream = source;
|
|
|
|
newf->funcs.Close = SSPI_Close;
|
|
|
|
newf->funcs.Flush = NULL;
|
|
|
|
newf->funcs.GetLen = SSPI_GetLen;
|
|
|
|
newf->funcs.ReadBytes = SSPI_ReadBytes;
|
|
|
|
newf->funcs.Seek = SSPI_Seek;
|
|
|
|
newf->funcs.Tell = SSPI_Tell;
|
|
|
|
newf->funcs.WriteBytes = SSPI_WriteBytes;
|
|
|
|
newf->funcs.seekstyle = SS_UNSEEKABLE;
|
|
|
|
|
|
|
|
SSPI_ExpandBuffer(&newf->outraw, 8192);
|
|
|
|
SSPI_ExpandBuffer(&newf->outcrypt, 8192);
|
|
|
|
SSPI_ExpandBuffer(&newf->inraw, 8192);
|
|
|
|
SSPI_ExpandBuffer(&newf->incrypt, 8192);
|
|
|
|
|
|
|
|
if (server)
|
|
|
|
SSPI_GenServerCredentials(newf);
|
|
|
|
|
|
|
|
return &newf->funcs;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef SECPKG_ATTR_UNIQUE_BINDINGS
|
|
|
|
#define SECPKG_ATTR_UNIQUE_BINDINGS 25
|
|
|
|
typedef struct _SecPkgContext_Bindings
|
|
|
|
{
|
|
|
|
unsigned long BindingsLength;
|
|
|
|
SEC_CHANNEL_BINDINGS *Bindings;
|
|
|
|
} SecPkgContext_Bindings, *PSecPkgContext_Bindings;
|
|
|
|
#endif
|
2021-06-21 13:43:57 +00:00
|
|
|
static int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
sslfile_t *f = (sslfile_t*)vf;
|
|
|
|
SecPkgContext_Bindings bindings;
|
|
|
|
if (vf->Close != SSPI_Close)
|
|
|
|
return -2; //not one of ours.
|
|
|
|
|
|
|
|
bindings.BindingsLength = 0;
|
|
|
|
bindings.Bindings = NULL;
|
|
|
|
ret = 0;
|
|
|
|
switch(secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_UNIQUE_BINDINGS, &bindings))
|
|
|
|
{
|
|
|
|
case SEC_E_OK:
|
|
|
|
if (bindings.Bindings->cbApplicationDataLength <= *bindsize)
|
|
|
|
{
|
|
|
|
//will contain 'tls-unique:BINARYDATA'
|
|
|
|
*bindsize = bindings.Bindings->cbApplicationDataLength-11;
|
|
|
|
memcpy(binddata, ((unsigned char*) bindings.Bindings) + bindings.Bindings->dwApplicationDataOffset+11, bindings.Bindings->cbApplicationDataLength-11);
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
//FIXME: leak
|
|
|
|
//secur.pFreeContextBuffer(bindings.Bindings);
|
|
|
|
break;
|
|
|
|
case SEC_E_UNSUPPORTED_FUNCTION:
|
|
|
|
ret = -1; //schannel doesn't support it. too old an OS, I guess.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "netinc.h"
|
2021-06-21 13:43:57 +00:00
|
|
|
#if defined(HAVE_DTLS)
|
2017-09-20 11:27:13 +00:00
|
|
|
static void *SSPI_DTLS_CreateContext(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
sslfile_t *ctx;
|
|
|
|
if (!SSL_Inited())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ctx = Z_Malloc(sizeof(*ctx));
|
|
|
|
ctx->datagram = true;
|
|
|
|
ctx->handshaking = isserver?HS_STARTSERVER:HS_STARTCLIENT;
|
|
|
|
ctx->cbctx = cbctx;
|
|
|
|
ctx->transmit = push;
|
|
|
|
|
|
|
|
while(*remotehost)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int c = utf8_decode(&err, remotehost, (void*)&remotehost);
|
|
|
|
if (c > WCHAR_MAX)
|
|
|
|
err = true; //no 16bit surrogates. they're evil.
|
|
|
|
else if (i == sizeof(ctx->wpeername)/sizeof(ctx->wpeername[0]) - 1)
|
|
|
|
err = true; //no space to store it
|
|
|
|
else
|
|
|
|
ctx->wpeername[i++] = c;
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
Z_Free(ctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx->wpeername[i] = 0;
|
|
|
|
|
|
|
|
SSPI_ExpandBuffer(&ctx->outraw, 8192);
|
|
|
|
SSPI_ExpandBuffer(&ctx->outcrypt, 65536);
|
|
|
|
SSPI_ExpandBuffer(&ctx->inraw, 8192);
|
|
|
|
SSPI_ExpandBuffer(&ctx->incrypt, 65536);
|
|
|
|
|
|
|
|
if (isserver)
|
|
|
|
SSPI_GenServerCredentials(ctx);
|
|
|
|
else
|
|
|
|
SSPI_Handshake(ctx); //begin the initial handshake now
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SSPI_DTLS_DestroyContext(void *vctx)
|
|
|
|
{
|
|
|
|
SSPI_Close(vctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static neterr_t SSPI_DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
sslfile_t *f = (sslfile_t *)ctx;
|
|
|
|
|
|
|
|
//Con_Printf("DTLS_Transmit: %i\n", datasize);
|
|
|
|
|
|
|
|
//sspi likes writing over the source data. make sure nothing is hurt by copying it out first.
|
|
|
|
f->outraw.avail = 0;
|
|
|
|
SSPI_CopyIntoBuffer(&f->outraw, data, datasize, true);
|
|
|
|
|
|
|
|
if (f->handshaking)
|
|
|
|
{
|
|
|
|
SSPI_Handshake(f);
|
|
|
|
|
|
|
|
if (f->handshaking == HS_ERROR)
|
|
|
|
ret = NETERR_DISCONNECTED;
|
2020-08-13 10:09:39 +00:00
|
|
|
else
|
|
|
|
ret = NETERR_CLOGGED; //not ready yet
|
2017-09-20 11:27:13 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SSPI_Encode(f);
|
|
|
|
ret = NETERR_SENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-06-21 13:43:57 +00:00
|
|
|
static neterr_t SSPI_DTLS_Received(void *ctx, sizebuf_t *msg)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
sslfile_t *f = (sslfile_t *)ctx;
|
|
|
|
|
|
|
|
//Con_Printf("DTLS_Received: %i\n", datasize);
|
|
|
|
|
2021-06-21 13:43:57 +00:00
|
|
|
f->incrypt.data = msg->data;
|
|
|
|
f->incrypt.avail = f->incrypt.datasize = msg->cursize;
|
2017-09-20 11:27:13 +00:00
|
|
|
|
|
|
|
if (f->handshaking)
|
|
|
|
{
|
|
|
|
SSPI_Handshake(f);
|
|
|
|
ret = NETERR_CLOGGED; //not ready yet
|
|
|
|
|
|
|
|
if (f->handshaking == HS_ERROR)
|
|
|
|
ret = NETERR_DISCONNECTED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SSPI_Decode(f);
|
|
|
|
ret = NETERR_SENT;
|
|
|
|
|
2021-06-21 13:43:57 +00:00
|
|
|
if (f->inraw.avail > msg->maxsize)
|
|
|
|
msg->cursize = f->inraw.avail;
|
|
|
|
else
|
|
|
|
msg->cursize = msg->maxsize;
|
|
|
|
memcpy(msg->data, f->inraw.data, msg->cursize);
|
2017-09-20 11:27:13 +00:00
|
|
|
f->inraw.avail = 0;
|
|
|
|
}
|
|
|
|
f->incrypt.data = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static neterr_t SSPI_DTLS_Timeouts(void *ctx)
|
|
|
|
{
|
|
|
|
sslfile_t *f = (sslfile_t *)ctx;
|
|
|
|
if (f->handshaking)
|
|
|
|
{
|
|
|
|
// SSPI_Handshake(f);
|
|
|
|
return NETERR_CLOGGED;
|
|
|
|
}
|
|
|
|
return NETERR_SENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const dtlsfuncs_t dtlsfuncs_schannel =
|
|
|
|
{
|
|
|
|
SSPI_DTLS_CreateContext,
|
2022-01-08 10:01:05 +00:00
|
|
|
NULL,
|
2017-06-21 01:24:25 +00:00
|
|
|
SSPI_DTLS_DestroyContext,
|
|
|
|
SSPI_DTLS_Transmit,
|
|
|
|
SSPI_DTLS_Received,
|
2017-09-20 11:27:13 +00:00
|
|
|
SSPI_DTLS_Timeouts,
|
|
|
|
};
|
2021-06-21 13:43:57 +00:00
|
|
|
/*static const dtlsfuncs_t *SSPI_DTLS_InitServer(void)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
|
|
|
//FIXME: at this point, schannel is still returning errors when I try acting as a server.
|
|
|
|
//so just block any attempt to use this as a server.
|
|
|
|
//clients don't need/get certs.
|
2021-06-21 13:43:57 +00:00
|
|
|
return &dtlsfuncs_schannel;
|
|
|
|
}*/
|
|
|
|
static const dtlsfuncs_t *SSPI_DTLS_InitClient(void)
|
2017-09-20 11:27:13 +00:00
|
|
|
{
|
|
|
|
return &dtlsfuncs_schannel;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-25 21:29:30 +00:00
|
|
|
|
2020-04-29 10:43:22 +00:00
|
|
|
//#include <ntstatus.h> //windows sucks too much to actually include this. oh well.
|
|
|
|
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
|
|
|
|
#define STATUS_INVALID_SIGNATURE ((NTSTATUS)0xC000A000)
|
2021-06-21 13:43:57 +00:00
|
|
|
static enum hashvalidation_e SSPI_VerifyHash(const qbyte *hashdata, size_t hashsize, const qbyte *pemcert, size_t pemcertsize, const qbyte *signdata, size_t signsize)
|
2020-03-25 21:29:30 +00:00
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
BCRYPT_KEY_HANDLE pubkey;
|
2021-06-21 13:43:57 +00:00
|
|
|
const char *pem = pemcert;
|
2020-03-25 21:29:30 +00:00
|
|
|
const char *pemend;
|
|
|
|
qbyte *der;
|
|
|
|
size_t dersize;
|
|
|
|
|
|
|
|
static const void *(WINAPI *pCertCreateContext) (DWORD dwContextType, DWORD dwEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara);
|
2020-04-29 10:43:22 +00:00
|
|
|
static BOOL (WINAPI *pCryptImportPublicKeyInfoEx2) (DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD dwFlags, void *pvAuxInfo, BCRYPT_KEY_HANDLE *phKey);
|
|
|
|
static BOOL (WINAPI *pCertFreeCertificateContext) (PCCERT_CONTEXT pCertContext);
|
2020-03-25 21:29:30 +00:00
|
|
|
static dllhandle_t *crypt32;
|
|
|
|
static dllfunction_t crypt32funcs[] = {
|
|
|
|
{(void**)&pCertCreateContext, "CertCreateContext"},
|
|
|
|
{(void**)&pCryptImportPublicKeyInfoEx2, "CryptImportPublicKeyInfoEx2"}, //WARNING: fails on wine.
|
|
|
|
{(void**)&pCertFreeCertificateContext, "CertFreeCertificateContext"},
|
|
|
|
{NULL,NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static NTSTATUS (WINAPI *pBCryptVerifySignature) (BCRYPT_KEY_HANDLE hKey, VOID *pPaddingInfo, PUCHAR pbHash, ULONG cbHash, PUCHAR pbSignature, ULONG cbSignature, ULONG dwFlags);
|
|
|
|
static NTSTATUS (WINAPI *pBCryptDestroyKey) (BCRYPT_KEY_HANDLE hKey);
|
|
|
|
static dllhandle_t *bcrypt;
|
|
|
|
static dllfunction_t bcryptfuncs[] = {
|
|
|
|
{(void**)&pBCryptVerifySignature, "BCryptVerifySignature"},
|
|
|
|
{(void**)&pBCryptDestroyKey, "BCryptDestroyKey"},
|
|
|
|
{NULL,NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!crypt32)
|
|
|
|
crypt32 = Sys_LoadLibrary("crypt32.dll", crypt32funcs);
|
|
|
|
if (!bcrypt)
|
|
|
|
bcrypt = Sys_LoadLibrary("bcrypt.dll", bcryptfuncs);
|
|
|
|
if (!crypt32 || !bcrypt)
|
|
|
|
{
|
|
|
|
Con_Printf("Unable to obtain required crypto functions\n");
|
|
|
|
return VH_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pem)
|
|
|
|
return VH_AUTHORITY_UNKNOWN; //no public cert/key for authority.
|
|
|
|
pem = strstr(pem, "-----BEGIN CERTIFICATE-----");
|
|
|
|
if (!pem)
|
|
|
|
return VH_UNSUPPORTED; //not a pem
|
|
|
|
pem += strlen("-----BEGIN CERTIFICATE-----");
|
|
|
|
pemend = strstr(pem, "-----END CERTIFICATE-----");
|
|
|
|
if (!pemend)
|
|
|
|
return VH_UNSUPPORTED;
|
|
|
|
dersize = Base64_DecodeBlock(pem, pemend, NULL, 0); //guess
|
|
|
|
der = alloca(dersize);
|
|
|
|
dersize = Base64_DecodeBlock(pem, pemend, der, dersize);
|
|
|
|
//okay, now its in binary der format.
|
|
|
|
|
|
|
|
//make sense of the cert and pull out its public key...
|
|
|
|
{
|
|
|
|
const CERT_CONTEXT* cert = pCertCreateContext(CERT_STORE_CERTIFICATE_CONTEXT, X509_ASN_ENCODING, der, dersize, 0, NULL);
|
|
|
|
if (!pCryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, 0, NULL, &pubkey))
|
|
|
|
return VH_UNSUPPORTED;
|
|
|
|
pCertFreeCertificateContext(cert);
|
|
|
|
}
|
|
|
|
|
|
|
|
//yay, now we can do what we actually wanted in the first place.
|
2021-06-21 13:43:57 +00:00
|
|
|
status = pBCryptVerifySignature(pubkey, NULL, (qbyte*)hashdata, hashsize, (qbyte*)signdata, signsize, 0);
|
2020-03-25 21:29:30 +00:00
|
|
|
pBCryptDestroyKey(pubkey);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
return VH_CORRECT; //its okay
|
|
|
|
else if (status == STATUS_INVALID_SIGNATURE)
|
|
|
|
return VH_INCORRECT; //its bad
|
|
|
|
return VH_UNSUPPORTED; //some weird transient error...?
|
|
|
|
}
|
|
|
|
|
2021-06-21 13:43:57 +00:00
|
|
|
ftecrypto_t crypto_sspi =
|
|
|
|
{
|
|
|
|
"WinSSPI",
|
|
|
|
SSPI_OpenVFS,
|
|
|
|
SSPI_GetChannelBinding,
|
|
|
|
SSPI_DTLS_InitClient,
|
|
|
|
NULL,//SSPI_DTLS_InitServer,
|
|
|
|
SSPI_VerifyHash,
|
|
|
|
NULL,//SSPI_GenerateHash,
|
|
|
|
};
|
2017-09-20 11:27:13 +00:00
|
|
|
#endif
|