macOS: Switch to BearSSL

This commit is contained in:
UnknownShadow200 2025-06-30 20:09:58 +10:00
parent c0cf269159
commit 1de9fa76f9
5 changed files with 892 additions and 762 deletions

File diff suppressed because it is too large Load Diff

View File

@ -60,20 +60,20 @@ Don't forget to add `-DCC_BUILD_GL11` to the compilation command line so that th
ClassiCube runs on: ClassiCube runs on:
* Windows - 95 and later * Windows - 95 and later
* macOS - 10.5 or later (can be compiled for 10.3/10.4 though) * macOS - 10.5 or later (can be compiled for 10.3/10.4 though)
* Linux - needs `libcurl` and `libopenal` * Linux - needs `libopenal`
* Android - 2.3 or later * Android - 2.3 or later
* iOS - 8.0 or later * iOS - 8.0 or later
* Most web browsers (even runs on IE11) * Most web browsers (even runs on IE11)
And also runs on: And also runs on:
* Raspberry Pi - needs <code>libcurl</code> and <code>libopenal</code> * Raspberry Pi - needs <code>libopenal</code>
* FreeBSD - needs <code>libexecinfo</code>, <code>curl</code> and <code>openal-soft</code> packages (can [download from here](https://www.classicube.net/download/#dl-fbsd)) * FreeBSD - needs <code>libexecinfo</code> and <code>openal-soft</code> packages (can [download from here](https://www.classicube.net/download/#dl-fbsd))
* NetBSD - needs <code>libexecinfo</code>, <code>curl</code> and <code>openal-soft</code> packages (can [download from here](https://www.classicube.net/download/#dl-nbsd)) * NetBSD - needs <code>libexecinfo</code> and <code>openal-soft</code> packages (can [download from here](https://www.classicube.net/download/#dl-nbsd))
* OpenBSD - needs <code>libexecinfo</code>, <code>curl</code> and <code>openal</code> packages * OpenBSD - needs <code>libexecinfo</code> and <code>openal</code> packages
* Solaris - needs <code>curl</code> and <code>openal</code> packages * Solaris - needs <code>openal</code> packages
* Haiku - needs <code>openal</code> package (if you have a GitHub account, can [download from here](https://github.com/ClassiCube/ClassiCube/actions/workflows/build_haiku.yml)) * Haiku - needs <code>openal</code> package (if you have a GitHub account, can [download from here](https://github.com/ClassiCube/ClassiCube/actions/workflows/build_haiku.yml))
* BeOS - untested on actual hardware * BeOS - untested on actual hardware
* IRIX - needs <code>curl</code> and <code>openal</code> packages * IRIX - needs <code>openal</code> packages
* SerenityOS - needs <code>SDL2</code> * SerenityOS - needs <code>SDL2</code>
* Classic Mac OS (System 7 and later) * Classic Mac OS (System 7 and later)
* Dreamcast - unfinished, but usable (can [download from here](https://www.classicube.net/download/dreamcast)) * Dreamcast - unfinished, but usable (can [download from here](https://www.classicube.net/download/dreamcast))
@ -427,7 +427,6 @@ Further information (e.g. style) for ClassiCube's source code can be found in th
<details> <details>
<summary><h2>Open source technologies (click to expand)</h2></summary> <summary><h2>Open source technologies (click to expand)</h2></summary>
* [curl](https://curl.se/) - HTTP/HTTPS for linux and macOS
* [FreeType](https://www.freetype.org/) - Font handling for all platforms * [FreeType](https://www.freetype.org/) - Font handling for all platforms
* [GCC](https://gcc.gnu.org/) - Compiles client for linux * [GCC](https://gcc.gnu.org/) - Compiles client for linux
* [MinGW-w64](http://mingw-w64.org/doku.php) - Compiles client for windows * [MinGW-w64](http://mingw-w64.org/doku.php) - Compiles client for windows

View File

@ -186,6 +186,10 @@ int Certs_VerifyChain(struct X509CertContext* chain) {
#include <Security/SecPolicy.h> #include <Security/SecPolicy.h>
#include <Security/SecTrust.h> #include <Security/SecTrust.h>
#include <Security/SecCertificate.h> #include <Security/SecCertificate.h>
#ifdef CC_BUILD_MACOS
#include <Security/SecPolicySearch.h>
#include <Security/oidsalg.h>
#endif
#include "Errors.h" #include "Errors.h"
void CertsBackend_Init(void) { void CertsBackend_Init(void) {
@ -196,7 +200,22 @@ static SecPolicyRef policy;
static void CreateChain(struct X509CertContext* x509, CFMutableArrayRef chain) { static void CreateChain(struct X509CertContext* x509, CFMutableArrayRef chain) {
struct X509Cert* certs = x509->certs; struct X509Cert* certs = x509->certs;
for (int i = 0; i < x509->numCerts; i++) int i;
#ifdef CC_BUILD_MACOS
/* Use older APIs that work on macOS earlier than 10.6 */
for (i = 0; i < x509->numCerts; i++)
{
CSSM_DATA data;
data.Data = certs[i].data;
data.Length = certs[i].offset;
SecCertificateRef cert = NULL;
int res = SecCertificateCreateFromData(&data, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
if (!res && cert) CFArrayAppendValue(chain, cert);
}
#else
for (i = 0; i < x509->numCerts; i++)
{ {
CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, certs[i].data, certs[i].offset, kCFAllocatorNull); CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, certs[i].data, certs[i].offset, kCFAllocatorNull);
@ -204,10 +223,21 @@ static void CreateChain(struct X509CertContext* x509, CFMutableArrayRef chain) {
if (cert) CFArrayAppendValue(chain, cert); if (cert) CFArrayAppendValue(chain, cert);
CFRelease(data); CFRelease(data);
} }
#endif
} }
static void CreateX509Policy(void) { static void CreateX509Policy(void) {
#ifdef CC_BUILD_MACOS
SecPolicySearchRef search;
int err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &search);
if (err) return;
err = SecPolicySearchCopyNext(search, &policy);
CFRelease(search);
#else
/* Use older APIs that work on macOS earlier than 10.6 */
policy = SecPolicyCreateBasicX509(); policy = SecPolicyCreateBasicX509();
#endif
} }
int Certs_VerifyChain(struct X509CertContext* x509) { int Certs_VerifyChain(struct X509CertContext* x509) {

View File

@ -275,22 +275,21 @@ typedef cc_uint8 cc_bool;
#elif defined __APPLE__ #elif defined __APPLE__
#define CC_BUILD_DARWIN #define CC_BUILD_DARWIN
#define CC_BUILD_POSIX #define CC_BUILD_POSIX
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_APPLESEC
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#if defined __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ #if defined __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
#define CC_BUILD_MOBILE #define CC_BUILD_MOBILE
#define CC_BUILD_GLES #define CC_BUILD_GLES
#define CC_BUILD_IOS #define CC_BUILD_IOS
#define CC_BUILD_TOUCH #define CC_BUILD_TOUCH
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL2 #define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL2
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_APPLESEC
#else #else
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_COCOA #define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_COCOA
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1 #define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define CC_BUILD_MACOS #define CC_BUILD_MACOS
#endif #endif
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#elif defined Macintosh #elif defined Macintosh
#define CC_BUILD_MACCLASSIC #define CC_BUILD_MACCLASSIC
#define CC_BUILD_LOWMEM #define CC_BUILD_LOWMEM

View File

@ -126,243 +126,7 @@ static cc_string* Http_GetUserAgent_UNSAFE(void) {
} }
#if CC_NET_BACKEND == CC_NET_BACKEND_LIBCURL #if CC_NET_BACKEND == CC_NET_BACKEND_BUILTIN
/*########################################################################################################################*
*-----------------------------------------------------libcurl backend-----------------------------------------------------*
*#########################################################################################################################*/
#include "Errors.h"
#include <stddef.h>
/* === BEGIN CURL HEADERS === */
typedef void CURL;
struct curl_slist;
typedef int CURLcode;
#define CURL_GLOBAL_DEFAULT ((1<<0) | (1<<1)) /* SSL and Win32 options */
#define CURLOPT_WRITEDATA (10000 + 1)
#define CURLOPT_URL (10000 + 2)
#define CURLOPT_ERRORBUFFER (10000 + 10)
#define CURLOPT_WRITEFUNCTION (20000 + 11)
#define CURLOPT_POSTFIELDS (10000 + 15)
#define CURLOPT_USERAGENT (10000 + 18)
#define CURLOPT_HTTPHEADER (10000 + 23)
#define CURLOPT_HEADERDATA (10000 + 29)
#define CURLOPT_VERBOSE (0 + 41)
#define CURLOPT_HEADER (0 + 42)
#define CURLOPT_NOBODY (0 + 44)
#define CURLOPT_POST (0 + 47)
#define CURLOPT_FOLLOWLOCATION (0 + 52)
#define CURLOPT_POSTFIELDSIZE (0 + 60)
#define CURLOPT_SSL_VERIFYPEER (0 + 64)
#define CURLOPT_MAXREDIRS (0 + 68)
#define CURLOPT_HEADERFUNCTION (20000 + 79)
#define CURLOPT_HTTPGET (0 + 80)
#define CURLOPT_SSL_VERIFYHOST (0 + 81)
#define CURLOPT_HTTP_VERSION (0 + 84)
#define CURL_HTTP_VERSION_1_1 2L /* stick to HTTP 1.1 */
#if defined CC_BUILD_WIN
#define APIENTRY __cdecl
#else
#define APIENTRY
#endif
static CURLcode (APIENTRY *_curl_global_init)(long flags);
static void (APIENTRY *_curl_global_cleanup)(void);
static CURL* (APIENTRY *_curl_easy_init)(void);
static CURLcode (APIENTRY *_curl_easy_perform)(CURL *c);
static CURLcode (APIENTRY *_curl_easy_setopt)(CURL *c, int opt, ...);
static void (APIENTRY *_curl_easy_cleanup)(CURL* c);
static void (APIENTRY *_curl_slist_free_all)(struct curl_slist* l);
static struct curl_slist* (APIENTRY *_curl_slist_append)(struct curl_slist* l, const char* v);
static const char* (APIENTRY *_curl_easy_strerror)(CURLcode res);
/* === END CURL HEADERS === */
#if defined CC_BUILD_WIN
static const cc_string curlLib = String_FromConst("libcurl.dll");
static const cc_string curlAlt = String_FromConst("curl.dll");
#elif defined CC_BUILD_DARWIN
static const cc_string curlLib = String_FromConst("libcurl.4.dylib");
static const cc_string curlAlt = String_FromConst("libcurl.dylib");
#elif defined CC_BUILD_NETBSD
static const cc_string curlLib = String_FromConst("libcurl.so");
static const cc_string curlAlt = String_FromConst("/usr/pkg/lib/libcurl.so");
#elif defined CC_BUILD_BSD
static const cc_string curlLib = String_FromConst("libcurl.so");
static const cc_string curlAlt = String_FromConst("libcurl.so");
#elif defined CC_BUILD_SERENITY
static const cc_string curlLib = String_FromConst("/usr/local/lib/libcurl.so");
static const cc_string curlAlt = String_FromConst("/usr/local/lib/libcurl.so");
#elif defined CC_BUILD_OS2
static const cc_string curlLib = String_FromConst("/@unixroot/usr/lib/curl4.dll");
static const cc_string curlAlt = String_FromConst("/@unixroot/usr/local/lib/curl4.dll");
#else
static const cc_string curlLib = String_FromConst("libcurl.so.4");
static const cc_string curlAlt = String_FromConst("libcurl.so.3");
#endif
static cc_bool LoadCurlFuncs(void) {
static const struct DynamicLibSym funcs[] = {
#if !defined CC_BUILD_OS2
DynamicLib_ReqSym(curl_global_init), DynamicLib_ReqSym(curl_global_cleanup),
DynamicLib_ReqSym(curl_easy_init), DynamicLib_ReqSym(curl_easy_perform),
DynamicLib_ReqSym(curl_easy_setopt), DynamicLib_ReqSym(curl_easy_cleanup),
DynamicLib_ReqSym(curl_slist_free_all), DynamicLib_ReqSym(curl_slist_append),
/* Non-essential function missing in older curl versions */
DynamicLib_OptSym(curl_easy_strerror)
#else
DynamicLib_ReqSymC(curl_global_init), DynamicLib_ReqSymC(curl_global_cleanup),
DynamicLib_ReqSymC(curl_easy_init), DynamicLib_ReqSymC(curl_easy_perform),
DynamicLib_ReqSymC(curl_easy_setopt), DynamicLib_ReqSymC(curl_easy_cleanup),
DynamicLib_ReqSymC(curl_slist_free_all), DynamicLib_ReqSymC(curl_slist_append),
/* Non-essential function missing in older curl versions */
DynamicLib_OptSymC(curl_easy_strerror)
#endif
};
cc_bool success;
void* lib;
success = DynamicLib_LoadAll(&curlLib, funcs, Array_Elems(funcs), &lib);
if (!lib) {
success = DynamicLib_LoadAll(&curlAlt, funcs, Array_Elems(funcs), &lib);
}
return success;
}
static CURL* curl;
static cc_bool curlSupported, curlVerbose;
static cc_bool HttpBackend_DescribeError(cc_result res, cc_string* dst) {
const char* err;
if (!_curl_easy_strerror) return false;
err = _curl_easy_strerror((CURLcode)res);
if (!err) return false;
String_AppendConst(dst, err);
return true;
}
static void HttpBackend_Init(void) {
static const cc_string msg = String_FromConst("Failed to init libcurl. All HTTP requests will therefore fail.");
CURLcode res;
if (!LoadCurlFuncs()) { Logger_WarnFunc(&msg); return; }
res = _curl_global_init(CURL_GLOBAL_DEFAULT);
if (res) { Logger_SimpleWarn(res, "initing curl"); return; }
curl = _curl_easy_init();
if (!curl) { Logger_SimpleWarn(res, "initing curl_easy"); return; }
curlSupported = true;
curlVerbose = Options_GetBool("curl-verbose", false);
}
static void Http_AddHeader(struct HttpRequest* req, const char* key, const cc_string* value) {
cc_string tmp; char tmpBuffer[1024];
String_InitArray_NT(tmp, tmpBuffer);
String_Format2(&tmp, "%c: %s", key, value);
tmp.buffer[tmp.length] = '\0';
req->meta = _curl_slist_append((struct curl_slist*)req->meta, tmp.buffer);
}
/* Processes a HTTP header downloaded from the server */
static size_t Http_ProcessHeader(char* buffer, size_t size, size_t nitems, void* userdata) {
struct HttpRequest* req = (struct HttpRequest*)userdata;
size_t len = nitems;
cc_string line;
/* line usually has \r\n at end */
if (len && buffer[len - 1] == '\n') len--;
if (len && buffer[len - 1] == '\r') len--;
line = String_Init(buffer, len, len);
Http_ParseHeader(req, &line);
return nitems;
}
/* Processes a chunk of data downloaded from the web server */
static size_t Http_ProcessData(char *buffer, size_t size, size_t nitems, void* userdata) {
struct HttpRequest* req = (struct HttpRequest*)userdata;
int ok = Http_BufferExpand(req, nitems);
if (!ok) Process_Abort("Out of memory for HTTP request");
Mem_Copy(&req->data[req->size], buffer, nitems);
Http_BufferExpanded(req, nitems);
return nitems;
}
/* Sets general curl options for a request */
static void Http_SetCurlOpts(struct HttpRequest* req) {
_curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
_curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
_curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 20L);
_curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
_curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_ProcessHeader);
_curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
_curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_ProcessData);
_curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
if (curlVerbose) _curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
if (httpsVerify) return;
_curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
}
static cc_result HttpBackend_Do(struct HttpRequest* req, cc_string* url) {
char urlStr[NATIVE_STR_LEN];
void* post_data = req->data;
CURLcode res;
if (!curlSupported) return ERR_NOT_SUPPORTED;
req->meta = NULL;
Http_SetRequestHeaders(req);
_curl_easy_setopt(curl, CURLOPT_HTTPHEADER, req->meta);
Http_SetCurlOpts(req);
String_EncodeUtf8(urlStr, url);
_curl_easy_setopt(curl, CURLOPT_URL, urlStr);
if (req->requestType == REQUEST_TYPE_HEAD) {
_curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
} else if (req->requestType == REQUEST_TYPE_POST) {
_curl_easy_setopt(curl, CURLOPT_POST, 1L);
_curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->size);
_curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->data);
/* per curl docs, we must persist POST data until request finishes */
req->data = NULL;
req->size = 0;
} else {
/* Undo POST/HEAD state */
_curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
}
/* must be at least CURL_ERROR_SIZE (256) in size */
req->error = Mem_TryAllocCleared(257, 1);
_curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, req->error);
/* TODO stackalloc instead and then copy to dynamic array later? */
/* probably not worth the extra complexity though */
req->_capacity = 0;
req->progress = HTTP_PROGRESS_FETCHING_DATA;
res = _curl_easy_perform(curl);
req->progress = 100;
/* Free error string if it isn't needed */
if (req->error && !req->error[0]) {
Mem_Free(req->error);
req->error = NULL;
}
_curl_slist_free_all((struct curl_slist*)req->meta);
/* can free now that request has finished */
Mem_Free(post_data);
_curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, NULL);
return res;
}
#elif CC_NET_BACKEND == CC_NET_BACKEND_BUILTIN
#include "Errors.h" #include "Errors.h"
#include "PackedCol.h" #include "PackedCol.h"
#include "SSL.h" #include "SSL.h"