diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp index c8ee3f5430d..e8b9f4df1c3 100644 --- a/core/crypto/crypto.cpp +++ b/core/crypto/crypto.cpp @@ -44,8 +44,11 @@ CryptoKey *CryptoKey::create() { } void CryptoKey::_bind_methods() { - ClassDB::bind_method(D_METHOD("save", "path"), &CryptoKey::save); - ClassDB::bind_method(D_METHOD("load", "path"), &CryptoKey::load); + ClassDB::bind_method(D_METHOD("save", "path", "public_only"), &CryptoKey::save, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("load", "path", "public_only"), &CryptoKey::load, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("is_public_only"), &CryptoKey::is_public_only); + ClassDB::bind_method(D_METHOD("save_to_string", "public_only"), &CryptoKey::save_to_string, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("load_from_string", "string_key", "public_only"), &CryptoKey::load_from_string, DEFVAL(false)); } X509Certificate *(*X509Certificate::_create)() = NULL; @@ -98,7 +101,12 @@ RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_origi } else if (el == "key") { CryptoKey *key = CryptoKey::create(); if (key) - key->load(p_path); + key->load(p_path, false); + return key; + } else if (el == "pub") { + CryptoKey *key = CryptoKey::create(); + if (key) + key->load(p_path, true); return key; } return NULL; @@ -108,6 +116,7 @@ void ResourceFormatLoaderCrypto::get_recognized_extensions(List *p_exten p_extensions->push_back("crt"); p_extensions->push_back("key"); + p_extensions->push_back("pub"); } bool ResourceFormatLoaderCrypto::handles_type(const String &p_type) const { @@ -120,7 +129,7 @@ String ResourceFormatLoaderCrypto::get_resource_type(const String &p_path) const String el = p_path.get_extension().to_lower(); if (el == "crt") return "X509Certificate"; - else if (el == "key") + else if (el == "key" || el == "pub") return "CryptoKey"; return ""; } @@ -133,7 +142,8 @@ Error ResourceFormatSaverCrypto::save(const String &p_path, const RES &p_resourc if (cert.is_valid()) { err = cert->save(p_path); } else if (key.is_valid()) { - err = key->save(p_path); + String el = p_path.get_extension().to_lower(); + err = key->save(p_path, el == "pub"); } else { ERR_FAIL_V(ERR_INVALID_PARAMETER); } @@ -149,7 +159,10 @@ void ResourceFormatSaverCrypto::get_recognized_extensions(const RES &p_resource, p_extensions->push_back("crt"); } if (key) { - p_extensions->push_back("key"); + if (!key->is_public_only()) { + p_extensions->push_back("key"); + } + p_extensions->push_back("pub"); } } bool ResourceFormatSaverCrypto::recognize(const RES &p_resource) const { diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index d3f5bcf134b..0b179ab3dcc 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -46,8 +46,11 @@ protected: public: static CryptoKey *create(); - virtual Error load(String p_path) = 0; - virtual Error save(String p_path) = 0; + virtual Error load(String p_path, bool p_public_only = false) = 0; + virtual Error save(String p_path, bool p_public_only = false) = 0; + virtual String save_to_string(bool p_public_only = false) = 0; + virtual Error load_from_string(String p_string_key, bool p_public_only = false) = 0; + virtual bool is_public_only() const = 0; }; class X509Certificate : public Resource { diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index 2bc7c9130e0..1ab8dc96cc9 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -50,7 +50,7 @@ CryptoKey *CryptoKeyMbedTLS::create() { return memnew(CryptoKeyMbedTLS); } -Error CryptoKeyMbedTLS::load(String p_path) { +Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use"); PoolByteArray out; @@ -66,22 +66,33 @@ Error CryptoKeyMbedTLS::load(String p_path) { } memdelete(f); - int ret = mbedtls_pk_parse_key(&pkey, out.read().ptr(), out.size(), NULL, 0); + int ret = 0; + if (p_public_only) { + ret = mbedtls_pk_parse_public_key(&pkey, out.read().ptr(), out.size()); + } else { + ret = mbedtls_pk_parse_key(&pkey, out.read().ptr(), out.size(), NULL, 0); + } // We MUST zeroize the memory for safety! mbedtls_platform_zeroize(out.write().ptr(), out.size()); - ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing private key '" + itos(ret) + "'."); + ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing key '" + itos(ret) + "'."); + public_only = p_public_only; return OK; } -Error CryptoKeyMbedTLS::save(String p_path) { +Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); unsigned char w[16000]; memset(w, 0, sizeof(w)); - int ret = mbedtls_pk_write_key_pem(&pkey, w, 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) { memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written. @@ -95,6 +106,37 @@ Error CryptoKeyMbedTLS::save(String p_path) { return OK; } +Error CryptoKeyMbedTLS::load_from_string(String p_string_key, bool p_public_only) { + int ret = 0; + if (p_public_only) { + ret = mbedtls_pk_parse_public_key(&pkey, (unsigned char *)p_string_key.utf8().get_data(), p_string_key.utf8().size()); + } else { + ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)p_string_key.utf8().get_data(), p_string_key.utf8().size(), NULL, 0); + } + 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; +} + X509Certificate *X509CertificateMbedTLS::create() { return memnew(X509CertificateMbedTLS); } @@ -229,6 +271,7 @@ Ref CryptoMbedTLS::generate_rsa(int p_bytes) { int ret = mbedtls_pk_setup(&(out->pkey), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); ERR_FAIL_COND_V(ret != 0, NULL); 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, NULL); return out; } diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h index 23434769d41..ab57797efd3 100644 --- a/modules/mbedtls/crypto_mbedtls.h +++ b/modules/mbedtls/crypto_mbedtls.h @@ -44,15 +44,19 @@ class CryptoKeyMbedTLS : public CryptoKey { private: mbedtls_pk_context pkey; - int locks; + int locks = 0; + bool public_only = true; public: static CryptoKey *create(); static void make_default() { CryptoKey::_create = create; } static void finalize() { CryptoKey::_create = NULL; } - virtual Error load(String p_path); - virtual Error save(String p_path); + virtual Error load(String p_path, bool p_public_only); + virtual Error save(String p_path, bool p_public_only); + virtual String save_to_string(bool p_public_only); + virtual Error load_from_string(String p_string_key, bool p_public_only); + virtual bool is_public_only() const { return public_only; }; CryptoKeyMbedTLS() { mbedtls_pk_init(&pkey);