Rework tls/dtls stuff into a more formal crypto interface instead of lots of ifdefs all over the place.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5891 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-06-21 13:43:57 +00:00
parent 1057453158
commit d4714cab52
17 changed files with 229 additions and 246 deletions

View file

@ -274,25 +274,6 @@ ELSEIF(${WIN32})
ELSEIF(${UNIX} AND NOT FTE_USE_SDL) #linux(ish)
#openbsd will have issues with snd_linux.c
IF(FTE_PRIVATE_USE_ONLY)
#the openssl license is incompatible with the GPL, so while we have code to use it distributing the binaries built with it is not a (legal) option.
#note that openssl 3.0.0 upwards are apache-2 licensed, which IS gpl-3 compatible. debian has not caught up with that yet, however.
FIND_PACKAGE(OpenSSL)
IF(NOT OPENSSL_FOUND)
MESSAGE(WARNING "openssl library NOT available. HTTPS/DTLS will not be available.")
ELSEIF(OPENSSL_VERSION_MAJOR LESS 3 AND NOT FTE_PRIVATE_USE_ONLY)
MESSAGE(WARNING "openssl library version is not 3 or above. Ignoring due to incompatible license.")
ELSE()
MESSAGE(WARNING "Using openssl.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};HAVE_OPENSSL)
SET(FTE_ARCH_FILES ${FTE_ARCH_FILES} engine/common/net_ssl_openssl.c)
SET(FTE_LIBS ${FTE_LIBS} ${OPENSSL_LIBRARIES})
SET(FTESV_ARCH_FILES ${FTESV_ARCH_FILES} engine/common/net_ssl_openssl.c)
SET(FTESV_LIBS ${FTESV_LIBS} ${OPENSSL_LIBRARIES})
ENDIF()
ENDIF()
FIND_PACKAGE(GnuTLS)
IF(NOT GNUTLS_FOUND)
MESSAGE(WARNING "gnutls library NOT available. HTTPS/DTLS will not be available.")
@ -328,7 +309,6 @@ ELSEIF(${UNIX} AND NOT FTE_USE_SDL) #linux(ish)
engine/client/sys_linux.c
engine/common/sys_linux_threads.c
engine/common/net_ssl_gnutls.c
# engine/common/net_ssl_openssl.c
engine/client/snd_al.c
engine/client/snd_alsa.c
@ -391,14 +371,9 @@ ELSEIF(${UNIX} AND NOT FTE_USE_SDL) #linux(ish)
engine/server/sv_sys_unix.c
engine/common/sys_linux_threads.c
engine/common/net_ssl_gnutls.c
# engine/common/net_ssl_openssl.c
)
SET(FTESV_LIBS ${FTESV_LIBS} ${SYS_LIBS} ${CMAKE_DL_LIBS} pthread)
# SET(FTE_DEFINES ${FTE_DEFINES};HAVE_OPENSSL)
# SET(FTESV_DEFINES ${FTESV_DEFINES};HAVE_OPENSSL)
# SET(FTE_LIBS ${FTE_LIBS} ssl crypto)
# SET(FTESV_LIBS ${FTE_LIBS} ssl crypto)
ELSEIF(1) #SDL
# FIND_PACKAGE(Freetype REQUIRED)
# INCLUDE_DIRECTORIES(engine/libs engine/libs/freetype2/include)

View file

@ -361,9 +361,12 @@ void PM_ValidateAuthenticity(package_t *p, enum hashvalidation_e validated)
size_t hashsize = 0;
qbyte signdata[1024];
size_t signsize = 0;
int r;
int r, i;
char authority[MAX_QPATH], *sig;
const qbyte *pubkey;
size_t pubkeysize;
#ifndef _DEBUG
#pragma message("Temporary code.")
//this is temporary code and should be removed once everything else has been fixed.
@ -412,28 +415,25 @@ void PM_ValidateAuthenticity(package_t *p, enum hashvalidation_e validated)
sig++;
}
else
{
strcpy(authority, "Spike"); //legacy bollocks
sig = p->signature;
}
hashsize = Base16_DecodeBlock(p->filesha512, hashdata, sizeof(hashdata));
signsize = Base64_DecodeBlock(sig, NULL, signdata, sizeof(signdata));
r = VH_UNSUPPORTED;//preliminary
}
(void)signsize;
(void)hashsize;
pubkey = Auth_GetKnownCertificate(authority, &pubkeysize);
if (!pubkey)
r = VH_AUTHORITY_UNKNOWN;
//try and get one of our providers to verify it...
#ifdef HAVE_WINSSPI
if (r == VH_UNSUPPORTED)
r = SSPI_VerifyHash(hashdata, hashsize, authority, signdata, signsize);
#endif
#ifdef HAVE_GNUTLS
if (r == VH_UNSUPPORTED)
r = GNUTLS_VerifyHash(hashdata, hashsize, authority, signdata, signsize);
#endif
#ifdef HAVE_OPENSSL
if (r == VH_UNSUPPORTED)
r = OSSL_VerifyHash(hashdata, hashsize, authority, signdata, signsize);
#endif
for (i = 0; r==VH_UNSUPPORTED && i < cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->VerifyHash)
r = cryptolib[i]->VerifyHash(hashdata, hashsize, pubkey, pubkeysize, signdata, signsize);
}
p->flags &= ~(DPF_SIGNATUREACCEPTED|DPF_SIGNATUREREJECTED|DPF_SIGNATUREUNKNOWN);
if (r == VH_CORRECT)
@ -1379,8 +1379,11 @@ static qboolean PM_ParsePackageList(const char *f, unsigned int parseflags, cons
char authority[MAX_OSPATH];
char signdata[MAX_OSPATH];
char signature_base64[MAX_OSPATH];
qbyte *pubkey;
size_t pubkeysize;
size_t signsize;
enum hashvalidation_e r;
int i;
hashfunc_t *hf = &hash_sha512;
void *hashdata = Z_Malloc(hf->digestsize);
void *hashctx = Z_Malloc(hf->contextsize);
@ -1395,20 +1398,16 @@ static qboolean PM_ParsePackageList(const char *f, unsigned int parseflags, cons
Z_Free(hashctx);
r = VH_UNSUPPORTED;//preliminary
(void)signsize;
pubkey = Auth_GetKnownCertificate(authority, &pubkeysize);
if (!pubkey)
r = VH_AUTHORITY_UNKNOWN;
//try and get one of our providers to verify it...
#ifdef HAVE_WINSSPI
if (r == VH_UNSUPPORTED)
r = SSPI_VerifyHash(hashdata, hf->digestsize, authority, signdata, signsize);
#endif
#ifdef HAVE_GNUTLS
if (r == VH_UNSUPPORTED)
r = GNUTLS_VerifyHash(hashdata, hf->digestsize, authority, signdata, signsize);
#endif
#ifdef HAVE_OPENSSL
if (r == VH_UNSUPPORTED)
r = OSSL_VerifyHash(hashdata, hf->digestsize, authority, signdata, signsize);
#endif
for (i = 0; r==VH_UNSUPPORTED && i < cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->VerifyHash)
r = cryptolib[i]->VerifyHash(hashdata, hf->digestsize, pubkey, pubkeysize, signdata, signsize);
}
Z_Free(hashdata);
source.validated = r;

View file

@ -1076,7 +1076,19 @@ char *Sys_ConsoleInput(void)
return NULL;
}
#ifdef HAVE_GNUTLS
//begin meta generation helper
#include "fs.h"
static int Crypto_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax)
{
int i;
int sigsize = -1;
for (i = 0; sigsize==-1 && i<cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->GenerateSignature)
sigsize = cryptolib[i]->GenerateSignature(hashdata, hashsize, signdata, signsizemax);
}
return sigsize;
}
static void DoSign(const char *fname, int signtype)
{
qbyte digest[1024];
@ -1112,25 +1124,20 @@ static void DoSign(const char *fname, int signtype)
Base16_EncodeBlock(digest, h->digestsize, base64, sizeof(base64));
printf(" \\\"sha512=%s\\\"", base64);
sigsize = GNUTLS_GenerateSignature(digest, h->digestsize, signature, sizeof(signature));
sigsize = Crypto_GenerateSignature(digest, h->digestsize, signature, sizeof(signature));
Base64_EncodeBlock(signature, sigsize, base64, sizeof(base64));
printf(" \\\"sign=%s:%s\\\"\n", auth, base64);
}
else if (signtype == 2)
{ //signature "auth" "signdata"
//printf(" \\\"dlsize=%zu\\\"", ts);
//Base16_EncodeBlock(digest, h->digestsize, base64, sizeof(base64));
//printf(" \\\"sha512=%s\\\"", base64);
sigsize = GNUTLS_GenerateSignature(digest, h->digestsize, signature, sizeof(signature));
{ //spits out the raw signature.
sigsize = Crypto_GenerateSignature(digest, h->digestsize, signature, sizeof(signature));
Base64_EncodeBlock(signature, sigsize, base64, sizeof(base64));
printf("%s\n", base64);
}
}
}
#endif
//end meta helpers
#ifdef _POSIX_C_SOURCE
static void SigCont(int code)
@ -1285,7 +1292,7 @@ int main (int c, const char **v)
if (COM_CheckParm("-nostdout"))
nostdout = 1;
#ifdef HAVE_GNUTLS
//begin meta generation helpers
//fteqw -privcert privcert.key -pubcert pubcert.key -sign binaryfile.pk3
i = COM_CheckParm("-sign");
if (!i)
@ -1301,7 +1308,7 @@ int main (int c, const char **v)
DoSign(com_argv[i+1], atoi(com_argv[i+0]+5));
return EXIT_SUCCESS;
}
#endif
//end
if (parms.binarydir)
Sys_Printf("Binary is located at \"%s\"\n", parms.binarydir);

View file

@ -419,10 +419,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef USE_EGL
#endif
#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) || defined(HAVE_WINSSPI)
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI)
#define HAVE_SSL
#endif
#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) || defined(HAVE_WINSSPI)
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI)
//FIXME: HAVE_WINSSPI does not work as a server.
//FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade.
//FIXME: we don't cache server certs

View file

@ -5566,9 +5566,6 @@ static void COM_Version_f (void)
#ifdef HAVE_GNUTLS //on linux
Con_Printf(" GnuTLS");
#endif
#ifdef HAVE_OPENSSL //on linux. hardlinked, so typically set only via the makefile.
Con_Printf(" OpenSSL");
#endif
#ifdef HAVE_WINSSPI //on windows
Con_Printf(" WINSSPI");
#endif

View file

@ -159,7 +159,6 @@
//FIXME: Stuff that Spike has added that Eukara needs to decide whether to keep or not.
#define HAVE_OPUS
//#define HAVE_SPEEX
//#define HAVE_OPENSSL
//#define IMAGEFMT_HDR
//#define IMAGEFMT_PBM
//#define IMAGEFMT_PSD

View file

@ -147,7 +147,6 @@
#define HAVE_PACKET //we can send unreliable messages!
#define HAVE_TCP //we can create/accept TCP connections.
#define HAVE_GNUTLS //on linux
//#define HAVE_OPENSSL //on linux. hardlinked, so typically set only via the makefile.
#define HAVE_WINSSPI //on windows
#define FTPSERVER //sv_ftp cvar.
#define WEBCLIENT //uri_get+any internal downloads etc

View file

@ -10,7 +10,6 @@
#undef FTPSERVER
#undef HAVE_TCP
#undef HAVE_GNUTLS
#undef HAVE_OPENSSL
#undef HAVE_WINSSPI
#undef SUPPORT_ICE
#undef SUBSERVERS

View file

@ -149,7 +149,6 @@
#define HAVE_PACKET //we can send unreliable messages!
//#define HAVE_TCP //we can create/accept TCP connections.
//#define HAVE_GNUTLS //on linux
//#define HAVE_OPENSSL //on linux. hardlinked, so typically set only via the makefile.
//#define HAVE_WINSSPI //on windows
//#define FTPSERVER //sv_ftp cvar.
//#define WEBCLIENT //uri_get+any internal downloads etc

View file

@ -147,7 +147,6 @@
#define HAVE_PACKET //we can send unreliable messages!
#define HAVE_TCP //we can create/accept TCP connections.
#define HAVE_GNUTLS //on linux
//#define HAVE_OPENSSL //on linux. hardlinked, so typically set only via the makefile.
#define HAVE_WINSSPI //on windows
//#define FTPSERVER //sv_ftp cvar.
#define WEBCLIENT //uri_get+any internal downloads etc

View file

@ -179,7 +179,6 @@
#undef WAYLANDQUAKE
#undef SERVER_DEMO_PLAYBACK /* deprecated */
#undef DECOMPRESS_BPTC
#undef HAVE_OPENSSL /* incomplete */
#undef IMAGEFMT_HDR
#undef IMAGEFMT_PBM
#undef IMAGEFMT_PSD

View file

@ -194,6 +194,8 @@ void NET_DTLS_Timeouts(struct ftenet_connections_s *col);
#endif
extern cvar_t timeout;
extern cvar_t tls_ignorecertificateerrors; //evil evil evil.
struct ftecrypto_s;
qboolean NET_RegisterCrypto(void *module, struct ftecrypto_s *driver);
//============================================================================

View file

@ -903,7 +903,7 @@ static gnutls_certificate_credentials_t xcred[2];
static gnutls_datum_t cookie_key;
#endif
vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
static vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
{
#define privname "privkey.pem"
vfsfile_t *privf;
@ -926,7 +926,7 @@ vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
return privf;
#undef privname
}
vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize)
static vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize)
{
#define fullchainname "fullchain.pem"
#define pubname "cert.pem"
@ -1231,7 +1231,7 @@ static qboolean SSL_InitConnection(gnutlsfile_t *newf, qboolean isserver, qboole
return true;
}
vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver)
static vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver)
{
gnutlsfile_t *newf;
@ -1270,7 +1270,7 @@ vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isse
return &newf->funcs;
}
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
static int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
{
gnutls_datum_t cb;
gnutlsfile_t *f = (gnutlsfile_t*)vf;
@ -1293,9 +1293,9 @@ int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
}
//crypto: generates a signed blob
int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax)
static int GNUTLS_GenerateSignature(const qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax)
{
gnutls_datum_t hash = {hashdata, hashsize};
gnutls_datum_t hash = {(qbyte*)hashdata, hashsize};
gnutls_datum_t sign = {NULL, 0};
gnutls_certificate_credentials_t cred;
@ -1324,24 +1324,21 @@ int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata,
}
//crypto: verifies a signed blob matches an authority's public cert. windows equivelent https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-signing-a-hash-and-verifying-the-hash-signature
enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize)
static enum hashvalidation_e GNUTLS_VerifyHash(const qbyte *hashdata, size_t hashsize, const qbyte *pubkeydata, size_t pubkeysize, const qbyte *signdata, size_t signsize)
{
gnutls_datum_t hash = {hashdata, hashsize};
gnutls_datum_t sign = {signdata, signsize};
gnutls_datum_t hash = {(qbyte*)hashdata, hashsize};
gnutls_datum_t sign = {(qbyte*)signdata, signsize};
int r;
gnutls_datum_t rawcert;
gnutls_datum_t rawcert = {(qbyte*)pubkeydata, pubkeysize};
#if 1
size_t sz;
gnutls_pubkey_t pubkey;
gnutls_x509_crt_t cert;
rawcert.data = Auth_GetKnownCertificate(authority, &sz);
if (!rawcert.data)
return VH_AUTHORITY_UNKNOWN;
if (!Init_GNUTLS())
return VH_UNSUPPORTED;
rawcert.size = sz;
qgnutls_pubkey_init(&pubkey);
qgnutls_x509_crt_init(&cert);
@ -1437,7 +1434,7 @@ static neterr_t GNUDTLS_Transmit(void *ctx, const qbyte *data, size_t datasize)
return NETERR_SENT;
}
static neterr_t GNUDTLS_Received(void *ctx, qbyte *data, size_t datasize)
static neterr_t GNUDTLS_Received(void *ctx, sizebuf_t *message)
{
int cli_addr = 0xdeadbeef;
int ret;
@ -1450,7 +1447,7 @@ static neterr_t GNUDTLS_Received(void *ctx, qbyte *data, size_t datasize)
memset(&f->prestate, 0, sizeof(f->prestate));
ret = qgnutls_dtls_cookie_verify(&cookie_key,
&cli_addr, sizeof(cli_addr),
data, datasize,
message->data, message->cursize,
&f->prestate);
if (ret < 0)
@ -1473,8 +1470,8 @@ static neterr_t GNUDTLS_Received(void *ctx, qbyte *data, size_t datasize)
f->handshaking = true;
}
f->readdata = data;
f->readsize = datasize;
f->readdata = message->data;
f->readsize = message->cursize;
if (f->handshaking)
{
@ -1487,7 +1484,7 @@ static neterr_t GNUDTLS_Received(void *ctx, qbyte *data, size_t datasize)
return NETERR_DISCONNECTED;
}
ret = qgnutls_record_recv(f->session, net_message_buffer, sizeof(net_message_buffer));
ret = qgnutls_record_recv(f->session, message->data, message->maxsize);
//Sys_Printf("DTLS_Received returned %i of %i\n", ret, f->readsize);
f->readsize = 0;
if (ret <= 0)
@ -1505,8 +1502,8 @@ static neterr_t GNUDTLS_Received(void *ctx, qbyte *data, size_t datasize)
// Sys_Printf("DTLS_Received temp error\n");
return NETERR_CLOGGED;
}
net_message.cursize = ret;
data[ret] = 0;
message->cursize = ret;
message->data[ret] = 0;
// Sys_Printf("DTLS_Received returned %s\n", data);
return NETERR_SENT;
}
@ -1540,26 +1537,37 @@ static const dtlsfuncs_t dtlsfuncs_gnutls =
GNUDTLS_Received,
GNUDTLS_Timeouts,
};
const dtlsfuncs_t *GNUDTLS_InitServer(void)
static const dtlsfuncs_t *GNUDTLS_InitServer(void)
{
if (!SSL_InitGlobal(true))
return NULL; //unable to init a server certificate. don't allow dtls to init.
return &dtlsfuncs_gnutls;
}
const dtlsfuncs_t *GNUDTLS_InitClient(void)
static const dtlsfuncs_t *GNUDTLS_InitClient(void)
{
return &dtlsfuncs_gnutls;
}
#else
#define GNUDTLS_InitServer NULL
#define GNUDTLS_InitClient NULL
#endif
ftecrypto_t crypto_gnutls =
{
"GNUTLS",
GNUTLS_OpenVFS,
GNUTLS_GetChannelBinding,
GNUDTLS_InitClient,
GNUDTLS_InitServer,
GNUTLS_VerifyHash,
GNUTLS_GenerateSignature,
};
#else
#warning "GNUTLS version is too old (3.0+ required). Please clean and then recompile with CFLAGS=-DNO_GNUTLS"
ftecrypto_t crypto_gnutls;
qboolean SSL_InitGlobal(qboolean isserver) {return false;}
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver) {return NULL;}
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) {return -1;}
const dtlsfuncs_t *GNUDTLS_InitClient(void) {return NULL;}
const dtlsfuncs_t *GNUDTLS_InitServer(void) {return NULL;}
#endif
#endif

View file

@ -996,7 +996,7 @@ static qboolean QDECL SSPI_Close (struct vfsfile_s *file)
}
#include <wchar.h>
vfsfile_t *SSPI_OpenVFS(const char *servername, vfsfile_t *source, qboolean server)
static vfsfile_t *SSPI_OpenVFS(const char *servername, vfsfile_t *source, qboolean server)
{
sslfile_t *newf;
int i = 0;
@ -1071,7 +1071,7 @@ typedef struct _SecPkgContext_Bindings
SEC_CHANNEL_BINDINGS *Bindings;
} SecPkgContext_Bindings, *PSecPkgContext_Bindings;
#endif
int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
static int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
{
int ret;
sslfile_t *f = (sslfile_t*)vf;
@ -1105,59 +1105,7 @@ int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
}
#include "netinc.h"
#if 0
struct fakedtls_s
{
void *cbctx;
neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize);
};
static void *FAKEDTLS_CreateContext(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver)
{
struct fakedtls_s *ctx = Z_Malloc(sizeof(*ctx));
ctx->cbctx = cbctx;
ctx->push = push;
return ctx;
}
static void FAKEDTLS_DestroyContext(void *vctx)
{
Z_Free(vctx);
}
static neterr_t FAKEDTLS_Transmit(void *vctx, const qbyte *data, size_t datasize)
{
struct fakedtls_s *ctx = vctx;
neterr_t r;
*(int*)data ^= 0xdeadbeef;
r = ctx->push(ctx->cbctx, data, datasize);
*(int*)data ^= 0xdeadbeef;
return r;
}
static neterr_t FAKEDTLS_Received(void *ctx, qbyte *data, size_t datasize)
{
*(int*)data ^= 0xdeadbeef;
return NETERR_SENT;
}
static neterr_t FAKEDTLS_Timeouts(void *ctx)
{
// fakedtls_s *f = (fakedtls_s *)ctx;
return NETERR_SENT;
}
static const dtlsfuncs_t dtlsfuncs_fakedtls =
{
FAKEDTLS_CreateContext,
FAKEDTLS_DestroyContext,
FAKEDTLS_Transmit,
FAKEDTLS_Received,
FAKEDTLS_Timeouts,
};
const dtlsfuncs_t *FAKEDTLS_InitServer(void)
{
return &dtlsfuncs_fakedtls;
}
const dtlsfuncs_t *FAKEDTLS_InitClient(void)
{
return &dtlsfuncs_fakedtls;
}
#elif defined(HAVE_DTLS)
#if defined(HAVE_DTLS)
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;
@ -1236,15 +1184,15 @@ static neterr_t SSPI_DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize
return ret;
}
static neterr_t SSPI_DTLS_Received(void *ctx, qbyte *data, size_t datasize)
static neterr_t SSPI_DTLS_Received(void *ctx, sizebuf_t *msg)
{
int ret;
sslfile_t *f = (sslfile_t *)ctx;
//Con_Printf("DTLS_Received: %i\n", datasize);
f->incrypt.data = data;
f->incrypt.avail = f->incrypt.datasize = datasize;
f->incrypt.data = msg->data;
f->incrypt.avail = f->incrypt.datasize = msg->cursize;
if (f->handshaking)
{
@ -1259,12 +1207,12 @@ static neterr_t SSPI_DTLS_Received(void *ctx, qbyte *data, size_t datasize)
SSPI_Decode(f);
ret = NETERR_SENT;
memcpy(net_message_buffer, f->inraw.data, f->inraw.avail);
net_message.cursize = f->inraw.avail;
if (f->inraw.avail > msg->maxsize)
msg->cursize = f->inraw.avail;
else
msg->cursize = msg->maxsize;
memcpy(msg->data, f->inraw.data, msg->cursize);
f->inraw.avail = 0;
net_message_buffer[net_message.cursize] = 0;
// Con_Printf("returning %i bytes: %s\n", net_message.cursize, net_message_buffer);
}
f->incrypt.data = NULL;
return ret;
@ -1288,14 +1236,14 @@ static const dtlsfuncs_t dtlsfuncs_schannel =
SSPI_DTLS_Received,
SSPI_DTLS_Timeouts,
};
const dtlsfuncs_t *SSPI_DTLS_InitServer(void)
/*static const dtlsfuncs_t *SSPI_DTLS_InitServer(void)
{
//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.
return NULL;
}
const dtlsfuncs_t *SSPI_DTLS_InitClient(void)
return &dtlsfuncs_schannel;
}*/
static const dtlsfuncs_t *SSPI_DTLS_InitClient(void)
{
return &dtlsfuncs_schannel;
}
@ -1305,12 +1253,11 @@ const dtlsfuncs_t *SSPI_DTLS_InitClient(void)
//#include <ntstatus.h> //windows sucks too much to actually include this. oh well.
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
#define STATUS_INVALID_SIGNATURE ((NTSTATUS)0xC000A000)
enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize)
static enum hashvalidation_e SSPI_VerifyHash(const qbyte *hashdata, size_t hashsize, const qbyte *pemcert, size_t pemcertsize, const qbyte *signdata, size_t signsize)
{
NTSTATUS status;
BCRYPT_KEY_HANDLE pubkey;
size_t sz;
const char *pem = Auth_GetKnownCertificate(authority, &sz);
const char *pem = pemcert;
const char *pemend;
qbyte *der;
size_t dersize;
@ -1368,7 +1315,7 @@ enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const ch
}
//yay, now we can do what we actually wanted in the first place.
status = pBCryptVerifySignature(pubkey, NULL, hashdata, hashsize, signdata, signsize, 0);
status = pBCryptVerifySignature(pubkey, NULL, (qbyte*)hashdata, hashsize, (qbyte*)signdata, signsize, 0);
pBCryptDestroyKey(pubkey);
if (status == STATUS_SUCCESS)
return VH_CORRECT; //its okay
@ -1377,4 +1324,14 @@ enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const ch
return VH_UNSUPPORTED; //some weird transient error...?
}
ftecrypto_t crypto_sspi =
{
"WinSSPI",
SSPI_OpenVFS,
SSPI_GetChannelBinding,
SSPI_DTLS_InitClient,
NULL,//SSPI_DTLS_InitServer,
SSPI_VerifyHash,
NULL,//SSPI_GenerateHash,
};
#endif

View file

@ -125,7 +125,8 @@ static cvar_t net_dns_ipv6 = CVARD("net_dns_ipv6", "1", "If 0, disables dns
cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network access, including name resolution and socket creation. Does not affect loopback/internal connections.");
#if defined(HAVE_SSL)
cvar_t tls_ignorecertificateerrors = CVARFD("tls_ignorecertificateerrors", "0", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOUNSAFEEXPAND|CVAR_NOSET, "This should NEVER be set to 1!");
static cvar_t tls_provider = CVARFD("tls_provider", "0", CVAR_NOTFROMSERVER, "Controls which TLS provider to use.\n0: Auto.\n1: GNUTLS\n2: OpenSSL\n3: SSPI");
static void QDECL NET_TLS_Provider_Changed(struct cvar_s *var, char *oldvalue);
static cvar_t tls_provider = CVARFCD("tls_provider", "", CVAR_NOTFROMSERVER, NET_TLS_Provider_Changed, "Controls which TLS provider to use.");
#endif
#if defined(TCPCONNECT) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV))
#ifdef HAVE_SERVER
@ -210,6 +211,64 @@ static neterr_t FTENET_DTLS_SendPacket(ftenet_connections_t *col, int length, co
static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, const void *data, netadr_t *to);
static void *cryptolibmodule[cryptolib_count];
ftecrypto_t *cryptolib[cryptolib_count] =
{
NULL,
NULL,
NULL,
NULL,
#ifdef HAVE_WINSSPI
&crypto_sspi,
#endif
#ifdef HAVE_GNUTLS
&crypto_gnutls,
#endif
};
static void NET_TLS_Provider_Changed(struct cvar_s *var, char *oldvalue)
{
int i;
var->ival = 0;
if (!*var->string || !strcmp(var->string, "0"))
return;
for (i = 0; i < cryptolib_count; i++)
{
if (cryptolib[i] && !Q_strcasecmp(var->string, cryptolib[i]->drivername))
var->ival = i+1;
}
if (host_initialized && !var->ival)
{
Con_Printf("%s: \"%s\" not loaded, valid values are:", var->name, var->string);
for (i = 0; i < cryptolib_count; i++)
if (cryptolib[i])
Con_Printf(" %s", cryptolib[i]->drivername);
Con_Printf("\n");
}
}
qboolean NET_RegisterCrypto(void *module, ftecrypto_t *driver)
{
int i;
if (!driver)
{
for (i = 0; i < cryptolib_count; i++)
if (cryptolibmodule[i] == module)
cryptolibmodule[i] = NULL, cryptolib[i] = NULL;
Cvar_ForceCallback(&tls_provider);
return true;
}
else
{
for (i = 0; i < cryptolib_count; i++)
if (!cryptolib[i])
{
cryptolibmodule[i] = module, cryptolib[i] = driver;
Cvar_ForceCallback(&tls_provider);
return true;
}
return false;
}
}
//=============================================================================
int NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s)
@ -2247,6 +2306,7 @@ void *Auth_GetKnownCertificate(const char *certname, size_t *size)
qbyte *cert;
} certs[] =
{ //the contents of a -pubcert FILE
//note: not enforced for pk3 files (which we will otherwise happily randomly download of random servers anyway).
{"Spike", "-----BEGIN CERTIFICATE-----\n"
"MIIDnTCCAgUCCjE1ODQ4ODg2OTEwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAxMF\n"
"U3Bpa2UwHhcNMjAwMzIyMTQ1MTMwWhcNMzAwMzIwMTQ1MTMxWjAQMQ4wDAYDVQQD\n"
@ -2329,6 +2389,7 @@ void *TLS_GetKnownCertificate(const char *certname, size_t *size)
vfsfile_t *FS_OpenSSL(const char *peername, vfsfile_t *source, qboolean isserver)
{
int i;
vfsfile_t *f = NULL;
char hostname[MAX_OSPATH];
@ -2356,18 +2417,13 @@ vfsfile_t *FS_OpenSSL(const char *peername, vfsfile_t *source, qboolean isserver
else
*hostname = 0;
#ifdef HAVE_GNUTLS
if (!f && (!tls_provider.ival || tls_provider.ival==1))
f = GNUTLS_OpenVFS(hostname, source, isserver);
#endif
#ifdef HAVE_OPENSSL
if (!f && (!tls_provider.ival || tls_provider.ival==2))
f = OSSL_OpenVFS(hostname, source, isserver);
#endif
#ifdef HAVE_WINSSPI
if (!f && (!tls_provider.ival || tls_provider.ival==3))
f = SSPI_OpenVFS(hostname, source, isserver);
#endif
if (tls_provider.ival>0 && tls_provider.ival <= cryptolib_count && cryptolib[tls_provider.ival-1])
f = !cryptolib[tls_provider.ival-1]->OpenStream?NULL:cryptolib[tls_provider.ival-1]->OpenStream(hostname, source, isserver);
else for (i = 0; !f && i < cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->OpenStream)
f = cryptolib[i]->OpenStream(hostname, source, isserver);
}
if (!f) //it all failed.
{
Con_Printf("%s: no tls provider available\n", peername);
@ -2378,18 +2434,12 @@ vfsfile_t *FS_OpenSSL(const char *peername, vfsfile_t *source, qboolean isserver
int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize)
{
int r = -1;
#ifdef HAVE_GNUTLS
if (r == -1)
r = GNUTLS_GetChannelBinding(stream, data, datasize);
#endif
#ifdef HAVE_OPENSSL
if (r == -1)
r = OSSL_GetChannelBinding(stream, data, datasize);
#endif
#ifdef HAVE_WINSSPI
if (r == -1)
r = SSPI_GetChannelBinding(stream, data, datasize);
#endif
int i;
for (i = 0; r==-1 && i < cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->GetChannelBinding)
r = cryptolib[i]->GetChannelBinding(stream, data, datasize);
}
return r;
}
#endif
@ -2880,35 +2930,27 @@ void NET_DTLS_Timeouts(ftenet_connections_t *col)
const dtlsfuncs_t *DTLS_InitServer(void)
{
const dtlsfuncs_t *f = NULL;
#ifdef HAVE_GNUTLS
if (!f && (!tls_provider.ival || tls_provider.ival==1))
f = GNUDTLS_InitServer();
#endif
#ifdef HAVE_OPENSSL
if (!f && (!tls_provider.ival || tls_provider.ival==2))
f = OSSL_InitServer();
#endif
#ifdef HAVE_WINSSPI
if (!f && (!tls_provider.ival || tls_provider.ival==3))
f = SSPI_DTLS_InitServer();
#endif
int i;
if (tls_provider.ival>0 && tls_provider.ival <= cryptolib_count && cryptolib[tls_provider.ival-1])
f = !cryptolib[tls_provider.ival-1]->DTLS_InitServer?NULL:cryptolib[tls_provider.ival-1]->DTLS_InitServer();
else for (i = 0; !f && i < cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->DTLS_InitServer)
f = cryptolib[i]->DTLS_InitServer();
}
return f;
}
const dtlsfuncs_t *DTLS_InitClient(void)
{
const dtlsfuncs_t *f = NULL;
#ifdef HAVE_GNUTLS
if (!f && (!tls_provider.ival || tls_provider.ival==1))
f = GNUDTLS_InitClient();
#endif
#ifdef HAVE_OPENSSL
if (!f && (!tls_provider.ival || tls_provider.ival==2))
f = OSSL_InitClient();
#endif
#ifdef HAVE_WINSSPI
if (!f && (!tls_provider.ival || tls_provider.ival==3))
f = SSPI_DTLS_InitClient();
#endif
int i;
if (tls_provider.ival>0 && tls_provider.ival <= cryptolib_count && cryptolib[tls_provider.ival-1])
f = !cryptolib[tls_provider.ival-1]->DTLS_InitClient?NULL:cryptolib[tls_provider.ival-1]->DTLS_InitClient();
else for (i = 0; !f && i < cryptolib_count; i++)
{
if (cryptolib[i] && cryptolib[i]->DTLS_InitClient)
f = cryptolib[i]->DTLS_InitClient();
}
return f;
}
@ -3013,7 +3055,7 @@ qboolean NET_DTLS_Decode(ftenet_connections_t *col)
if (NET_CompareAdr(&peer->addr, &net_from))
{
peer->timeout = realtime+timeout.value; //refresh the timeout if our peer is still alive.
switch(peer->funcs->Received(peer->dtlsstate, net_message.data, net_message.cursize))
switch(peer->funcs->Received(peer->dtlsstate, &net_message))
{
case NETERR_DISCONNECTED:
Sys_Printf("disconnected %p\n", peer->dtlsstate);
@ -6278,6 +6320,8 @@ ftenet_generic_connection_t *FTENET_TCP_EstablishConnection(ftenet_connections_t
hostonly[port-host] = 0;
newcon->tcpstreams->clientstream = FS_OpenSSL(hostonly, newcon->tcpstreams->clientstream, false);
if (!newcon->tcpstreams->clientstream)
return NULL;
}
#endif

View file

@ -351,35 +351,32 @@ typedef struct dtlsfuncs_s
void *(*CreateContext)(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver); //if remotehost is null then their certificate will not be validated.
void (*DestroyContext)(void *ctx);
neterr_t (*Transmit)(void *ctx, const qbyte *data, size_t datasize);
neterr_t (*Received)(void *ctx, qbyte *data, size_t datasize);
neterr_t (*Received)(void *ctx, sizebuf_t *message); //operates in-place...
neterr_t (*Timeouts)(void *ctx);
void (*GetPeerCertificate)(void *ctx);
} dtlsfuncs_t;
const dtlsfuncs_t *DTLS_InitServer(void);
const dtlsfuncs_t *DTLS_InitClient(void);
#endif
#ifdef HAVE_WINSSPI
vfsfile_t *SSPI_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const struct dtlsfuncs_s *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available.
const struct dtlsfuncs_s *SSPI_DTLS_InitClient(void); //should always return something, if implemented.
enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize);
#endif
#ifdef HAVE_GNUTLS
vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const struct dtlsfuncs_s *GNUDTLS_InitServer(void); //returns NULL if there's no cert available.
const struct dtlsfuncs_s *GNUDTLS_InitClient(void); //should always return something, if implemented.
enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize);
int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax);
#endif
#ifdef HAVE_OPENSSL
vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const struct dtlsfuncs_s *OSSL_InitServer(void); //returns NULL if there's no cert available.
const struct dtlsfuncs_s *OSSL_InitClient(void); //should always return something, if implemented.
enum hashvalidation_e OSSL_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize);
#endif
typedef struct ftecrypto_s
{
const char *drivername;
//tlsey things
vfsfile_t *(*OpenStream)(const char *hostname, vfsfile_t *source, qboolean isserver); //establish a tls connection around a tcp stream
int (*GetChannelBinding)(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); //returns -1 if functions don't match those from OpenStream
//dtls entry points
const struct dtlsfuncs_s *(*DTLS_InitClient)(void); //should always return something, if implemented.
const struct dtlsfuncs_s *(*DTLS_InitServer)(void); //returns NULL if there's no cert available.
//digital signature stuff. note: uses sha2_512
enum hashvalidation_e (*VerifyHash)(const qbyte *hashdata, size_t hashsize, const qbyte *certdata, size_t certsize, const qbyte *signdata, size_t signsize);
int (*GenerateSignature)(const qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax);
} ftecrypto_t;
#define cryptolib_count 6
extern ftecrypto_t crypto_sspi, crypto_gnutls;
extern ftecrypto_t *cryptolib[cryptolib_count];

View file

@ -401,6 +401,8 @@ static qboolean QDECL PlugBI_ExportInterface(const char *name, void *interfacept
return Media_RegisterEncoder(currentplug, interfaceptr);
#endif
#endif
if (!strcmp(name, "Crypto"))
return NET_RegisterCrypto(currentplug, interfaceptr);
#ifdef HAVE_CLIENT
if (!strcmp(name, plugvrfuncs_name))
return R_RegisterVRDriver(currentplug, interfaceptr);
@ -1529,6 +1531,7 @@ void Plug_Close(plugin_t *plug)
#ifdef HAVE_CLIENT
S_UnregisterSoundInputModule(plug);
#endif
NET_RegisterCrypto(plug, NULL);
FS_UnRegisterFileSystemModule(plug);
Mod_UnRegisterAllModelFormats(plug);