initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled

This commit is contained in:
2025-09-16 20:46:46 -04:00
commit 9d30169a8d
13378 changed files with 7050105 additions and 0 deletions

151
modules/mbedtls/SCsub Normal file
View File

@@ -0,0 +1,151 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
Import("env_modules")
env_mbed_tls = env_modules.Clone()
# Thirdparty source files
thirdparty_obj = []
if env["builtin_mbedtls"]:
thirdparty_sources = [
"aes.c",
"aesce.c",
"aesni.c",
"aria.c",
"asn1parse.c",
"asn1write.c",
"base64.c",
"bignum.c",
"bignum_core.c",
"bignum_mod_raw.c",
"camellia.c",
"ccm.c",
"chacha20.c",
"chachapoly.c",
"cipher.c",
"cipher_wrap.c",
"cmac.c",
"constant_time.c",
"ctr_drbg.c",
"debug.c",
"des.c",
"dhm.c",
"ecdh.c",
"ecdsa.c",
"ecjpake.c",
"ecp.c",
"ecp_curves.c",
"entropy.c",
"entropy_poll.c",
"error.c",
"gcm.c",
"hkdf.c",
"hmac_drbg.c",
"md.c",
"md5.c",
"memory_buffer_alloc.c",
"mps_reader.c",
"mps_trace.c",
"net_sockets.c",
"nist_kw.c",
"oid.c",
"padlock.c",
"pem.c",
"pk.c",
"pk_ecc.c",
"pk_wrap.c",
"pkcs12.c",
"pkcs5.c",
"pkcs7.c",
"pkparse.c",
"pkwrite.c",
"platform.c",
"platform_util.c",
"poly1305.c",
"psa_crypto.c",
"psa_crypto_aead.c",
"psa_crypto_cipher.c",
"psa_crypto_client.c",
"psa_crypto_driver_wrappers_no_static.c",
"psa_crypto_ecp.c",
"psa_crypto_ffdh.c",
"psa_crypto_hash.c",
"psa_crypto_mac.c",
"psa_crypto_pake.c",
"psa_crypto_rsa.c",
"psa_crypto_se.c",
"psa_crypto_slot_management.c",
"psa_crypto_storage.c",
"psa_its_file.c",
"psa_util.c",
"ripemd160.c",
"rsa.c",
"rsa_alt_helpers.c",
"sha1.c",
"sha3.c",
"sha256.c",
"sha512.c",
"ssl_cache.c",
"ssl_ciphersuites.c",
"ssl_client.c",
"ssl_cookie.c",
"ssl_debug_helpers_generated.c",
"ssl_msg.c",
"ssl_ticket.c",
"ssl_tls.c",
"ssl_tls12_client.c",
"ssl_tls12_server.c",
"ssl_tls13_client.c",
"ssl_tls13_generic.c",
"ssl_tls13_keys.c",
"ssl_tls13_server.c",
"threading.c",
"timing.c",
"version.c",
"version_features.c",
"x509.c",
"x509_create.c",
"x509_crl.c",
"x509_crt.c",
"x509_csr.c",
"x509write.c",
"x509write_crt.c",
"x509write_csr.c",
]
thirdparty_dir = "#thirdparty/mbedtls/library/"
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_mbed_tls.Prepend(CPPEXTPATH=["#thirdparty/mbedtls/include/"])
config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
config_path = f"<{config_path}>" if env_mbed_tls["ninja"] and env_mbed_tls.msvc else f'\\"{config_path}\\"'
env_mbed_tls.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
env_thirdparty = env_mbed_tls.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env_thirdparty.Depends(thirdparty_obj, "#thirdparty/mbedtls/include/godot_module_mbedtls_config.h")
env.modules_sources += thirdparty_obj
# Godot source files
module_obj = []
env_mbed_tls.add_source_files(module_obj, "*.cpp")
if env["tests"]:
env_mbed_tls.Append(CPPDEFINES=["TESTS_ENABLED"])
env_mbed_tls.add_source_files(module_obj, "./tests/*.cpp")
if env["disable_exceptions"]:
env_mbed_tls.Append(CPPDEFINES=["DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS"])
env.modules_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
env.Depends(module_obj, thirdparty_obj)

View File

@@ -0,0 +1,6 @@
def can_build(env, platform):
return True
def configure(env):
pass

View File

@@ -0,0 +1,535 @@
/**************************************************************************/
/* crypto_mbedtls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "crypto_mbedtls.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
#include "core/io/file_access.h"
#include "core/os/os.h"
#include <mbedtls/debug.h>
#include <mbedtls/md.h>
#include <mbedtls/pem.h>
#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
#define PEM_END_CRT "-----END CERTIFICATE-----\n"
#define PEM_MIN_SIZE 54
CryptoKey *CryptoKeyMbedTLS::create(bool p_notify_postinitialize) {
return static_cast<CryptoKey *>(ClassDB::creator<CryptoKeyMbedTLS>(p_notify_postinitialize));
}
Error CryptoKeyMbedTLS::load(const String &p_path, bool p_public_only) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use");
PackedByteArray out;
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'.");
uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
int ret = 0;
if (p_public_only) {
ret = mbedtls_pk_parse_public_key(&pkey, out.ptr(), out.size());
} else {
ret = _parse_key(out.ptr(), out.size());
}
// We MUST zeroize the memory for safety!
mbedtls_platform_zeroize(out.ptrw(), out.size());
ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing key '" + itos(ret) + "'.");
public_only = p_public_only;
return OK;
}
Error CryptoKeyMbedTLS::save(const String &p_path, bool p_public_only) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'.");
unsigned char w[16000];
memset(w, 0, sizeof(w));
int ret = 0;
if (p_public_only) {
ret = mbedtls_pk_write_pubkey_pem(&pkey, w, sizeof(w));
} else {
ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w));
}
if (ret != 0) {
mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written.
ERR_FAIL_V_MSG(FAILED, "Error writing key '" + itos(ret) + "'.");
}
size_t len = strlen((char *)w);
f->store_buffer(w, len);
mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize temporary buffer.
return OK;
}
Error CryptoKeyMbedTLS::load_from_string(const String &p_string_key, bool p_public_only) {
int ret = 0;
const CharString string_key_utf8 = p_string_key.utf8();
if (p_public_only) {
ret = mbedtls_pk_parse_public_key(&pkey, (const unsigned char *)string_key_utf8.get_data(), string_key_utf8.size());
} else {
ret = _parse_key((const unsigned char *)string_key_utf8.get_data(), string_key_utf8.size());
}
ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing key '" + itos(ret) + "'.");
public_only = p_public_only;
return OK;
}
String CryptoKeyMbedTLS::save_to_string(bool p_public_only) {
unsigned char w[16000];
memset(w, 0, sizeof(w));
int ret = 0;
if (p_public_only) {
ret = mbedtls_pk_write_pubkey_pem(&pkey, w, sizeof(w));
} else {
ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w));
}
if (ret != 0) {
mbedtls_platform_zeroize(w, sizeof(w));
ERR_FAIL_V_MSG("", "Error saving key '" + itos(ret) + "'.");
}
String s = String::utf8((char *)w);
return s;
}
int CryptoKeyMbedTLS::_parse_key(const uint8_t *p_buf, int p_size) {
#if MBEDTLS_VERSION_MAJOR >= 3
mbedtls_entropy_context rng_entropy;
mbedtls_ctr_drbg_context rng_drbg;
mbedtls_ctr_drbg_init(&rng_drbg);
mbedtls_entropy_init(&rng_entropy);
int ret = mbedtls_ctr_drbg_seed(&rng_drbg, mbedtls_entropy_func, &rng_entropy, nullptr, 0);
ERR_FAIL_COND_V_MSG(ret != 0, ret, vformat("mbedtls_ctr_drbg_seed returned -0x%x\n", (unsigned int)-ret));
ret = mbedtls_pk_parse_key(&pkey, p_buf, p_size, nullptr, 0, mbedtls_ctr_drbg_random, &rng_drbg);
mbedtls_ctr_drbg_free(&rng_drbg);
mbedtls_entropy_free(&rng_entropy);
return ret;
#else
return mbedtls_pk_parse_key(&pkey, p_buf, p_size, nullptr, 0);
#endif
}
X509Certificate *X509CertificateMbedTLS::create(bool p_notify_postinitialize) {
return static_cast<X509Certificate *>(ClassDB::creator<X509CertificateMbedTLS>(p_notify_postinitialize));
}
Error X509CertificateMbedTLS::load(const String &p_path) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is already in use.");
PackedByteArray out;
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, vformat("Cannot open X509CertificateMbedTLS file '%s'.", p_path));
uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
int ret = mbedtls_x509_crt_parse(&cert, out.ptr(), out.size());
ERR_FAIL_COND_V_MSG(ret < 0, FAILED, vformat("Error parsing X509 certificates from file '%s': %d.", p_path, ret));
if (ret > 0) { // Some certs parsed fine, don't error.
print_verbose(vformat("MbedTLS: Some X509 certificates could not be parsed from file '%s' (%d certificates skipped).", p_path, ret));
}
return OK;
}
Error X509CertificateMbedTLS::load_from_memory(const uint8_t *p_buffer, int p_len) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is already in use.");
int ret = mbedtls_x509_crt_parse(&cert, p_buffer, p_len);
ERR_FAIL_COND_V_MSG(ret < 0, FAILED, vformat("Error parsing X509 certificates: %d.", ret));
if (ret > 0) { // Some certs parsed fine, don't error.
print_verbose(vformat("MbedTLS: Some X509 certificates could not be parsed (%d certificates skipped).", ret));
}
return OK;
}
Error X509CertificateMbedTLS::save(const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, vformat("Cannot save X509CertificateMbedTLS file '%s'.", p_path));
mbedtls_x509_crt *crt = &cert;
while (crt) {
unsigned char w[4096];
size_t wrote = 0;
int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote);
if (ret != 0 || wrote == 0) {
ERR_FAIL_V_MSG(FAILED, "Error writing certificate '" + itos(ret) + "'.");
}
f->store_buffer(w, wrote - 1); // don't write the string terminator
crt = crt->next;
}
return OK;
}
String X509CertificateMbedTLS::save_to_string() {
String buffer;
mbedtls_x509_crt *crt = &cert;
while (crt) {
unsigned char w[4096];
size_t wrote = 0;
int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote);
ERR_FAIL_COND_V_MSG(ret != 0 || wrote == 0, String(), "Error saving the certificate.");
// PEM is base64, aka ascii
buffer += String::ascii(Span((char *)w, wrote));
crt = crt->next;
}
if (buffer.length() <= PEM_MIN_SIZE) {
// When the returned value of variable 'buffer' would consist of no Base-64 data, return an empty String instead.
return String();
}
return buffer;
}
Error X509CertificateMbedTLS::load_from_string(const String &p_string_key) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is already in use.");
CharString cs = p_string_key.utf8();
int ret = mbedtls_x509_crt_parse(&cert, (const unsigned char *)cs.get_data(), cs.size());
ERR_FAIL_COND_V_MSG(ret < 0, FAILED, vformat("Error parsing X509 certificates: %d.", ret));
if (ret > 0) { // Some certs parsed fine, don't error.
print_verbose(vformat("MbedTLS: Some X509 certificates could not be parsed (%d certificates skipped).", ret));
}
return OK;
}
bool HMACContextMbedTLS::is_md_type_allowed(mbedtls_md_type_t p_md_type) {
switch (p_md_type) {
case MBEDTLS_MD_SHA1:
case MBEDTLS_MD_SHA256:
return true;
default:
return false;
}
}
HMACContext *HMACContextMbedTLS::create(bool p_notify_postinitialize) {
return static_cast<HMACContext *>(ClassDB::creator<HMACContextMbedTLS>(p_notify_postinitialize));
}
Error HMACContextMbedTLS::start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) {
ERR_FAIL_COND_V_MSG(ctx != nullptr, ERR_FILE_ALREADY_IN_USE, "HMACContext already started.");
// HMAC keys can be any size.
ERR_FAIL_COND_V_MSG(p_key.is_empty(), ERR_INVALID_PARAMETER, "Key must not be empty.");
hash_type = p_hash_type;
mbedtls_md_type_t ht = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, hash_len);
bool allowed = HMACContextMbedTLS::is_md_type_allowed(ht);
ERR_FAIL_COND_V_MSG(!allowed, ERR_INVALID_PARAMETER, "Unsupported hash type.");
ctx = memalloc(sizeof(mbedtls_md_context_t));
mbedtls_md_init((mbedtls_md_context_t *)ctx);
mbedtls_md_setup((mbedtls_md_context_t *)ctx, mbedtls_md_info_from_type((mbedtls_md_type_t)ht), 1);
int ret = mbedtls_md_hmac_starts((mbedtls_md_context_t *)ctx, (const uint8_t *)p_key.ptr(), (size_t)p_key.size());
return ret ? FAILED : OK;
}
Error HMACContextMbedTLS::update(const PackedByteArray &p_data) {
ERR_FAIL_NULL_V_MSG(ctx, ERR_INVALID_DATA, "Start must be called before update.");
ERR_FAIL_COND_V_MSG(p_data.is_empty(), ERR_INVALID_PARAMETER, "Src must not be empty.");
int ret = mbedtls_md_hmac_update((mbedtls_md_context_t *)ctx, (const uint8_t *)p_data.ptr(), (size_t)p_data.size());
return ret ? FAILED : OK;
}
PackedByteArray HMACContextMbedTLS::finish() {
ERR_FAIL_NULL_V_MSG(ctx, PackedByteArray(), "Start must be called before finish.");
ERR_FAIL_COND_V_MSG(hash_len == 0, PackedByteArray(), "Unsupported hash type.");
PackedByteArray out;
out.resize(hash_len);
unsigned char *out_ptr = (unsigned char *)out.ptrw();
int ret = mbedtls_md_hmac_finish((mbedtls_md_context_t *)ctx, out_ptr);
mbedtls_md_free((mbedtls_md_context_t *)ctx);
memfree((mbedtls_md_context_t *)ctx);
ctx = nullptr;
hash_len = 0;
ERR_FAIL_COND_V_MSG(ret, PackedByteArray(), "Error received while finishing HMAC");
return out;
}
HMACContextMbedTLS::~HMACContextMbedTLS() {
if (ctx != nullptr) {
mbedtls_md_free((mbedtls_md_context_t *)ctx);
memfree((mbedtls_md_context_t *)ctx);
}
}
Crypto *CryptoMbedTLS::create(bool p_notify_postinitialize) {
return static_cast<Crypto *>(ClassDB::creator<CryptoMbedTLS>(p_notify_postinitialize));
}
void CryptoMbedTLS::initialize_crypto() {
Crypto::_create = create;
Crypto::_load_default_certificates = load_default_certificates;
X509CertificateMbedTLS::make_default();
CryptoKeyMbedTLS::make_default();
HMACContextMbedTLS::make_default();
}
void CryptoMbedTLS::finalize_crypto() {
Crypto::_create = nullptr;
Crypto::_load_default_certificates = nullptr;
if (default_certs) {
memdelete(default_certs);
default_certs = nullptr;
}
X509CertificateMbedTLS::finalize();
CryptoKeyMbedTLS::finalize();
HMACContextMbedTLS::finalize();
}
CryptoMbedTLS::CryptoMbedTLS() {
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);
if (ret != 0) {
ERR_PRINT(" failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
}
}
CryptoMbedTLS::~CryptoMbedTLS() {
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
}
X509CertificateMbedTLS *CryptoMbedTLS::default_certs = nullptr;
X509CertificateMbedTLS *CryptoMbedTLS::get_default_certificates() {
return default_certs;
}
void CryptoMbedTLS::load_default_certificates(const String &p_path) {
ERR_FAIL_COND(default_certs != nullptr);
default_certs = memnew(X509CertificateMbedTLS);
ERR_FAIL_NULL(default_certs);
if (!p_path.is_empty()) {
// Use certs defined in project settings.
default_certs->load(p_path);
} else {
// Try to use system certs otherwise.
String system_certs = OS::get_singleton()->get_system_ca_certificates();
if (!system_certs.is_empty()) {
CharString cs = system_certs.utf8();
default_certs->load_from_memory((const uint8_t *)cs.get_data(), cs.size());
print_verbose("Loaded system CA certificates");
}
#ifdef BUILTIN_CERTS_ENABLED
else {
// Use builtin certs if there are no system certs.
PackedByteArray certs;
certs.resize(_certs_uncompressed_size + 1);
const int64_t decompressed_size = Compression::decompress(certs.ptrw(), _certs_uncompressed_size, _certs_compressed, _certs_compressed_size, Compression::MODE_DEFLATE);
ERR_FAIL_COND_MSG(decompressed_size != _certs_uncompressed_size, "Error decompressing builtin CA certificates. Decompressed size did not match expected size.");
certs.write[_certs_uncompressed_size] = 0; // Make sure it ends with string terminator
default_certs->load_from_memory(certs.ptr(), certs.size());
print_verbose("Loaded builtin CA certificates");
}
#endif
}
}
Ref<CryptoKey> CryptoMbedTLS::generate_rsa(int p_bytes) {
Ref<CryptoKeyMbedTLS> out;
out.instantiate();
int ret = mbedtls_pk_setup(&(out->pkey), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
ERR_FAIL_COND_V(ret != 0, nullptr);
ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(out->pkey), mbedtls_ctr_drbg_random, &ctr_drbg, p_bytes, 65537);
out->public_only = false;
ERR_FAIL_COND_V(ret != 0, nullptr);
return out;
}
Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoKey> p_key, const String &p_issuer_name, const String &p_not_before, const String &p_not_after) {
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
ERR_FAIL_COND_V_MSG(key.is_null(), nullptr, "Invalid private key argument.");
mbedtls_x509write_cert crt;
mbedtls_x509write_crt_init(&crt);
mbedtls_x509write_crt_set_subject_key(&crt, &(key->pkey));
mbedtls_x509write_crt_set_issuer_key(&crt, &(key->pkey));
mbedtls_x509write_crt_set_subject_name(&crt, p_issuer_name.utf8().get_data());
mbedtls_x509write_crt_set_issuer_name(&crt, p_issuer_name.utf8().get_data());
mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3);
mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
uint8_t rand_serial[20];
mbedtls_ctr_drbg_random(&ctr_drbg, rand_serial, sizeof(rand_serial));
#if MBEDTLS_VERSION_MAJOR >= 3
mbedtls_x509write_crt_set_serial_raw(&crt, rand_serial, sizeof(rand_serial));
#else
mbedtls_mpi serial;
mbedtls_mpi_init(&serial);
ERR_FAIL_COND_V(mbedtls_mpi_read_binary(&serial, rand_serial, sizeof(rand_serial)), nullptr);
mbedtls_x509write_crt_set_serial(&crt, &serial);
#endif
mbedtls_x509write_crt_set_validity(&crt, p_not_before.utf8().get_data(), p_not_after.utf8().get_data());
mbedtls_x509write_crt_set_basic_constraints(&crt, 1, -1);
mbedtls_x509write_crt_set_basic_constraints(&crt, 1, 0);
unsigned char buf[4096];
memset(buf, 0, 4096);
int ret = mbedtls_x509write_crt_pem(&crt, buf, 4096, mbedtls_ctr_drbg_random, &ctr_drbg);
#if MBEDTLS_VERSION_MAJOR < 3
mbedtls_mpi_free(&serial);
#endif
mbedtls_x509write_crt_free(&crt);
ERR_FAIL_COND_V_MSG(ret != 0, nullptr, "Failed to generate certificate: " + itos(ret));
buf[4095] = '\0'; // Make sure strlen can't fail.
Ref<X509CertificateMbedTLS> out;
out.instantiate();
out->load_from_memory(buf, strlen((char *)buf) + 1); // Use strlen to find correct output size.
return out;
}
PackedByteArray CryptoMbedTLS::generate_random_bytes(int p_bytes) {
ERR_FAIL_COND_V(p_bytes < 0, PackedByteArray());
PackedByteArray out;
out.resize(p_bytes);
int left = p_bytes;
int pos = 0;
// Ensure we generate random in chunks of no more than MBEDTLS_CTR_DRBG_MAX_REQUEST bytes or mbedtls_ctr_drbg_random will fail.
while (left > 0) {
int to_read = MIN(left, MBEDTLS_CTR_DRBG_MAX_REQUEST);
int ret = mbedtls_ctr_drbg_random(&ctr_drbg, out.ptrw() + pos, to_read);
ERR_FAIL_COND_V_MSG(ret != 0, PackedByteArray(), vformat("Failed to generate %d random bytes(s). Error: %d.", p_bytes, ret));
left -= to_read;
pos += to_read;
}
return out;
}
mbedtls_md_type_t CryptoMbedTLS::md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
switch (p_hash_type) {
case HashingContext::HASH_MD5:
r_size = 16;
return MBEDTLS_MD_MD5;
case HashingContext::HASH_SHA1:
r_size = 20;
return MBEDTLS_MD_SHA1;
case HashingContext::HASH_SHA256:
r_size = 32;
return MBEDTLS_MD_SHA256;
default:
r_size = 0;
ERR_FAIL_V_MSG(MBEDTLS_MD_NONE, "Invalid hash type.");
}
}
Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, Ref<CryptoKey> p_key) {
int size;
mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, Vector<uint8_t>(), "Invalid hash type.");
ERR_FAIL_COND_V_MSG(p_hash.size() != size, Vector<uint8_t>(), "Invalid hash provided. Size must be " + itos(size));
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
ERR_FAIL_COND_V_MSG(key.is_null(), Vector<uint8_t>(), "Invalid key provided.");
ERR_FAIL_COND_V_MSG(key->is_public_only(), Vector<uint8_t>(), "Invalid key provided. Cannot sign with public_only keys.");
size_t sig_size = 0;
#if MBEDTLS_VERSION_MAJOR >= 3
unsigned char buf[MBEDTLS_PK_SIGNATURE_MAX_SIZE];
#else
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
#endif
Vector<uint8_t> out;
int ret = mbedtls_pk_sign(&(key->pkey), type, p_hash.ptr(), size, buf,
#if MBEDTLS_VERSION_MAJOR >= 3
sizeof(buf),
#endif
&sig_size, mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while signing: " + itos(ret));
out.resize(sig_size);
memcpy(out.ptrw(), buf, sig_size);
return out;
}
bool CryptoMbedTLS::verify(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, const Vector<uint8_t> &p_signature, Ref<CryptoKey> p_key) {
int size;
mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, false, "Invalid hash type.");
ERR_FAIL_COND_V_MSG(p_hash.size() != size, false, "Invalid hash provided. Size must be " + itos(size));
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
ERR_FAIL_COND_V_MSG(key.is_null(), false, "Invalid key provided.");
return mbedtls_pk_verify(&(key->pkey), type, p_hash.ptr(), size, p_signature.ptr(), p_signature.size()) == 0;
}
Vector<uint8_t> CryptoMbedTLS::encrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_plaintext) {
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
ERR_FAIL_COND_V_MSG(key.is_null(), Vector<uint8_t>(), "Invalid key provided.");
uint8_t buf[1024];
size_t size;
Vector<uint8_t> out;
int ret = mbedtls_pk_encrypt(&(key->pkey), p_plaintext.ptr(), p_plaintext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while encrypting: " + itos(ret));
out.resize(size);
memcpy(out.ptrw(), buf, size);
return out;
}
Vector<uint8_t> CryptoMbedTLS::decrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_ciphertext) {
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
ERR_FAIL_COND_V_MSG(key.is_null(), Vector<uint8_t>(), "Invalid key provided.");
ERR_FAIL_COND_V_MSG(key->is_public_only(), Vector<uint8_t>(), "Invalid key provided. Cannot decrypt using a public_only key.");
uint8_t buf[2048];
size_t size;
Vector<uint8_t> out;
int ret = mbedtls_pk_decrypt(&(key->pkey), p_ciphertext.ptr(), p_ciphertext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while decrypting: " + itos(ret));
out.resize(size);
memcpy(out.ptrw(), buf, size);
return out;
}

View File

@@ -0,0 +1,155 @@
/**************************************************************************/
/* crypto_mbedtls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/crypto/crypto.h"
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ssl.h>
class CryptoMbedTLS;
class TLSContextMbedTLS;
class CryptoKeyMbedTLS : public CryptoKey {
GDSOFTCLASS(CryptoKeyMbedTLS, CryptoKey);
private:
mbedtls_pk_context pkey;
int locks = 0;
bool public_only = true;
int _parse_key(const uint8_t *p_buf, int p_size);
public:
static CryptoKey *create(bool p_notify_postinitialize = true);
static void make_default() { CryptoKey::_create = create; }
static void finalize() { CryptoKey::_create = nullptr; }
Error load(const String &p_path, bool p_public_only) override;
Error save(const String &p_path, bool p_public_only) override;
String save_to_string(bool p_public_only) override;
Error load_from_string(const String &p_string_key, bool p_public_only) override;
bool is_public_only() const override { return public_only; }
CryptoKeyMbedTLS() {
mbedtls_pk_init(&pkey);
locks = 0;
}
~CryptoKeyMbedTLS() override {
mbedtls_pk_free(&pkey);
}
_FORCE_INLINE_ void lock() { locks++; }
_FORCE_INLINE_ void unlock() { locks--; }
friend class CryptoMbedTLS;
friend class TLSContextMbedTLS;
};
class X509CertificateMbedTLS : public X509Certificate {
GDSOFTCLASS(X509CertificateMbedTLS, X509Certificate);
private:
mbedtls_x509_crt cert;
int locks;
public:
static X509Certificate *create(bool p_notify_postinitialize = true);
static void make_default() { X509Certificate::_create = create; }
static void finalize() { X509Certificate::_create = nullptr; }
Error load(const String &p_path) override;
Error load_from_memory(const uint8_t *p_buffer, int p_len) override;
Error save(const String &p_path) override;
String save_to_string() override;
Error load_from_string(const String &p_string_key) override;
X509CertificateMbedTLS() {
mbedtls_x509_crt_init(&cert);
locks = 0;
}
~X509CertificateMbedTLS() override {
mbedtls_x509_crt_free(&cert);
}
_FORCE_INLINE_ void lock() { locks++; }
_FORCE_INLINE_ void unlock() { locks--; }
friend class CryptoMbedTLS;
friend class TLSContextMbedTLS;
};
class HMACContextMbedTLS : public HMACContext {
private:
HashingContext::HashType hash_type;
int hash_len = 0;
void *ctx = nullptr;
public:
static HMACContext *create(bool p_notify_postinitialize = true);
static void make_default() { HMACContext::_create = create; }
static void finalize() { HMACContext::_create = nullptr; }
static bool is_md_type_allowed(mbedtls_md_type_t p_md_type);
Error start(HashingContext::HashType p_hash_type, const PackedByteArray &p_key) override;
Error update(const PackedByteArray &p_data) override;
PackedByteArray finish() override;
HMACContextMbedTLS() {}
~HMACContextMbedTLS() override;
};
class CryptoMbedTLS : public Crypto {
private:
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
static X509CertificateMbedTLS *default_certs;
public:
static Crypto *create(bool p_notify_postinitialize = true);
static void initialize_crypto();
static void finalize_crypto();
static X509CertificateMbedTLS *get_default_certificates();
static void load_default_certificates(const String &p_path);
static mbedtls_md_type_t md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
PackedByteArray generate_random_bytes(int p_bytes) override;
Ref<CryptoKey> generate_rsa(int p_bytes) override;
Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, const String &p_issuer_name, const String &p_not_before, const String &p_not_after) override;
Vector<uint8_t> sign(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, Ref<CryptoKey> p_key) override;
bool verify(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, const Vector<uint8_t> &p_signature, Ref<CryptoKey> p_key) override;
Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_plaintext) override;
Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_ciphertext) override;
CryptoMbedTLS();
~CryptoMbedTLS() override;
};

View File

@@ -0,0 +1,77 @@
/**************************************************************************/
/* dtls_server_mbedtls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "dtls_server_mbedtls.h"
#include "packet_peer_mbed_dtls.h"
Error DTLSServerMbedTLS::setup(Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(cookies->setup() != OK, ERR_ALREADY_IN_USE);
tls_options = p_options;
return OK;
}
void DTLSServerMbedTLS::stop() {
cookies->clear();
}
Ref<PacketPeerDTLS> DTLSServerMbedTLS::take_connection(Ref<PacketPeerUDP> p_udp_peer) {
Ref<PacketPeerMbedDTLS> out;
ERR_FAIL_COND_V(tls_options.is_null(), out);
ERR_FAIL_COND_V(p_udp_peer.is_null(), out);
out.instantiate();
out->accept_peer(p_udp_peer, tls_options, cookies);
return out;
}
DTLSServer *DTLSServerMbedTLS::_create_func(bool p_notify_postinitialize) {
return static_cast<DTLSServer *>(ClassDB::creator<DTLSServerMbedTLS>(p_notify_postinitialize));
}
void DTLSServerMbedTLS::initialize() {
_create = _create_func;
available = true;
}
void DTLSServerMbedTLS::finalize() {
_create = nullptr;
available = false;
}
DTLSServerMbedTLS::DTLSServerMbedTLS() {
cookies.instantiate();
}
DTLSServerMbedTLS::~DTLSServerMbedTLS() {
stop();
}

View File

@@ -0,0 +1,53 @@
/**************************************************************************/
/* dtls_server_mbedtls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "tls_context_mbedtls.h"
#include "core/io/dtls_server.h"
class DTLSServerMbedTLS : public DTLSServer {
private:
static DTLSServer *_create_func(bool p_notify_postinitialize);
Ref<TLSOptions> tls_options;
Ref<CookieContextMbedTLS> cookies;
public:
static void initialize();
static void finalize();
Error setup(Ref<TLSOptions> p_options) override;
void stop() override;
Ref<PacketPeerDTLS> take_connection(Ref<PacketPeerUDP> p_peer) override;
DTLSServerMbedTLS();
~DTLSServerMbedTLS() override;
};

View File

@@ -0,0 +1,282 @@
/**************************************************************************/
/* packet_peer_mbed_dtls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "packet_peer_mbed_dtls.h"
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
if (buf == nullptr || len == 0) {
return 0;
}
PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
ERR_FAIL_NULL_V(sp, 0);
Error err = sp->base->put_packet((const uint8_t *)buf, len);
if (err == ERR_BUSY) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
} else if (err != OK) {
ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);
}
return len;
}
int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
if (buf == nullptr || len == 0) {
return 0;
}
PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
ERR_FAIL_NULL_V(sp, 0);
int pc = sp->base->get_available_packet_count();
if (pc == 0) {
return MBEDTLS_ERR_SSL_WANT_READ;
} else if (pc < 0) {
ERR_FAIL_V(MBEDTLS_ERR_SSL_INTERNAL_ERROR);
}
const uint8_t *buffer;
int buffer_size = 0;
Error err = sp->base->get_packet(&buffer, buffer_size);
if (err != OK) {
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
memcpy(buf, buffer, buffer_size);
return buffer_size;
}
void PacketPeerMbedDTLS::_cleanup() {
tls_ctx->clear();
base = Ref<PacketPeer>();
status = STATUS_DISCONNECTED;
}
int PacketPeerMbedDTLS::_set_cookie() {
// Setup DTLS session cookie for this client
uint8_t client_id[18];
IPAddress addr = base->get_packet_address();
uint16_t port = base->get_packet_port();
memcpy(client_id, addr.get_ipv6(), 16);
memcpy(&client_id[16], (uint8_t *)&port, 2);
return mbedtls_ssl_set_client_transport_id(tls_ctx->get_context(), client_id, 18);
}
Error PacketPeerMbedDTLS::_do_handshake() {
int ret = 0;
while ((ret = mbedtls_ssl_handshake(tls_ctx->get_context())) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
if (ret != MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
ERR_PRINT("TLS handshake error: " + itos(ret));
TLSContextMbedTLS::print_mbedtls_error(ret);
}
_cleanup();
status = STATUS_ERROR;
return FAILED;
}
// Will retry via poll later
return OK;
}
status = STATUS_CONNECTED;
return OK;
}
Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, const String &p_hostname, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_base.is_null() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_hostname, p_options.is_valid() ? p_options : TLSOptions::client());
ERR_FAIL_COND_V(err != OK, err);
base = p_base;
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
status = STATUS_HANDSHAKING;
if (_do_handshake() != OK) {
status = STATUS_ERROR_HOSTNAME_MISMATCH;
return FAILED;
}
return OK;
}
Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies) {
ERR_FAIL_COND_V(p_base.is_null() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_DATAGRAM, p_options, p_cookies);
ERR_FAIL_COND_V(err != OK, err);
base = p_base;
base->set_blocking_mode(false);
mbedtls_ssl_session_reset(tls_ctx->get_context());
int ret = _set_cookie();
if (ret != 0) {
_cleanup();
ERR_FAIL_V_MSG(FAILED, "Error setting DTLS client cookie");
}
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
mbedtls_ssl_set_timer_cb(tls_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
status = STATUS_HANDSHAKING;
if (_do_handshake() != OK) {
status = STATUS_ERROR;
return FAILED;
}
return OK;
}
Error PacketPeerMbedDTLS::put_packet(const uint8_t *p_buffer, int p_bytes) {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
if (p_bytes == 0) {
return OK;
}
int ret = mbedtls_ssl_write(tls_ctx->get_context(), p_buffer, p_bytes);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
// Non blocking io.
} else if (ret <= 0) {
TLSContextMbedTLS::print_mbedtls_error(ret);
_cleanup();
return ERR_CONNECTION_ERROR;
}
return OK;
}
Error PacketPeerMbedDTLS::get_packet(const uint8_t **r_buffer, int &r_bytes) {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
r_bytes = 0;
int ret = mbedtls_ssl_read(tls_ctx->get_context(), packet_buffer, PACKET_BUFFER_SIZE);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
ret = 0; // non blocking io
} else if (ret <= 0) {
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
// Also send close notify back
disconnect_from_peer();
} else {
_cleanup();
status = STATUS_ERROR;
TLSContextMbedTLS::print_mbedtls_error(ret);
}
return ERR_CONNECTION_ERROR;
}
*r_buffer = packet_buffer;
r_bytes = ret;
return OK;
}
void PacketPeerMbedDTLS::poll() {
if (status == STATUS_HANDSHAKING) {
_do_handshake();
return;
} else if (status != STATUS_CONNECTED) {
return;
}
ERR_FAIL_COND(base.is_null());
int ret = mbedtls_ssl_read(tls_ctx->get_context(), nullptr, 0);
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
// Also send close notify back
disconnect_from_peer();
} else {
_cleanup();
status = STATUS_ERROR;
TLSContextMbedTLS::print_mbedtls_error(ret);
}
}
}
int PacketPeerMbedDTLS::get_available_packet_count() const {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, 0);
return mbedtls_ssl_get_bytes_avail(&(tls_ctx->tls)) > 0 ? 1 : 0;
}
int PacketPeerMbedDTLS::get_max_packet_size() const {
return 488; // 512 (UDP in Godot) - 24 (DTLS header)
}
PacketPeerMbedDTLS::PacketPeerMbedDTLS() {
tls_ctx.instantiate();
}
PacketPeerMbedDTLS::~PacketPeerMbedDTLS() {
disconnect_from_peer();
}
void PacketPeerMbedDTLS::disconnect_from_peer() {
if (status != STATUS_CONNECTED && status != STATUS_HANDSHAKING) {
return;
}
if (status == STATUS_CONNECTED) {
int ret = 0;
// Send SSL close notification, blocking, but ignore other errors.
do {
ret = mbedtls_ssl_close_notify(tls_ctx->get_context());
} while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
}
_cleanup();
}
PacketPeerMbedDTLS::Status PacketPeerMbedDTLS::get_status() const {
return status;
}
PacketPeerDTLS *PacketPeerMbedDTLS::_create_func(bool p_notify_postinitialize) {
return static_cast<PacketPeerDTLS *>(ClassDB::creator<PacketPeerMbedDTLS>(p_notify_postinitialize));
}
void PacketPeerMbedDTLS::initialize_dtls() {
_create = _create_func;
available = true;
}
void PacketPeerMbedDTLS::finalize_dtls() {
_create = nullptr;
available = false;
}

View File

@@ -0,0 +1,84 @@
/**************************************************************************/
/* packet_peer_mbed_dtls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "tls_context_mbedtls.h"
#include "core/io/packet_peer_dtls.h"
#include <mbedtls/timing.h>
class PacketPeerMbedDTLS : public PacketPeerDTLS {
private:
enum {
PACKET_BUFFER_SIZE = 65536
};
uint8_t packet_buffer[PACKET_BUFFER_SIZE];
Status status = STATUS_DISCONNECTED;
String hostname;
Ref<PacketPeerUDP> base;
static PacketPeerDTLS *_create_func(bool p_notify_postinitialize);
static int bio_recv(void *ctx, unsigned char *buf, size_t len);
static int bio_send(void *ctx, const unsigned char *buf, size_t len);
void _cleanup();
protected:
Ref<TLSContextMbedTLS> tls_ctx;
mbedtls_timing_delay_context timer;
Error _do_handshake();
int _set_cookie();
public:
virtual void poll();
virtual Error accept_peer(Ref<PacketPeerUDP> p_base, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
virtual Error connect_to_peer(Ref<PacketPeerUDP> p_base, const String &p_hostname, Ref<TLSOptions> p_options = Ref<TLSOptions>());
virtual Status get_status() const;
virtual void disconnect_from_peer();
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
virtual int get_available_packet_count() const;
virtual int get_max_packet_size() const;
static void initialize_dtls();
static void finalize_dtls();
PacketPeerMbedDTLS();
~PacketPeerMbedDTLS();
};

View File

@@ -0,0 +1,134 @@
/**************************************************************************/
/* register_types.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "register_types.h"
#include "crypto_mbedtls.h"
#include "dtls_server_mbedtls.h"
#include "packet_peer_mbed_dtls.h"
#include "stream_peer_mbedtls.h"
#include "core/config/project_settings.h"
#if MBEDTLS_VERSION_MAJOR >= 3
#include <psa/crypto.h>
#endif
#ifdef TESTS_ENABLED
#include "tests/test_crypto_mbedtls.h"
#endif
#ifdef GODOT_MBEDTLS_THREADING_ALT
extern "C" {
void godot_mbedtls_mutex_init(mbedtls_threading_mutex_t *p_mutex) {
ERR_FAIL_NULL(p_mutex);
p_mutex->mutex = memnew(Mutex);
}
void godot_mbedtls_mutex_free(mbedtls_threading_mutex_t *p_mutex) {
ERR_FAIL_NULL(p_mutex);
ERR_FAIL_NULL(p_mutex->mutex);
memdelete((Mutex *)p_mutex->mutex);
}
int godot_mbedtls_mutex_lock(mbedtls_threading_mutex_t *p_mutex) {
ERR_FAIL_NULL_V(p_mutex, MBEDTLS_ERR_THREADING_BAD_INPUT_DATA);
ERR_FAIL_NULL_V(p_mutex->mutex, MBEDTLS_ERR_THREADING_BAD_INPUT_DATA);
((Mutex *)p_mutex->mutex)->lock();
return 0;
}
int godot_mbedtls_mutex_unlock(mbedtls_threading_mutex_t *p_mutex) {
ERR_FAIL_NULL_V(p_mutex, MBEDTLS_ERR_THREADING_BAD_INPUT_DATA);
ERR_FAIL_NULL_V(p_mutex->mutex, MBEDTLS_ERR_THREADING_BAD_INPUT_DATA);
((Mutex *)p_mutex->mutex)->unlock();
return 0;
}
};
#endif
static bool godot_mbedtls_initialized = false;
void initialize_mbedtls_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
return;
}
GLOBAL_DEF("network/tls/enable_tls_v1.3", true);
#ifdef GODOT_MBEDTLS_THREADING_ALT
mbedtls_threading_set_alt(
godot_mbedtls_mutex_init,
godot_mbedtls_mutex_free,
godot_mbedtls_mutex_lock,
godot_mbedtls_mutex_unlock);
#endif
#if MBEDTLS_VERSION_MAJOR >= 3
int status = psa_crypto_init();
ERR_FAIL_COND_MSG(status != PSA_SUCCESS, "Failed to initialize psa crypto. The mbedTLS modules will not work.");
#endif
#ifdef DEBUG_ENABLED
if (OS::get_singleton()->is_stdout_verbose()) {
mbedtls_debug_set_threshold(1);
}
#endif
godot_mbedtls_initialized = true;
CryptoMbedTLS::initialize_crypto();
StreamPeerMbedTLS::initialize_tls();
PacketPeerMbedDTLS::initialize_dtls();
DTLSServerMbedTLS::initialize();
}
void uninitialize_mbedtls_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
return;
}
if (!godot_mbedtls_initialized) {
return;
}
#if MBEDTLS_VERSION_MAJOR >= 3
mbedtls_psa_crypto_free();
#endif
DTLSServerMbedTLS::finalize();
PacketPeerMbedDTLS::finalize_dtls();
StreamPeerMbedTLS::finalize_tls();
CryptoMbedTLS::finalize_crypto();
#ifdef GODOT_MBEDTLS_THREADING_ALT
mbedtls_threading_free_alt();
#endif
}

View File

@@ -0,0 +1,36 @@
/**************************************************************************/
/* register_types.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "modules/register_module_types.h"
void initialize_mbedtls_module(ModuleInitializationLevel p_level);
void uninitialize_mbedtls_module(ModuleInitializationLevel p_level);

View File

@@ -0,0 +1,315 @@
/**************************************************************************/
/* stream_peer_mbedtls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "stream_peer_mbedtls.h"
#include "core/io/stream_peer_tcp.h"
int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
if (buf == nullptr || len == 0) {
return 0;
}
StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx);
ERR_FAIL_NULL_V(sp, 0);
int sent;
Error err = sp->base->put_partial_data((const uint8_t *)buf, len, sent);
if (err != OK) {
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
if (sent == 0) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
}
return sent;
}
int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
if (buf == nullptr || len == 0) {
return 0;
}
StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx);
ERR_FAIL_NULL_V(sp, 0);
int got;
Error err = sp->base->get_partial_data((uint8_t *)buf, len, got);
if (err != OK) {
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
if (got == 0) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return got;
}
void StreamPeerMbedTLS::_cleanup() {
tls_ctx->clear();
base = Ref<StreamPeer>();
status = STATUS_DISCONNECTED;
}
Error StreamPeerMbedTLS::_do_handshake() {
int ret = mbedtls_ssl_handshake(tls_ctx->get_context());
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
// Handshake is still in progress, will retry via poll later.
return OK;
} else if (ret != 0) {
// An error occurred.
ERR_PRINT("TLS handshake error: " + itos(ret));
TLSContextMbedTLS::print_mbedtls_error(ret);
disconnect_from_stream();
status = STATUS_ERROR;
return FAILED;
}
status = STATUS_CONNECTED;
return OK;
}
Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, const String &p_common_name, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_base.is_null(), ERR_INVALID_PARAMETER);
Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_STREAM, p_common_name, p_options.is_valid() ? p_options : TLSOptions::client());
ERR_FAIL_COND_V(err != OK, err);
base = p_base;
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
status = STATUS_HANDSHAKING;
if (_do_handshake() != OK) {
status = STATUS_ERROR_HOSTNAME_MISMATCH;
return FAILED;
}
return OK;
}
Error StreamPeerMbedTLS::accept_stream(Ref<StreamPeer> p_base, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_base.is_null(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
Error err = tls_ctx->init_server(MBEDTLS_SSL_TRANSPORT_STREAM, p_options);
ERR_FAIL_COND_V(err != OK, err);
base = p_base;
mbedtls_ssl_set_bio(tls_ctx->get_context(), this, bio_send, bio_recv, nullptr);
status = STATUS_HANDSHAKING;
if (_do_handshake() != OK) {
return FAILED;
}
status = STATUS_CONNECTED;
return OK;
}
Error StreamPeerMbedTLS::put_data(const uint8_t *p_data, int p_bytes) {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
Error err;
int sent = 0;
while (p_bytes > 0) {
err = put_partial_data(p_data, p_bytes, sent);
if (err != OK) {
return err;
}
p_data += sent;
p_bytes -= sent;
}
return OK;
}
Error StreamPeerMbedTLS::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
r_sent = 0;
if (p_bytes == 0) {
return OK;
}
do {
int ret = mbedtls_ssl_write(tls_ctx->get_context(), &p_data[r_sent], p_bytes - r_sent);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
// Non blocking IO.
break;
} else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
// Clean close
disconnect_from_stream();
return ERR_FILE_EOF;
} else if (ret <= 0) {
TLSContextMbedTLS::print_mbedtls_error(ret);
disconnect_from_stream();
return ERR_CONNECTION_ERROR;
}
r_sent += ret;
} while (r_sent < p_bytes);
return OK;
}
Error StreamPeerMbedTLS::get_data(uint8_t *p_buffer, int p_bytes) {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
Error err;
int got = 0;
while (p_bytes > 0) {
err = get_partial_data(p_buffer, p_bytes, got);
if (err != OK) {
return err;
}
p_buffer += got;
p_bytes -= got;
}
return OK;
}
Error StreamPeerMbedTLS::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_UNCONFIGURED);
r_received = 0;
do {
int ret = mbedtls_ssl_read(tls_ctx->get_context(), &p_buffer[r_received], p_bytes - r_received);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
// Non blocking IO.
break;
} else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
// Clean close
disconnect_from_stream();
return ERR_FILE_EOF;
} else if (ret <= 0) {
TLSContextMbedTLS::print_mbedtls_error(ret);
disconnect_from_stream();
return ERR_CONNECTION_ERROR;
}
r_received += ret;
} while (r_received < p_bytes);
return OK;
}
void StreamPeerMbedTLS::poll() {
ERR_FAIL_COND(status != STATUS_CONNECTED && status != STATUS_HANDSHAKING);
ERR_FAIL_COND(base.is_null());
if (status == STATUS_HANDSHAKING) {
_do_handshake();
return;
}
// We could pass nullptr as second parameter, but some behavior sanitizers don't seem to like that.
// Passing a 1 byte buffer to workaround it.
uint8_t byte;
int ret = mbedtls_ssl_read(tls_ctx->get_context(), &byte, 0);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
// Nothing to read/write (non blocking IO)
} else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
// Clean close (disconnect)
disconnect_from_stream();
return;
} else if (ret < 0) {
TLSContextMbedTLS::print_mbedtls_error(ret);
disconnect_from_stream();
return;
}
Ref<StreamPeerTCP> tcp = base;
if (tcp.is_valid() && tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
disconnect_from_stream();
return;
}
}
int StreamPeerMbedTLS::get_available_bytes() const {
ERR_FAIL_COND_V(status != STATUS_CONNECTED, 0);
return mbedtls_ssl_get_bytes_avail(&(tls_ctx->tls));
}
StreamPeerMbedTLS::StreamPeerMbedTLS() {
tls_ctx.instantiate();
}
StreamPeerMbedTLS::~StreamPeerMbedTLS() {
disconnect_from_stream();
}
void StreamPeerMbedTLS::disconnect_from_stream() {
if (status != STATUS_CONNECTED && status != STATUS_HANDSHAKING) {
return;
}
Ref<StreamPeerTCP> tcp = base;
if (tcp.is_valid() && tcp->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
// We are still connected on the socket, try to send close notify.
mbedtls_ssl_close_notify(tls_ctx->get_context());
}
_cleanup();
}
StreamPeerMbedTLS::Status StreamPeerMbedTLS::get_status() const {
return status;
}
Ref<StreamPeer> StreamPeerMbedTLS::get_stream() const {
return base;
}
StreamPeerTLS *StreamPeerMbedTLS::_create_func(bool p_notify_postinitialize) {
return static_cast<StreamPeerTLS *>(ClassDB::creator<StreamPeerMbedTLS>(p_notify_postinitialize));
}
void StreamPeerMbedTLS::initialize_tls() {
_create = _create_func;
}
void StreamPeerMbedTLS::finalize_tls() {
_create = nullptr;
}

View File

@@ -0,0 +1,77 @@
/**************************************************************************/
/* stream_peer_mbedtls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "tls_context_mbedtls.h"
#include "core/io/stream_peer_tls.h"
class StreamPeerMbedTLS : public StreamPeerTLS {
private:
Status status = STATUS_DISCONNECTED;
String hostname;
Ref<StreamPeer> base;
static StreamPeerTLS *_create_func(bool p_notify_postinitialize);
static int bio_recv(void *ctx, unsigned char *buf, size_t len);
static int bio_send(void *ctx, const unsigned char *buf, size_t len);
void _cleanup();
protected:
Ref<TLSContextMbedTLS> tls_ctx;
Error _do_handshake();
public:
virtual void poll();
virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<TLSOptions> p_options);
virtual Error connect_to_stream(Ref<StreamPeer> p_base, const String &p_common_name, Ref<TLSOptions> p_options);
virtual Status get_status() const;
virtual Ref<StreamPeer> get_stream() const;
virtual void disconnect_from_stream();
virtual Error put_data(const uint8_t *p_data, int p_bytes);
virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent);
virtual Error get_data(uint8_t *p_buffer, int p_bytes);
virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received);
virtual int get_available_bytes() const;
static void initialize_tls();
static void finalize_tls();
StreamPeerMbedTLS();
~StreamPeerMbedTLS();
};

View File

@@ -0,0 +1,102 @@
/**************************************************************************/
/* test_crypto_mbedtls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "test_crypto_mbedtls.h"
#include "../crypto_mbedtls.h"
#include "tests/test_macros.h"
#include "tests/test_utils.h"
namespace TestCryptoMbedTLS {
void hmac_digest_test(HashingContext::HashType ht, String expected_hex) {
CryptoMbedTLS crypto;
PackedByteArray key = String("supersecretkey").to_utf8_buffer();
PackedByteArray msg = String("Return of the MAC!").to_utf8_buffer();
PackedByteArray digest = crypto.hmac_digest(ht, key, msg);
String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
CHECK(hex == expected_hex);
}
void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex) {
HMACContextMbedTLS ctx;
PackedByteArray key = String("supersecretkey").to_utf8_buffer();
PackedByteArray msg1 = String("Return of ").to_utf8_buffer();
PackedByteArray msg2 = String("the MAC!").to_utf8_buffer();
Error err = ctx.start(ht, key);
CHECK(err == OK);
err = ctx.update(msg1);
CHECK(err == OK);
err = ctx.update(msg2);
CHECK(err == OK);
PackedByteArray digest = ctx.finish();
String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
CHECK(hex == expected_hex);
}
Ref<CryptoKey> create_crypto_key(const String &p_key_path, bool p_public_only) {
Ref<CryptoKey> crypto_key = Ref<CryptoKey>(CryptoKey::create());
crypto_key->load(p_key_path, p_public_only);
return crypto_key;
}
String read_file_s(const String &p_file_path) {
Ref<FileAccess> file_access = FileAccess::open(p_file_path, FileAccess::READ);
REQUIRE(file_access.is_valid());
return file_access->get_as_utf8_string();
}
bool files_equal(const String &p_in_path, const String &p_out_path) {
const String s_in = read_file_s(p_in_path);
const String s_out = read_file_s(p_out_path);
return s_in == s_out;
}
void crypto_key_public_only_test(const String &p_key_path, bool p_public_only) {
Ref<CryptoKey> crypto_key = create_crypto_key(p_key_path, p_public_only);
bool is_equal = crypto_key->is_public_only() == p_public_only;
CHECK(is_equal);
}
void crypto_key_save_test(const String &p_in_path, const String &p_out_path, bool p_public_only) {
Ref<CryptoKey> crypto_key = create_crypto_key(p_in_path, p_public_only);
crypto_key->save(p_out_path, p_public_only);
bool is_equal = files_equal(p_in_path, p_out_path);
CHECK(is_equal);
}
void crypto_key_save_public_only_test(const String &p_in_priv_path, const String &p_in_pub_path, const String &p_out_path) {
Ref<CryptoKey> crypto_key = create_crypto_key(p_in_priv_path, false);
crypto_key->save(p_out_path, true);
bool is_equal = files_equal(p_in_pub_path, p_out_path);
CHECK(is_equal);
}
} // namespace TestCryptoMbedTLS

View File

@@ -0,0 +1,89 @@
/**************************************************************************/
/* test_crypto_mbedtls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/crypto/crypto.h"
#include "core/crypto/hashing_context.h"
#include "tests/test_macros.h"
#include "tests/test_utils.h"
namespace TestCryptoMbedTLS {
void hmac_digest_test(HashingContext::HashType ht, String expected_hex);
TEST_CASE("[CryptoMbedTLS] HMAC digest") {
// SHA-256
hmac_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
// SHA-1
hmac_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
}
void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex);
TEST_CASE("[HMACContext] HMAC digest") {
// SHA-256
hmac_context_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
// SHA-1
hmac_context_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
}
void crypto_key_public_only_test(const String &p_key_path, bool public_only);
TEST_CASE("[Crypto] CryptoKey is_public_only") {
crypto_key_public_only_test(TestUtils::get_data_path("crypto/in.key"), false);
crypto_key_public_only_test(TestUtils::get_data_path("crypto/in.pub"), true);
}
void crypto_key_save_test(const String &p_in_path, const String &p_out_path, bool public_only);
TEST_CASE("[Crypto] CryptoKey save") {
const String in_priv_path = TestUtils::get_data_path("crypto/in.key");
const String out_priv_path = TestUtils::get_data_path("crypto/out.key");
crypto_key_save_test(in_priv_path, out_priv_path, false);
const String in_pub_path = TestUtils::get_data_path("crypto/in.pub");
const String out_pub_path = TestUtils::get_data_path("crypto/out.pub");
crypto_key_save_test(in_pub_path, out_pub_path, true);
}
void crypto_key_save_public_only_test(const String &p_in_priv_path, const String &p_in_pub_path, const String &p_out_path);
TEST_CASE("[Crypto] CryptoKey save public_only") {
const String in_priv_path = TestUtils::get_data_path("crypto/in.key");
const String in_pub_path = TestUtils::get_data_path("crypto/in.pub");
const String out_path = TestUtils::get_data_path("crypto/out_public_only.pub");
crypto_key_save_public_only_test(in_priv_path, in_pub_path, out_path);
}
} // namespace TestCryptoMbedTLS

View File

@@ -0,0 +1,265 @@
/**************************************************************************/
/* tls_context_mbedtls.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "tls_context_mbedtls.h"
#include "core/config/project_settings.h"
#ifdef TOOLS_ENABLED
#include "editor/settings/editor_settings.h"
#endif // TOOLS_ENABLED
static void my_debug(void *ctx, int level,
const char *file, int line,
const char *str) {
printf("%s:%04d: %s", file, line, str);
fflush(stdout);
}
void TLSContextMbedTLS::print_mbedtls_error(int p_ret) {
printf("mbedtls error: returned -0x%x\n\n", -p_ret);
fflush(stdout);
}
/// CookieContextMbedTLS
Error CookieContextMbedTLS::setup() {
ERR_FAIL_COND_V_MSG(inited, ERR_ALREADY_IN_USE, "This cookie context is already in use");
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
mbedtls_ssl_cookie_init(&cookie_ctx);
inited = true;
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);
if (ret != 0) {
clear(); // Never leave unusable resources around.
ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error " + itos(ret));
}
ret = mbedtls_ssl_cookie_setup(&cookie_ctx, mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0) {
clear();
ERR_FAIL_V_MSG(FAILED, "mbedtls_ssl_cookie_setup returned an error " + itos(ret));
}
return OK;
}
void CookieContextMbedTLS::clear() {
if (!inited) {
return;
}
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
mbedtls_ssl_cookie_free(&cookie_ctx);
}
CookieContextMbedTLS::CookieContextMbedTLS() {
}
CookieContextMbedTLS::~CookieContextMbedTLS() {
clear();
}
/// TLSContextMbedTLS
Error TLSContextMbedTLS::_setup(int p_endpoint, int p_transport, int p_authmode) {
ERR_FAIL_COND_V_MSG(inited, ERR_ALREADY_IN_USE, "This SSL context is already active");
mbedtls_ssl_init(&tls);
mbedtls_ssl_config_init(&conf);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
inited = true;
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);
if (ret != 0) {
clear(); // Never leave unusable resources around.
ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error " + itos(ret));
}
ret = mbedtls_ssl_config_defaults(&conf, p_endpoint, p_transport, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {
clear();
ERR_FAIL_V_MSG(FAILED, "mbedtls_ssl_config_defaults returned an error" + itos(ret));
}
mbedtls_ssl_conf_authmode(&conf, p_authmode);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
return OK;
}
Error TLSContextMbedTLS::init_server(int p_transport, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies) {
ERR_FAIL_COND_V(p_options.is_null() || !p_options->is_server(), ERR_INVALID_PARAMETER);
// Check key and certificate(s)
pkey = p_options->get_private_key();
certs = p_options->get_own_certificate();
ERR_FAIL_COND_V(pkey.is_null() || certs.is_null(), ERR_INVALID_PARAMETER);
Error err = _setup(MBEDTLS_SSL_IS_SERVER, p_transport, MBEDTLS_SSL_VERIFY_NONE); // TODO client auth.
ERR_FAIL_COND_V(err != OK, err);
// Locking key and certificate(s)
pkey->lock();
certs->lock();
// Adding key and certificate
int ret = mbedtls_ssl_conf_own_cert(&conf, &(certs->cert), &(pkey->pkey));
if (ret != 0) {
clear();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid cert/key combination " + itos(ret));
}
// Adding CA chain if available.
if (certs->cert.next) {
mbedtls_ssl_conf_ca_chain(&conf, certs->cert.next, nullptr);
}
// DTLS Cookies
if (p_transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
if (p_cookies.is_null() || !p_cookies->inited) {
clear();
ERR_FAIL_V(ERR_BUG);
}
cookies = p_cookies;
mbedtls_ssl_conf_dtls_cookies(&conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &(cookies->cookie_ctx));
}
#if MBEDTLS_VERSION_MAJOR >= 3
#ifdef TOOLS_ENABLED
if (EditorSettings::get_singleton()) {
if (!EditorSettings::get_singleton()->get_setting("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
} else
#endif
{
if (!GLOBAL_GET("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
}
#endif
mbedtls_ssl_setup(&tls, &conf);
return OK;
}
Error TLSContextMbedTLS::init_client(int p_transport, const String &p_hostname, Ref<TLSOptions> p_options) {
ERR_FAIL_COND_V(p_options.is_null() || p_options->is_server(), ERR_INVALID_PARAMETER);
int authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
bool unsafe = p_options->is_unsafe_client();
if (unsafe && p_options->get_trusted_ca_chain().is_null()) {
authmode = MBEDTLS_SSL_VERIFY_NONE;
}
Error err = _setup(MBEDTLS_SSL_IS_CLIENT, p_transport, authmode);
ERR_FAIL_COND_V(err != OK, err);
if (unsafe) {
// No hostname verification for unsafe clients.
mbedtls_ssl_set_hostname(&tls, nullptr);
} else {
String cn = p_options->get_common_name_override();
if (cn.is_empty()) {
cn = p_hostname;
}
mbedtls_ssl_set_hostname(&tls, cn.utf8().get_data());
}
X509CertificateMbedTLS *cas = nullptr;
if (p_options->get_trusted_ca_chain().is_valid()) {
// Locking CA certificates
certs = p_options->get_trusted_ca_chain();
certs->lock();
cas = certs.ptr();
} else {
// Fall back to default certificates (no need to lock those).
cas = CryptoMbedTLS::get_default_certificates();
if (cas == nullptr) {
clear();
ERR_FAIL_V_MSG(ERR_UNCONFIGURED, "SSL module failed to initialize!");
}
}
#if MBEDTLS_VERSION_MAJOR >= 3
#ifdef TOOLS_ENABLED
if (EditorSettings::get_singleton()) {
if (!EditorSettings::get_singleton()->get_setting("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
} else
#endif
{
if (!GLOBAL_GET("network/tls/enable_tls_v1.3").operator bool()) {
mbedtls_ssl_conf_max_tls_version(&conf, MBEDTLS_SSL_VERSION_TLS1_2);
}
}
#endif
// Set valid CAs
mbedtls_ssl_conf_ca_chain(&conf, &(cas->cert), nullptr);
mbedtls_ssl_setup(&tls, &conf);
return OK;
}
void TLSContextMbedTLS::clear() {
if (!inited) {
return;
}
mbedtls_ssl_free(&tls);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
// Unlock and key and certificates
if (certs.is_valid()) {
certs->unlock();
}
certs = Ref<X509Certificate>();
if (pkey.is_valid()) {
pkey->unlock();
}
pkey = Ref<CryptoKeyMbedTLS>();
cookies = Ref<CookieContextMbedTLS>();
inited = false;
}
mbedtls_ssl_context *TLSContextMbedTLS::get_context() {
ERR_FAIL_COND_V(!inited, nullptr);
return &tls;
}
TLSContextMbedTLS::TLSContextMbedTLS() {
}
TLSContextMbedTLS::~TLSContextMbedTLS() {
clear();
}

View File

@@ -0,0 +1,87 @@
/**************************************************************************/
/* tls_context_mbedtls.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "crypto_mbedtls.h"
#include "core/object/ref_counted.h"
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/debug.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ssl.h>
#include <mbedtls/ssl_cookie.h>
class TLSContextMbedTLS;
class CookieContextMbedTLS : public RefCounted {
friend class TLSContextMbedTLS;
protected:
bool inited = false;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_cookie_ctx cookie_ctx;
public:
Error setup();
void clear();
CookieContextMbedTLS();
~CookieContextMbedTLS() override;
};
class TLSContextMbedTLS : public RefCounted {
protected:
bool inited = false;
public:
static void print_mbedtls_error(int p_ret);
Ref<X509CertificateMbedTLS> certs;
Ref<CryptoKeyMbedTLS> pkey;
Ref<CookieContextMbedTLS> cookies;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context tls;
mbedtls_ssl_config conf;
Error _setup(int p_endpoint, int p_transport, int p_authmode);
Error init_server(int p_transport, Ref<TLSOptions> p_options, Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
Error init_client(int p_transport, const String &p_hostname, Ref<TLSOptions> p_options);
void clear();
mbedtls_ssl_context *get_context();
TLSContextMbedTLS();
~TLSContextMbedTLS() override;
};