diff --git a/Makefile b/Makefile
index aadb6ee98..4c1107ce5 100644
--- a/Makefile
+++ b/Makefile
@@ -23,6 +23,8 @@ TARGET := $(ENAME)
TRACK_DEPENDENCIES=1
# link using C Compiler by default
LINK = $(CC)
+# Whether to add BearSSL source files to list of files to compile
+BEARSSL=1
#################################################################
@@ -73,13 +75,11 @@ endif
ifeq ($(PLAT),linux)
LIBS = -lX11 -lXi -lpthread -lGL -ldl
BUILD_DIR = build/linux
- BEARSSL = 1
endif
ifeq ($(PLAT),sunos)
LIBS = -lsocket -lX11 -lXi -lGL
BUILD_DIR = build/solaris
- BEARSSL = 1
endif
ifeq ($(PLAT),hp-ux)
@@ -87,7 +87,6 @@ ifeq ($(PLAT),hp-ux)
LDFLAGS =
LIBS = -lm -lX11 -lXi -lXext -L/opt/graphics/OpenGL/lib -lGL -lpthread
BUILD_DIR = build/hpux
- BEARSSL = 1
endif
ifeq ($(PLAT),darwin)
@@ -96,7 +95,6 @@ ifeq ($(PLAT),darwin)
LDFLAGS = -rdynamic -framework Cocoa -framework OpenGL -framework IOKit -lobjc
BUILD_DIR = build/macos
TARGET = $(ENAME).app
- BEARSSL = 1
endif
ifeq ($(PLAT),freebsd)
@@ -104,7 +102,6 @@ ifeq ($(PLAT),freebsd)
LDFLAGS = -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/freebsd
- BEARSSL = 1
endif
ifeq ($(PLAT),openbsd)
@@ -112,7 +109,6 @@ ifeq ($(PLAT),openbsd)
LDFLAGS = -L /usr/X11R6/lib -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/openbsd
- BEARSSL = 1
endif
ifeq ($(PLAT),netbsd)
@@ -120,7 +116,6 @@ ifeq ($(PLAT),netbsd)
LDFLAGS = -L /usr/X11R7/lib -L /usr/pkg/lib -rdynamic -Wl,-R/usr/X11R7/lib
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/netbsd
- BEARSSL = 1
endif
ifeq ($(PLAT),dragonfly)
@@ -128,7 +123,6 @@ ifeq ($(PLAT),dragonfly)
LDFLAGS = -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/flybsd
- BEARSSL = 1
endif
ifeq ($(PLAT),haiku)
@@ -138,7 +132,6 @@ ifeq ($(PLAT),haiku)
LINK = $(CXX)
LIBS = -lGL -lnetwork -lbe -lgame -ltracker
BUILD_DIR = build/haiku
- BEARSSL = 1
endif
ifeq ($(PLAT),beos)
@@ -148,20 +141,25 @@ ifeq ($(PLAT),beos)
LINK = $(CXX)
LIBS = -lGL -lnetwork -lbe -lgame -ltracker
BUILD_DIR = build/beos
- TRACK_DEPENDENCIES=0
+ TRACK_DEPENDENCIES = 0
+ BEARSSL = 0
endif
ifeq ($(PLAT),serenityos)
LIBS = -lgl -lSDL2
BUILD_DIR = build/serenity
- BEARSSL = 1
endif
ifeq ($(PLAT),irix)
CC = gcc
LIBS = -lGL -lX11 -lXi -lpthread -ldl
BUILD_DIR = build/irix
- BEARSSL = 1
+endif
+
+ifeq ($(PLAT),rpi)
+ CFLAGS += -DCC_BUILD_RPI
+ LIBS = -lpthread -lX11 -lXi -lEGL -lGLESv2 -ldl
+ BUILD_DIR = build/rpi
endif
ifeq ($(PLAT),riscos)
@@ -176,6 +174,7 @@ ifeq ($(PLAT),dos)
LDFLAGS = -g
OEXT = .exe
BUILD_DIR = build/dos
+ BEARSSL = 0
endif
@@ -192,12 +191,11 @@ ifdef TERMINAL
LIBS := $(subst mwindows,mconsole,$(LIBS))
endif
-ifdef BEARSSL
+ifeq ($(BEARSSL),1)
BUILD_DIRS += $(BUILD_DIR)/third_party/bearssl
BEARSSL_SOURCES = $(wildcard third_party/bearssl/*.c)
BEARSSL_OBJECTS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(BEARSSL_SOURCES))
OBJECTS += $(BEARSSL_OBJECTS)
- CFLAGS += -DCC_SSL_BACKEND=CC_SSL_BACKEND_BEARSSL -DCC_NET_BACKEND=CC_NET_BACKEND_BUILTIN
endif
ifdef RELEASE
diff --git a/misc/windows/min-wincrypt.h b/misc/windows/min-wincrypt.h
index 715ee0f7a..6c0f30026 100644
--- a/misc/windows/min-wincrypt.h
+++ b/misc/windows/min-wincrypt.h
@@ -2,17 +2,79 @@
#define CC_CRYPT32_FUNC
#endif
+typedef void* HCERTSTORE;
+typedef void* PCCERT_CONTEXT;
+
+#define szOID_PKIX_KP_SERVER_AUTH "1.3.6.1.5.5.7.3.1"
+#define szOID_SERVER_GATED_CRYPTO "1.3.6.1.4.1.311.10.3.3"
+#define szOID_SGC_NETSCAPE "2.16.840.1.113730.4.1"
+
+#define CERT_STORE_PROV_MEMORY ((LPCSTR)2)
+#define CERT_STORE_ADD_ALWAYS 4
+#define X509_ASN_ENCODING 0x1
+
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData;
BYTE* pbData;
} DATA_BLOB;
+typedef struct _CTL_USAGE {
+ DWORD cUsageIdentifier;
+ LPSTR *rgpszUsageIdentifier;
+} CERT_ENHKEY_USAGE;
+
+#define USAGE_MATCH_TYPE_AND 0x0
+#define USAGE_MATCH_TYPE_OR 0x1
+
+typedef struct _CERT_USAGE_MATCH {
+ DWORD dwType;
+ CERT_ENHKEY_USAGE Usage;
+} CERT_USAGE_MATCH;
+
+typedef struct _CERT_CHAIN_PARA {
+ DWORD cbSize;
+ CERT_USAGE_MATCH RequestedUsage;
+} CERT_CHAIN_PARA;
+
+typedef struct _CERT_TRUST_STATUS {
+ DWORD dwErrorStatus;
+ DWORD dwInfoStatus;
+} CERT_TRUST_STATUS, *PCERT_TRUST_STATUS;
+
+typedef struct _CERT_CHAIN_CONTEXT {
+ DWORD cbSize;
+ CERT_TRUST_STATUS TrustStatus;
+ DWORD cChain;
+ void* rgpChain;
+ DWORD cLowerQualityChainContext;
+ void* rgpLowerQualityChainContext;
+ BOOL fHasRevocationFreshnessTime;
+ DWORD dwRevocationFreshnessTime;
+ DWORD dwCreateFlags;
+ GUID ChainId;
+} CERT_CHAIN_CONTEXT, *PCERT_CHAIN_CONTEXT;
+typedef const CERT_CHAIN_CONTEXT* PCCERT_CHAIN_CONTEXT;
+
+
CC_CRYPT32_FUNC BOOL (WINAPI *_CryptProtectData )(DATA_BLOB* dataIn, PCWSTR dataDescr, PVOID entropy, PVOID reserved, PVOID promptStruct, DWORD flags, DATA_BLOB* dataOut);
CC_CRYPT32_FUNC BOOL (WINAPI *_CryptUnprotectData)(DATA_BLOB* dataIn, PWSTR* dataDescr, PVOID entropy, PVOID reserved, PVOID promptStruct, DWORD flags, DATA_BLOB* dataOut);
+CC_CRYPT32_FUNC HCERTSTORE (WINAPI *_CertOpenStore)(LPCSTR storeProvider, DWORD encodingType, void* cryptProv, DWORD flags, const void* para);
+CC_CRYPT32_FUNC BOOL (WINAPI *_CertCloseStore)(HCERTSTORE certStore, DWORD flags);
+CC_CRYPT32_FUNC BOOL (WINAPI *_CertAddEncodedCertificateToStore)(HCERTSTORE certStore, DWORD certEncodingType, const BYTE* certEncoded, DWORD lenEncoded, DWORD addDisposition, PCCERT_CONTEXT* certContext);
+
+CC_CRYPT32_FUNC BOOL (WINAPI *_CertGetCertificateChain)(PVOID chainEngine, PCCERT_CONTEXT certContext, LPFILETIME time, HCERTSTORE additionalStore, CERT_CHAIN_PARA* chainPara, DWORD flags, PVOID reserved, PCCERT_CHAIN_CONTEXT* chainContext);
+CC_CRYPT32_FUNC void (WINAPI *_CertFreeCertificateChain)(PCCERT_CHAIN_CONTEXT chainContext);
+
+CC_CRYPT32_FUNC BOOL (WINAPI *_CertFreeCertificateContext)(PCCERT_CONTEXT certContext);
+
static void Crypt32_LoadDynamicFuncs(void) {
static const struct DynamicLibSym funcs[] = {
- DynamicLib_OptSym(CryptProtectData), DynamicLib_OptSym(CryptUnprotectData)
+ DynamicLib_OptSym(CryptProtectData), DynamicLib_OptSym(CryptUnprotectData),
+ DynamicLib_ReqSym(CertGetCertificateChain), DynamicLib_ReqSym(CertFreeCertificateChain),
+ DynamicLib_ReqSym(CertOpenStore), DynamicLib_ReqSym(CertCloseStore),
+ DynamicLib_ReqSym(CertAddEncodedCertificateToStore),
+ DynamicLib_ReqSym(CertFreeCertificateContext),
};
static const cc_string crypt32 = String_FromConst("CRYPT32.DLL");
@@ -20,4 +82,4 @@ static void Crypt32_LoadDynamicFuncs(void) {
if (crypt32_lib) return;
DynamicLib_LoadAll(&crypt32, funcs, Array_Elems(funcs), &crypt32_lib);
-}
\ No newline at end of file
+}
diff --git a/readme.md b/readme.md
index 450f9a12a..a12917b7b 100644
--- a/readme.md
+++ b/readme.md
@@ -117,14 +117,18 @@ Assuming that you used the installer from https://sourceforge.net/projects/mingw
1. Install MinGW-W64
2. Use either *Run Terminal* from Start Menu or run *mingw-w64.bat* in the installation folder
3. Navigate to the directory with ClassiCube's source code
-4. Run `gcc -fno-math-errno *.c -o ClassiCube.exe -mwindows -lwinmm`
+4. Run either:
+ * `make mingw` - produces a simple non-optimised executable, easier to debug
+ * `make mingw RELEASE=1` - produces an optimised executable, harder to debug
##### Using MinGW
Assuming that you used the installer from https://osdn.net/projects/mingw/ :
1. Install MinGW. You need mingw32-base-bin and msys-base-bin packages.
2. Run *msys.bat* in the *C:\MinGW\msys\1.0* folder.
-2. Navigate to the directory with ClassiCube's source code
-4. Run `gcc -fno-math-errno *.c -o ClassiCube.exe -mwindows -lwinmm`
+3. Navigate to the directory with ClassiCube's source code
+4. Run either:
+ * `make mingw` - produces a simple non-optimised executable, easier to debug
+ * `make mingw RELEASE=1` - produces an optimised executable, harder to debug
##### Using TCC (Tiny C Compiler)
Setting up TCC:
@@ -135,7 +139,7 @@ Setting up TCC:
Compiling with TCC:
1. Navigate to the directory with ClassiCube's source code
2. In `ExtMath.c`, change `fabsf` to `fabs` and `sqrtf` to `sqrt`
-3. Run `tcc.exe -o ClassiCube.exe *.c -lwinmm -lgdi32 -luser32 -lcomdlg32 -lshell32`
+3. Run `tcc.exe -o ClassiCube.exe src/*.c third_party/bearssl/*.c -lwinmm -lgdi32 -luser32 -lcomdlg32 -lshell32`
(Note: You may need to specify the full path to `tcc.exe` instead of just `tcc.exe`)
## Compiling - Linux
@@ -149,16 +153,16 @@ For Ubuntu, these are the `libx11-dev`, `libxi-dev` and `libgl1-mesa-dev` packag
##### Cross compiling for Windows (32 bit):
1. Install MinGW-w64 if necessary. (Ubuntu: `gcc-mingw-w64` package)
-2. Run ```i686-w64-mingw32-gcc -fno-math-errno src/*.c -o ClassiCube.exe -mwindows -lwinmm```
+2. Run ```make mingw CC=i686-w64-mingw32-gcc```
##### Cross compiling for Windows (64 bit):
1. Install MinGW-w64 if necessary. (Ubuntu: `gcc-mingw-w64` package)
-2. Run ```x86_64-w64-mingw32-gcc -fno-math-errno src/*.c -o ClassiCube.exe -mwindows -lwinmm```
+2. Run ```make mingw CC=x86_64-w64-mingw32-gcc```
##### Raspberry Pi
Although the regular linux compiliation flags will work fine, to take full advantage of the hardware:
-```gcc -fno-math-errno src/*.c -o ClassiCube -DCC_BUILD_RPI -rdynamic -lpthread -lX11 -lXi -lEGL -lGLESv2 -ldl```
+```make rpi```
## Compiling - macOS
1. Install a C compiler if necessary. The easiest way of obtaining one is by installing **Xcode**.
diff --git a/src/Certs.c b/src/Certs.c
index baf3046c3..561dc6858 100644
--- a/src/Certs.c
+++ b/src/Certs.c
@@ -288,6 +288,78 @@ int Certs_VerifyChain(struct X509CertContext* x509) {
return JavaSCall_Int(env, JAVA_sslVerifyChain, NULL);
}
+#elif CC_CRT_BACKEND == CC_CRT_BACKEND_WINCRYPTO
+#define CC_CRYPT32_FUNC extern
+#include "Funcs.h"
+
+#define WIN32_LEAN_AND_MEAN
+#define NOSERVICE
+#define NOMCX
+#define NOIME
+#ifndef UNICODE
+#define UNICODE
+#define _UNICODE
+#endif
+
+#include
+/* Compatibility versions so compiling works on older Windows SDKs */
+#include "../misc/windows/min-wincrypt.h" /* #include */
+
+void CertsBackend_Init(void) {
+ Crypt32_LoadDynamicFuncs();
+}
+
+static const LPCSTR const usage[] = {
+ szOID_PKIX_KP_SERVER_AUTH,
+ szOID_SERVER_GATED_CRYPTO,
+ szOID_SGC_NETSCAPE
+};
+
+static BOOL BuildChain(struct X509CertContext* x509, HCERTSTORE store, PCCERT_CONTEXT* end_cert, PCCERT_CHAIN_CONTEXT* chain) {
+ struct X509Cert* cert = &x509->certs[0];
+ CERT_CHAIN_PARA para = { 0 };
+ int i;
+
+ BOOL ok = _CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, cert->data, cert->offset,
+ CERT_STORE_ADD_ALWAYS, end_cert);
+ if (!ok || !(*end_cert)) return FALSE;
+
+ for (i = 1; i < x509->numCerts; i++)
+ {
+ cert = &x509->certs[i];
+ ok = _CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, cert->data, cert->offset,
+ CERT_STORE_ADD_ALWAYS, NULL);
+
+ }
+
+ para.cbSize = sizeof(para);
+ para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+ para.RequestedUsage.Usage.cUsageIdentifier = Array_Elems(usage);
+ para.RequestedUsage.Usage.rgpszUsageIdentifier = (LPSTR*)usage;
+
+ return _CertGetCertificateChain(NULL, *end_cert, NULL, NULL, ¶, 0, NULL, chain);
+}
+
+int Certs_VerifyChain(struct X509CertContext* x509) {
+ PCCERT_CHAIN_CONTEXT chain = NULL;
+ PCCERT_CONTEXT end_cert = NULL;
+ HCERTSTORE store;
+ DWORD res = 200;
+
+ if (!_CertOpenStore) return ERR_NOT_SUPPORTED;
+ store = _CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL);
+ if (!store) return ERR_NOT_SUPPORTED;
+
+ if (BuildChain(x509, store, &end_cert, &chain)) {
+ res = chain->TrustStatus.dwErrorStatus;
+ if (res) Platform_Log1("Cert validation failed: %h", &res);
+ }
+
+ _CertFreeCertificateChain(chain);
+ _CertFreeCertificateContext(end_cert);
+ _CertCloseStore(store, 0);
+ return res;
+}
#endif
#endif
diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj
index 3ea71e143..80aa3886a 100644
--- a/src/ClassiCube.vcxproj
+++ b/src/ClassiCube.vcxproj
@@ -188,7 +188,7 @@
true
5.02
main
- opengl32.lib;Winmm.lib;crypt32.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;crypt32.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
@@ -208,7 +208,7 @@
Windows
true
main
- opengl32.lib;Winmm.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
@@ -230,7 +230,7 @@
true
5.02
main
- opengl32.lib;Winmm.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
@@ -252,7 +252,7 @@
true
5.02
main
- opengl32.lib;Winmm.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;ucrtd.lib;vcruntimed.lib;msvcrtd.lib;%(AdditionalDependencies)
@@ -281,7 +281,7 @@
5.02
Default
main
- opengl32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
@@ -308,7 +308,7 @@
true
true
main
- opengl32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
@@ -338,7 +338,7 @@
5.02
Default
main
- opengl32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
@@ -368,7 +368,7 @@
5.02
Default
main
- opengl32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
+ crypt32.lib;Winmm.lib;libucrt.lib;libvcruntime.lib;%(AdditionalDependencies)
@@ -452,9 +452,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters
index 052217a08..12c91f621 100644
--- a/src/ClassiCube.vcxproj.filters
+++ b/src/ClassiCube.vcxproj.filters
@@ -127,6 +127,9 @@
{cd88d7cb-c252-4b8f-8f90-c776cfc1e6b6}
+
+ {dec80279-6e40-46a8-b024-ee04e8931638}
+
@@ -635,6 +638,363 @@
Source Files
+
+ Source Files\Network
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
+
+ Source Files\BearSSL
+
diff --git a/src/Core.h b/src/Core.h
index f468ce1ec..375972ca2 100644
--- a/src/Core.h
+++ b/src/Core.h
@@ -147,16 +147,15 @@ typedef cc_uint8 cc_bool;
#define CC_GFX_BACKEND_VULKAN 6
#define CC_GFX_BACKEND_GL11 7
-#define CC_SSL_BACKEND_NONE 1
-#define CC_SSL_BACKEND_BEARSSL 2
-#define CC_SSL_BACKEND_SCHANNEL 3
+#define CC_SSL_BACKEND_NONE 1
+#define CC_SSL_BACKEND_BEARSSL 2
-#define CC_NET_BACKEND_BUILTIN 1
-#define CC_NET_BACKEND_LIBCURL 2
+#define CC_NET_BACKEND_BUILTIN 1
-#define CC_CRT_BACKEND_OPENSSL 1
-#define CC_CRT_BACKEND_APPLESEC 2
-#define CC_CRT_BACKEND_ANDROID 3
+#define CC_CRT_BACKEND_OPENSSL 1
+#define CC_CRT_BACKEND_APPLESEC 2
+#define CC_CRT_BACKEND_ANDROID 3
+#define CC_CRT_BACKEND_WINCRYPTO 4
#define CC_AUD_BACKEND_OPENAL 1
#define CC_AUD_BACKEND_WINMM 2
@@ -213,7 +212,8 @@ typedef cc_uint8 cc_bool;
#elif defined _WIN32 && !defined __WINSCW__
#define CC_BUILD_WIN
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
- #define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_SCHANNEL
+ #define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
+ #define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_WINCRYPTO
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_WINMM
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_D3D9
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_WIN32
diff --git a/src/Platform_Windows.c b/src/Platform_Windows.c
index 160298225..a9dd02b00 100644
--- a/src/Platform_Windows.c
+++ b/src/Platform_Windows.c
@@ -17,16 +17,10 @@
#define _UNICODE
#endif
#include
-/*
-#include
-#include
-#include
-#include
-*/
-/* Compatibility versions so compiling works on older Windows SDKs */
-#include "../misc/windows/min-winsock2.h"
-#include "../misc/windows/min-shellapi.h"
-#include "../misc/windows/min-wincrypt.h"
+/* Use own minimal versions of WinAPI headers so that compiling works on older Windows SDKs */
+#include "../misc/windows/min-winsock2.h" /* #include #include */
+#include "../misc/windows/min-shellapi.h" /* #include */
+#include "../misc/windows/min-wincrypt.h" /* #include */
#include "../misc/windows/min-kernel32.h"
static HANDLE heap;
diff --git a/src/SSL.c b/src/SSL.c
index 9c665035b..12bc3222a 100644
--- a/src/SSL.c
+++ b/src/SSL.c
@@ -1,410 +1,7 @@
#include "SSL.h"
#include "Errors.h"
-#if CC_SSL_BACKEND == CC_SSL_BACKEND_SCHANNEL
-#define WIN32_LEAN_AND_MEAN
-#define NOSERVICE
-#define NOMCX
-#define NOIME
-#define NOMINMAX
-#include
-#define SECURITY_WIN32
-#include
-#include
-#include "Platform.h"
-#include "String.h"
-#include "Funcs.h"
-
-/* https://gist.github.com/mmozeiko/c0dfcc8fec527a90a02145d2cc0bfb6d */
-/* https://web.archive.org/web/20210116110926/http://www.coastrd.com/c-schannel-smtp */
-
-/* https://hpbn.co/transport-layer-security-tls/ */
-#define TLS_MAX_PACKET_SIZE (16384 + 512) /* 16kb record size + header/mac/padding */
-/* TODO: Check against sizes.cbMaximumMessage */
-
-static void* schannel_lib;
-static INIT_SECURITY_INTERFACE_A _InitSecurityInterfaceA;
-static cc_bool _verifyCerts;
-
-static ACQUIRE_CREDENTIALS_HANDLE_FN_A FP_AcquireCredentialsHandleA;
-static FREE_CREDENTIALS_HANDLE_FN FP_FreeCredentialsHandle;
-static INITIALIZE_SECURITY_CONTEXT_FN_A FP_InitializeSecurityContextA;
-static ACCEPT_SECURITY_CONTEXT_FN FP_AcceptSecurityContext;
-static COMPLETE_AUTH_TOKEN_FN FP_CompleteAuthToken;
-static DELETE_SECURITY_CONTEXT_FN FP_DeleteSecurityContext;
-static QUERY_CONTEXT_ATTRIBUTES_FN_A FP_QueryContextAttributesA;
-static FREE_CONTEXT_BUFFER_FN FP_FreeContextBuffer;
-static ENCRYPT_MESSAGE_FN FP_EncryptMessage;
-static DECRYPT_MESSAGE_FN FP_DecryptMessage;
-
-void SSLBackend_Init(cc_bool verifyCerts) {
- /* secur32.dll is available on Win9x and later */
- /* Security.dll is available on NT 4 and later */
-
- /* Officially, InitSecurityInterfaceA and then AcquireCredentialsA from */
- /* secur32.dll (or security.dll) should be called - however */
- /* AcquireCredentialsA fails with SEC_E_SECPKG_NOT_FOUND on Win 9x */
- /* But if you instead directly call those functions from schannel.dll, */
- /* then it DOES work. (and on later Windows versions, those functions */
- /* exported from schannel.dll are just DLL forwards to secur32.dll */
- static const struct DynamicLibSym funcs[] = {
- DynamicLib_ReqSym(InitSecurityInterfaceA)
- };
- static const cc_string schannel = String_FromConst("schannel.dll");
- _verifyCerts = verifyCerts;
- /* TODO: Load later?? it's unsafe to do on a background thread though */
- DynamicLib_LoadAll(&schannel, funcs, Array_Elems(funcs), &schannel_lib);
-}
-
-cc_bool SSLBackend_DescribeError(cc_result res, cc_string* dst) {
- switch (res) {
- case SEC_E_UNTRUSTED_ROOT:
- String_AppendConst(dst, "The website's SSL certificate was issued by an authority that is not trusted");
- return true;
- case SEC_E_CERT_EXPIRED:
- String_AppendConst(dst, "The website's SSL certificate has expired");
- return true;
- case TRUST_E_CERT_SIGNATURE:
- String_AppendConst(dst, "The signature of the website's SSL certificate cannot be verified");
- return true;
- case SEC_E_UNSUPPORTED_FUNCTION:
- /* https://learn.microsoft.com/en-us/windows/win32/secauthn/schannel-error-codes-for-tls-and-ssl-alerts */
- /* TLS1_ALERT_PROTOCOL_VERSION maps to this error code */
- String_AppendConst(dst, "The website uses an incompatible SSL/TLS version");
- return true;
- }
- return false;
-}
-
-
-struct SSLContext {
- cc_socket socket;
- CredHandle handle;
- CtxtHandle context;
- SecPkgContext_StreamSizes sizes;
- DWORD flags;
- int bufferLen;
- int leftover; /* number of unprocessed bytes leftover from last successful DecryptMessage */
- int decryptedSize;
- char* decryptedData;
- char incoming[TLS_MAX_PACKET_SIZE];
-};
-
-/* Undefined in older MinGW versions */
-#define _SP_PROT_TLS1_1_CLIENT 0x00000200
-#define _SP_PROT_TLS1_2_CLIENT 0x00000800
-
-static SECURITY_STATUS SSL_CreateHandle(struct SSLContext* ctx) {
- SCHANNEL_CRED cred = { 0 };
- cred.dwVersion = SCHANNEL_CRED_VERSION;
- cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | (_verifyCerts ? SCH_CRED_AUTO_CRED_VALIDATION : SCH_CRED_MANUAL_CRED_VALIDATION);
- cred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | _SP_PROT_TLS1_1_CLIENT | _SP_PROT_TLS1_2_CLIENT;
-
- /* TODO: SCHANNEL_NAME_A ? */
- return FP_AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
- &cred, NULL, NULL, &ctx->handle, NULL);
-}
-
-static cc_result SSL_RecvRaw(struct SSLContext* ctx) {
- cc_uint32 read;
- cc_result res;
-
- /* server is sending too much garbage data instead of proper TLS packets ?? */
- if (ctx->bufferLen == sizeof(ctx->incoming)) return ERR_INVALID_ARGUMENT;
-
- res = Socket_Read(ctx->socket, ctx->incoming + ctx->bufferLen,
- sizeof(ctx->incoming) - ctx->bufferLen, &read);
-
- if (res) return res;
- if (!read) return ERR_END_OF_STREAM;
-
- ctx->bufferLen += read;
- return 0;
-}
-
-
-/* Sends the initial TLS handshake ClientHello message to the server */
-static SECURITY_STATUS SSL_Connect(struct SSLContext* ctx, const char* hostname) {
- SecBuffer out_buffers[1];
- SecBufferDesc out_desc;
- SECURITY_STATUS res;
- DWORD flags = ctx->flags;
-
- out_buffers[0].BufferType = SECBUFFER_TOKEN;
- out_buffers[0].pvBuffer = NULL;
- out_buffers[0].cbBuffer = 0;
-
- out_desc.ulVersion = SECBUFFER_VERSION;
- out_desc.cBuffers = Array_Elems(out_buffers);
- out_desc.pBuffers = out_buffers;
-
- res = FP_InitializeSecurityContextA(&ctx->handle, NULL, (char*)hostname, flags, 0, 0,
- NULL, 0, &ctx->context, &out_desc, &flags, NULL);
- if (res != SEC_I_CONTINUE_NEEDED) return res;
- res = 0;
-
- /* Send initial handshake to the server (if there is one) */
- if (out_buffers[0].pvBuffer) {
- res = Socket_WriteAll(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer);
- FP_FreeContextBuffer(out_buffers[0].pvBuffer);
- }
- return res;
-}
-
-/* Performs (Negotiates) the rest of the TLS handshake */
-static SECURITY_STATUS SSL_Negotiate(struct SSLContext* ctx) {
- SecBuffer in_buffers[2];
- SecBuffer out_buffers[1];
- SecBufferDesc in_desc;
- SecBufferDesc out_desc;
- cc_uint32 leftover_len;
- SECURITY_STATUS sec;
- cc_result res;
- DWORD flags;
-
- for (;;)
- {
- /* buffer 0 = data received from server which SChannel processes */
- /* buffer 1 = any leftover data which SChannel didn't process this time */
- /* (this data must be persisted, as it will be used next time around) */
- in_buffers[0].BufferType = SECBUFFER_TOKEN;
- in_buffers[0].pvBuffer = ctx->incoming;
- in_buffers[0].cbBuffer = ctx->bufferLen;
- in_buffers[1].BufferType = SECBUFFER_EMPTY;
- in_buffers[1].pvBuffer = NULL;
- in_buffers[1].cbBuffer = 0;
-
- out_buffers[0].BufferType = SECBUFFER_TOKEN;
- out_buffers[0].pvBuffer = NULL;
- out_buffers[0].cbBuffer = 0;
-
- in_desc.ulVersion = SECBUFFER_VERSION;
- in_desc.cBuffers = Array_Elems(in_buffers);
- in_desc.pBuffers = in_buffers;
-
- out_desc.ulVersion = SECBUFFER_VERSION;
- out_desc.cBuffers = Array_Elems(out_buffers);
- out_desc.pBuffers = out_buffers;
-
- flags = ctx->flags;
- sec = FP_InitializeSecurityContextA(&ctx->handle, &ctx->context, NULL, flags, 0, 0,
- &in_desc, 0, NULL, &out_desc, &flags, NULL);
-
- if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
- /* SChannel didn't process the entirety of the input buffer */
- /* So move the leftover data back to the front of the input buffer */
- leftover_len = in_buffers[1].cbBuffer;
- Mem_Move(ctx->incoming, ctx->incoming + (ctx->bufferLen - leftover_len), leftover_len);
- ctx->bufferLen = leftover_len;
- } else if (sec != SEC_E_INCOMPLETE_MESSAGE) {
- /* SChannel processed entirely of input buffer */
- ctx->bufferLen = 0;
- }
-
- /* Handshake completed */
- if (sec == SEC_E_OK) break;
-
- /* Need to send data to the server */
- if (sec == SEC_I_CONTINUE_NEEDED) {
- res = Socket_WriteAll(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer);
- FP_FreeContextBuffer(out_buffers[0].pvBuffer); /* TODO always free? */
-
- if (res) return res;
- continue;
- }
-
- if (sec != SEC_E_INCOMPLETE_MESSAGE) return sec;
- /* SEC_E_INCOMPLETE_MESSAGE case - need to read more data from the server first */
- if ((res = SSL_RecvRaw(ctx))) return res;
- }
-
- FP_QueryContextAttributesA(&ctx->context, SECPKG_ATTR_STREAM_SIZES, &ctx->sizes);
- return 0;
-}
-
-
-static void SSL_LoadSecurityFunctions(PSecurityFunctionTableA sspiFPs) {
- FP_AcquireCredentialsHandleA = sspiFPs->AcquireCredentialsHandleA;
- FP_FreeCredentialsHandle = sspiFPs->FreeCredentialsHandle;
- FP_InitializeSecurityContextA = sspiFPs->InitializeSecurityContextA;
- FP_AcceptSecurityContext = sspiFPs->AcceptSecurityContext;
- FP_CompleteAuthToken = sspiFPs->CompleteAuthToken;
- FP_DeleteSecurityContext = sspiFPs->DeleteSecurityContext;
- FP_QueryContextAttributesA = sspiFPs->QueryContextAttributesA;
- FP_FreeContextBuffer = sspiFPs->FreeContextBuffer;
-
- FP_EncryptMessage = sspiFPs->EncryptMessage;
- FP_DecryptMessage = sspiFPs->DecryptMessage;
- /* Old Windows versions don't have EncryptMessage/DecryptMessage, */
- /* but have the older SealMessage/UnsealMessage functions instead */
- if (!FP_EncryptMessage) FP_EncryptMessage = (ENCRYPT_MESSAGE_FN)sspiFPs->Reserved3;
- if (!FP_DecryptMessage) FP_DecryptMessage = (DECRYPT_MESSAGE_FN)sspiFPs->Reserved4;
-}
-
-cc_result SSL_Init(cc_socket socket, const cc_string* host_, void** out_ctx) {
- PSecurityFunctionTableA sspiFPs;
- struct SSLContext* ctx;
- SECURITY_STATUS res;
- cc_winstring host;
- if (!_InitSecurityInterfaceA) return HTTP_ERR_NO_SSL;
-
- if (!FP_InitializeSecurityContextA) {
- sspiFPs = _InitSecurityInterfaceA();
- if (!sspiFPs) return ERR_NOT_SUPPORTED;
- SSL_LoadSecurityFunctions(sspiFPs);
- }
-
- ctx = Mem_TryAllocCleared(1, sizeof(struct SSLContext));
- if (!ctx) return ERR_OUT_OF_MEMORY;
- *out_ctx = (void*)ctx;
-
- ctx->flags = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
- if (!_verifyCerts) ctx->flags |= ISC_REQ_MANUAL_CRED_VALIDATION;
-
- ctx->socket = socket;
- Platform_EncodeString(&host, host_);
-
- if ((res = SSL_CreateHandle(ctx))) return res;
- if ((res = SSL_Connect(ctx, host.ansi))) return res;
- if ((res = SSL_Negotiate(ctx))) return res;
- return 0;
-}
-
-
-static cc_result SSL_ReadDecrypted(struct SSLContext* ctx, cc_uint8* data, cc_uint32 count, cc_uint32* read) {
- int len = min(count, ctx->decryptedSize);
- Mem_Copy(data, ctx->decryptedData, len);
-
- if (len == ctx->decryptedSize) {
- /* incoming buffer stores decrypted data and then any leftover ciphertext */
- /* So move the leftover ciphertext back to the start of the input buffer */
- /* TODO: Share function with handshake function */
- Mem_Move(ctx->incoming, ctx->incoming + (ctx->bufferLen - ctx->leftover), ctx->leftover);
- ctx->bufferLen = ctx->leftover;
- ctx->leftover = 0;
-
- ctx->decryptedData = NULL;
- ctx->decryptedSize = 0;
- } else {
- ctx->decryptedData += len;
- ctx->decryptedSize -= len;
- }
-
- *read = len;
- return 0;
-}
-
-cc_result SSL_Read(void* ctx_, cc_uint8* data, cc_uint32 count, cc_uint32* read) {
- struct SSLContext* ctx = ctx_;
- SecBuffer buffers[4];
- SecBufferDesc desc;
- SECURITY_STATUS sec;
- cc_result res;
-
- /* decrypted data from previously */
- if (ctx->decryptedData) return SSL_ReadDecrypted(ctx, data, count, read);
-
- for (;;)
- {
- /* if any ciphertext data, then try to decrypt it */
- if (ctx->bufferLen) {
- /* https://learn.microsoft.com/en-us/windows/win32/secauthn/stream-contexts */
- buffers[0].BufferType = SECBUFFER_DATA;
- buffers[0].pvBuffer = ctx->incoming;
- buffers[0].cbBuffer = ctx->bufferLen;
- buffers[1].BufferType = SECBUFFER_EMPTY;
- buffers[2].BufferType = SECBUFFER_EMPTY;
- buffers[3].BufferType = SECBUFFER_EMPTY;
-
- desc.ulVersion = SECBUFFER_VERSION;
- desc.cBuffers = Array_Elems(buffers);
- desc.pBuffers = buffers;
-
- sec = FP_DecryptMessage(&ctx->context, &desc, 0, NULL);
- if (sec == SEC_E_OK) {
- /* After successful decryption the SecBuffers will be: */
- /* buffers[0] = headers */
- /* buffers[1] = content */
- /* buffers[2] = trailers */
- /* buffers[3] = extra, if any leftover unprocessed data */
- ctx->decryptedData = buffers[1].pvBuffer;
- ctx->decryptedSize = buffers[1].cbBuffer;
- ctx->leftover = buffers[3].BufferType == SECBUFFER_EXTRA ? buffers[3].cbBuffer : 0;
-
- return SSL_ReadDecrypted(ctx, data, count, read);
- }
-
- /* TODO properly close the connection with TLS shutdown when this happens */
- if (sec == SEC_I_CONTEXT_EXPIRED) return SSL_ERR_CONTEXT_DEAD;
-
- if (sec != SEC_E_INCOMPLETE_MESSAGE) return sec;
- /* SEC_E_INCOMPLETE_MESSAGE case - still need to read more data from the server first */
- }
-
- /* not enough data received yet to decrypt, so need to read more data from the server */
- if ((res = SSL_RecvRaw(ctx))) return res;
- }
- return 0;
-}
-
-static cc_result SSL_WriteChunk(struct SSLContext* s, const cc_uint8* data, cc_uint32 count) {
- char buffer[TLS_MAX_PACKET_SIZE];
- SecBuffer buffers[3];
- SecBufferDesc desc;
- SECURITY_STATUS res;
- int total;
-
- /* https://learn.microsoft.com/en-us/windows/win32/secauthn/encryptmessage--schannel */
- buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
- buffers[0].pvBuffer = buffer;
- buffers[0].cbBuffer = s->sizes.cbHeader;
- buffers[1].BufferType = SECBUFFER_DATA;
- buffers[1].pvBuffer = buffer + s->sizes.cbHeader;
- buffers[1].cbBuffer = count;
- buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
- buffers[2].pvBuffer = buffer + s->sizes.cbHeader + count;
- buffers[2].cbBuffer = s->sizes.cbTrailer;
-
- /* See https://learn.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-encryptmessage */
- /* ".. The message is encrypted in place, overwriting the original contents of the structure" */
- Mem_Copy(buffers[1].pvBuffer, data, count);
-
- desc.ulVersion = SECBUFFER_VERSION;
- desc.cBuffers = Array_Elems(buffers);
- desc.pBuffers = buffers;
- if ((res = FP_EncryptMessage(&s->context, 0, &desc, 0))) return res;
-
- /* NOTE: Okay to write in one go, since all three buffers will be contiguous */
- /* (as TLS record header size will always be the same size) */
- total = buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer;
- return Socket_WriteAll(s->socket, buffer, total);
-}
-
-cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count) {
- struct SSLContext* s = ctx;
- cc_result res;
-
- /* TODO: Don't loop here? move to HTTPConnection instead?? */
- while (count)
- {
- int len = min(count, s->sizes.cbMaximumMessage);
- if ((res = SSL_WriteChunk(s, data, len))) return res;
-
- data += len;
- count -= len;
- }
- return 0;
-}
-
-cc_result SSL_Free(void* ctx_) {
- /* TODO send TLS close */
- struct SSLContext* ctx = (struct SSLContext*)ctx_;
- FP_DeleteSecurityContext(&ctx->context);
- FP_FreeCredentialsHandle(&ctx->handle);
- Mem_Free(ctx);
- return 0;
-}
-#elif CC_SSL_BACKEND == CC_SSL_BACKEND_BEARSSL
+#if CC_SSL_BACKEND == CC_SSL_BACKEND_BEARSSL
#include "String.h"
#include "Certs.h"
#include "../third_party/bearssl/bearssl.h"