Merge pull request #11508 from akallabeth/settings-serialize

[common,settings] new settings (de)serialization API
This commit is contained in:
akallabeth 2025-04-22 12:16:52 +02:00 committed by GitHub
commit 1f7b7fbb5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 2828 additions and 186 deletions

View File

@ -3,6 +3,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "preload")
set(WITH_SERVER ON CACHE BOOL "qa default")
set(WITH_SAMPLE ON CACHE BOOL "qa default")
set(WITH_SIMD ON CACHE BOOL "qa default")
set(WITH_OPAQUE_SETTINGS ON CACHE BOOL "qa default")
set(WITH_STREAMPOOL_DEBUG ON CACHE BOOL "preload")
set(WITH_VERBOSE_WINPR_ASSERT OFF CACHE BOOL "qa default")
set(ENABLE_WARNING_VERBOSE ON CACHE BOOL "preload")

View File

@ -10,6 +10,7 @@ set(WITH_PROXY ON CACHE BOOL "qa default")
set(WITH_PULSE ON CACHE BOOL "qa default")
set(WITH_CUPS ON CACHE BOOL "qa default")
set(WITH_OPENCL ON CACHE BOOL "qa default")
set(WITH_OPAQUE_SETTINGS ON CACHE BOOL "qa default")
set(WITH_PCSC ON CACHE BOOL "qa default")
set(WITH_SOXR ON CACHE BOOL "qa default")
set(WITH_SIMD ON CACHE BOOL "qa default")

View File

@ -1,45 +1,60 @@
include(CMakeDependentOption)
option(WITH_JSON_DISABLED "Build without any JSON support" OFF)
cmake_dependent_option(WITH_CJSON_REQUIRED "Build with cJSON (fail if not found)" OFF "NOT WITH_JSON_DISABLED" OFF)
cmake_dependent_option(WITH_JSONC_REQUIRED "Build with JSON-C (fail if not found)" OFF "NOT WITH_JSON_DISABLED" OFF)
cmake_dependent_option(
WITH_CJSON_REQUIRED "Build with cJSON (fail if not found)" OFF "NOT WITH_JSON_DISABLED;NOT WITH_JSONC_REQUIRED" OFF
)
cmake_dependent_option(
WITH_JSONC_REQUIRED "Build with JSON-C (fail if not found)" OFF "NOT WITH_JSON_DISABLED;NOT WITH_CJSON_REQUIRED" OFF
)
if(NOT WITH_JSON_DISABLED)
find_package(cJSON)
# Fallback detection:
# older ubuntu releases did not ship CMake or pkg-config files
# for cJSON. Be optimistic and try pkg-config and as last resort
# try manual detection
if(NOT CJSON_FOUND)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(CJSON libcjson)
endif()
if(NOT WITH_JSONC_REQUIRED)
find_package(cJSON)
# Fallback detection:
# older ubuntu releases did not ship CMake or pkg-config files
# for cJSON. Be optimistic and try pkg-config and as last resort
# try manual detection
if(NOT CJSON_FOUND)
find_path(CJSON_INCLUDE_DIRS NAMES cjson/cJSON.h)
find_library(CJSON_LIBRARIES NAMES cjson)
if(NOT "${CJSON_LIBRARIES}" STREQUAL "CJSON_LIBRARIES-NOTFOUND" AND NOT "${CJSON_INCLUDE_DIRS}" STREQUAL
"CJSON_INCLUDE_DIRS-NOTFOUND"
)
set(CJSON_FOUND ON)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(CJSON libcjson)
endif()
if(NOT CJSON_FOUND)
find_path(CJSON_INCLUDE_DIRS NAMES cjson/cJSON.h)
find_library(CJSON_LIBRARIES NAMES cjson)
if(NOT "${CJSON_LIBRARIES}" STREQUAL "CJSON_LIBRARIES-NOTFOUND" AND NOT "${CJSON_INCLUDE_DIRS}" STREQUAL
"CJSON_INCLUDE_DIRS-NOTFOUND"
)
set(CJSON_FOUND ON)
endif()
endif()
endif()
endif()
if(WITH_CJSON_REQUIRED)
if(NOT CJSON_FOUND)
message(FATAL_ERROR "cJSON was requested but not found")
if(WITH_CJSON_REQUIRED)
if(NOT CJSON_FOUND)
message(FATAL_ERROR "cJSON was requested but not found")
endif()
endif()
else()
unset(CJSON_FOUND)
endif()
if(WITH_JSONC_REQUIRED)
find_package(JSONC REQUIRED)
else()
elseif(NOT WITH_CJSON_REQUIRED)
find_package(JSONC)
endif()
if(WITH_CJSON_REQUIRED)
unset(JSONC_FOUND)
endif()
if(NOT JSONC_FOUND AND NOT CJSON_FOUND)
if(WITH_CJSON_REQUIRED OR WITH_JSONC_REQUIRED)
message(FATAL_ERROR "cJSON (${WITH_CJSON_REQUIRED}) or json-c (${WITH_JSONC_REQUIRED}) required but not found")
endif()
set(WITH_WINPR_JSON OFF CACHE INTERNAL "internal")
message("compiling without JSON support. Install cJSON or json-c to enable")
endif()

View File

@ -35,16 +35,62 @@ extern "C"
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
FREERDP_API rdpPrivateKey* freerdp_key_new(void);
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
FREERDP_API rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile);
WINPR_DEPRECATED_VAR(
"[since 3.16.0] use freerdp_key_new_from_file_enc",
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
FREERDP_API rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile));
WINPR_DEPRECATED_VAR("[since 3.16.0] use freerdp_key_new_from_pem_enc",
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
FREERDP_API rdpPrivateKey* freerdp_key_new_from_pem(const char* pem));
/** @brief Create a private key from file \b keyfile with optional password \b password
*
* @param keyfile The file to read the key from
* @param password The optional password the key is enecrypted with, \b NULL for unencrypted
* @return An allocated private key, \b NULL in case of failure.
* @since version 3.16.0
*/
FREERDP_API rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile,
const char* password);
/** @brief Create a private key from a PEM file with optional \b password
*
* @param pem The PEM string to use
* @param password The optional password, use \b NULL if no encryption is used.
* @return An allocated private key, \b NULL in case of failure.
* @since version 3.16.0
*/
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
FREERDP_API rdpPrivateKey* freerdp_key_new_from_pem(const char* pem);
FREERDP_API rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password);
FREERDP_API BOOL freerdp_key_is_rsa(const rdpPrivateKey* key);
FREERDP_API size_t freerdp_key_get_bits(const rdpPrivateKey* key);
/** @brief Create a PEM from a private key
*
* @param key The key to convert
* @param plen Optional pointer, value set to strlen of the PEM
* @param password Optional password string. If \b NULL an unencrypted PEM is written.
* @return A PEM string or \b NULL in case of errors
*
* @since version 3.16.0
*/
WINPR_ATTR_MALLOC(free, 1)
FREERDP_API char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen,
const char* password);
/** @brief Create a new private key
*
* @param key The key to initialize
* @param type The key type (RSA, ...)
* @param count The number of arguments following, depends on type
* @return \b TRUE for success, \b FALSE otherwise
* @since version 3.16.0
*/
FREERDP_API BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...);
#ifdef __cplusplus
}
#endif

View File

@ -773,6 +773,28 @@ extern "C"
const rdpMonitor* monitors,
size_t count);
/** @brief A function that converts a \b rdpSettings struct to a \b JSON serialized string.
*
* @param settings The settings instance to serialize
* @param pretty Format the resulting \b JSON human readable
* @param plength An optional pointer that receives the length (strlen) of the returned string.
* @return A \b JSON string representing the serialized form of the \b rdpSettings or \b NULL
* in case of an error.
* @since version 3.16.0
*/
FREERDP_API char* freerdp_settings_serialize(const rdpSettings* settings, BOOL pretty,
size_t* plength);
/** @brief A function that converts a \b JSON string to a \b rdpSettings struct
*
* @param json The \b JSON string
* @param length The strlen of the \b JSON string
* @return An allocated \b rdpSettings struct or \b NULL in case of an error
* @since version 3.16.0
*/
WINPR_ATTR_MALLOC(freerdp_settings_free, 1)
FREERDP_API rdpSettings* freerdp_settings_deserialize(const char* json, size_t length);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -2366,8 +2366,7 @@ BOOL freerdp_settings_set_uint32(WINPR_ATTR_UNUSED rdpSettings* settings,
break;
case FreeRDP_ReceivedCapabilitiesSize:
settings->ReceivedCapabilitiesSize = cnv.c;
break;
return freerdp_capability_buffer_resize(settings, cnv.c);
case FreeRDP_RedirectedSessionId:
settings->RedirectedSessionId = cnv.c;
@ -2494,8 +2493,7 @@ BOOL freerdp_settings_set_uint32(WINPR_ATTR_UNUSED rdpSettings* settings,
break;
case FreeRDP_TargetNetAddressCount:
settings->TargetNetAddressCount = cnv.c;
break;
return freerdp_target_net_addresses_resize(settings, cnv.c);
case FreeRDP_TcpAckTimeout:
settings->TcpAckTimeout = cnv.c;

View File

@ -79,11 +79,14 @@ BOOL freerdp_settings_clone_keys(rdpSettings* dst, const rdpSettings* src)
break;
case FREERDP_SETTINGS_TYPE_POINTER: /* pointer */
{
const void* sval =
freerdp_settings_get_pointer(src, (FreeRDP_Settings_Keys_Pointer)cur->id);
if (!freerdp_settings_set_pointer(dst, (FreeRDP_Settings_Keys_Pointer)cur->id,
sval))
return FALSE;
if (cur->id == FreeRDP_instance)
{
const void* sval =
freerdp_settings_get_pointer(src, (FreeRDP_Settings_Keys_Pointer)cur->id);
if (!freerdp_settings_set_pointer(dst, (FreeRDP_Settings_Keys_Pointer)cur->id,
sval))
return FALSE;
}
}
break;
default:

View File

@ -586,7 +586,7 @@ int aad_recv(rdpAad* aad, wStream* s)
static BOOL generate_rsa_2048(rdpAad* aad)
{
WINPR_ASSERT(aad);
return freerdp_key_generate(aad->key, 2048);
return freerdp_key_generate(aad->key, "RSA", 1, 2048);
}
static char* generate_rsa_digest_base64_str(rdpAad* aad, const char* input, size_t ilen)

View File

@ -752,38 +752,6 @@ BOOL freerdp_settings_set_default_order_support(rdpSettings* settings)
return TRUE;
}
BOOL freerdp_capability_buffer_allocate(rdpSettings* settings, UINT32 count)
{
WINPR_ASSERT(settings);
WINPR_ASSERT(count > 0);
WINPR_ASSERT(count == 32);
freerdp_capability_buffer_free(settings);
WINPR_ASSERT(settings->ReceivedCapabilitiesSize == 0);
settings->ReceivedCapabilitiesSize = count;
void* tmp = realloc(settings->ReceivedCapabilities, count * sizeof(BYTE));
if (!tmp)
return FALSE;
memset(tmp, 0, count * sizeof(BYTE));
settings->ReceivedCapabilities = tmp;
tmp = realloc((void*)settings->ReceivedCapabilityData, count * sizeof(BYTE*));
if (!tmp)
return FALSE;
memset(tmp, 0, count * sizeof(BYTE*));
settings->ReceivedCapabilityData = (BYTE**)tmp;
tmp = realloc(settings->ReceivedCapabilityDataSizes, count * sizeof(UINT32));
if (!tmp)
return FALSE;
memset(tmp, 0, count * sizeof(UINT32));
settings->ReceivedCapabilityDataSizes = tmp;
return (settings->ReceivedCapabilities && settings->ReceivedCapabilityData &&
settings->ReceivedCapabilityDataSizes);
}
#if !defined(WITH_FULL_CONFIG_PATH)
static char* freerdp_settings_get_legacy_config_path(void)
{
@ -998,7 +966,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, NULL, 1))
goto out_fail;
if (!freerdp_capability_buffer_allocate(settings, 32))
if (!freerdp_capability_buffer_resize(settings, 32))
goto out_fail;
{
@ -1396,12 +1364,12 @@ static BOOL freerdp_settings_int_buffer_copy(rdpSettings* _settings, const rdpSe
if (!_settings->OrderSupport)
goto out_fail;
if (!freerdp_capability_buffer_copy(_settings, settings))
goto out_fail;
CopyMemory(_settings->OrderSupport, settings->OrderSupport, 32);
}
if (!freerdp_capability_buffer_copy(_settings, settings))
goto out_fail;
const UINT32 glyphCacheCount = 10;
const GLYPH_CACHE_DEFINITION* glyphCache =
freerdp_settings_get_pointer(settings, FreeRDP_GlyphCache);
@ -1432,7 +1400,6 @@ static BOOL freerdp_settings_int_buffer_copy(rdpSettings* _settings, const rdpSe
const UINT32 nrports = freerdp_settings_get_uint32(settings, FreeRDP_TargetNetAddressCount);
if (!freerdp_target_net_adresses_reset(_settings, nrports))
goto out_fail;
;
for (UINT32 i = 0; i < nrports; i++)
{
@ -1526,34 +1493,6 @@ BOOL freerdp_settings_copy(rdpSettings* _settings, const rdpSettings* settings)
* NULL to fix issues during cleanup */
rc = freerdp_settings_clone_keys(_settings, settings);
_settings->LoadBalanceInfo = NULL;
_settings->ServerRandom = NULL;
_settings->ClientRandom = NULL;
_settings->ServerCertificate = NULL;
_settings->RdpServerCertificate = NULL;
_settings->RdpServerRsaKey = NULL;
_settings->ChannelDefArray = NULL;
_settings->MonitorDefArray = NULL;
_settings->MonitorIds = NULL;
_settings->OrderSupport = NULL;
_settings->BitmapCacheV2CellInfo = NULL;
_settings->GlyphCache = NULL;
_settings->FragCache = NULL;
_settings->ClientAutoReconnectCookie = NULL;
_settings->ServerAutoReconnectCookie = NULL;
_settings->ClientTimeZone = NULL;
_settings->RedirectionPassword = NULL;
_settings->RedirectionTsvUrl = NULL;
_settings->TargetNetAddresses = NULL;
_settings->TargetNetPorts = NULL;
_settings->RedirectionGuid = NULL;
_settings->DeviceArray = NULL;
_settings->StaticChannelArray = NULL;
_settings->DynamicChannelArray = NULL;
_settings->ReceivedCapabilities = NULL;
_settings->ReceivedCapabilityData = NULL;
_settings->ReceivedCapabilityDataSizes = NULL;
_settings->ServerLicenseProductIssuersCount = 0;
_settings->ServerLicenseProductIssuers = NULL;
@ -1702,17 +1641,7 @@ BOOL freerdp_target_net_adresses_reset(rdpSettings* settings, size_t size)
{
freerdp_target_net_addresses_free(settings);
if (size > 0)
{
if (!freerdp_settings_set_pointer_len_(settings, FreeRDP_TargetNetPorts,
FreeRDP_UINT32_UNUSED, NULL, size, sizeof(UINT32)))
return FALSE;
if (!freerdp_settings_set_pointer_len_(settings, FreeRDP_TargetNetAddresses,
FreeRDP_TargetNetAddressCount, NULL, size,
sizeof(char*)))
return FALSE;
}
return TRUE;
return freerdp_target_net_addresses_resize(settings, size);
}
BOOL freerdp_settings_enforce_monitor_exists(rdpSettings* settings)

View File

@ -48,7 +48,7 @@ FREERDP_LOCAL BOOL freerdp_settings_set_string_(rdpSettings* settings,
FREERDP_LOCAL BOOL freerdp_settings_set_string_copy_(rdpSettings* settings,
FreeRDP_Settings_Keys_String id,
const char* val, size_t len, BOOL cleanup);
FREERDP_LOCAL BOOL freerdp_capability_buffer_allocate(rdpSettings* settings, UINT32 count);
FREERDP_LOCAL BOOL freerdp_capability_buffer_resize(rdpSettings* settings, size_t count);
FREERDP_LOCAL BOOL identity_set_from_settings_with_pwd(SEC_WINNT_AUTH_IDENTITY_W* identity,
const rdpSettings* settings,
@ -75,4 +75,6 @@ FREERDP_LOCAL BOOL freerdp_settings_set_pointer_len_(rdpSettings* settings,
const void* data, size_t len, size_t size);
FREERDP_LOCAL BOOL freerdp_target_net_adresses_reset(rdpSettings* settings, size_t size);
FREERDP_LOCAL BOOL freerdp_target_net_addresses_resize(rdpSettings* settings, size_t count);
#endif /* FREERDP_LIB_CORE_SETTINGS_H */

View File

@ -2,6 +2,7 @@
#include <winpr/user.h>
#include <winpr/crypto.h>
#include <winpr/json.h>
#include <freerdp/settings.h>
#include <freerdp/codecs.h>
@ -256,7 +257,7 @@ static BOOL test_copy(void)
goto fail;
if (freerdp_settings_print_diff(log, WLOG_WARN, settings, copy))
goto fail;
if (!freerdp_settings_print_diff(log, WLOG_WARN, settings, modified))
if (!freerdp_settings_print_diff(log, WLOG_INFO, settings, modified))
goto fail;
rc = TRUE;
@ -555,6 +556,16 @@ static BOOL check_key_helpers(size_t key, const char* stype)
winpr_RAND(&intEntryType, sizeof(intEntryType));
winpr_RAND(&val.u64, sizeof(val.u64));
switch (key)
{
case FreeRDP_ReceivedCapabilitiesSize:
case FreeRDP_TargetNetAddressCount:
val.u64 %= 512;
break;
default:
break;
}
switch (type)
{
case RDP_SETTINGS_TYPE_BOOL:
@ -598,8 +609,8 @@ static BOOL check_key_helpers(size_t key, const char* stype)
have = freerdp_settings_set_value_for_name(settings, name, value);
if (have != expect)
{
printf("[%s] have[%s] != expect[%s]\n", stype, have ? "TRUE" : "FALSE",
expect ? "TRUE" : "FALSE");
printf("[%s] %s=%s have [%s] != expect[%s]\n", stype, name, value,
have ? "TRUE" : "FALSE", expect ? "TRUE" : "FALSE");
goto fail;
}
@ -1517,6 +1528,342 @@ fail:
return rc;
}
static BOOL test_serialize_with(rdpSettings* src, const char* name)
{
BOOL rc = FALSE;
size_t slen = 0;
rdpSettings* dst = NULL;
char* str = NULL;
if (!src)
goto fail;
str = freerdp_settings_serialize(src, TRUE, &slen);
if (!str || (slen == 0))
goto fail;
dst = freerdp_settings_deserialize(str, slen);
if (!dst)
goto fail;
rc = !freerdp_settings_print_diff(WLog_Get("TestSettings::serialize"), WLOG_WARN, src, dst);
fail:
freerdp_settings_free(src);
freerdp_settings_free(dst);
free(str);
printf("Test %s: %s\n", name, rc ? "success" : "failure");
return rc;
}
static BOOL test_serialize_strings(DWORD flags, const char* str)
{
rdpSettings* src = freerdp_settings_new(flags);
if (!src)
return FALSE;
for (SSIZE_T x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++)
{
union
{
SSIZE_T s;
FreeRDP_Settings_Keys_Pointer ptr;
} iter;
iter.s = x;
SSIZE_T type = freerdp_settings_get_type_for_key(iter.s);
switch (type)
{
case RDP_SETTINGS_TYPE_STRING:
if (!freerdp_settings_set_string(src, iter.ptr, str))
{
freerdp_settings_free(src);
return FALSE;
}
break;
default:
break;
}
}
char buffer[128] = { 0 };
(void)_snprintf(buffer, sizeof(buffer), "%s flags 0x%08" PRIx32 " {%s}", __func__, flags, str);
return test_serialize_with(src, buffer);
}
static BOOL add_argv(rdpSettings* src, size_t argc, const char* argv[])
{
ADDIN_ARGV* val = freerdp_addin_argv_new(argc, argv);
if (!val)
return FALSE;
if (!freerdp_static_channel_collection_add(src, val))
return FALSE;
if (!freerdp_static_channel_collection_add(src, freerdp_addin_argv_clone(val)))
return FALSE;
if (!freerdp_dynamic_channel_collection_add(src, freerdp_addin_argv_clone(val)))
return FALSE;
return TRUE;
}
static BOOL add_dev_argv(rdpSettings* src, size_t argc, const char* argv[])
{
FreeRDP_Settings_Keys_Pointer key = FreeRDP_DeviceArray;
size_t count = 6;
if (!freerdp_settings_set_pointer_len(src, key, NULL, count))
return FALSE;
const uint32_t types[] = { RDPDR_DTYP_SERIAL, RDPDR_DTYP_PARALLEL, RDPDR_DTYP_PRINT,
RDPDR_DTYP_FILESYSTEM, RDPDR_DTYP_SMARTCARD };
for (size_t x = 0; x < count; x++)
{
const uint32_t type = types[x % ARRAYSIZE(types)];
RDPDR_DEVICE* arg = freerdp_device_new(type, argc, argv);
if (!arg)
return FALSE;
const BOOL rc = freerdp_settings_set_pointer_array(src, key, x, arg);
freerdp_device_free(arg);
if (!rc)
return FALSE;
}
return TRUE;
}
static BOOL fill_random(rdpSettings* src, FreeRDP_Settings_Keys_Pointer key, size_t elem,
size_t len)
{
if (!freerdp_settings_set_pointer_len(src, key, NULL, len))
return FALSE;
uint8_t* data = freerdp_settings_get_pointer_writable(src, key);
if (!data)
return FALSE;
winpr_RAND(data, len * elem);
return TRUE;
}
static BOOL fill_random_timezone(rdpSettings* src)
{
FreeRDP_Settings_Keys_Pointer key = FreeRDP_ClientTimeZone;
if (!fill_random(src, key, sizeof(TIME_ZONE_INFORMATION), 1))
return FALSE;
TIME_ZONE_INFORMATION* data = freerdp_settings_get_pointer_writable(src, key);
if (!data)
return FALSE;
(void)ConvertUtf8ToWChar("testXXXXDaylight", data->DaylightName, ARRAYSIZE(data->DaylightName));
(void)ConvertUtf8ToWChar("testXXXX", data->StandardName, ARRAYSIZE(data->StandardName));
return TRUE;
}
static BOOL set_private_key(rdpSettings* src)
{
if (!freerdp_settings_set_pointer_len(src, FreeRDP_RdpServerRsaKey, NULL, 1))
return FALSE;
rdpPrivateKey* key =
freerdp_settings_get_pointer_array_writable(src, FreeRDP_RdpServerRsaKey, 0);
if (!key)
return FALSE;
return freerdp_key_generate(key, "RSA", 1, 4096);
}
static BOOL set_cert(rdpSettings* src, FreeRDP_Settings_Keys_Pointer key)
{
const char pem[] = "-----BEGIN CERTIFICATE-----\n"
"MIICvTCCAaWgAwIBAgIEZrM9yjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlt\n"
"b3RvcmhlYWQwHhcNMjUwNDE1MTExMjE5WhcNMjYwNDE1MTExMjE5WjAUMRIwEAYD\n"
"VQQDDAltb3RvcmhlYWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw\n"
"g0tADY3kh5Hi6YsTsQbuaPs50zlTpIv+rCCK3BNIblsIh4cSO1YGdWfB0gP9bUD1\n"
"L7mPWRnIiAvwrRA/Mgyo+UgiYj/aE3xxN3adB9/QsUzNrI07o6L8MupV4237txMj\n"
"uxVmarB4c7E4wFgSxwbMQPhQtoNNew3bY+EeqhQBMFfYy4z+rg60xl0QHGcMePY/\n"
"xz0WMHrIz6FhZfBIr+BGViRtjIchbjcU0HfTSujX+MT0D5MBISe8aiFvrewFItfT\n"
"vglriDLeNMiB9U/aRLV8OtW+heGNhi5qSC9JXEW70OFeGAoqtwyRHLnSh38Fo2xv\n"
"fEc90zjkCan8usEDKuzBAgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0G\n"
"CSqGSIb3DQEBCwUAA4IBAQBY1wkJ6XWduNmTi+UNdcZ5e9GWV/3+SYLtFALwKVrU\n"
"KQQbsYnGLfyUKXFc7e9JoZ+UCTJgY3EyL+6p79io+cFeTtpp1RVKljibbeRAP01W\n"
"WbcxcHZFKgBlH1KNSeO7iOAPet3aCaVDKl1XSU7fhxtsfBBI9YTtaMZM5e9WhuHK\n"
"lL11Un6ePThX+4NG1yYp0X+emqUHd/qaq8IShnU6ajvzoloWGf4vLlDSsuFHJJsK\n"
"LnshNFOFGAjp1Se4DjhtUSr6Xofdse+kx9cSQazCZ5vFJNeHkxr0B7ojQ4bN37Tg\n"
"2uyfSclCCLnmjcoRMlIGUiL2bevCPDRNRWiblDgx3tGG\n"
"-----END CERTIFICATE-----\n";
rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
if (!cert)
return FALSE;
return freerdp_settings_set_pointer_len(src, key, cert, 1);
}
static BOOL set_string_array(rdpSettings* src, FreeRDP_Settings_Keys_Pointer key, uint32_t max)
{
uint32_t count = 0;
winpr_RAND(&count, sizeof(count));
count = count % max;
if (!freerdp_settings_set_pointer_len(src, key, NULL, count))
return FALSE;
for (uint32_t x = 0; x < count; x++)
{
char buffer[32] = { 0 };
(void)_snprintf(buffer, sizeof(buffer), "foobar-0x%08" PRIu32, x);
if (!freerdp_settings_set_pointer_array(src, key, x, buffer))
return FALSE;
}
return TRUE;
}
static BOOL test_serialize_pointer(DWORD flags)
{
rdpSettings* src = freerdp_settings_new(flags);
if (!src)
return FALSE;
const char* argv1[] = { "foobar", "lala", "haha" };
const char* argv2[] = { "lala", "haha" };
const char* argv3[] = { "haha" };
if (!add_argv(src, ARRAYSIZE(argv1), argv1))
goto fail;
if (!add_argv(src, ARRAYSIZE(argv2), argv2))
goto fail;
if (!add_argv(src, ARRAYSIZE(argv3), argv3))
goto fail;
if (!add_dev_argv(src, ARRAYSIZE(argv3), argv3))
goto fail;
struct key_len_pair
{
FreeRDP_Settings_Keys_Pointer key;
size_t elem;
size_t len;
};
const struct key_len_pair keys[] = {
{ FreeRDP_ServerRandom, 1, 123 },
{ FreeRDP_RedirectionPassword, 1, 13 },
{ FreeRDP_ClientRandom, 1, 23 },
{ FreeRDP_RedirectionGuid, 1, 22 },
{ FreeRDP_LoadBalanceInfo, 1, 21 },
{ FreeRDP_ServerCertificate, 1, 512 },
{ FreeRDP_RedirectionTsvUrl, 1, 33 },
{ FreeRDP_GlyphCache, sizeof(GLYPH_CACHE_DEFINITION), 10 },
{ FreeRDP_FragCache, sizeof(GLYPH_CACHE_DEFINITION), 1 },
{ FreeRDP_BitmapCacheV2CellInfo, sizeof(BITMAP_CACHE_V2_CELL_INFO), 1 },
{ FreeRDP_OrderSupport, 1, 32 },
{ FreeRDP_ClientAutoReconnectCookie, sizeof(ARC_CS_PRIVATE_PACKET), 1 },
{ FreeRDP_ServerAutoReconnectCookie, sizeof(ARC_SC_PRIVATE_PACKET), 1 },
{ FreeRDP_Password51, 1, 54 },
{ FreeRDP_MonitorIds, 1, 111 },
{ FreeRDP_MonitorDefArray, 1, 7 },
{ FreeRDP_ChannelDefArray, 1, 31 },
{ FreeRDP_ReceivedCapabilities, sizeof(uint8_t), 33 },
{ FreeRDP_ReceivedCapabilityData, sizeof(uint8_t*), 33 },
{ FreeRDP_ReceivedCapabilityDataSizes, sizeof(UINT32), 33 }
};
for (size_t x = 0; x < ARRAYSIZE(keys); x++)
{
const struct key_len_pair* cur = &keys[x];
if (!fill_random(src, cur->key, cur->elem, cur->len))
goto fail;
}
if (!fill_random_timezone(src))
goto fail;
void* ptr = NULL;
winpr_RAND((void*)&ptr, sizeof(void*));
if (!freerdp_settings_set_pointer(src, FreeRDP_instance, ptr))
return FALSE;
if (!set_private_key(src))
goto fail;
if (!set_cert(src, FreeRDP_RedirectionTargetCertificate))
goto fail;
if (!set_cert(src, FreeRDP_RdpServerCertificate))
goto fail;
if (!set_string_array(src, FreeRDP_ServerLicenseProductIssuers, 43))
goto fail;
char addresses[12][43] = { 0 };
char* strptr[12] = { 0 };
for (size_t x = 0; x < ARRAYSIZE(addresses); x++)
{
(void)_snprintf(addresses[x], 43, "foobar-0x%08" PRIx32, x);
strptr[x] = addresses[x];
}
if (!freerdp_target_net_addresses_copy(src, strptr, ARRAYSIZE(addresses)))
goto fail;
for (size_t x = 0; x < ARRAYSIZE(addresses); x++)
{
uint32_t port = 0;
winpr_RAND(&port, sizeof(port));
if (!freerdp_settings_set_pointer_array(src, FreeRDP_TargetNetPorts, x, &port))
goto fail;
}
uint32_t count = freerdp_settings_get_uint32(src, FreeRDP_ReceivedCapabilitiesSize);
if (count != 33)
goto fail;
void* caps = freerdp_settings_get_pointer_writable(src, FreeRDP_ReceivedCapabilities);
if (!caps)
goto fail;
winpr_RAND(caps, count);
for (uint32_t x = 0; x < count; x++)
{
uint8_t* buffer = calloc(64, sizeof(uint8_t));
if (!buffer)
goto fail;
winpr_RAND(buffer, sizeof(buffer));
uint32_t blen = (buffer[0] % 52) + 13;
if (!freerdp_settings_set_pointer_array(src, FreeRDP_ReceivedCapabilityData, x, buffer))
goto fail;
if (!freerdp_settings_set_pointer_array(src, FreeRDP_ReceivedCapabilityDataSizes, x, &blen))
goto fail;
}
char buffer[128] = { 0 };
(void)_snprintf(buffer, sizeof(buffer), "%s flags 0x%08" PRIx32, __func__, flags);
return test_serialize_with(src, buffer);
fail:
printf("Test %s: (pre)failure\n", __func__);
freerdp_settings_free(src);
return FALSE;
}
static BOOL test_serialize(void)
{
if (WINPR_JSON_version(NULL, 0) < 0)
return TRUE;
for (uint32_t flags = 0; flags <= (FREERDP_SETTINGS_SERVER_MODE | FREERDP_SETTINGS_REMOTE_MODE);
flags++)
{
char buffer[32] = { 0 };
(void)_snprintf(buffer, sizeof(buffer), "default (flags 0x%08" PRIx32 ")", flags);
if (!test_serialize_with(freerdp_settings_new(flags), buffer))
return FALSE;
if (!test_serialize_strings(flags, "foobar"))
return FALSE;
if (!test_serialize_strings(flags, ""))
return FALSE;
if (!test_serialize_strings(flags, NULL))
return FALSE;
if (!test_serialize_pointer(flags))
return FALSE;
}
return TRUE;
}
int TestSettings(int argc, char* argv[])
{
int rc = -1;
@ -1526,6 +1873,8 @@ int TestSettings(int argc, char* argv[])
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_serialize())
goto fail;
if (!test_dyn_channels())
goto fail;
if (!test_static_channels())

View File

@ -37,6 +37,7 @@
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include "privatekey.h"
#include "cert_common.h"
@ -118,7 +119,8 @@ fail:
}
#endif
static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile)
static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile,
const char* password)
{
EVP_PKEY* evp = NULL;
BIO* bio = NULL;
@ -137,7 +139,7 @@ static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL from
return NULL;
}
evp = PEM_read_bio_PrivateKey(bio, NULL, NULL, 0);
evp = PEM_read_bio_PrivateKey(bio, NULL, NULL, WINPR_CAST_CONST_PTR_AWAY(password, void*));
BIO_free_all(bio);
if (!evp)
WLog_ERR(TAG, "PEM_read_bio_PrivateKey returned NULL [input length %" PRIuz "]", len);
@ -226,11 +228,16 @@ fail:
}
rdpPrivateKey* freerdp_key_new_from_pem(const char* pem)
{
return freerdp_key_new_from_pem_enc(pem, NULL);
}
rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password)
{
rdpPrivateKey* key = freerdp_key_new();
if (!key || !pem)
goto fail;
key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE);
key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE, password);
if (!key->evp)
goto fail;
if (!key_read_private(key))
@ -243,12 +250,16 @@ fail:
rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile)
{
return freerdp_key_new_from_file_enc(keyfile, NULL);
}
rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile, const char* password)
{
rdpPrivateKey* key = freerdp_key_new();
if (!key || !keyfile)
goto fail;
key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE);
key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE, password);
if (!key->evp)
goto fail;
if (!key_read_private(key))
@ -378,10 +389,30 @@ size_t freerdp_key_get_bits(const rdpPrivateKey* key)
return WINPR_ASSERTING_INT_CAST(size_t, rc);
}
BOOL freerdp_key_generate(rdpPrivateKey* key, size_t key_length)
BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...)
{
BOOL rc = FALSE;
if (!type)
{
WLog_ERR(TAG, "Invalid argument type=%s", type);
return FALSE;
}
if (strncmp("RSA", type, 4) != 0)
{
WLog_ERR(TAG, "Argument type=%s is currently not supported, aborting", type);
return FALSE;
}
if (count != 1)
{
WLog_ERR(TAG, "Argument type=%s requires count=1, got %" PRIuz ", aborting", type, count);
return FALSE;
}
va_list ap;
va_start(ap, count);
const int key_length = va_arg(ap, int);
va_end(ap);
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
RSA* rsa = NULL;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
@ -423,7 +454,7 @@ BOOL freerdp_key_generate(rdpPrivateKey* key, size_t key_length)
rc = TRUE;
#else
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
if (!pctx)
return FALSE;
@ -433,7 +464,7 @@ BOOL freerdp_key_generate(rdpPrivateKey* key, size_t key_length)
if (key_length > INT_MAX)
goto fail;
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, (int)key_length) != 1)
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, key_length) != 1)
goto fail;
EVP_PKEY_free(key->evp);
@ -550,3 +581,101 @@ WINPR_DIGEST_CTX* freerdp_key_digest_sign(rdpPrivateKey* key, WINPR_MD_TYPE dige
}
return md_ctx;
}
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
{
BOOL rc = FALSE;
WINPR_ASSERT(bio);
WINPR_ASSERT(ppem);
const size_t blocksize = 2048;
size_t offset = 0;
size_t length = blocksize;
char* pem = NULL;
*ppem = NULL;
if (plength)
*plength = 0;
while (offset < length)
{
char* tmp = realloc(pem, length + 1);
if (!tmp)
goto fail;
pem = tmp;
ERR_clear_error();
const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
if (status < 0)
{
WLog_ERR(TAG, "failed to read certificate");
goto fail;
}
if (status == 0)
break;
offset += (size_t)status;
if (length - offset > 0)
break;
length += blocksize;
}
if (pem)
{
if (offset >= length)
goto fail;
pem[offset] = '\0';
}
*ppem = pem;
if (plength)
*plength = offset;
rc = TRUE;
fail:
if (!rc)
free(pem);
return rc;
}
char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen, const char* password)
{
WINPR_ASSERT(key);
if (!key->evp)
return NULL;
/**
* Don't manage certificates internally, leave it up entirely to the external client
* implementation
*/
BIO* bio = BIO_new(BIO_s_mem());
if (!bio)
{
WLog_ERR(TAG, "BIO_new() failure");
return NULL;
}
char* pem = NULL;
const EVP_CIPHER* enc = NULL;
if (password)
enc = EVP_aes_256_cbc_hmac_sha256();
const int status = PEM_write_bio_PrivateKey(bio, key->evp, enc, NULL, 0, 0,
WINPR_CAST_CONST_PTR_AWAY(password, void*));
if (status < 0)
{
WLog_ERR(TAG, "PEM_write_bio_PrivateKey failure: %d", status);
goto fail;
}
(void)bio_read_pem(bio, &pem, plen);
fail:
BIO_free_all(bio);
return pem;
}

View File

@ -45,8 +45,6 @@ extern "C"
FREERDP_LOCAL const rdpCertInfo* freerdp_key_get_info(const rdpPrivateKey* key);
FREERDP_LOCAL const BYTE* freerdp_key_get_exponent(const rdpPrivateKey* key, size_t* plength);
FREERDP_LOCAL BOOL freerdp_key_generate(rdpPrivateKey* key, size_t bits);
/** \brief returns a pointer to a EVP_PKEY structure.
* Call EVP_PKEY_free when done.
*/

View File

@ -1499,7 +1499,7 @@ BOOL vgids_init(vgidsContext* ctx, const char* cert, const char* privateKey, con
if (!ctx->certificate)
goto init_failed;
ctx->privateKey = freerdp_key_new_from_pem(privateKey);
ctx->privateKey = freerdp_key_new_from_pem_enc(privateKey, NULL);
if (!ctx->privateKey)
goto init_failed;

View File

@ -376,7 +376,7 @@ static void* mf_peer_main_loop(void* arg)
WINPR_ASSERT(settings);
/* Initialize the real server settings here */
rdpPrivateKey* key = freerdp_key_new_from_file(info->key);
rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, NULL);
if (!key)
goto fail;
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))

View File

@ -1115,7 +1115,7 @@ static DWORD WINAPI test_peer_mainloop(LPVOID arg)
goto fail;
}
rdpPrivateKey* key = freerdp_key_new_from_file(info->key);
rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, NULL);
if (!key)
goto fail;
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))

View File

@ -255,7 +255,7 @@ static BOOL wf_peer_read_settings(freerdp_peer* client)
&(PrivateKeyFile)))
PrivateKeyFile = _strdup("server.key");
rdpPrivateKey* key = freerdp_key_new_from_file(PrivateKeyFile);
rdpPrivateKey* key = freerdp_key_new_from_file_enc(PrivateKeyFile, NULL);
free(PrivateKeyFile);
if (!key)

View File

@ -480,7 +480,7 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
pdata->module = server->module;
const proxyConfig* config = pdata->config = server->config;
rdpPrivateKey* key = freerdp_key_new_from_pem(config->PrivateKeyPEM);
rdpPrivateKey* key = freerdp_key_new_from_pem_enc(config->PrivateKeyPEM, NULL);
if (!key)
return FALSE;

View File

@ -925,7 +925,7 @@ static BOOL shadow_server_init_certificate(rdpShadowServer* server)
rdpSettings* settings = server->settings;
WINPR_ASSERT(settings);
rdpPrivateKey* key = freerdp_key_new_from_file(server->PrivateKeyFile);
rdpPrivateKey* key = freerdp_key_new_from_file_enc(server->PrivateKeyFile, NULL);
if (!key)
goto out_fail;
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))

View File

@ -104,7 +104,8 @@ int WINPR_JSON_version(char* buffer, size_t len)
#elif defined(WITH_CJSON)
return _snprintf(buffer, len, "cJSON %s", cJSON_Version());
#else
return _snprintf(buffer, len, "JSON support not available");
(void)_snprintf(buffer, len, "JSON support not available");
return -1;
#endif
}