From 97496cbb22bbe9e28491318262cb94a2325a41ec Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Mon, 28 Nov 2022 09:30:00 +0100 Subject: [PATCH] New upstream version 2.9.0+dfsg1 --- CMakeLists.txt | 2 +- ChangeLog | 26 ++ channels/audin/client/audin_main.c | 25 +- channels/drive/client/drive_file.c | 106 ++++--- channels/drive/client/drive_file.h | 8 +- channels/drive/client/drive_main.c | 11 +- channels/urbdrc/client/data_transfer.c | 32 +- .../urbdrc/client/libusb/libusb_udevice.c | 12 +- client/X11/xf_graphics.c | 4 +- config.h.in | 3 + include/freerdp/freerdp.h | 22 ++ include/freerdp/peer.h | 9 + libfreerdp/codec/zgfx.c | 11 +- libfreerdp/core/activation.c | 4 +- libfreerdp/core/capabilities.c | 2 +- libfreerdp/core/connection.c | 98 +++--- libfreerdp/core/connection.h | 28 +- libfreerdp/core/fastpath.c | 2 +- libfreerdp/core/freerdp.c | 11 + libfreerdp/core/peer.c | 272 +++++++++++++++-- libfreerdp/core/rdp.c | 25 +- libfreerdp/core/rdp.h | 2 +- server/proxy/pf_context.h | 3 + server/proxy/pf_input.c | 31 +- winpr/CMakeLists.txt | 4 +- winpr/include/winpr/ssl.h | 1 + winpr/include/winpr/string.h | 5 + winpr/include/winpr/wlog.h | 1 + winpr/libwinpr/crt/string.c | 63 +++- winpr/libwinpr/crypto/CMakeLists.txt | 17 +- winpr/libwinpr/crypto/hash.c | 268 ++++++++++++---- winpr/libwinpr/crypto/hmac_md5.c | 54 ++++ winpr/libwinpr/crypto/hmac_md5.h | 19 ++ winpr/libwinpr/crypto/md4.c | 266 ++++++++++++++++ winpr/libwinpr/crypto/md4.h | 46 +++ winpr/libwinpr/crypto/md5.c | 287 ++++++++++++++++++ winpr/libwinpr/crypto/md5.h | 48 +++ winpr/libwinpr/crypto/test/TestCryptoHash.c | 26 +- winpr/libwinpr/utils/ssl.c | 29 +- 39 files changed, 1630 insertions(+), 253 deletions(-) create mode 100644 winpr/libwinpr/crypto/hmac_md5.c create mode 100644 winpr/libwinpr/crypto/hmac_md5.h create mode 100644 winpr/libwinpr/crypto/md4.c create mode 100644 winpr/libwinpr/crypto/md4.h create mode 100644 winpr/libwinpr/crypto/md5.c create mode 100644 winpr/libwinpr/crypto/md5.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aa1131d..811cd39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.8.1") +set(RAW_VERSION_STRING "2.9.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index b878eac..68c4038 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +# 2022-11-16 Version 2.9.0 + +Notewhorth changes: +* Backported #8252: Support sending server redirection PDU +* Backported #8406: Ensure X11 client cursor is never smaller 1x1 +* Backported #8403: Fixed multiple client side input validation issues + (CVE-2022-39316, CVE-2022-39317, CVE-2022-39318, CVE-2022-39319, + CVE-2022-39320, CVE-2022-41877, CVE-2022-39347) +* Backported #7282: Proxy server now discards input events sent before + activation was received +* Backported #8324: Internal replacements for md4, md5 and hmac-md5 + For the time being the RDP protocol requires these outdated hash + algorithms. So any distribution that wants to ship a working + FreeRDP should check the options WITH_INTERNAL_MD4 (and depending + on OpenSSL deprecation status WITH_INTERNAL_MD5) + +Fixed issues: +* Backported #8341: Null checks in winpr_Digest_Free +* Backported #8335: Missing NULL return in winpr_Digest_New +* Backported #8192: Support for audin version 2 microphone channel +* Backported #7282: Discard input events before activation (Fixes #8374) + +For a complete and detailed change log since the last release run: +git log 2.8.1..2.9.0 + + # 2022-10-12 Version 2.8.1 Notewhorth changes: diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 81a6e8f..23561b1 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -43,13 +43,18 @@ #include "audin_main.h" -#define MSG_SNDIN_VERSION 0x01 -#define MSG_SNDIN_FORMATS 0x02 -#define MSG_SNDIN_OPEN 0x03 -#define MSG_SNDIN_OPEN_REPLY 0x04 -#define MSG_SNDIN_DATA_INCOMING 0x05 -#define MSG_SNDIN_DATA 0x06 -#define MSG_SNDIN_FORMATCHANGE 0x07 +#define SNDIN_VERSION 0x02 + +enum +{ + MSG_SNDIN_VERSION = 0x01, + MSG_SNDIN_FORMATS = 0x02, + MSG_SNDIN_OPEN = 0x03, + MSG_SNDIN_OPEN_REPLY = 0x04, + MSG_SNDIN_DATA_INCOMING = 0x05, + MSG_SNDIN_DATA = 0x06, + MSG_SNDIN_FORMATCHANGE = 0x07 +} MSG_SNDIN_CMD; typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK; struct _AUDIN_LISTENER_CALLBACK @@ -105,6 +110,7 @@ struct _AUDIN_PLUGIN IWTSListener* listener; BOOL initialized; + UINT32 version; }; static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); @@ -138,7 +144,7 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) { wStream* out; - const UINT32 ClientVersion = 0x01; + const UINT32 ClientVersion = SNDIN_VERSION; UINT32 ServerVersion; if (Stream_GetRemainingLength(s) < 4) @@ -149,7 +155,7 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c ServerVersion, ClientVersion); /* Do not answer server packet, we do not support the channel version. */ - if (ServerVersion != ClientVersion) + if (ServerVersion > ClientVersion) { WLog_Print(audin->log, WLOG_WARN, "Incompatible channel version server=%" PRIu32 @@ -157,6 +163,7 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c ServerVersion, ClientVersion); return CHANNEL_RC_OK; } + audin->version = ServerVersion; out = Stream_New(NULL, 5); diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index 3054385..1ea4ab9 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -61,10 +61,14 @@ } while (0) #endif -static void drive_file_fix_path(WCHAR* path) +static BOOL drive_file_fix_path(WCHAR* path, size_t length) { size_t i; - size_t length = _wcslen(path); + + if ((length == 0) || (length > UINT32_MAX)) + return FALSE; + + WINPR_ASSERT(path); for (i = 0; i < length; i++) { @@ -75,58 +79,82 @@ static void drive_file_fix_path(WCHAR* path) #ifdef WIN32 if ((length == 3) && (path[1] == L':') && (path[2] == L'/')) - return; + return FALSE; #else if ((length == 1) && (path[0] == L'/')) - return; + return FALSE; #endif if ((length > 0) && (path[length - 1] == L'/')) path[length - 1] = L'\0'; + + return TRUE; } static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path, - size_t PathLength) + size_t PathWCharLength) { - WCHAR* fullpath; - size_t base_path_length; + BOOL ok = FALSE; + WCHAR* fullpath = NULL; + size_t length; - if (!base_path || (!path && (PathLength > 0))) - return NULL; + if (!base_path || (!path && (PathWCharLength > 0))) + goto fail; - base_path_length = _wcslen(base_path) * 2; - fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR)); + const size_t base_path_length = _wcsnlen(base_path, MAX_PATH); + length = base_path_length + PathWCharLength + 1; + fullpath = (WCHAR*)calloc(length, sizeof(WCHAR)); if (!fullpath) + goto fail; + + CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR)); + if (path) + CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR)); + + if (!drive_file_fix_path(fullpath, length)) + goto fail; + + /* Ensure the path does not contain sequences like '..' */ + const WCHAR dotdot[] = { '.', '.', '\0' }; + if (_wcsstr(&fullpath[base_path_length], dotdot)) { - WLog_ERR(TAG, "malloc failed!"); - return NULL; + char abuffer[MAX_PATH] = { 0 }; + ConvertFromUnicode(CP_UTF8, 0, &fullpath[base_path_length], -1, (char**)&abuffer, + ARRAYSIZE(abuffer) - 1, NULL, NULL); + + WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!", + &abuffer[base_path_length]); + goto fail; } - CopyMemory(fullpath, base_path, base_path_length); - if (path) - CopyMemory((char*)fullpath + base_path_length, path, PathLength); - drive_file_fix_path(fullpath); + ok = TRUE; +fail: + if (!ok) + { + free(fullpath); + fullpath = NULL; + } return fullpath; } static BOOL drive_file_remove_dir(const WCHAR* path) { - WIN32_FIND_DATAW findFileData; + WIN32_FIND_DATAW findFileData = { 0 }; BOOL ret = TRUE; - HANDLE dir; - WCHAR* fullpath; - WCHAR* path_slash; - size_t base_path_length; + HANDLE dir = INVALID_HANDLE_VALUE; + WCHAR* fullpath = NULL; + WCHAR* path_slash = NULL; + size_t base_path_length = 0; if (!path) return FALSE; - base_path_length = _wcslen(path) * 2; - path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3); + base_path_length = _wcslen(path); + path_slash = (WCHAR*)calloc(base_path_length + 3, sizeof(WCHAR)); if (!path_slash) { @@ -134,12 +162,11 @@ static BOOL drive_file_remove_dir(const WCHAR* path) return FALSE; } - CopyMemory(path_slash, path, base_path_length); - path_slash[base_path_length / 2] = L'/'; - path_slash[base_path_length / 2 + 1] = L'*'; + CopyMemory(path_slash, path, base_path_length * sizeof(WCHAR)); + path_slash[base_path_length] = L'/'; + path_slash[base_path_length + 1] = L'*'; DEBUG_WSTR("Search in %s", path_slash); dir = FindFirstFileW(path_slash, &findFileData); - path_slash[base_path_length / 2 + 1] = 0; if (dir == INVALID_HANDLE_VALUE) { @@ -149,7 +176,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) do { - size_t len = _wcslen(findFileData.cFileName); + const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName)); if ((len == 1 && findFileData.cFileName[0] == L'.') || (len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.')) @@ -157,7 +184,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) continue; } - fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2); + fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len); DEBUG_WSTR("Delete %s", fullpath); if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) @@ -333,13 +360,13 @@ static BOOL drive_file_init(DRIVE_FILE* file) return file->file_handle != INVALID_HANDLE_VALUE; } -DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, - UINT32 FileAttributes, UINT32 SharedAccess) +DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength, + UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition, + UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess) { DRIVE_FILE* file; - if (!base_path || (!path && (PathLength > 0))) + if (!base_path || (!path && (PathWCharLength > 0))) return NULL; file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE)); @@ -359,7 +386,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat file->CreateDisposition = CreateDisposition; file->CreateOptions = CreateOptions; file->SharedAccess = SharedAccess; - drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength)); + drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength)); if (!drive_file_init(file)) { @@ -714,13 +741,10 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN return FALSE; fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input), - FileNameLength); + FileNameLength / sizeof(WCHAR)); if (!fullpath) - { - WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); return FALSE; - } #ifdef _WIN32 @@ -759,7 +783,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN } BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, - const WCHAR* path, UINT32 PathLength, wStream* output) + const WCHAR* path, UINT32 PathWCharLength, wStream* output) { size_t length; WCHAR* ent_path; @@ -773,7 +797,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT if (file->find_handle != INVALID_HANDLE_VALUE) FindClose(file->find_handle); - ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength); + ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength); /* open new search handle and retrieve the first entry */ file->find_handle = FindFirstFileW(ent_path, &file->find_data); free(ent_path); diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index ed789d6..6d3bd70 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -51,9 +51,9 @@ struct _DRIVE_FILE UINT32 CreateOptions; }; -DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, - UINT32 FileAttributes, UINT32 SharedAccess); +DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength, + UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition, + UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess); BOOL drive_file_free(DRIVE_FILE* file); BOOL drive_file_open(DRIVE_FILE* file); @@ -64,6 +64,6 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input); BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, - const WCHAR* path, UINT32 PathLength, wStream* output); + const WCHAR* path, UINT32 PathWCharLength, wStream* output); #endif /* FREERDP_CHANNEL_DRIVE_FILE_H */ diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index 1b54225..b6cf2ad 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -184,8 +184,8 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) path = (const WCHAR*)Stream_Pointer(irp->input); FileId = irp->devman->id_sequence++; - file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition, - CreateOptions, FileAttributes, SharedAccess); + file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess, + CreateDisposition, CreateOptions, FileAttributes, SharedAccess); if (!file) { @@ -629,6 +629,9 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, PathLength); Stream_Seek(irp->input, 23); /* Padding */ path = (WCHAR*)Stream_Pointer(irp->input); + if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength)) + return ERROR_INVALID_DATA; + file = drive_get_file_by_id(drive, irp->FileId); if (file == NULL) @@ -636,8 +639,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) irp->IoStatus = STATUS_UNSUCCESSFUL; Stream_Write_UINT32(irp->output, 0); /* Length */ } - else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength, - irp->output)) + else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, + PathLength / sizeof(WCHAR), irp->output)) { irp->IoStatus = drive_map_windows_err(GetLastError()); } diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index 6987961..ed6ccf3 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -97,7 +97,13 @@ static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId, UINT32 OutputBufferSize) { const UINT32 InterfaceId = (STREAM_ID_PROXY << 30) | (InterfaceField & 0x3FFFFFFF); - wStream* out = Stream_New(NULL, OutputBufferSize + 28); + +#if UINT32_MAX >= SIZE_MAX + if (OutputBufferSize > UINT32_MAX - 28ull) + return NULL; +#endif + + wStream* out = Stream_New(NULL, OutputBufferSize + 28ull); if (!out) return NULL; @@ -241,6 +247,10 @@ static UINT urbdrc_process_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* c Stream_Read_UINT32(s, OutputBufferSize); Stream_Read_UINT32(s, RequestId); + + if (OutputBufferSize > UINT32_MAX - 4) + return ERROR_INVALID_DATA; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, OutputBufferSize + 4); @@ -673,7 +683,11 @@ static UINT urb_control_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callba buffer = Stream_Pointer(out); if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) + return ERROR_INVALID_DATA; Stream_Copy(s, out, OutputBufferSize); + } /** process TS_URB_CONTROL_TRANSFER */ if (!pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType, @@ -720,6 +734,15 @@ static UINT urb_bulk_or_interrupt_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBA Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ Stream_Read_UINT32(s, OutputBufferSize); EndpointAddress = (PipeHandle & 0x000000ff); + + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) + { + return ERROR_INVALID_DATA; + } + } + /** process TS_URB_BULK_OR_INTERRUPT_TRANSFER */ return pdev->bulk_or_interrupt_transfer( pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, noAck, @@ -804,6 +827,13 @@ static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback packetDescriptorData = Stream_Pointer(s); Stream_Seek(s, NumberOfPackets * 12); Stream_Read_UINT32(s, OutputBufferSize); + + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) + return ERROR_INVALID_DATA; + } + return pdev->isoch_transfer( pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, StartFrame, ErrorCount, noAck, packetDescriptorData, NumberOfPackets, OutputBufferSize, diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 505c31d..ef87f19 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -1221,12 +1221,18 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* c if (!Buffer) Stream_Seek(user_data->data, (NumberOfPackets * 12)); - iso_packet_size = BufferSize / NumberOfPackets; - iso_transfer = libusb_alloc_transfer(NumberOfPackets); + if (NumberOfPackets > 0) + { + iso_packet_size = BufferSize / NumberOfPackets; + iso_transfer = libusb_alloc_transfer((int)NumberOfPackets); + } if (iso_transfer == NULL) { - WLog_Print(urbdrc->log, WLOG_ERROR, "Error: libusb_alloc_transfer."); + WLog_Print(urbdrc->log, WLOG_ERROR, + "Error: libusb_alloc_transfer [NumberOfPackets=%" PRIu32 ", BufferSize=%" PRIu32 + " ]", + NumberOfPackets, BufferSize); async_transfer_user_data_free(user_data); return -1; } diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 7050569..82b0b95 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -258,8 +258,8 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo xscale = (settings->SmartSizing ? xfc->scaledWidth / (double)settings->DesktopWidth : 1); yscale = (settings->SmartSizing ? xfc->scaledHeight / (double)settings->DesktopHeight : 1); - xTargetSize = pointer->width * xscale; - yTargetSize = pointer->height * yscale; + xTargetSize = MAX(1, pointer->width * xscale); + yTargetSize = MAX(1, pointer->height * yscale); WLog_DBG(TAG, "%s: scaled: %" PRIu32 "x%" PRIu32 ", desktop: %" PRIu32 "x%" PRIu32, __func__, xfc->scaledWidth, xfc->savedHeight, settings->DesktopWidth, settings->DesktopHeight); diff --git a/config.h.in b/config.h.in index 801b085..650d5ad 100644 --- a/config.h.in +++ b/config.h.in @@ -183,4 +183,7 @@ /* Proxy */ #cmakedefine WITH_PROXY_MODULES +#cmakedefine WITH_INTERNAL_MD4 +#cmakedefine WITH_INTERNAL_MD5 + #endif /* FREERDP_CONFIG_H */ diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index b5b38c0..77ceb54 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -70,6 +70,25 @@ extern "C" #define VERIFY_CERT_FLAG_MISMATCH 0x80 #define VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1 0x100 + typedef enum + { + CONNECTION_STATE_INITIAL, + CONNECTION_STATE_NEGO, + CONNECTION_STATE_NLA, + CONNECTION_STATE_MCS_CONNECT, + CONNECTION_STATE_MCS_ERECT_DOMAIN, + CONNECTION_STATE_MCS_ATTACH_USER, + CONNECTION_STATE_MCS_CHANNEL_JOIN, + CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT, + CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE, + CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT, + CONNECTION_STATE_LICENSING, + CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING, + CONNECTION_STATE_CAPABILITIES_EXCHANGE, + CONNECTION_STATE_FINALIZATION, + CONNECTION_STATE_ACTIVE + } CONNECTION_STATE; + /* Message types used by gateway messaging callback */ #define GATEWAY_MESSAGE_CONSENT 1 #define GATEWAY_MESSAGE_SERVICE 2 @@ -527,6 +546,9 @@ extern "C" FREERDP_API const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length); + FREERDP_API CONNECTION_STATE freerdp_get_state(rdpContext* context); + FREERDP_API const char* freerdp_state_string(CONNECTION_STATE state); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 4176f25..90bbb46 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -48,6 +48,13 @@ typedef BOOL (*psPeerCapabilities)(freerdp_peer* peer); typedef BOOL (*psPeerPostConnect)(freerdp_peer* peer); typedef BOOL (*psPeerActivate)(freerdp_peer* peer); typedef BOOL (*psPeerLogon)(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic); +typedef BOOL (*psPeerSendServerRedirection)(freerdp_peer* peer, UINT32 sessionId, + const char* targetNetAddress, const char* routingToken, + const char* userName, const char* domain, + const char* password, const char* targetFQDN, + const char* targetNetBiosName, DWORD tsvUrlLength, + const BYTE* tsvUrl, UINT32 targetNetAddressesCount, + const char** targetNetAddresses); typedef BOOL (*psPeerAdjustMonitorsLayout)(freerdp_peer* peer); typedef BOOL (*psPeerClientCapabilities)(freerdp_peer* peer); @@ -133,6 +140,8 @@ struct rdp_freerdp_peer psPeerClientCapabilities ClientCapabilities; psPeerComputeNtlmHash ComputeNtlmHash; psPeerLicenseCallback LicenseCallback; + + psPeerSendServerRedirection SendServerRedirection; }; #ifdef __cplusplus diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 20fbd35..e260aa6 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -230,19 +230,19 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t BYTE* pbSegment; size_t cbSegment; - if (!zgfx || !stream) + if (!zgfx || !stream || (segmentSize < 2)) return FALSE; cbSegment = segmentSize - 1; - if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize < 1) || - (segmentSize > UINT32_MAX)) + if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize > UINT32_MAX)) return FALSE; Stream_Read_UINT8(stream, flags); /* header (1 byte) */ zgfx->OutputCount = 0; pbSegment = Stream_Pointer(stream); - Stream_Seek(stream, cbSegment); + if (!Stream_SafeSeek(stream, cbSegment)) + return FALSE; if (!(flags & PACKET_COMPRESSED)) { @@ -346,6 +346,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) return FALSE; + if (count > zgfx->cBitsRemaining / 8) + return FALSE; + CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, count); zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count); diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index 3c9606e..c6e335b 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -350,7 +350,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) UINT16 lengthSourceDescriptor; UINT32 timeout; - if (rdp->state == CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) rdp->deactivation_reactivation = TRUE; else rdp->deactivation_reactivation = FALSE; @@ -390,7 +390,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) if (freerdp_shall_disconnect(rdp->instance)) return TRUE; - if (rdp->state == CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) return TRUE; Sleep(100); diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 433f4ce..786e30c 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -2780,7 +2780,7 @@ static BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, rdpSettings* setti Stream_Read_UINT32(&sub, captureFlags); /* captureFlags (4 bytes) */ Stream_Read_UINT32(&sub, rfxCapsLength); /* capsLength (4 bytes) */ settings->RemoteFxCaptureFlags = captureFlags; - settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? TRUE : FALSE; + settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? FALSE : TRUE; if (rfxCapsLength) { diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index a1a01e9..815418e 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -188,6 +188,7 @@ static int rdp_client_connect_finalize(rdpRdp* rdp); static BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp); +static BOOL rdp_set_state(rdpRdp* rdp, CONNECTION_STATE state); static BOOL rdp_client_reset_codecs(rdpContext* context) { @@ -358,7 +359,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) rdp->transport->ReceiveExtra = rdp; transport_set_blocking_mode(rdp->transport, FALSE); - if (rdp->state != CONNECTION_STATE_NLA) + if (rdp_get_state(rdp) != CONNECTION_STATE_NLA) { if (!mcs_client_begin(rdp->mcs)) return FALSE; @@ -372,7 +373,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) return FALSE; } - if (rdp->state == CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) return TRUE; Sleep(100); @@ -1137,68 +1138,69 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state) { int status = 0; + WLog_DBG(TAG, "%s %s --> %s", __FUNCTION__, rdp_get_state_string(rdp), rdp_state_string(state)); switch (state) { case CONNECTION_STATE_INITIAL: - rdp->state = CONNECTION_STATE_INITIAL; + rdp_set_state(rdp, CONNECTION_STATE_INITIAL); break; case CONNECTION_STATE_NEGO: - rdp->state = CONNECTION_STATE_NEGO; + rdp_set_state(rdp, CONNECTION_STATE_NEGO); break; case CONNECTION_STATE_NLA: - rdp->state = CONNECTION_STATE_NLA; + rdp_set_state(rdp, CONNECTION_STATE_NLA); break; case CONNECTION_STATE_MCS_CONNECT: - rdp->state = CONNECTION_STATE_MCS_CONNECT; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CONNECT); break; case CONNECTION_STATE_MCS_ERECT_DOMAIN: - rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN); break; case CONNECTION_STATE_MCS_ATTACH_USER: - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); break; case CONNECTION_STATE_MCS_CHANNEL_JOIN: - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN); break; case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: - rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + rdp_set_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT); break; case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: - rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE); break; case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: - rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + rdp_set_state(rdp, CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT); break; case CONNECTION_STATE_LICENSING: - rdp->state = CONNECTION_STATE_LICENSING; + rdp_set_state(rdp, CONNECTION_STATE_LICENSING); break; case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: - rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + rdp_set_state(rdp, CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING); break; case CONNECTION_STATE_CAPABILITIES_EXCHANGE: - rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); break; case CONNECTION_STATE_FINALIZATION: - rdp->state = CONNECTION_STATE_FINALIZATION; + rdp_set_state(rdp, CONNECTION_STATE_FINALIZATION); update_reset_state(rdp->update); rdp->finalize_sc_pdus = 0; break; case CONNECTION_STATE_ACTIVE: - rdp->state = CONNECTION_STATE_ACTIVE; + rdp_set_state(rdp, CONNECTION_STATE_ACTIVE); { ActivatedEventArgs activatedEvent; rdpContext* context = rdp->context; @@ -1218,8 +1220,8 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state) ConnectionStateChangeEventArgs stateEvent; rdpContext* context = rdp->context; EventArgsInit(&stateEvent, "libfreerdp"); - stateEvent.state = rdp->state; - stateEvent.active = rdp->state == CONNECTION_STATE_ACTIVE; + stateEvent.state = rdp_get_state(rdp); + stateEvent.active = rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE; PubSub_OnConnectionStateChange(context->pubSub, context, &stateEvent); } @@ -1406,7 +1408,7 @@ BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength) { freerdp_peer* peer = rdp->context->peer; - if (rdp->state != CONNECTION_STATE_CAPABILITIES_EXCHANGE) + if (rdp_get_state(rdp) != CONNECTION_STATE_CAPABILITIES_EXCHANGE) return FALSE; if (!rdp_recv_confirm_active(rdp, s, pduLength)) @@ -1455,74 +1457,76 @@ int rdp_server_transition_to_state(rdpRdp* rdp, int state) { int status = 0; freerdp_peer* client = NULL; + const int cstate = rdp_get_state(rdp); - if (rdp->state >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT) + if (cstate >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT) client = rdp->context->peer; - if (rdp->state < CONNECTION_STATE_ACTIVE) + if (cstate < CONNECTION_STATE_ACTIVE) { if (client) client->activated = FALSE; } + WLog_DBG(TAG, "%s %s --> %s", __FUNCTION__, rdp_get_state_string(rdp), rdp_state_string(state)); switch (state) { case CONNECTION_STATE_INITIAL: - rdp->state = CONNECTION_STATE_INITIAL; + rdp_set_state(rdp, CONNECTION_STATE_INITIAL); break; case CONNECTION_STATE_NEGO: - rdp->state = CONNECTION_STATE_NEGO; + rdp_set_state(rdp, CONNECTION_STATE_NEGO); break; case CONNECTION_STATE_MCS_CONNECT: - rdp->state = CONNECTION_STATE_MCS_CONNECT; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CONNECT); break; case CONNECTION_STATE_MCS_ERECT_DOMAIN: - rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN); break; case CONNECTION_STATE_MCS_ATTACH_USER: - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); break; case CONNECTION_STATE_MCS_CHANNEL_JOIN: - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN); break; case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: - rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + rdp_set_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT); break; case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: - rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE); break; case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: - rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + rdp_set_state(rdp, CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT); break; case CONNECTION_STATE_LICENSING: - rdp->state = CONNECTION_STATE_LICENSING; + rdp_set_state(rdp, CONNECTION_STATE_LICENSING); break; case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: - rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + rdp_set_state(rdp, CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING); break; case CONNECTION_STATE_CAPABILITIES_EXCHANGE: - rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); rdp->AwaitCapabilities = FALSE; break; case CONNECTION_STATE_FINALIZATION: - rdp->state = CONNECTION_STATE_FINALIZATION; + rdp_set_state(rdp, CONNECTION_STATE_FINALIZATION); rdp->finalize_sc_pdus = 0; break; case CONNECTION_STATE_ACTIVE: - rdp->state = CONNECTION_STATE_ACTIVE; + rdp_set_state(rdp, CONNECTION_STATE_ACTIVE); update_reset_state(rdp->update); if (client) @@ -1539,7 +1543,7 @@ int rdp_server_transition_to_state(rdpRdp* rdp, int state) return -1; } - if (rdp->state >= CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) >= CONNECTION_STATE_ACTIVE) { IFCALLRET(client->Activate, client->activated, client); @@ -1573,7 +1577,7 @@ const char* rdp_client_connection_state_string(int state) } } -const char* rdp_server_connection_state_string(int state) +const char* rdp_state_string(CONNECTION_STATE state) { switch (state) { @@ -1612,9 +1616,21 @@ const char* rdp_server_connection_state_string(int state) } } -int rdp_client_get_state(rdpRdp* rdp) +CONNECTION_STATE rdp_get_state(rdpRdp* rdp) { - if (!rdp) - return -1; + WINPR_ASSERT(rdp); return rdp->state; } + +BOOL rdp_set_state(rdpRdp* rdp, CONNECTION_STATE state) +{ + WINPR_ASSERT(rdp); + rdp->state = state; + return TRUE; +} + +const char* rdp_get_state_string(rdpRdp* rdp) +{ + int state = rdp_get_state(rdp); + return rdp_state_string(state); +} diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index 8458c60..946f745 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -30,25 +30,6 @@ #include #include -enum CONNECTION_STATE -{ - CONNECTION_STATE_INITIAL, - CONNECTION_STATE_NEGO, - CONNECTION_STATE_NLA, - CONNECTION_STATE_MCS_CONNECT, - CONNECTION_STATE_MCS_ERECT_DOMAIN, - CONNECTION_STATE_MCS_ATTACH_USER, - CONNECTION_STATE_MCS_CHANNEL_JOIN, - CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT, - CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE, - CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT, - CONNECTION_STATE_LICENSING, - CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING, - CONNECTION_STATE_CAPABILITIES_EXCHANGE, - CONNECTION_STATE_FINALIZATION, - CONNECTION_STATE_ACTIVE -}; - enum CLIENT_CONNECTION_STATE { CLIENT_STATE_INITIAL, @@ -66,8 +47,9 @@ FREERDP_LOCAL BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s); FREERDP_LOCAL int rdp_client_connect_license(rdpRdp* rdp, wStream* s); FREERDP_LOCAL int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); FREERDP_LOCAL int rdp_client_transition_to_state(rdpRdp* rdp, int state); -FREERDP_LOCAL const char* rdp_client_connection_state_string(int state); -FREERDP_LOCAL int rdp_client_get_state(rdpRdp* rdp); + +FREERDP_LOCAL CONNECTION_STATE rdp_get_state(rdpRdp* rdp); +FREERDP_LOCAL const char* rdp_state_string(CONNECTION_STATE state); FREERDP_LOCAL BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s); FREERDP_LOCAL BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s); @@ -78,6 +60,8 @@ FREERDP_LOCAL BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s, UIN FREERDP_LOCAL BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s); FREERDP_LOCAL BOOL rdp_server_reactivate(rdpRdp* rdp); FREERDP_LOCAL int rdp_server_transition_to_state(rdpRdp* rdp, int state); -FREERDP_LOCAL const char* rdp_server_connection_state_string(int state); +FREERDP_LOCAL const char* rdp_get_state_string(rdpRdp* rdp); + +FREERDP_LOCAL const char* rdp_client_connection_state_string(int state); #endif /* FREERDP_LIB_CORE_CONNECTION_H */ diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 7a67638..0b3549a 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -948,7 +948,7 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, size_t goto fail; rdp = fastpath->rdp; - state = rdp_client_get_state(rdp); + state = rdp_get_state(rdp); if (state != CONNECTION_STATE_ACTIVE) { WLog_WARN(TAG, "[%s] called before activation [%s]", __FUNCTION__, diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 7d9eba4..b31d7d8 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -1135,3 +1135,14 @@ const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length) return (const char*)nego_get_routing_token(context->rdp->nego, length); } + +CONNECTION_STATE freerdp_get_state(rdpContext* context) +{ + WINPR_ASSERT(context); + return rdp_get_state(context->rdp); +} + +const char* freerdp_state_string(CONNECTION_STATE state) +{ + return rdp_state_string(state); +} diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index aff32c2..41730ef 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -203,7 +203,6 @@ static BOOL freerdp_peer_initialize(freerdp_peer* client) settings->ServerMode = TRUE; settings->FrameAcknowledge = 0; settings->LocalConnection = client->local; - rdp->state = CONNECTION_STATE_INITIAL; if (settings->RdpKeyFile) { @@ -475,13 +474,13 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) freerdp_peer* client = (freerdp_peer*)extra; rdpRdp* rdp = client->context->rdp; - switch (rdp->state) + switch (rdp_get_state(rdp)) { case CONNECTION_STATE_INITIAL: if (!rdp_server_accept_nego(rdp, s)) { WLog_ERR(TAG, "%s: %s - rdp_server_accept_nego() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -510,7 +509,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_connect_initial() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -522,7 +521,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_erect_domain_request() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -534,7 +533,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_attach_user_request() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -546,7 +545,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_channel_join_request() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -560,7 +559,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_establish_keys() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -578,7 +577,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_recv_client_info() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -606,7 +605,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - callback internal " "error, aborting", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; case LICENSE_CB_ABORT: @@ -641,7 +640,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_send_demand_active() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -654,7 +653,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "peer_recv_pdu() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -670,7 +669,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "peer_recv_pdu() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -681,7 +680,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (peer_recv_pdu(client, s) < 0) { WLog_ERR(TAG, "%s: %s - peer_recv_pdu() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -691,15 +690,14 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (peer_recv_pdu(client, s) < 0) { WLog_ERR(TAG, "%s: %s - peer_recv_pdu() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } break; default: - WLog_ERR(TAG, "%s state %d", rdp_server_connection_state_string(rdp->state), - rdp->state); + WLog_ERR(TAG, "%s state %d", rdp_state_string(rdp_get_state(rdp)), rdp_get_state(rdp)); return -1; } @@ -745,6 +743,245 @@ static BOOL freerdp_peer_send_channel_data(freerdp_peer* client, UINT16 channelI return rdp_send_channel_data(client->context->rdp, channelId, data, size); } +static BOOL freerdp_peer_send_server_redirection_pdu( + freerdp_peer* peer, UINT32 sessionId, const char* targetNetAddress, const char* routingToken, + const char* userName, const char* domain, const char* password, const char* targetFQDN, + const char* targetNetBiosName, DWORD tsvUrlLength, const BYTE* tsvUrl, + UINT32 targetNetAddressesCount, const char** targetNetAddresses) +{ + wStream* s = rdp_send_stream_pdu_init(peer->context->rdp); + UINT16 length; + UINT32 redirFlags; + + UINT32 targetNetAddressLength; + UINT32 loadBalanceInfoLength; + UINT32 userNameLength; + UINT32 domainLength; + UINT32 passwordLength; + UINT32 targetFQDNLength; + UINT32 targetNetBiosNameLength; + UINT32 targetNetAddressesLength; + UINT32* targetNetAddressesWLength; + + LPWSTR targetNetAddressW = NULL; + LPWSTR userNameW = NULL; + LPWSTR domainW = NULL; + LPWSTR passwordW = NULL; + LPWSTR targetFQDNW = NULL; + LPWSTR targetNetBiosNameW = NULL; + LPWSTR* targetNetAddressesW = NULL; + + length = 12; /* Flags (2) + length (2) + sessionId (4) + redirection flags (4) */ + redirFlags = 0; + + if (targetNetAddress) + { + redirFlags |= LB_TARGET_NET_ADDRESS; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetNetAddress, -1, &targetNetAddressW, 0); + targetNetAddressLength = (strlen(targetNetAddress) + 1) * sizeof(WCHAR); + + length += 4 + targetNetAddressLength; + } + + if (routingToken) + { + redirFlags |= LB_LOAD_BALANCE_INFO; + loadBalanceInfoLength = + 13 + strlen(routingToken) + 2; /* Add routing token prefix and suffix */ + length += 4 + loadBalanceInfoLength; + } + + if (userName) + { + redirFlags |= LB_USERNAME; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)userName, -1, &userNameW, 0); + userNameLength = (strlen(userName) + 1) * sizeof(WCHAR); + + length += 4 + userNameLength; + } + + if (domain) + { + redirFlags |= LB_DOMAIN; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)domain, -1, &domainW, 0); + domainLength = (strlen(domain) + 1) * sizeof(WCHAR); + + length += 4 + domainLength; + } + + if (password) + { + redirFlags |= LB_PASSWORD; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)password, -1, &passwordW, 0); + passwordLength = (strlen(password) + 1) * sizeof(WCHAR); + + length += 4 + passwordLength; + } + + if (targetFQDN) + { + redirFlags |= LB_TARGET_FQDN; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetFQDN, -1, &targetFQDNW, 0); + targetFQDNLength = (strlen(targetFQDN) + 1) * sizeof(WCHAR); + + length += 4 + targetFQDNLength; + } + + if (targetNetBiosName) + { + redirFlags |= LB_TARGET_NETBIOS_NAME; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetNetBiosName, -1, &targetNetBiosNameW, 0); + targetNetBiosNameLength = (strlen(targetNetBiosName) + 1) * sizeof(WCHAR); + + length += 4 + targetNetBiosNameLength; + } + + if (tsvUrl) + { + redirFlags |= LB_CLIENT_TSV_URL; + length += 4 + tsvUrlLength; + } + + if (targetNetAddresses) + { + UINT32 i; + + redirFlags |= LB_TARGET_NET_ADDRESSES; + + targetNetAddressesLength = 0; + targetNetAddressesW = calloc(targetNetAddressesCount, sizeof(LPWSTR)); + targetNetAddressesWLength = calloc(targetNetAddressesCount, sizeof(UINT32)); + for (i = 0; i < targetNetAddressesCount; i++) + { + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetNetAddresses[i], -1, &targetNetAddressesW[i], + 0); + targetNetAddressesWLength[i] = (strlen(targetNetAddresses[i]) + 1) * sizeof(WCHAR); + targetNetAddressesLength += 4 + targetNetAddressesWLength[i]; + } + + length += 4 + 4 + targetNetAddressesLength; + } + + Stream_Write_UINT16(s, 0); + Stream_Write_UINT16(s, SEC_REDIRECTION_PKT); + Stream_Write_UINT16(s, length); + + if (!Stream_EnsureRemainingCapacity(s, length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + goto fail; + } + + if (sessionId) + Stream_Write_UINT32(s, sessionId); + else + Stream_Write_UINT32(s, 0); + + Stream_Write_UINT32(s, redirFlags); + + if (redirFlags & LB_TARGET_NET_ADDRESS) + { + Stream_Write_UINT32(s, targetNetAddressLength); + Stream_Write(s, targetNetAddressW, targetNetAddressLength); + free(targetNetAddressW); + } + + if (redirFlags & LB_LOAD_BALANCE_INFO) + { + Stream_Write_UINT32(s, loadBalanceInfoLength); + Stream_Write(s, "Cookie: msts=", 13); + Stream_Write(s, routingToken, strlen(routingToken)); + Stream_Write_UINT8(s, 0x0d); + Stream_Write_UINT8(s, 0x0a); + } + + if (redirFlags & LB_USERNAME) + { + Stream_Write_UINT32(s, userNameLength); + Stream_Write(s, userNameW, userNameLength); + free(userNameW); + } + + if (redirFlags & LB_DOMAIN) + { + Stream_Write_UINT32(s, domainLength); + Stream_Write(s, domainW, domainLength); + free(domainW); + } + + if (redirFlags & LB_PASSWORD) + { + Stream_Write_UINT32(s, passwordLength); + Stream_Write(s, passwordW, passwordLength); + free(passwordW); + } + + if (redirFlags & LB_TARGET_FQDN) + { + Stream_Write_UINT32(s, targetFQDNLength); + Stream_Write(s, targetFQDNW, targetFQDNLength); + free(targetFQDNW); + } + + if (redirFlags & LB_TARGET_NETBIOS_NAME) + { + Stream_Write_UINT32(s, targetNetBiosNameLength); + Stream_Write(s, targetNetBiosNameW, targetNetBiosNameLength); + free(targetNetBiosNameW); + } + + if (redirFlags & LB_CLIENT_TSV_URL) + { + Stream_Write_UINT32(s, tsvUrlLength); + Stream_Write(s, tsvUrl, tsvUrlLength); + } + + if (redirFlags & LB_TARGET_NET_ADDRESSES) + { + UINT32 i; + Stream_Write_UINT32(s, targetNetAddressesLength); + Stream_Write_UINT32(s, targetNetAddressesCount); + for (i = 0; i < targetNetAddressesCount; i++) + { + Stream_Write_UINT32(s, targetNetAddressesWLength[i]); + Stream_Write(s, targetNetAddressesW[i], targetNetAddressesWLength[i]); + free(targetNetAddressesW[i]); + } + free(targetNetAddressesW); + free(targetNetAddressesWLength); + } + + Stream_Write_UINT8(s, 0); + rdp_send_pdu(peer->context->rdp, s, PDU_TYPE_SERVER_REDIRECTION, 0); + + return TRUE; + +fail: + free(targetNetAddressW); + free(userNameW); + free(domainW); + free(passwordW); + free(targetFQDNW); + free(targetNetBiosNameW); + free(targetNetAddressesWLength); + + if (targetNetAddressesCount > 0) + { + UINT32 i; + for (i = 0; i < targetNetAddressesCount; i++) + free(targetNetAddressesW[i]); + free(targetNetAddressesW); + } + + return FALSE; +} + static BOOL freerdp_peer_is_write_blocked(freerdp_peer* peer) { rdpTransport* transport = peer->context->rdp->transport; @@ -980,6 +1217,7 @@ freerdp_peer* freerdp_peer_new(int sockfd) client->Close = freerdp_peer_close; client->Disconnect = freerdp_peer_disconnect; client->SendChannelData = freerdp_peer_send_channel_data; + client->SendServerRedirection = freerdp_peer_send_server_redirection_pdu; client->IsWriteBlocked = freerdp_peer_is_write_blocked; client->DrainOutputBuffer = freerdp_peer_drain_output_buffer; client->HasMoreToRead = freerdp_peer_has_more_to_read; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 610d81e..4de2561 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1502,13 +1502,14 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) * enters the active state, an auto-detect PDU can be received * on the MCS message channel. */ - if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) && (rdp->state < CONNECTION_STATE_ACTIVE)) + if ((rdp_get_state(rdp) > CONNECTION_STATE_MCS_CHANNEL_JOIN) && + (rdp_get_state(rdp) < CONNECTION_STATE_ACTIVE)) { if (rdp_client_connect_auto_detect(rdp, s)) return 0; } - switch (rdp->state) + switch (rdp_get_state(rdp)) { case CONNECTION_STATE_NLA: if (nla_get_state(rdp->nla) < NLA_STATE_AUTH_INFO) @@ -1516,7 +1517,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (nla_recv_pdu(rdp->nla, s) < 1) { WLog_ERR(TAG, "%s: %s - nla_recv_pdu() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -1527,7 +1528,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (nego_get_state(rdp->nego) != NEGO_STATE_FINAL) { WLog_ERR(TAG, "%s: %s - nego_recv() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -1567,7 +1568,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (!mcs_client_begin(rdp->mcs)) { WLog_ERR(TAG, "%s: %s - mcs_client_begin() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -1618,7 +1619,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_client_connect_mcs_channel_join_confirm() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); status = -1; } @@ -1629,7 +1630,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (status < 0) WLog_DBG(TAG, "%s: %s - rdp_client_connect_license() - %i", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), status); + rdp_state_string(rdp_get_state(rdp)), status); break; @@ -1640,7 +1641,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_DBG(TAG, "%s: %s - " "rdp_client_connect_demand_active() - %i", - __FUNCTION__, rdp_server_connection_state_string(rdp->state), status); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp)), status); break; @@ -1655,7 +1656,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (status < 0) WLog_DBG(TAG, "%s: %s - rdp_recv_pdu() - %i", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), status); + rdp_state_string(rdp_get_state(rdp)), status); break; @@ -1664,13 +1665,13 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (status < 0) WLog_DBG(TAG, "%s: %s - rdp_recv_pdu() - %i", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), status); + rdp_state_string(rdp_get_state(rdp)), status); break; default: - WLog_ERR(TAG, "%s: %s state %d", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), rdp->state); + WLog_ERR(TAG, "%s: %s state %d", __FUNCTION__, rdp_state_string(rdp_get_state(rdp)), + rdp_get_state(rdp)); status = -1; break; } diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index d36a932..8212482 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -132,7 +132,7 @@ struct rdp_rdp { - int state; + CONNECTION_STATE state; freerdp* instance; rdpContext* context; rdpNla* nla; diff --git a/server/proxy/pf_context.h b/server/proxy/pf_context.h index 7c49fa7..2a5b7a9 100644 --- a/server/proxy/pf_context.h +++ b/server/proxy/pf_context.h @@ -94,6 +94,9 @@ struct p_client_context UINT64 frames_count; wHashTable* vc_ids; /* channel_name -> channel_id map */ + + BOOL input_state_sync_pending; + UINT32 input_state; }; typedef struct p_client_context pClientContext; diff --git a/server/proxy/pf_input.c b/server/proxy/pf_input.c index 2a9baaa..9703ac0 100644 --- a/server/proxy/pf_input.c +++ b/server/proxy/pf_input.c @@ -23,11 +23,28 @@ #include "pf_context.h" #include "pf_modules.h" +static BOOL pf_server_check_and_sync_input_state(pClientContext* pc) +{ + if (freerdp_get_state(&pc->context) < CONNECTION_STATE_ACTIVE) + return FALSE; + if (pc->input_state_sync_pending) + { + BOOL rc = freerdp_input_send_synchronize_event(pc->context.input, pc->input_state); + if (rc) + pc->input_state_sync_pending = FALSE; + } + return TRUE; +} + static BOOL pf_server_synchronize_event(rdpInput* input, UINT32 flags) { pServerContext* ps = (pServerContext*)input->context; pClientContext* pc = ps->pdata->pc; - return freerdp_input_send_synchronize_event(pc->context.input, flags); + + pc->input_state = flags; + pc->input_state_sync_pending = TRUE; + pf_server_check_and_sync_input_state(pc); + return TRUE; } static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) @@ -37,6 +54,9 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) proxyConfig* config = ps->pdata->config; proxyKeyboardEventInfo event; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Keyboard) return TRUE; @@ -55,6 +75,9 @@ static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT pClientContext* pc = ps->pdata->pc; proxyConfig* config = ps->pdata->config; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Keyboard) return TRUE; @@ -68,6 +91,9 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1 proxyConfig* config = ps->pdata->config; proxyMouseEventInfo event; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Mouse) return TRUE; @@ -87,6 +113,9 @@ static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 pClientContext* pc = ps->pdata->pc; proxyConfig* config = ps->pdata->config; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Mouse) return TRUE; diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index c9fbc5c..05eefe4 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.8.1") +set(RAW_VERSION_STRING "2.9.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) @@ -82,6 +82,8 @@ else() set(WINPR_VERSION_FULL "${WINPR_VERSION}") endif() +option(WITH_INTERNAL_MD4 "Use compiled in md4 hash functions instead of OpenSSL/MBedTLS" OFF) +option(WITH_INTERNAL_MD5 "Use compiled in md5 hash functions instead of OpenSSL/MBedTLS" OFF) if(NOT IOS) check_include_files(stdbool.h WINPR_HAVE_STDBOOL_H) check_include_files(stdint.h WINPR_HAVE_STDINT_H) diff --git a/winpr/include/winpr/ssl.h b/winpr/include/winpr/ssl.h index 942a062..ff50097 100644 --- a/winpr/include/winpr/ssl.h +++ b/winpr/include/winpr/ssl.h @@ -22,6 +22,7 @@ #define WINPR_SSL_H #include +#include #define WINPR_SSL_INIT_DEFAULT 0x00 #define WINPR_SSL_INIT_ALREADY_INITIALIZED 0x01 diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index d7a849c..bb98dff 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -60,10 +60,13 @@ extern "C" WINPR_API int _strnicmp(const char* string1, const char* string2, size_t count); WINPR_API int _wcscmp(const WCHAR* string1, const WCHAR* string2); + WINPR_API int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count); WINPR_API size_t _wcslen(const WCHAR* str); WINPR_API size_t _wcsnlen(const WCHAR* str, size_t maxNumberOfElements); + WINPR_API WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch); + WINPR_API WCHAR* _wcschr(const WCHAR* str, WCHAR c); WINPR_API WCHAR* _wcsrchr(const WCHAR* str, WCHAR c); @@ -73,8 +76,10 @@ extern "C" #else #define _wcscmp wcscmp +#define _wcsncmp wcsncmp #define _wcslen wcslen #define _wcsnlen wcsnlen +#define _wcsstr wcsstr #define _wcschr wcschr #define _wcsrchr wcsrchr diff --git a/winpr/include/winpr/wlog.h b/winpr/include/winpr/wlog.h index 292eac3..1eedffa 100644 --- a/winpr/include/winpr/wlog.h +++ b/winpr/include/winpr/wlog.h @@ -30,6 +30,7 @@ extern "C" #include #include +#include #include #include diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index 748210e..6596b42 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -26,6 +26,7 @@ #include #include +#include #include /* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */ @@ -97,17 +98,39 @@ int _strnicmp(const char* string1, const char* string2, size_t count) int _wcscmp(const WCHAR* string1, const WCHAR* string2) { - WCHAR value1, value2; + WINPR_ASSERT(string1); + WINPR_ASSERT(string2); - while (*string1 && (*string1 == *string2)) + while (TRUE) { - string1++; - string2++; + const WCHAR w1 = *string1++; + const WCHAR w2 = *string2++; + + if (w1 != w2) + return (int)w1 - w2; + else if ((w1 == '\0') || (w2 == '\0')) + return (int)w1 - w2; } - Data_Read_UINT16(string1, value1); - Data_Read_UINT16(string2, value2); - return value1 - value2; + return 0; +} + +int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) +{ + WINPR_ASSERT(string1); + WINPR_ASSERT(string2); + + for (size_t x = 0; x < count; x++) + { + const WCHAR a = string1[x]; + const WCHAR b = string2[x]; + + if (a != b) + return (int)a - b; + else if ((a == '\0') || (b == '\0')) + return (int)a - b; + } + return 0; } /* _wcslen -> wcslen */ @@ -116,8 +139,7 @@ size_t _wcslen(const WCHAR* str) { const WCHAR* p = (const WCHAR*)str; - if (!p) - return 0; + WINPR_ASSERT(p); while (*p) p++; @@ -131,8 +153,7 @@ size_t _wcsnlen(const WCHAR* str, size_t max) { size_t x; - if (!str) - return 0; + WINPR_ASSERT(str); for (x = 0; x < max; x++) { @@ -143,6 +164,26 @@ size_t _wcsnlen(const WCHAR* str, size_t max) return x; } +/* _wcsstr -> wcsstr */ + +WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch) +{ + WINPR_ASSERT(str); + WINPR_ASSERT(strSearch); + + if (strSearch[0] == '\0') + return str; + + const size_t searchLen = _wcslen(strSearch); + while (*str) + { + if (_wcsncmp(str, strSearch, searchLen) == 0) + return str; + str++; + } + return NULL; +} + /* _wcschr -> wcschr */ WCHAR* _wcschr(const WCHAR* str, WCHAR c) diff --git a/winpr/libwinpr/crypto/CMakeLists.txt b/winpr/libwinpr/crypto/CMakeLists.txt index d215744..92077ec 100644 --- a/winpr/libwinpr/crypto/CMakeLists.txt +++ b/winpr/libwinpr/crypto/CMakeLists.txt @@ -15,13 +15,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -winpr_module_add( +set(SRCS hash.c rand.c cipher.c cert.c crypto.c - crypto.h) + crypto.h +) +if (WITH_INTERNAL_MD4) + list(APPEND SRCS md4.c md4.h) +endif() + +if (WITH_INTERNAL_MD5) + list(APPEND SRCS md5.c md5.h) + list(APPEND SRCS hmac_md5.c hmac_md5.h) +endif() + +winpr_module_add( + ${SRCS} +) if(OPENSSL_FOUND) winpr_include_directory_add(${OPENSSL_INCLUDE_DIR}) diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 5e94039..9e564a1 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -21,7 +21,7 @@ #endif #include - +#include #include #ifdef WITH_OPENSSL @@ -39,6 +39,15 @@ #include #endif +#if defined(WITH_INTERNAL_MD4) +#include "md4.h" +#endif + +#if defined(WITH_INTERNAL_MD5) +#include "md5.h" +#include "hmac_md5.h" +#endif + /** * HMAC */ @@ -146,41 +155,68 @@ const char* winpr_md_type_to_string(WINPR_MD_TYPE md) return NULL; } +struct _winpr_hmac_ctx_private_st +{ + WINPR_MD_TYPE md; + +#if defined(WITH_INTERNAL_MD5) + WINPR_HMAC_MD5_CTX hmac_md5; +#endif +#if defined(WITH_OPENSSL) + HMAC_CTX* hmac; +#endif +#if defined(WITH_MBEDTLS) + mbedtls_md_context_t hmac; +#endif +}; + WINPR_HMAC_CTX* winpr_HMAC_New(void) { - WINPR_HMAC_CTX* ctx = NULL; + WINPR_HMAC_CTX* ctx = calloc(1, sizeof(WINPR_HMAC_CTX)); + if (!ctx) + return NULL; #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = NULL; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - if (!(hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX)))) - return NULL; + if (!(ctx->hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX)))) + goto fail; - HMAC_CTX_init(hmac); + HMAC_CTX_init(ctx->hmac); #else - if (!(hmac = HMAC_CTX_new())) - return NULL; + if (!(ctx->hmac = HMAC_CTX_new())) + goto fail; #endif - ctx = (WINPR_HMAC_CTX*)hmac; #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* hmac; - - if (!(hmac = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t)))) - return NULL; - - mbedtls_md_init(hmac); - ctx = (WINPR_HMAC_CTX*)hmac; + mbedtls_md_init(&ctx->hmac); #endif return ctx; + +fail: + winpr_HMAC_Free(ctx); + return NULL; } BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, size_t keylen) { + WINPR_ASSERT(ctx); + + ctx->md = md; + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + hmac_md5_init(&ctx->hmac_md5, key, keylen); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; const EVP_MD* evp = winpr_openssl_get_evp_md(md); if (!evp || !hmac) @@ -197,7 +233,7 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz #endif #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* hmac = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* hmac = &ctx->hmac; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type); @@ -221,8 +257,21 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) { + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + hmac_md5_update(&ctx->hmac_md5, input, ilen); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; #if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */ @@ -234,7 +283,7 @@ BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) #endif #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = &ctx->hmac; if (mbedtls_md_hmac_update(mdctx, input, ilen) == 0) return TRUE; @@ -245,17 +294,23 @@ BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) { -#if defined(WITH_OPENSSL) - HMAC_CTX* hmac; -#elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx; + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + if (olen < WINPR_MD5_DIGEST_LENGTH) + return FALSE; + hmac_md5_finalize(&ctx->hmac_md5, output); + return TRUE; #endif - - if (!ctx) - return FALSE; + default: + break; + } #if defined(WITH_OPENSSL) - hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; #if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Final(hmac, output, NULL); /* no return value on OpenSSL 0.9.x */ @@ -267,7 +322,7 @@ BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) #endif #elif defined(WITH_MBEDTLS) - mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = &ctx->hmac; if (mbedtls_md_hmac_finish(mdctx, output) == 0) return TRUE; @@ -278,8 +333,11 @@ BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) { + if (!ctx) + return; + #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; if (hmac) { @@ -293,15 +351,14 @@ void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) } #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* hmac = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* hmac = &ctx->hmac; if (hmac) - { mbedtls_md_free(hmac); - free(hmac); - } #endif + + free(ctx); } BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, const BYTE* input, size_t ilen, @@ -332,34 +389,60 @@ out: * Generic Digest API */ -WINPR_DIGEST_CTX* winpr_Digest_New(void) +struct _winpr_digest_ctx_private_st { - WINPR_DIGEST_CTX* ctx = NULL; + WINPR_MD_TYPE md; + +#if defined(WITH_INTERNAL_MD4) + WINPR_MD4_CTX md4; +#endif +#if defined(WITH_INTERNAL_MD5) + WINPR_MD5_CTX md5; +#endif #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx; +#endif +#if defined(WITH_MBEDTLS) + mbedtls_md_context_t* mdctx; +#endif +}; + +WINPR_DIGEST_CTX* winpr_Digest_New(void) +{ + WINPR_DIGEST_CTX* ctx = calloc(1, sizeof(WINPR_DIGEST_CTX)); + if (!ctx) + return NULL; + +#if defined(WITH_OPENSSL) #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - mdctx = EVP_MD_CTX_create(); + ctx->mdctx = EVP_MD_CTX_create(); #else - mdctx = EVP_MD_CTX_new(); + ctx->mdctx = EVP_MD_CTX_new(); #endif - ctx = (WINPR_DIGEST_CTX*)mdctx; + if (!ctx->mdctx) + goto fail; + #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx; - mdctx = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t)); + ctx->mdctx = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t)); - if (mdctx) - mbedtls_md_init(mdctx); + if (!ctx->mdctx) + goto fail; - ctx = (WINPR_DIGEST_CTX*)mdctx; + mbedtls_md_init(ctx->mdctx); #endif return ctx; + +fail: + winpr_Digest_Free(ctx); + return NULL; } #if defined(WITH_OPENSSL) static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, const EVP_MD* evp) { - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; + WINPR_ASSERT(ctx); + EVP_MD_CTX* mdctx = ctx->mdctx; if (!mdctx || !evp) return FALSE; @@ -373,7 +456,8 @@ static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, const EVP_MD* evp) #elif defined(WITH_MBEDTLS) static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + WINPR_ASSERT(ctx); + mbedtls_md_context_t* mdctx = ctx->mdctx; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type); @@ -397,15 +481,16 @@ static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { + WINPR_ASSERT(ctx); + #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; const EVP_MD* evp = winpr_openssl_get_evp_md(md); /* Only MD5 is supported for FIPS allow override */ if (md != WINPR_MD_MD5) return FALSE; - EVP_MD_CTX_set_flags(mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); return winpr_Digest_Init_Internal(ctx, evp); #elif defined(WITH_MBEDTLS) @@ -419,6 +504,25 @@ BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { + WINPR_ASSERT(ctx); + + ctx->md = md; + switch (md) + { +#if defined(WITH_INTERNAL_MD4) + case WINPR_MD_MD4: + winpr_MD4_Init(&ctx->md4); + return TRUE; +#endif +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + winpr_MD5_Init(&ctx->md5); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) const EVP_MD* evp = winpr_openssl_get_evp_md(md); return winpr_Digest_Init_Internal(ctx, evp); @@ -429,14 +533,32 @@ BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) { + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD4) + case WINPR_MD_MD4: + winpr_MD4_Update(&ctx->md4, input, ilen); + return TRUE; +#endif +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + winpr_MD5_Update(&ctx->md5, input, ilen); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; + EVP_MD_CTX* mdctx = ctx->mdctx; if (EVP_DigestUpdate(mdctx, input, ilen) != 1) return FALSE; #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = ctx->mdctx; if (mbedtls_md_update(mdctx, input, ilen) != 0) return FALSE; @@ -447,14 +569,37 @@ BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) { + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD4) + case WINPR_MD_MD4: + if (olen < WINPR_MD4_DIGEST_LENGTH) + return FALSE; + winpr_MD4_Final(output, &ctx->md4); + return TRUE; +#endif +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + if (olen < WINPR_MD5_DIGEST_LENGTH) + return FALSE; + winpr_MD5_Final(output, &ctx->md5); + return TRUE; +#endif + + default: + break; + } + #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; + EVP_MD_CTX* mdctx = ctx->mdctx; if (EVP_DigestFinal_ex(mdctx, output, NULL) == 1) return TRUE; #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = ctx->mdctx; if (mbedtls_md_finish(mdctx, output) == 0) return TRUE; @@ -465,29 +610,28 @@ BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx) { + if (!ctx) + return; #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; - - if (mdctx) + if (ctx->mdctx) { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - EVP_MD_CTX_destroy(mdctx); + EVP_MD_CTX_destroy(ctx->mdctx); #else - EVP_MD_CTX_free(mdctx); + EVP_MD_CTX_free(ctx->mdctx); #endif } #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; - - if (mdctx) + if (ctx->mdctx) { - mbedtls_md_free(mdctx); - free(mdctx); + mbedtls_md_free(ctx->mdctx); + free(ctx->mdctx); } #endif + free(ctx); } BOOL winpr_Digest_Allow_FIPS(WINPR_MD_TYPE md, const BYTE* input, size_t ilen, BYTE* output, diff --git a/winpr/libwinpr/crypto/hmac_md5.c b/winpr/libwinpr/crypto/hmac_md5.c new file mode 100644 index 0000000..4bc9b93 --- /dev/null +++ b/winpr/libwinpr/crypto/hmac_md5.c @@ -0,0 +1,54 @@ +#include +#include "hmac_md5.h" +#include "md5.h" + +void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, unsigned char* key, size_t key_len) +{ + const WINPR_HMAC_MD5_CTX empty = { 0 }; + unsigned char k_ipad[KEY_IOPAD_SIZE] = { 0 }; + unsigned char k_opad[KEY_IOPAD_SIZE] = { 0 }; + + assert(ctx); + *ctx = empty; + + if (key_len <= KEY_IOPAD_SIZE) + { + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + } + else + { + WINPR_MD5_CTX lctx = { 0 }; + + winpr_MD5_Init(&lctx); + winpr_MD5_Update(&lctx, key, key_len); + winpr_MD5_Final(k_ipad, &lctx); + memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE); + } + for (size_t i = 0; i < KEY_IOPAD_SIZE; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + winpr_MD5_Init(&ctx->icontext); + winpr_MD5_Update(&ctx->icontext, k_ipad, KEY_IOPAD_SIZE); + + winpr_MD5_Init(&ctx->ocontext); + winpr_MD5_Update(&ctx->ocontext, k_opad, KEY_IOPAD_SIZE); +} + +void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, unsigned char* text, size_t text_len) +{ + assert(ctx); + winpr_MD5_Update(&ctx->icontext, text, text_len); +} + +void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac) +{ + assert(ctx); + winpr_MD5_Final(hmac, &ctx->icontext); + + winpr_MD5_Update(&ctx->ocontext, hmac, 16); + winpr_MD5_Final(hmac, &ctx->ocontext); +} diff --git a/winpr/libwinpr/crypto/hmac_md5.h b/winpr/libwinpr/crypto/hmac_md5.h new file mode 100644 index 0000000..a1ea6a0 --- /dev/null +++ b/winpr/libwinpr/crypto/hmac_md5.h @@ -0,0 +1,19 @@ +#ifndef WINPR_HMAC_MD5 +#define WINPR_HMAC_MD5 + +#include + +#include "md5.h" + +#define KEY_IOPAD_SIZE 64 +typedef struct +{ + WINPR_MD5_CTX icontext; + WINPR_MD5_CTX ocontext; +} WINPR_HMAC_MD5_CTX; + +void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, unsigned char* key, size_t key_len); +void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, unsigned char* text, size_t text_len); +void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac); + +#endif diff --git a/winpr/libwinpr/crypto/md4.c b/winpr/libwinpr/crypto/md4.c new file mode 100644 index 0000000..c33aea3 --- /dev/null +++ b/winpr/libwinpr/crypto/md4.c @@ -0,0 +1,266 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include + +#include "md4.h" + +/* + * The basic MD4 functions. + * + * F and G are optimized compared to their RFC 1320 definitions, with the + * optimization for F borrowed from Colin Plumb's MD5 implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The MD4 transformation for all three rounds. + */ +#define STEP(f, a, b, c, d, x, s) \ + (a) += f((b), (c), (d)) + (x); \ + (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * winpr_MD4_u32plus. In practice, this problem may occur if these MD4 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD4 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) (*(winpr_MD4_u32plus*)&ptr[(n)*4]) +#define GET(n) SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = (winpr_MD4_u32plus)ptr[(n)*4] | ((winpr_MD4_u32plus)ptr[(n)*4 + 1] << 8) | \ + ((winpr_MD4_u32plus)ptr[(n)*4 + 2] << 16) | \ + ((winpr_MD4_u32plus)ptr[(n)*4 + 3] << 24)) +#define GET(n) (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void* body(WINPR_MD4_CTX* ctx, const void* data, unsigned long size) +{ + const unsigned char* ptr; + winpr_MD4_u32plus a, b, c, d; + winpr_MD4_u32plus saved_a, saved_b, saved_c, saved_d; + const winpr_MD4_u32plus ac1 = 0x5a827999, ac2 = 0x6ed9eba1; + + ptr = (const unsigned char*)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do + { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + STEP(F, a, b, c, d, SET(0), 3) + STEP(F, d, a, b, c, SET(1), 7) + STEP(F, c, d, a, b, SET(2), 11) + STEP(F, b, c, d, a, SET(3), 19) + STEP(F, a, b, c, d, SET(4), 3) + STEP(F, d, a, b, c, SET(5), 7) + STEP(F, c, d, a, b, SET(6), 11) + STEP(F, b, c, d, a, SET(7), 19) + STEP(F, a, b, c, d, SET(8), 3) + STEP(F, d, a, b, c, SET(9), 7) + STEP(F, c, d, a, b, SET(10), 11) + STEP(F, b, c, d, a, SET(11), 19) + STEP(F, a, b, c, d, SET(12), 3) + STEP(F, d, a, b, c, SET(13), 7) + STEP(F, c, d, a, b, SET(14), 11) + STEP(F, b, c, d, a, SET(15), 19) + + /* Round 2 */ + STEP(G, a, b, c, d, GET(0) + ac1, 3) + STEP(G, d, a, b, c, GET(4) + ac1, 5) + STEP(G, c, d, a, b, GET(8) + ac1, 9) + STEP(G, b, c, d, a, GET(12) + ac1, 13) + STEP(G, a, b, c, d, GET(1) + ac1, 3) + STEP(G, d, a, b, c, GET(5) + ac1, 5) + STEP(G, c, d, a, b, GET(9) + ac1, 9) + STEP(G, b, c, d, a, GET(13) + ac1, 13) + STEP(G, a, b, c, d, GET(2) + ac1, 3) + STEP(G, d, a, b, c, GET(6) + ac1, 5) + STEP(G, c, d, a, b, GET(10) + ac1, 9) + STEP(G, b, c, d, a, GET(14) + ac1, 13) + STEP(G, a, b, c, d, GET(3) + ac1, 3) + STEP(G, d, a, b, c, GET(7) + ac1, 5) + STEP(G, c, d, a, b, GET(11) + ac1, 9) + STEP(G, b, c, d, a, GET(15) + ac1, 13) + + /* Round 3 */ + STEP(H, a, b, c, d, GET(0) + ac2, 3) + STEP(H, d, a, b, c, GET(8) + ac2, 9) + STEP(H, c, d, a, b, GET(4) + ac2, 11) + STEP(H, b, c, d, a, GET(12) + ac2, 15) + STEP(H, a, b, c, d, GET(2) + ac2, 3) + STEP(H, d, a, b, c, GET(10) + ac2, 9) + STEP(H, c, d, a, b, GET(6) + ac2, 11) + STEP(H, b, c, d, a, GET(14) + ac2, 15) + STEP(H, a, b, c, d, GET(1) + ac2, 3) + STEP(H, d, a, b, c, GET(9) + ac2, 9) + STEP(H, c, d, a, b, GET(5) + ac2, 11) + STEP(H, b, c, d, a, GET(13) + ac2, 15) + STEP(H, a, b, c, d, GET(3) + ac2, 3) + STEP(H, d, a, b, c, GET(11) + ac2, 9) + STEP(H, c, d, a, b, GET(7) + ac2, 11) + STEP(H, b, c, d, a, GET(15) + ac2, 15) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void winpr_MD4_Init(WINPR_MD4_CTX* ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, unsigned long size) +{ + winpr_MD4_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) + { + available = 64 - used; + + if (size < available) + { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char*)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) + { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) + { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} diff --git a/winpr/libwinpr/crypto/md4.h b/winpr/libwinpr/crypto/md4.h new file mode 100644 index 0000000..1ea008e --- /dev/null +++ b/winpr/libwinpr/crypto/md4.h @@ -0,0 +1,46 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md4.c for more information. + */ + +#if !defined(WINPR_MD4_H) +#define WINPR_MD4_H + +#include + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef UINT32 winpr_MD4_u32plus; + +typedef struct +{ + winpr_MD4_u32plus lo, hi; + winpr_MD4_u32plus a, b, c, d; + unsigned char buffer[64]; + winpr_MD4_u32plus block[16]; +} WINPR_MD4_CTX; + +extern void winpr_MD4_Init(WINPR_MD4_CTX* ctx); +extern void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, unsigned long size); +extern void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx); + +#endif diff --git a/winpr/libwinpr/crypto/md5.c b/winpr/libwinpr/crypto/md5.c new file mode 100644 index 0000000..96e8282 --- /dev/null +++ b/winpr/libwinpr/crypto/md5.c @@ -0,0 +1,287 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include + +#include "md5.h" + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * MD5_u32plus. In practice, this problem may occur if these MD5 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD5 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) (*(winpr_MD5_u32plus*)&ptr[(n)*4]) +#define GET(n) SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = (winpr_MD5_u32plus)ptr[(n)*4] | ((winpr_MD5_u32plus)ptr[(n)*4 + 1] << 8) | \ + ((winpr_MD5_u32plus)ptr[(n)*4 + 2] << 16) | \ + ((winpr_MD5_u32plus)ptr[(n)*4 + 3] << 24)) +#define GET(n) (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void* body(WINPR_MD5_CTX* ctx, const void* data, unsigned long size) +{ + const unsigned char* ptr; + winpr_MD5_u32plus a, b, c, d; + winpr_MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char*)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do + { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + + /* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + + /* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + + /* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void winpr_MD5_Init(WINPR_MD5_CTX* ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, unsigned long size) +{ + winpr_MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) + { + available = 64 - used; + + if (size < available) + { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char*)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) + { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) + { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} diff --git a/winpr/libwinpr/crypto/md5.h b/winpr/libwinpr/crypto/md5.h new file mode 100644 index 0000000..2056b9a --- /dev/null +++ b/winpr/libwinpr/crypto/md5.h @@ -0,0 +1,48 @@ + + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ + +#if !defined(WINPR_MD5_H) +#define WINPR_MD5_H + +#include + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef UINT32 winpr_MD5_u32plus; + +typedef struct +{ + winpr_MD5_u32plus lo, hi; + winpr_MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + winpr_MD5_u32plus block[16]; +} WINPR_MD5_CTX; + +extern void winpr_MD5_Init(WINPR_MD5_CTX* ctx); +extern void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, unsigned long size); +extern void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx); + +#endif diff --git a/winpr/libwinpr/crypto/test/TestCryptoHash.c b/winpr/libwinpr/crypto/test/TestCryptoHash.c index 8b91186..761d72d 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoHash.c +++ b/winpr/libwinpr/crypto/test/TestCryptoHash.c @@ -11,7 +11,7 @@ static const BYTE TEST_MD5_HASH[] = static BOOL test_crypto_hash_md5(void) { BOOL result = FALSE; - BYTE hash[WINPR_MD5_DIGEST_LENGTH]; + BYTE hash[WINPR_MD5_DIGEST_LENGTH] = { 0 }; WINPR_DIGEST_CTX* ctx; if (!(ctx = winpr_Digest_New())) @@ -64,7 +64,7 @@ static const BYTE TEST_MD4_HASH[] = static BOOL test_crypto_hash_md4(void) { BOOL result = FALSE; - BYTE hash[WINPR_MD4_DIGEST_LENGTH]; + BYTE hash[WINPR_MD4_DIGEST_LENGTH] = { 0 }; WINPR_DIGEST_CTX* ctx; if (!(ctx = winpr_Digest_New())) @@ -117,7 +117,7 @@ static const BYTE TEST_SHA1_HASH[] = static BOOL test_crypto_hash_sha1(void) { BOOL result = FALSE; - BYTE hash[WINPR_SHA1_DIGEST_LENGTH]; + BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = { 0 }; WINPR_DIGEST_CTX* ctx; if (!(ctx = winpr_Digest_New())) @@ -168,11 +168,11 @@ static const char TEST_HMAC_MD5_DATA[] = "Hi There"; static const BYTE TEST_HMAC_MD5_KEY[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; static const BYTE TEST_HMAC_MD5_HASH[] = - "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d"; + "\xb5\x79\x91\xa2\x20\x3d\x49\x2d\x73\xfb\x71\x43\xdf\xc5\x08\x28"; static BOOL test_crypto_hash_hmac_md5(void) { - BYTE hash[WINPR_MD5_DIGEST_LENGTH]; + BYTE hash[WINPR_MD5_DIGEST_LENGTH] = { 0 }; WINPR_HMAC_CTX* ctx; BOOL result = FALSE; @@ -193,6 +193,12 @@ static BOOL test_crypto_hash_hmac_md5(void) fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); goto out; } + if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_MD5_DATA, + strnlen(TEST_HMAC_MD5_DATA, sizeof(TEST_HMAC_MD5_DATA)))) + { + fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); + goto out; + } if (!winpr_HMAC_Final(ctx, hash, sizeof(hash))) { fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __FUNCTION__); @@ -225,11 +231,11 @@ static const char TEST_HMAC_SHA1_DATA[] = "Hi There"; static const BYTE TEST_HMAC_SHA1_KEY[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; static const BYTE TEST_HMAC_SHA1_HASH[] = - "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00"; + "\xab\x23\x08\x2d\xca\x0c\x75\xea\xca\x60\x09\xc0\xb8\x8c\x2d\xf4\xf4\xbf\x88\xee"; static BOOL test_crypto_hash_hmac_sha1(void) { - BYTE hash[WINPR_SHA1_DIGEST_LENGTH]; + BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = { 0 }; WINPR_HMAC_CTX* ctx; BOOL result = FALSE; @@ -250,6 +256,12 @@ static BOOL test_crypto_hash_hmac_sha1(void) fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); goto out; } + if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_SHA1_DATA, + strnlen(TEST_HMAC_SHA1_DATA, sizeof(TEST_HMAC_SHA1_DATA)))) + { + fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); + goto out; + } if (!winpr_HMAC_Final(ctx, hash, sizeof(hash))) { fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __FUNCTION__); diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index 301f940..1924909 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -42,6 +42,12 @@ static BOOL g_winpr_openssl_initialized_by_winpr = FALSE; +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +static OSSL_PROVIDER* s_winpr_openssl_provider_fips = NULL; +static OSSL_PROVIDER* s_winpr_openssl_provider_legacy = NULL; +static OSSL_PROVIDER* s_winpr_openssl_provider_default = NULL; +#endif + /** * Note from OpenSSL 1.1.0 "CHANGES": * OpenSSL now uses a new threading API. It is no longer necessary to @@ -249,7 +255,11 @@ static BOOL winpr_enable_fips(DWORD flags) WLog_DBG(TAG, "Ensuring openssl fips mode is enabled"); #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) - OSSL_PROVIDER_load(NULL, "fips"); + s_winpr_openssl_provider_fips = OSSL_PROVIDER_load(NULL, "fips"); + if (s_winpr_openssl_provider_fips == NULL) + { + WLog_WARN(TAG, "OpenSSL FIPS provider failled to load"); + } if (!EVP_default_properties_is_fips_enabled(NULL)) #else if (FIPS_mode() != 1) @@ -313,8 +323,16 @@ static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVO #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) /* The legacy provider is needed for MD4. */ - OSSL_PROVIDER_load(NULL, "legacy"); - OSSL_PROVIDER_load(NULL, "default"); + s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(NULL, "legacy"); + if (s_winpr_openssl_provider_legacy == NULL) + { + WLog_WARN(TAG, "OpenSSL LEGACY provider failed to load, no md4 support available!"); + } + s_winpr_openssl_provider_default = OSSL_PROVIDER_load(NULL, "default"); + if (s_winpr_openssl_provider_default == NULL) + { + WLog_WARN(TAG, "OpenSSL DEFAULT provider failed to load"); + } #endif g_winpr_openssl_initialized_by_winpr = TRUE; @@ -368,6 +386,11 @@ BOOL winpr_CleanupSSL(DWORD flags) #endif } +#endif +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + OSSL_PROVIDER_unload(s_winpr_openssl_provider_fips); + OSSL_PROVIDER_unload(s_winpr_openssl_provider_legacy); + OSSL_PROVIDER_unload(s_winpr_openssl_provider_default); #endif return TRUE; }