Add disabled-by-default openssl plugin. Try to fix up ffmpeg build rules.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5892 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
d4714cab52
commit
04689373a3
5 changed files with 911 additions and 12 deletions
|
@ -1074,6 +1074,34 @@ IF(FTE_PLUG_QI)
|
|||
SET(INSTALLTARGS ${INSTALLTARGS} plug_qi)
|
||||
ENDIF()
|
||||
|
||||
SET(FTE_PLUG_OPENSSL false CACHE BOOL "Compile OpenSSL (beware license).")
|
||||
IF(FTE_PLUG_OPENSSL)
|
||||
#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 (though not gpl-2). debian has not caught up with that yet, however.
|
||||
FIND_PACKAGE(OpenSSL)
|
||||
IF(NOT OPENSSL_FOUND)
|
||||
MESSAGE(WARNING "openssl library NOT available. you'll have to use some other library.")
|
||||
ELSE()
|
||||
IF(OPENSSL_VERSION_MAJOR LESS 3 AND NOT FTE_PRIVATE_USE_ONLY)
|
||||
MESSAGE(WARNING "openssl library version is not 3 or above. You may not distribute plugin binaries due to license conflict.")
|
||||
ELSE()
|
||||
MESSAGE(WARNING "Using openssl. Resulting plugin must be licensed as GPLv3.")
|
||||
ENDIF()
|
||||
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES})
|
||||
|
||||
ADD_LIBRARY(plug_openssl MODULE
|
||||
plugins/plugin.c
|
||||
plugins/net_ssl_openssl.c
|
||||
)
|
||||
SET_TARGET_PROPERTIES(plug_openssl PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}")
|
||||
SET_TARGET_PROPERTIES(plug_openssl PROPERTIES OUTPUT_NAME "openssl")
|
||||
SET_TARGET_PROPERTIES(plug_openssl PROPERTIES PREFIX "fteplug_")
|
||||
SET_TARGET_PROPERTIES(plug_openssl PROPERTIES LINK_FLAGS "-Wl,--no-undefined")
|
||||
TARGET_LINK_LIBRARIES(plug_openssl ${SYS_LIBS} ${OPENSSL_LIBRARIES})
|
||||
SET(INSTALLTARGS ${INSTALLTARGS} plug_openssl)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
#ODE Physics library plugin
|
||||
SET(FTE_PLUG_ODE true CACHE BOOL "Compile ODE rigid body physics plugin.")
|
||||
IF(FTE_PLUG_ODE)
|
||||
|
|
|
@ -38,22 +38,22 @@ TARGETS_WINDOWS="sv-rel m-rel qcc-rel qccgui-scintilla qccgui-dbg m-dbg sv-dbg p
|
|||
|
||||
|
||||
PLUGINS_DROID="qi ezhud irc"
|
||||
PLUGINS_LINUXx86="ode qi ezhud xmpp irc"
|
||||
PLUGINS_LINUXx64="ode qi ezhud xmpp irc"
|
||||
PLUGINS_LINUXx86="openxr ode qi ezhud xmpp irc"
|
||||
PLUGINS_LINUXx64="openxr ode qi ezhud xmpp irc"
|
||||
PLUGINS_LINUXx32="qi ezhud xmpp irc"
|
||||
PLUGINS_LINUXarmhf="qi ezhud xmpp irc"
|
||||
if [ "$(uname -m)" != "x86_64" ]; then
|
||||
PLUGINS_LINUXx86="ffmpeg ode qi ezhud xmpp irc"
|
||||
PLUGINS_LINUXx86="openxr ode qi ezhud xmpp irc"
|
||||
fi
|
||||
if [ "$(uname -m)" == "x86_64" ]; then
|
||||
PLUGINS_LINUX64="ffmpeg ode qi ezhud xmpp irc"
|
||||
PLUGINS_LINUX64="openxr ode qi ezhud xmpp irc"
|
||||
fi
|
||||
#windows is always cross compiled, so we don't have issues with non-native ffmpeg
|
||||
#windows doesn't cross compile, so no system dependancy issues
|
||||
#skip some dependancies if we're running on cygwin, ode is buggy.
|
||||
if [ "$(uname -s)" == "Linux" ]; then
|
||||
PLUGINS_WIN32="ffmpeg ode qi ezhud xmpp irc"
|
||||
PLUGINS_WIN64="ffmpeg ode qi ezhud xmpp irc"
|
||||
PLUGINS_WIN32="ode qi ezhud xmpp irc"
|
||||
PLUGINS_WIN64="ode qi ezhud xmpp irc"
|
||||
else
|
||||
PLUGINS_WIN32="qi ezhud xmpp irc"
|
||||
PLUGINS_WIN64="qi ezhud xmpp irc"
|
||||
|
@ -317,6 +317,9 @@ if [ "$BUILD_LINUXx86" == "y" ]; then
|
|||
if [[ "$PLUGINS_LINUXx86" =~ "ffmpeg" ]]; then
|
||||
debianpackages libswscale-dev libavcodec-dev || otherpackages || exit
|
||||
fi
|
||||
if [[ "$PLUGINS_LINUXx86" =~ "openxr" ]]; then
|
||||
debianpackages libopenxr-dev || otherpackages || exit
|
||||
fi
|
||||
fi
|
||||
if [ "$BUILD_LINUXx64" == "y" ]; then
|
||||
#for building linux targets
|
||||
|
@ -325,6 +328,9 @@ if [ "$BUILD_LINUXx64" == "y" ]; then
|
|||
if [[ "$PLUGINS_LINUXx64" =~ "ffmpeg" ]]; then
|
||||
debianpackages libswscale-dev libavcodec-dev || otherpackages || exit
|
||||
fi
|
||||
if [[ "$PLUGINS_LINUXx64" =~ "openxr" ]]; then
|
||||
debianpackages libopenxr-dev || otherpackages || exit
|
||||
fi
|
||||
fi
|
||||
if [ "$BUILD_LINUXx32" == "y" ]; then
|
||||
#for building linux targets
|
||||
|
@ -499,11 +505,11 @@ if [ $UID -ne 0 ] && [ $REBUILD_TOOLCHAINS == "y" ]; then
|
|||
echo "Prebuilding ODE library (linux x86_64)..."
|
||||
make FTE_TARGET=linux64 plugins-rel NATIVE_PLUGINS=ode CPUOPTIMISATIONS=-fno-finite-math-only 2>&1 >>/dev/null
|
||||
fi
|
||||
if [ "$BUILD_WIN32" == "y" ]; then
|
||||
if [ "$BUILD_WIN32" == "y" ] && [[ "$PLUGINS_WIN32" =~ "ffmpeg" ]]; then
|
||||
echo "Obtaining ffmpeg library (win32)..."
|
||||
make FTE_TARGET=win32 plugins-rel NATIVE_PLUGINS=ffmpeg 2>&1 >>/dev/null
|
||||
fi
|
||||
if [ "$BUILD_WIN64" == "y" ]; then
|
||||
if [ "$BUILD_WIN64" == "y" ] && [[ "$PLUGINS_WIN64" =~ "ffmpeg" ]]; then
|
||||
echo "Obtaining ffmpeg library (win64)..."
|
||||
make FTE_TARGET=win64 plugins-rel NATIVE_PLUGINS=ffmpeg 2>&1 >>/dev/null
|
||||
fi
|
||||
|
|
|
@ -2087,7 +2087,7 @@ endif
|
|||
plugins-dbg:
|
||||
@-mkdir -p $(DEBUG_DIR)
|
||||
@if test -e ../plugins/Makefile; \
|
||||
then $(MAKE) native -C ../plugins OUT_DIR="$(DEBUG_DIR)" CC="$(CC) $(W32_CFLAGS) $(DEBUG_CFLAGS)" CXX="$(CXX) $(W32_CFLAGS) $(subst -Wno-pointer-sign,,$(DEBUG_CFLAGS))" ARCH="$(ARCH)" BASE_CFLAGS="$(BASE_CFLAGS) $(BRANDFLAGS)" BASE_CXXFLAGS="$(subst -Wno-pointer-sign,,$(BASE_CFLAGS)) $(BRANDFLAGS)" FTE_TARGET="$(FTE_TARGET)"; \
|
||||
then $(MAKE) native -C ../plugins OUT_DIR="$(DEBUG_DIR)" CC="$(CC) $(W32_CFLAGS) $(DEBUG_CFLAGS)" CXX="$(CXX) $(W32_CFLAGS) $(subst -Wno-pointer-sign,,$(DEBUG_CFLAGS))" PKGCONFIG="$(PKGCONFIG)" ARCH="$(ARCH)" BASE_CFLAGS="$(BASE_CFLAGS) $(BRANDFLAGS)" BASE_CXXFLAGS="$(subst -Wno-pointer-sign,,$(BASE_CFLAGS)) $(BRANDFLAGS)" FTE_TARGET="$(FTE_TARGET)"; \
|
||||
else echo no plugins directory installed; \
|
||||
fi
|
||||
plugins:
|
||||
|
@ -2095,7 +2095,7 @@ plugins:
|
|||
plugins-rel:
|
||||
@-mkdir -p $(RELEASE_DIR)
|
||||
@if test -e ../plugins/Makefile; \
|
||||
then $(MAKE) native -C ../plugins OUT_DIR="$(RELEASE_DIR)" CC="$(CC) $(W32_CFLAGS) $(RELEASE_CFLAGS)" CXX="$(CXX) $(W32_CFLAGS) $(subst -Wno-pointer-sign,,$(RELEASE_CFLAGS))" ARCH="$(ARCH)" BASE_CFLAGS="$(BASE_CFLAGS) $(BRANDFLAGS)" BASE_CXXFLAGS="$(subst -Wno-pointer-sign,,$(BASE_CFLAGS)) $(BRANDFLAGS)" FTE_TARGET="$(FTE_TARGET)"; \
|
||||
then $(MAKE) native -C ../plugins OUT_DIR="$(RELEASE_DIR)" CC="$(CC) $(W32_CFLAGS) $(RELEASE_CFLAGS)" CXX="$(CXX) $(W32_CFLAGS) $(subst -Wno-pointer-sign,,$(RELEASE_CFLAGS))" PKGCONFIG="$(PKGCONFIG)" ARCH="$(ARCH)" BASE_CFLAGS="$(BASE_CFLAGS) $(BRANDFLAGS)" BASE_CXXFLAGS="$(subst -Wno-pointer-sign,,$(BASE_CFLAGS)) $(BRANDFLAGS)" FTE_TARGET="$(FTE_TARGET)"; \
|
||||
else echo no plugins directory installed; \
|
||||
fi
|
||||
plugins-rel:
|
||||
|
|
|
@ -120,6 +120,7 @@ help:
|
|||
#linux users are expected to have the library installed locally already. If your version is too old or missing, run the following command to install it (to /usr/local), then delete the gz and directory.
|
||||
#wget http://ffmpeg.org/releases/ffmpeg-1.2.tar.gz && cd tar xvfz ffmpeg-1.2.tar.gz && cd ffmpeg-1.2/ && ./configure --disable-yasm --enable-shared && make && sudo make install
|
||||
#we use ffmpeg's version for some reason, as opposed to libav. not sure what the differences are meant to be, but libav seemed to have non-depricated functions defined, docs that say to use them, and these functions missing.
|
||||
ifeq ($(findstring win,$(FTE_TARGET)),win)
|
||||
AV_VER=ffmpeg-4.0
|
||||
ifeq (0,1)
|
||||
AV_ARCHIVEEXT=.z7
|
||||
|
@ -213,6 +214,17 @@ $(PLUG_PREFIX)ffmpeg$(PLUG_NATIVE_EXT): $(AV_DEP) $(FFMPEG_ZIP)
|
|||
|
||||
$(PLUG_PREFIX)ffmpeg$(PLUG_NATIVE_EXT): $(AVPLUG_OBJS)
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -s -o $@ -shared $(PLUG_CFLAGS) $(AV_CFLAGS) $(AVPLUG_OBJS) $(PLUG_DEFFILE) $(PLUG_LDFLAGS) $(AV_LDFLAGS)
|
||||
|
||||
#above uses wget and zips and mess.
|
||||
else
|
||||
#just use pkg-config
|
||||
$(PLUG_PREFIX)ffmpeg$(PLUG_NATIVE_EXT): $(AVPLUG_OBJS)
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -s -o $@ -shared $(PLUG_CFLAGS) $(AVPLUG_OBJS) $(PLUG_DEFFILE) $(PLUG_LDFLAGS) `$(PKGCONFIG) --cflags --libs libavformat libavcodec libavutil libswscale`
|
||||
ifeq ($(shell $(PKGCONFIG) --exists libavformat libavcodec libavutil libswscale && echo 1),1)
|
||||
NATIVE_PLUGINS+=ffmpeg
|
||||
endif
|
||||
endif
|
||||
|
||||
######################################
|
||||
|
||||
######################################
|
||||
|
@ -355,8 +367,8 @@ NATIVE_PLUGINS+=irc
|
|||
|
||||
#OpenXR plugin...
|
||||
$(PLUG_PREFIX)openxr$(PLUG_NATIVE_EXT): openxr.c plugin.c
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS) -DXR_NO_PROTOTYPES `pkg-config --cflags openxr` -DGLQUAKE -DVKQUAKE -DD3D11QUAKE
|
||||
ifeq ($(shell pkg-config --exists openxr && echo 1),1)
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS) -DXR_NO_PROTOTYPES `$(PKGCONFIG) --cflags openxr` -DGLQUAKE -DVKQUAKE -DD3D11QUAKE
|
||||
ifeq ($(shell $(PKGCONFIG) --exists openxr && echo 1),1)
|
||||
NATIVE_PLUGINS+=openxr
|
||||
endif
|
||||
|
||||
|
@ -370,6 +382,13 @@ $(PLUG_PREFIX)models$(PLUG_NATIVE_EXT): models/gltf.c models/exportiqm.c models/
|
|||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) -Imodels $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS)
|
||||
#NATIVE_PLUGINS+=models
|
||||
|
||||
#Openssl crypto plugin, to replace microsoft's shoddy dtls implementation. could also be useful on the BSDs, yay system components?
|
||||
$(PLUG_PREFIX)openssl$(PLUG_NATIVE_EXT): net_ssl_openssl.c plugin.c
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS) `$(PKGCONFIG) --libs --cflags openssl`
|
||||
#ifeq ($(shell $(PKGCONFIG) --exists openssl && echo 1),1)
|
||||
#Disabled due to licensing issues #NATIVE_PLUGINS+=openssl
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
846
plugins/net_ssl_openssl.c
Normal file
846
plugins/net_ssl_openssl.c
Normal file
|
@ -0,0 +1,846 @@
|
|||
#include "plugin.h"
|
||||
#include "netinc.h"
|
||||
|
||||
plugfsfuncs_t *fsfuncs;
|
||||
|
||||
#undef SHA1
|
||||
#undef HMAC
|
||||
#include "openssl/bio.h"
|
||||
#include "openssl/ssl.h"
|
||||
#include "openssl/err.h"
|
||||
#include "openssl/conf.h"
|
||||
|
||||
#define assert(c) {if (!(c)) Con_Printf("assert failed: "STRINGIFY(c)"\n");}
|
||||
|
||||
static qboolean OSSL_Init(void);
|
||||
static int ossl_fte_certctx;
|
||||
struct fte_certctx_s
|
||||
{
|
||||
const char *peername;
|
||||
qboolean dtls;
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
X509 *servercert;
|
||||
EVP_PKEY *privatekey;
|
||||
} vhost;
|
||||
|
||||
static BIO_METHOD *biometh_vfs;
|
||||
|
||||
static int OSSL_Bio_FWrite(BIO *h, const char *buf, int size)
|
||||
{
|
||||
vfsfile_t *f = BIO_get_data(h);
|
||||
int r = VFS_WRITE(f, buf, size);
|
||||
BIO_clear_retry_flags(h);
|
||||
if (r == 0)
|
||||
{
|
||||
BIO_set_retry_write(h);
|
||||
r = -1; //paranoia
|
||||
}
|
||||
return r;
|
||||
}
|
||||
static int OSSL_Bio_FRead(BIO *h, char *buf, int size)
|
||||
{
|
||||
vfsfile_t *f = BIO_get_data(h);
|
||||
int r = VFS_READ(f, buf, size);
|
||||
BIO_clear_retry_flags(h);
|
||||
if (r == 0) //no data yet.
|
||||
{
|
||||
BIO_set_retry_read(h);
|
||||
r = -1; //shouldn't be needed, but I'm paranoid
|
||||
}
|
||||
return r;
|
||||
}
|
||||
static int OSSL_Bio_FPuts(BIO *h, const char *buf)
|
||||
{
|
||||
return OSSL_Bio_FWrite(h, buf, strlen(buf));
|
||||
}
|
||||
static long OSSL_Bio_FCtrl(BIO *h, int cmd, long arg1, void *arg2)
|
||||
{
|
||||
vfsfile_t *f = BIO_get_data(h);
|
||||
switch(cmd)
|
||||
{
|
||||
case BIO_CTRL_FLUSH:
|
||||
VFS_FLUSH(f);
|
||||
return 1;
|
||||
default:
|
||||
Con_Printf("OSSL_Bio_FCtrl: unknown cmd %i\n", cmd);
|
||||
case BIO_CTRL_PUSH:
|
||||
case BIO_CTRL_POP:
|
||||
return 0;
|
||||
}
|
||||
return 0; //failure
|
||||
}
|
||||
static long OSSL_Bio_FOtherCtrl(BIO *h, int cmd, BIO_info_cb *cb)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
default:
|
||||
Con_Printf("OSSL_Bio_FOtherCtrl unknown cmd %i\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
return 0; //failure
|
||||
}
|
||||
static int OSSL_Bio_FCreate(BIO *h)
|
||||
{ //we'll have to fill this in after we create the bio.
|
||||
BIO_set_data(h, NULL);
|
||||
return 1;
|
||||
}
|
||||
static int OSSL_Bio_FDestroy(BIO *h)
|
||||
{
|
||||
vfsfile_t *f = BIO_get_data(h);
|
||||
VFS_CLOSE(f);
|
||||
BIO_set_data(h, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int OSSL_PrintError_CB (const char *str, size_t len, void *u)
|
||||
{
|
||||
Con_Printf("%s\n", str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vfsfile_t funcs;
|
||||
struct fte_certctx_s cert;
|
||||
SSL_CTX *ctx;
|
||||
BIO *bio;
|
||||
SSL *ssl;
|
||||
} osslvfs_t;
|
||||
static int QDECL OSSL_FRead (struct vfsfile_s *file, void *buffer, int bytestoread)
|
||||
{
|
||||
osslvfs_t *o = (osslvfs_t*)file;
|
||||
int r = BIO_read(o->bio, buffer, bytestoread);
|
||||
if (r <= 0)
|
||||
{
|
||||
if (BIO_should_io_special(o->bio))
|
||||
{
|
||||
switch(BIO_get_retry_reason(o->bio))
|
||||
{
|
||||
//these are temporary errors, try again later.
|
||||
case BIO_RR_SSL_X509_LOOKUP:
|
||||
return -1; //certificate failure.
|
||||
case BIO_RR_ACCEPT:
|
||||
case BIO_RR_CONNECT:
|
||||
return -1; //should never happen
|
||||
};
|
||||
}
|
||||
if (BIO_should_retry(o->bio))
|
||||
return 0;
|
||||
return -1; //eof or something
|
||||
}
|
||||
return r;
|
||||
}
|
||||
static int QDECL OSSL_FWrite (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
||||
{
|
||||
osslvfs_t *o = (osslvfs_t*)file;
|
||||
int r = BIO_write(o->bio, buffer, bytestowrite);
|
||||
if (r <= 0)
|
||||
{
|
||||
if (BIO_should_io_special(o->bio))
|
||||
{
|
||||
switch(BIO_get_retry_reason(o->bio))
|
||||
{
|
||||
//these are temporary errors, try again later.
|
||||
case BIO_RR_SSL_X509_LOOKUP:
|
||||
return -1; //certificate failure.
|
||||
case BIO_RR_ACCEPT:
|
||||
case BIO_RR_CONNECT:
|
||||
return -1; //should never happen
|
||||
}
|
||||
}
|
||||
if (BIO_should_retry(o->bio))
|
||||
return 0;
|
||||
return -1; //eof or something
|
||||
}
|
||||
return r;
|
||||
}
|
||||
//static qboolean QDECL OSSL_Seek (struct vfsfile_s *file, qofs_t pos); //returns false for error
|
||||
//static qofs_t QDECL OSSL_Tell (struct vfsfile_s *file);
|
||||
//static qofs_t QDECL OSSL_GetLen (struct vfsfile_s *file); //could give some lag
|
||||
static qboolean QDECL OSSL_Close (struct vfsfile_s *file)
|
||||
{
|
||||
osslvfs_t *o = (osslvfs_t*)file;
|
||||
BIO_free(o->bio);
|
||||
SSL_CTX_free(o->ctx);
|
||||
free(o);
|
||||
return true; //success, I guess
|
||||
}
|
||||
//static void QDECL OSSL_Flush (struct vfsfile_s *file);
|
||||
|
||||
|
||||
|
||||
static qboolean print_cn_name(X509_NAME* const name, const char *utf8match, const char *prefix)
|
||||
{
|
||||
int idx = -1;
|
||||
qboolean success = 0;
|
||||
unsigned char *utf8 = NULL;
|
||||
X509_NAME_ENTRY* entry;
|
||||
ASN1_STRING* data;
|
||||
int length;
|
||||
|
||||
do
|
||||
{
|
||||
if(!name) break; /* failed */
|
||||
|
||||
idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
|
||||
if(!(idx > -1)) break; /* failed */
|
||||
|
||||
entry = X509_NAME_get_entry(name, idx);
|
||||
if(!entry) break; /* failed */
|
||||
|
||||
data = X509_NAME_ENTRY_get_data(entry);
|
||||
if(!data) break; /* failed */
|
||||
|
||||
length = ASN1_STRING_to_UTF8(&utf8, data);
|
||||
if(!utf8 || !(length > 0)) break; /* failed */
|
||||
|
||||
if (utf8match)
|
||||
success = !strcmp(utf8, utf8match);
|
||||
else
|
||||
{
|
||||
Con_Printf("%s%s", prefix, utf8);
|
||||
success = 1;
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
if(utf8)
|
||||
OPENSSL_free(utf8);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static int OSSL_Verify_Peer(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
SSL *ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
struct fte_certctx_s *uctx = SSL_get_ex_data(ssl, ossl_fte_certctx);
|
||||
|
||||
if(preverify_ok == 0)
|
||||
{
|
||||
int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
|
||||
int err = X509_STORE_CTX_get_error(x509_ctx);
|
||||
|
||||
X509* cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
||||
X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
|
||||
//X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;
|
||||
|
||||
if (err == X509_V_ERR_CERT_HAS_EXPIRED || err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
|
||||
{
|
||||
size_t knownsize;
|
||||
qbyte *knowndata = TLS_GetKnownCertificate(uctx->peername, &knownsize);
|
||||
if (knowndata)
|
||||
{ //check
|
||||
size_t blobsize;
|
||||
qbyte *blob;
|
||||
qbyte *end;
|
||||
blobsize = i2d_X509(cert, NULL);
|
||||
if (blobsize != knownsize)
|
||||
return 0; //fail if the size doesn't match.
|
||||
blob = alloca(blobsize);
|
||||
end = blob;
|
||||
i2d_X509(cert, &end);
|
||||
if (memcmp(blob, knowndata, blobsize))
|
||||
return 0;
|
||||
return 1; //exact match to a known cert. yay. allow it.
|
||||
}
|
||||
|
||||
#ifdef HAVE_CLIENT
|
||||
if (uctx->dtls)
|
||||
{
|
||||
unsigned int probs = 0;
|
||||
size_t blobsize;
|
||||
qbyte *blob;
|
||||
qbyte *end;
|
||||
blobsize = i2d_X509(cert, NULL);
|
||||
blob = alloca(blobsize);
|
||||
end = blob;
|
||||
i2d_X509(cert, &end);
|
||||
|
||||
switch(err)
|
||||
{
|
||||
case 0:
|
||||
probs |= CERTLOG_WRONGHOST;
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
probs |= CERTLOG_EXPIRED;
|
||||
break;
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
probs |= CERTLOG_MISSINGCA;
|
||||
break;
|
||||
default:
|
||||
probs |= CERTLOG_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (CertLog_ConnectOkay(uctx->peername, blob, blobsize, probs))
|
||||
return 1; //ignore the errors...
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Con_Printf(CON_ERROR"%s ", uctx->peername);
|
||||
//FIXME: this is probably on a worker thread. expect munged prints.
|
||||
//print_cn_name(sname, NULL, CON_ERROR);
|
||||
Con_Printf(" (issued by ");
|
||||
print_cn_name(iname, NULL, S_COLOR_YELLOW);
|
||||
Con_Printf(")");
|
||||
if(depth == 0) {
|
||||
/* If depth is 0, its the server's certificate. Print the SANs too */
|
||||
// print_san_name("Subject (san)", cert);
|
||||
}
|
||||
|
||||
if(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
|
||||
Con_Printf(": Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY\n");
|
||||
else if (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)
|
||||
Con_Printf(": Error = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE\n");
|
||||
else if(err == X509_V_ERR_CERT_UNTRUSTED)
|
||||
Con_Printf(": Error = X509_V_ERR_CERT_UNTRUSTED\n");
|
||||
else if(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
|
||||
Con_Printf(": Error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN\n");
|
||||
else if(err == X509_V_ERR_CERT_NOT_YET_VALID)
|
||||
Con_Printf(": Error = X509_V_ERR_CERT_NOT_YET_VALID\n");
|
||||
else if(err == X509_V_ERR_CERT_HAS_EXPIRED)
|
||||
Con_Printf(": Error = X509_V_ERR_CERT_HAS_EXPIRED\n");
|
||||
else if(err == X509_V_OK)
|
||||
Con_Printf(": Error = X509_V_OK\n");
|
||||
else if(err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
|
||||
Con_Printf(": Error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT\n");
|
||||
else
|
||||
Con_Printf(": Error = %d\n", err);
|
||||
}
|
||||
|
||||
if (!preverify_ok && cvarfuncs->GetFloat("tls_ignorecertificateerrors"))
|
||||
{
|
||||
Con_Printf(CON_ERROR "%s: Ignoring certificate errors (tls_ignorecertificateerrors is set)\n", uctx->peername);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
|
||||
static vfsfile_t *OSSL_OpenPrivKeyFile(char *nativename, size_t nativesize)
|
||||
{
|
||||
#define privname "privkey.pem"
|
||||
vfsfile_t *privf;
|
||||
const char *mode = nativename?"wb":"rb";
|
||||
/*int i = COM_CheckParm("-privkey");
|
||||
if (i++)
|
||||
{
|
||||
if (nativename)
|
||||
Q_strncpyz(nativename, com_argv[i], nativesize);
|
||||
privf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM);
|
||||
}
|
||||
else*/
|
||||
{
|
||||
if (nativename)
|
||||
if (!fsfuncs->NativePath(privname, FS_ROOT, nativename, nativesize))
|
||||
return NULL;
|
||||
|
||||
privf = fsfuncs->OpenVFS(privname, mode, FS_ROOT);
|
||||
}
|
||||
return privf;
|
||||
#undef privname
|
||||
}
|
||||
static vfsfile_t *OSSL_OpenPubKeyFile(char *nativename, size_t nativesize)
|
||||
{
|
||||
#define fullchainname "fullchain.pem"
|
||||
#define pubname "cert.pem"
|
||||
vfsfile_t *pubf = NULL;
|
||||
const char *mode = nativename?"wb":"rb";
|
||||
/*int i = COM_CheckParm("-pubkey");
|
||||
if (i++)
|
||||
{
|
||||
if (nativename)
|
||||
Q_strncpyz(nativename, com_argv[i], nativesize);
|
||||
pubf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM);
|
||||
}
|
||||
else*/
|
||||
{
|
||||
if (!pubf && (!nativename || fsfuncs->NativePath(fullchainname, FS_ROOT, nativename, nativesize)))
|
||||
pubf = fsfuncs->OpenVFS(fullchainname, mode, FS_ROOT);
|
||||
if (!pubf && (!nativename || fsfuncs->NativePath(pubname, FS_ROOT, nativename, nativesize)))
|
||||
pubf = fsfuncs->OpenVFS(pubname, mode, FS_ROOT);
|
||||
}
|
||||
return pubf;
|
||||
#undef pubname
|
||||
}
|
||||
static BIO *OSSL_BioFromFile(vfsfile_t *f)
|
||||
{
|
||||
qbyte buf[4096];
|
||||
int r;
|
||||
BIO *b = BIO_new(BIO_s_mem());
|
||||
if (f)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
r = VFS_READ(f, buf, sizeof(buf));
|
||||
if (r <= 0)
|
||||
break;
|
||||
BIO_write(b, buf, r);
|
||||
}
|
||||
VFS_CLOSE(f);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
static void OSSL_OpenPrivKey(void)
|
||||
{
|
||||
BIO *bio = OSSL_BioFromFile(OSSL_OpenPrivKeyFile(NULL,0));
|
||||
vhost.privatekey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
}
|
||||
static void OSSL_OpenPubKey(void)
|
||||
{
|
||||
BIO *bio = OSSL_BioFromFile(OSSL_OpenPubKeyFile(NULL,0));
|
||||
vhost.servercert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
static vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver)
|
||||
{
|
||||
BIO *sink;
|
||||
osslvfs_t *n;
|
||||
if (!OSSL_Init())
|
||||
return NULL; //FAIL!
|
||||
|
||||
n = calloc(sizeof(*n) + strlen(hostname)+1, 1);
|
||||
|
||||
n->funcs.ReadBytes = OSSL_FRead;
|
||||
n->funcs.WriteBytes = OSSL_FWrite;
|
||||
n->funcs.Seek = NULL;
|
||||
n->funcs.Tell = NULL;
|
||||
n->funcs.GetLen = NULL;
|
||||
n->funcs.Close = OSSL_Close;
|
||||
n->funcs.Flush = NULL;
|
||||
n->funcs.seekstyle = SS_UNSEEKABLE;
|
||||
|
||||
n->cert.peername = strcpy((char*)(n+1), hostname);
|
||||
n->cert.dtls = false;
|
||||
|
||||
ERR_print_errors_cb(OSSL_PrintError_CB, NULL);
|
||||
|
||||
sink = BIO_new(biometh_vfs);
|
||||
if (sink)
|
||||
{
|
||||
n->ctx = SSL_CTX_new(isserver?TLS_server_method():TLS_client_method());
|
||||
if (n->ctx)
|
||||
{
|
||||
assert(1==SSL_CTX_set_cipher_list(n->ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"));
|
||||
|
||||
SSL_CTX_set_session_cache_mode(n->ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
SSL_CTX_set_default_verify_paths(n->ctx);
|
||||
SSL_CTX_set_verify(n->ctx, SSL_VERIFY_PEER, OSSL_Verify_Peer);
|
||||
SSL_CTX_set_verify_depth(n->ctx, 5);
|
||||
SSL_CTX_set_options(n->ctx, SSL_OP_NO_COMPRESSION); //compression allows guessing the contents of the stream somehow.
|
||||
|
||||
if (isserver)
|
||||
{
|
||||
if (vhost.servercert && vhost.privatekey)
|
||||
{
|
||||
SSL_CTX_use_certificate(n->ctx, vhost.servercert);
|
||||
SSL_CTX_use_PrivateKey(n->ctx, vhost.privatekey);
|
||||
assert(1==SSL_CTX_check_private_key(n->ctx));
|
||||
}
|
||||
}
|
||||
|
||||
n->bio = BIO_new_ssl(n->ctx, !isserver);
|
||||
|
||||
//set up the source/sink
|
||||
BIO_set_data(sink, source); //source now belongs to the bio
|
||||
BIO_set_init(sink, true); //our sink is now ready...
|
||||
n->bio = BIO_push(n->bio, sink);
|
||||
BIO_free(sink);
|
||||
sink = NULL;
|
||||
|
||||
BIO_get_ssl(n->bio, &n->ssl);
|
||||
SSL_set_ex_data(n->ssl, ossl_fte_certctx, &n->cert);
|
||||
SSL_set_mode(n->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
SSL_set_tlsext_host_name(n->ssl, n->cert.peername); //let the server know which cert to send
|
||||
BIO_do_connect(n->bio);
|
||||
return &n->funcs;
|
||||
}
|
||||
BIO_free(sink);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*static int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
|
||||
{
|
||||
//FIXME: not yet supported. tbh I've no idea how to get that data. probably something convoluted.
|
||||
return -1;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
static BIO_METHOD *biometh_dtls;
|
||||
typedef struct {
|
||||
struct fte_certctx_s cert;
|
||||
|
||||
void *cbctx;
|
||||
neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize);
|
||||
|
||||
SSL_CTX *ctx;
|
||||
BIO *bio;
|
||||
SSL *ssl;
|
||||
|
||||
// BIO *sink;
|
||||
qbyte *pending;
|
||||
size_t pendingsize;
|
||||
} ossldtls_t;
|
||||
static int OSSL_Bio_DWrite(BIO *h, const char *buf, int size)
|
||||
{
|
||||
ossldtls_t *f = BIO_get_data(h);
|
||||
neterr_t r = f->push(f->cbctx, buf, size);
|
||||
|
||||
BIO_clear_retry_flags(h);
|
||||
switch(r)
|
||||
{
|
||||
case NETERR_SENT:
|
||||
return size;
|
||||
case NETERR_NOROUTE:
|
||||
case NETERR_DISCONNECTED:
|
||||
return -1;
|
||||
case NETERR_MTU:
|
||||
return -1;
|
||||
case NETERR_CLOGGED:
|
||||
BIO_set_retry_write(h);
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
static int OSSL_Bio_DRead(BIO *h, char *buf, int size)
|
||||
{
|
||||
ossldtls_t *f = BIO_get_data(h);
|
||||
|
||||
BIO_clear_retry_flags(h);
|
||||
if (f->pending)
|
||||
{
|
||||
size = min(size, f->pendingsize);
|
||||
memcpy(buf, f->pending, f->pendingsize);
|
||||
|
||||
//we've read it now, don't read it again.
|
||||
f->pending = 0;
|
||||
f->pendingsize = 0;
|
||||
return size;
|
||||
}
|
||||
//nothing available.
|
||||
BIO_set_retry_read(h);
|
||||
return -1;
|
||||
}
|
||||
static long OSSL_Bio_DCtrl(BIO *h, int cmd, long arg1, void *arg2)
|
||||
{
|
||||
// ossldtls_t *f = BIO_get_data(h);
|
||||
switch(cmd)
|
||||
{
|
||||
case BIO_CTRL_FLUSH:
|
||||
return 1;
|
||||
|
||||
|
||||
case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: //we're non-blocking, so this doesn't affect us.
|
||||
case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
|
||||
case BIO_CTRL_WPENDING:
|
||||
case BIO_CTRL_DGRAM_QUERY_MTU:
|
||||
case BIO_CTRL_DGRAM_SET_MTU:
|
||||
return 0;
|
||||
|
||||
|
||||
default:
|
||||
Con_Printf("OSSL_Bio_DCtrl: unknown cmd %i\n", cmd);
|
||||
case BIO_CTRL_PUSH:
|
||||
case BIO_CTRL_POP:
|
||||
return 0;
|
||||
}
|
||||
return 0; //failure
|
||||
}
|
||||
static long OSSL_Bio_DOtherCtrl(BIO *h, int cmd, BIO_info_cb *cb)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
default:
|
||||
Con_Printf("OSSL_Bio_DOtherCtrl unknown cmd %i\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
return 0; //failure
|
||||
}
|
||||
static int OSSL_Bio_DCreate(BIO *h)
|
||||
{ //we'll have to fill this in after we create the bio.
|
||||
BIO_set_data(h, NULL);
|
||||
return 1;
|
||||
}
|
||||
static int OSSL_Bio_DDestroy(BIO *h)
|
||||
{
|
||||
BIO_set_data(h, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *OSSL_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.
|
||||
ossldtls_t *n = calloc(sizeof(*n) + strlen(remotehost)+1, 1);
|
||||
BIO *sink;
|
||||
|
||||
n->cbctx = cbctx;
|
||||
n->push = push;
|
||||
|
||||
n->ctx = SSL_CTX_new(isserver?DTLS_server_method():DTLS_client_method());
|
||||
|
||||
n->cert.peername = strcpy((char*)(n+1), remotehost);
|
||||
n->cert.dtls = true;
|
||||
|
||||
if (n->ctx)
|
||||
{
|
||||
assert(1==SSL_CTX_set_cipher_list(n->ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"));
|
||||
|
||||
SSL_CTX_set_session_cache_mode(n->ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
SSL_CTX_set_verify(n->ctx, SSL_VERIFY_PEER, OSSL_Verify_Peer);
|
||||
SSL_CTX_set_verify_depth(n->ctx, 5);
|
||||
SSL_CTX_set_options(n->ctx, SSL_OP_NO_COMPRESSION); //compression allows guessing the contents of the stream somehow.
|
||||
|
||||
//SSL_CTX_use_certificate_file
|
||||
//FIXME: SSL_CTX_use_certificate_file aka SSL_CTX_use_certificate(PEM_read_bio_X509)
|
||||
//FIXME: SSL_CTX_use_PrivateKey_file aka SSL_CTX_use_PrivateKey(PEM_read_bio_PrivateKey)
|
||||
//assert(1==SSL_CTX_check_private_key(n->ctx));
|
||||
|
||||
{
|
||||
n->bio = BIO_new_ssl(n->ctx, !isserver);
|
||||
|
||||
//set up the source/sink
|
||||
sink = BIO_new(biometh_dtls);
|
||||
if (sink)
|
||||
{
|
||||
BIO_set_data(sink, n);
|
||||
BIO_set_init(sink, true); //our sink is now ready...
|
||||
n->bio = BIO_push(n->bio, sink);
|
||||
BIO_free(sink);
|
||||
sink = NULL;
|
||||
}
|
||||
|
||||
BIO_get_ssl(n->bio, &n->ssl);
|
||||
SSL_set_ex_data(n->ssl, ossl_fte_certctx, &n->cert);
|
||||
SSL_set_tlsext_host_name(n->ssl, remotehost); //let the server know which cert to send
|
||||
BIO_do_connect(n->bio);
|
||||
ERR_print_errors_cb(OSSL_PrintError_CB, NULL);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static void OSSL_DestroyContext(void *ctx)
|
||||
{
|
||||
ossldtls_t *o = (ossldtls_t*)ctx;
|
||||
BIO_free(o->bio);
|
||||
SSL_CTX_free(o->ctx);
|
||||
free(o);
|
||||
}
|
||||
static neterr_t OSSL_Transmit(void *ctx, const qbyte *data, size_t datasize)
|
||||
{ //we're sending data
|
||||
ossldtls_t *o = (ossldtls_t*)ctx;
|
||||
int r = BIO_write(o->bio, data, datasize);
|
||||
if (r <= 0)
|
||||
{
|
||||
if (BIO_should_io_special(o->bio))
|
||||
{
|
||||
switch(BIO_get_retry_reason(o->bio))
|
||||
{
|
||||
//these are temporary errors, try again later.
|
||||
case BIO_RR_SSL_X509_LOOKUP:
|
||||
return NETERR_NOROUTE; //certificate failure.
|
||||
case BIO_RR_ACCEPT:
|
||||
case BIO_RR_CONNECT:
|
||||
return NETERR_NOROUTE; //should never happen
|
||||
}
|
||||
}
|
||||
if (BIO_should_retry(o->bio))
|
||||
return 0;
|
||||
return NETERR_NOROUTE; //eof or something
|
||||
}
|
||||
return NETERR_SENT;
|
||||
}
|
||||
static neterr_t OSSL_Received(void *ctx, sizebuf_t *message)
|
||||
{ //we have received some encrypted data...
|
||||
ossldtls_t *o = (ossldtls_t*)ctx;
|
||||
int r;
|
||||
|
||||
o->pending = message->data;
|
||||
o->pendingsize = message->cursize;
|
||||
r = BIO_read(o->bio, message->data, message->maxsize);
|
||||
o->pending = NULL;
|
||||
o->pendingsize = 0;
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
message->cursize = r;
|
||||
return NETERR_SENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BIO_should_io_special(o->bio))
|
||||
{
|
||||
switch(BIO_get_retry_reason(o->bio))
|
||||
{
|
||||
//these are temporary errors, try again later.
|
||||
case BIO_RR_SSL_X509_LOOKUP:
|
||||
return NETERR_NOROUTE; //certificate failure.
|
||||
case BIO_RR_ACCEPT:
|
||||
case BIO_RR_CONNECT:
|
||||
return NETERR_NOROUTE; //should never happen
|
||||
}
|
||||
}
|
||||
if (BIO_should_retry(o->bio))
|
||||
return 0;
|
||||
return NETERR_NOROUTE; //eof or something
|
||||
}
|
||||
return NETERR_NOROUTE;
|
||||
}
|
||||
static neterr_t OSSL_Timeouts(void *ctx)
|
||||
{ //keep it ticking over, or something.
|
||||
return OSSL_Received(ctx, NULL);
|
||||
}
|
||||
|
||||
static dtlsfuncs_t ossl_dtlsfuncs =
|
||||
{
|
||||
OSSL_CreateContext,
|
||||
OSSL_DestroyContext,
|
||||
OSSL_Transmit,
|
||||
OSSL_Received,
|
||||
OSSL_Timeouts
|
||||
};
|
||||
static const dtlsfuncs_t *OSSL_InitClient(void)
|
||||
{
|
||||
if (OSSL_Init())
|
||||
return &ossl_dtlsfuncs;
|
||||
return NULL;
|
||||
}
|
||||
static const dtlsfuncs_t *OSSL_InitServer(void)
|
||||
{
|
||||
if (OSSL_Init())
|
||||
return &ossl_dtlsfuncs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static qboolean OSSL_Init(void)
|
||||
{
|
||||
static qboolean inited;
|
||||
static qboolean init_success;
|
||||
if (inited)
|
||||
return init_success;
|
||||
#ifdef LOADERTHREAD
|
||||
Sys_LockMutex(com_resourcemutex);
|
||||
if (inited) //now check again, just in case
|
||||
{
|
||||
Sys_UnlockMutex(com_resourcemutex);
|
||||
return init_success;
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
// OPENSSL_config(NULL);
|
||||
ERR_print_errors_cb(OSSL_PrintError_CB, NULL);
|
||||
|
||||
OSSL_OpenPubKey();
|
||||
OSSL_OpenPrivKey();
|
||||
|
||||
biometh_vfs = BIO_meth_new(BIO_get_new_index()|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR, "fte_vfs");
|
||||
if (biometh_vfs)
|
||||
{
|
||||
BIO_meth_set_write(biometh_vfs, OSSL_Bio_FWrite);
|
||||
BIO_meth_set_read(biometh_vfs, OSSL_Bio_FRead);
|
||||
BIO_meth_set_puts(biometh_vfs, OSSL_Bio_FPuts); //I cannot see how gets/puts can work with dtls...
|
||||
// BIO_meth_set_gets(biometh_vfs, OSSL_Bio_FGets);
|
||||
BIO_meth_set_ctrl(biometh_vfs, OSSL_Bio_FCtrl);
|
||||
BIO_meth_set_create(biometh_vfs, OSSL_Bio_FCreate);
|
||||
BIO_meth_set_destroy(biometh_vfs, OSSL_Bio_FDestroy);
|
||||
BIO_meth_set_callback_ctrl(biometh_vfs, OSSL_Bio_FOtherCtrl);
|
||||
init_success |= 1;
|
||||
}
|
||||
|
||||
biometh_dtls = BIO_meth_new(BIO_get_new_index()|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR, "fte_dtls");
|
||||
if (biometh_dtls)
|
||||
{
|
||||
BIO_meth_set_write(biometh_dtls, OSSL_Bio_DWrite);
|
||||
BIO_meth_set_read(biometh_dtls, OSSL_Bio_DRead);
|
||||
// BIO_meth_set_puts(biometh_dtls, OSSL_Bio_DPuts); //I cannot see how gets/puts can work with dtls...
|
||||
// BIO_meth_set_gets(biometh_dtls, OSSL_Bio_DGets);
|
||||
BIO_meth_set_ctrl(biometh_dtls, OSSL_Bio_DCtrl);
|
||||
BIO_meth_set_create(biometh_dtls, OSSL_Bio_DCreate);
|
||||
BIO_meth_set_destroy(biometh_dtls, OSSL_Bio_DDestroy);
|
||||
BIO_meth_set_callback_ctrl(biometh_dtls, OSSL_Bio_DOtherCtrl);
|
||||
init_success |= 2;
|
||||
}
|
||||
|
||||
ossl_fte_certctx = SSL_get_ex_new_index(0, "ossl_fte_certctx", NULL, NULL, NULL);
|
||||
|
||||
inited = true;
|
||||
#ifdef LOADERTHREAD
|
||||
Sys_UnlockMutex(com_resourcemutex);
|
||||
#endif
|
||||
return init_success;
|
||||
}
|
||||
|
||||
static enum hashvalidation_e OSSL_VerifyHash(const qbyte *hashdata, size_t hashsize, const qbyte *pubkeydata, size_t pubkeysize, const qbyte *signdata, size_t signsize)
|
||||
{
|
||||
int result = VH_UNSUPPORTED;
|
||||
BIO *bio_pubkey = BIO_new_mem_buf(pubkeydata, pubkeysize);
|
||||
if (bio_pubkey)
|
||||
{
|
||||
X509 *x509_pubkey = PEM_read_bio_X509(bio_pubkey, NULL, NULL, NULL);
|
||||
if (x509_pubkey)
|
||||
{
|
||||
EVP_PKEY *evp_pubkey = X509_get_pubkey(x509_pubkey);
|
||||
if (evp_pubkey)
|
||||
{
|
||||
RSA *rsa_pubkey = EVP_PKEY_get1_RSA(evp_pubkey);
|
||||
if (rsa_pubkey)
|
||||
{
|
||||
if (1 == RSA_verify(NID_sha512, hashdata, hashsize, signdata, signsize, rsa_pubkey))
|
||||
result = VH_CORRECT;
|
||||
else
|
||||
result = VH_INCORRECT;
|
||||
RSA_free(rsa_pubkey);
|
||||
}
|
||||
EVP_PKEY_free(evp_pubkey);
|
||||
}
|
||||
X509_free(x509_pubkey);
|
||||
}
|
||||
BIO_free(bio_pubkey);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ftecrypto_t crypto_openssl =
|
||||
{
|
||||
"OpenSSL",
|
||||
OSSL_OpenVFS,
|
||||
NULL,//OSSL_GetChannelBinding,
|
||||
OSSL_InitClient,
|
||||
OSSL_InitServer,
|
||||
OSSL_VerifyHash,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void *TLS_GetKnownCertificate(const char *certname, size_t *size){return NULL;}
|
||||
qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize, unsigned int certlogproblems){return false;}
|
||||
qboolean Plug_Init(void)
|
||||
{
|
||||
fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs));
|
||||
if (!fsfuncs)
|
||||
return false;
|
||||
return plugfuncs->ExportInterface("Crypto", &crypto_openssl, sizeof(crypto_openssl)); //export a named interface struct to the engine
|
||||
}
|
Loading…
Reference in a new issue