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
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:
151
modules/mbedtls/SCsub
Normal file
151
modules/mbedtls/SCsub
Normal 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)
|
6
modules/mbedtls/config.py
Normal file
6
modules/mbedtls/config.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
535
modules/mbedtls/crypto_mbedtls.cpp
Normal file
535
modules/mbedtls/crypto_mbedtls.cpp
Normal 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;
|
||||
}
|
155
modules/mbedtls/crypto_mbedtls.h
Normal file
155
modules/mbedtls/crypto_mbedtls.h
Normal 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;
|
||||
};
|
77
modules/mbedtls/dtls_server_mbedtls.cpp
Normal file
77
modules/mbedtls/dtls_server_mbedtls.cpp
Normal 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();
|
||||
}
|
53
modules/mbedtls/dtls_server_mbedtls.h
Normal file
53
modules/mbedtls/dtls_server_mbedtls.h
Normal 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;
|
||||
};
|
282
modules/mbedtls/packet_peer_mbed_dtls.cpp
Normal file
282
modules/mbedtls/packet_peer_mbed_dtls.cpp
Normal 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;
|
||||
}
|
84
modules/mbedtls/packet_peer_mbed_dtls.h
Normal file
84
modules/mbedtls/packet_peer_mbed_dtls.h
Normal 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();
|
||||
};
|
134
modules/mbedtls/register_types.cpp
Normal file
134
modules/mbedtls/register_types.cpp
Normal 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
|
||||
}
|
36
modules/mbedtls/register_types.h
Normal file
36
modules/mbedtls/register_types.h
Normal 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);
|
315
modules/mbedtls/stream_peer_mbedtls.cpp
Normal file
315
modules/mbedtls/stream_peer_mbedtls.cpp
Normal 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;
|
||||
}
|
77
modules/mbedtls/stream_peer_mbedtls.h
Normal file
77
modules/mbedtls/stream_peer_mbedtls.h
Normal 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();
|
||||
};
|
102
modules/mbedtls/tests/test_crypto_mbedtls.cpp
Normal file
102
modules/mbedtls/tests/test_crypto_mbedtls.cpp
Normal 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
|
89
modules/mbedtls/tests/test_crypto_mbedtls.h
Normal file
89
modules/mbedtls/tests/test_crypto_mbedtls.h
Normal 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
|
265
modules/mbedtls/tls_context_mbedtls.cpp
Normal file
265
modules/mbedtls/tls_context_mbedtls.cpp
Normal 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();
|
||||
}
|
87
modules/mbedtls/tls_context_mbedtls.h
Normal file
87
modules/mbedtls/tls_context_mbedtls.h
Normal 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;
|
||||
};
|
Reference in New Issue
Block a user