Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,43 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2023 David Fort <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if(NOT IOS AND NOT WIN32 AND NOT ANDROID)
find_package(KRB5)
if(KRB5_FOUND)
define_channel("rdpear")
freerdp_client_pc_add_requires_private("mit-krb5")
if(KRB5_FLAVOUR STREQUAL "Heimdal")
message(FATAL_ERROR "krb5 implementation Heimdal not supported with -DCHANNEL_RDPEAR=ON")
endif()
include_directories(common)
if(WITH_CLIENT_CHANNELS OR WITH_SERVER_CHANNELS)
add_subdirectory(common)
endif()
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
#if(WITH_SERVER_CHANNELS)
# add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
#endif()
endif()
endif()

View File

@@ -0,0 +1,20 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT OFF)
define_channel_options(
NAME
"rdpear"
TYPE
"dynamic"
DESCRIPTION
"Authentication redirection Virtual Channel Extension"
SPECIFICATIONS
"[MS-RDPEAR]"
DEFAULT
${OPTION_DEFAULT}
CLIENT_DEFAULT
${OPTION_CLIENT_DEFAULT}
SERVER_DEFAULT
${OPTION_SERVER_DEFAULT}
)

View File

@@ -0,0 +1,24 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2023 David Fort <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_client("rdpear")
set(${MODULE_PREFIX}_SRCS rdpear_main.c)
set(${MODULE_PREFIX}_LIBS winpr freerdp rdpear-common)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2024 David Fort <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
add_library(rdpear-common INTERFACE)
add_library(
rdpear-common-obj STATIC ndr.c rdpear_asn1.c rdpear_common.c rdpear-common/ndr.h rdpear-common/rdpear_asn1.h
rdpear-common/rdpear_common.h
)
target_include_directories(rdpear-common SYSTEM INTERFACE ${KRB5_INCLUDE_DIRS})
target_compile_options(rdpear-common INTERFACE ${KRB5_CFLAGS})
target_link_options(rdpear-common INTERFACE ${KRB5_LDFLAGS})
target_include_directories(rdpear-common-obj PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(rdpear-common-obj SYSTEM PRIVATE ${KRB5_INCLUDE_DIRS})
target_link_directories(rdpear-common INTERFACE ${KRB5_LIBRARY_DIRS})
target_link_libraries(rdpear-common INTERFACE ${KRB5_LIBRARIES} rdpear-common-obj)
freerdp_client_pc_add_library_private(rdpear-common-obj)
channel_install(rdpear-common ${FREERDP_ADDIN_PATH} "FreeRDPTargets")
channel_install(rdpear-common-obj ${FREERDP_ADDIN_PATH} "FreeRDPTargets")
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,268 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Authentication redirection virtual channel
*
* Copyright 2024 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CHANNELS_RDPEAR_NDR_H_
#define CHANNELS_RDPEAR_NDR_H_
#include <winpr/stream.h>
#include <freerdp/api.h>
#define NDR_PTR_NULL (0UL)
#define NDR_SIMPLE_TYPE_DECL(LOWER, UPPER) \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##LOWER(NdrContext* context, wStream* s, \
UPPER* v); \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##LOWER##_(NdrContext* context, wStream* s, \
const void* hints, void* v); \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##LOWER(NdrContext* context, wStream* s, \
UPPER v); \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##LOWER##_( \
NdrContext* context, wStream* s, const void* hints, const void* v); \
FREERDP_LOCAL \
extern const NdrMessageDescr ndr_##LOWER##_descr_s; \
WINPR_ATTR_NODISCARD FREERDP_LOCAL NdrMessageType ndr_##LOWER##_descr(void)
#define NDR_ARRAY_OF_TYPE_DECL(TYPE, UPPERTYPE) \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##TYPE##Array( \
NdrContext* context, wStream* s, const void* hints, void* v); \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##TYPE##Array( \
NdrContext* context, wStream* s, const void* hints, const void* v); \
FREERDP_LOCAL \
void ndr_destroy_##TYPE##Array(NdrContext* context, const void* hints, void* obj); \
FREERDP_LOCAL \
extern const NdrMessageDescr ndr_##TYPE##Array_descr_s; \
WINPR_ATTR_NODISCARD FREERDP_LOCAL NdrMessageType ndr_##TYPE##Array_descr(void); \
\
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_##TYPE##VaryingArray( \
NdrContext* context, wStream* s, const void* hints, void* v); \
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_##TYPE##VaryingArray( \
NdrContext* context, wStream* s, const void* hints, const void* v); \
extern const NdrMessageDescr ndr_##TYPE##VaryingArray_descr_s; \
NdrMessageType ndr_##TYPE##VaryingArray_descr(void)
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct NdrContext_s NdrContext;
typedef UINT32 ndr_refid;
typedef BOOL (*NDR_READER_FN)(NdrContext* context, wStream* s, const void* hints, void* target);
typedef BOOL (*NDR_WRITER_FN)(NdrContext* context, wStream* s, const void* hints,
const void* obj);
typedef void (*NDR_DESTROY_FN)(NdrContext* context, const void* hints, void* obj);
typedef void (*NDR_DUMP_FN)(wLog* logger, UINT32 lvl, size_t indentLevel, const void* obj);
/** @brief arity of a message */
typedef enum
{
NDR_ARITY_SIMPLE,
NDR_ARITY_ARRAYOF,
NDR_ARITY_VARYING_ARRAYOF,
} NdrTypeArity;
/** @brief message descriptor */
typedef struct
{
NdrTypeArity arity;
size_t itemSize;
WINPR_ATTR_NODISCARD NDR_READER_FN readFn;
WINPR_ATTR_NODISCARD NDR_WRITER_FN writeFn;
NDR_DESTROY_FN destroyFn;
NDR_DUMP_FN dumpFn;
} NdrMessageDescr;
typedef const NdrMessageDescr* NdrMessageType;
/** @brief pointer or not and if null is accepted */
typedef enum
{
NDR_NOT_POINTER,
NDR_POINTER_NON_NULL,
NDR_POINTER
} NdrPointerType;
/** @brief descriptor of a field in a structure */
typedef struct
{
const char* name;
size_t structOffset;
NdrPointerType pointerType;
ssize_t hintsField;
NdrMessageType typeDescr;
} NdrFieldStruct;
/** @brief structure descriptor */
typedef struct
{
const char* name;
size_t nfields;
const NdrFieldStruct* fields;
} NdrStructDescr;
/** @brief a deferred pointer */
typedef struct
{
ndr_refid ptrId;
const char* name;
void* hints;
void* target;
NdrMessageType msg;
} NdrDeferredEntry;
FREERDP_LOCAL void ndr_context_free(NdrContext* context);
static inline void ndr_context_destroy(NdrContext** pcontext)
{
WINPR_ASSERT(pcontext);
ndr_context_free(*pcontext);
*pcontext = nullptr;
}
WINPR_ATTR_MALLOC(ndr_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL NdrContext* ndr_context_new(BOOL bigEndianDrep, BYTE version);
FREERDP_LOCAL void ndr_context_reset(NdrContext* context);
WINPR_ATTR_MALLOC(ndr_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL NdrContext* ndr_context_copy(const NdrContext* src);
WINPR_ATTR_MALLOC(ndr_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL NdrContext* ndr_read_header(wStream* s);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_header(NdrContext* context, wStream* s);
NDR_SIMPLE_TYPE_DECL(uint8, UINT8);
NDR_SIMPLE_TYPE_DECL(uint16, UINT16);
NDR_SIMPLE_TYPE_DECL(uint32, UINT32);
NDR_SIMPLE_TYPE_DECL(uint64, UINT64);
NDR_ARRAY_OF_TYPE_DECL(uint8, BYTE);
NDR_ARRAY_OF_TYPE_DECL(uint16, UINT16);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_skip_bytes(NdrContext* context, wStream* s,
size_t nbytes);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_align(NdrContext* context, wStream* s,
size_t sz);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_align(NdrContext* context, wStream* s,
size_t sz);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_data(NdrContext* context, wStream* s,
const void* data, size_t sz);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_pickle(NdrContext* context, wStream* s);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_pickle(NdrContext* context, wStream* s);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_constructed(NdrContext* context, wStream* s,
wStream* target);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_constructed(NdrContext* context, wStream* s,
wStream* payload);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_start_constructed(NdrContext* context, wStream* s);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_end_constructed(NdrContext* context, wStream* s);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_wchar(NdrContext* context, wStream* s,
WCHAR* ptr);
/** @brief hints for a varying conformant array */
typedef struct
{
UINT32 length;
UINT32 maxLength;
} NdrVaryingArrayHints;
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_uconformant_varying_array(
NdrContext* context, wStream* s, const NdrVaryingArrayHints* hints, NdrMessageType itemType,
void* ptarget);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_uconformant_varying_array(
NdrContext* context, wStream* s, const NdrVaryingArrayHints* hints, NdrMessageType itemType,
const void* src);
/** @brief hints for a conformant array */
typedef struct
{
UINT32 count;
} NdrArrayHints;
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_uconformant_array(NdrContext* context,
wStream* s,
const NdrArrayHints* hints,
NdrMessageType itemType,
void* vtarget);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_write_uconformant_array(NdrContext* context,
wStream* s, UINT32 len,
NdrMessageType itemType,
const BYTE* ptr);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_struct_read_fromDescr(NdrContext* context,
wStream* s,
const NdrStructDescr* descr,
void* target);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_struct_write_fromDescr(NdrContext* context,
wStream* s,
const NdrStructDescr* descr,
const void* src);
FREERDP_LOCAL
void ndr_struct_dump_fromDescr(wLog* logger, UINT32 lvl, size_t identLevel,
const NdrStructDescr* descr, const void* obj);
FREERDP_LOCAL
void ndr_struct_destroy(NdrContext* context, const NdrStructDescr* descr, void* pptr);
WINPR_ATTR_NODISCARD FREERDP_LOCAL ndr_refid ndr_pointer_refid(const void* ptr);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_refpointer(NdrContext* context, wStream* s,
UINT32* refId);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_context_allocatePtr(NdrContext* context,
const void* ptr,
ndr_refid* prefId,
BOOL* pnewPtr);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_read_pointedMessageEx(NdrContext* context,
wStream* s, ndr_refid ptrId,
NdrMessageType descr,
void* hints, void** target);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_push_deferreds(NdrContext* context,
NdrDeferredEntry* deferreds,
size_t ndeferred);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_treat_deferred_read(NdrContext* context,
wStream* s);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL ndr_treat_deferred_write(NdrContext* context,
wStream* s);
#ifdef __cplusplus
}
#endif
#endif /* CHANNELS_RDPEAR_NDR_H_ */

View File

@@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* ASN1 routines for RDPEAR
*
* Copyright 2024 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RPDEAR_RDPEAR_ASN1_H__
#define RPDEAR_RDPEAR_ASN1_H__
#include <krb5.h>
#include <winpr/stream.h>
#include <freerdp/api.h>
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD FREERDP_LOCAL wStream* rdpear_enc_Checksum(UINT32 cksumtype,
krb5_checksum* csum);
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD FREERDP_LOCAL wStream* rdpear_enc_EncryptedData(UINT32 encType,
krb5_data* payload);
#endif /* RPDEAR_RDPEAR_ASN1_H__ */

View File

@@ -0,0 +1,243 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2023 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_RDPEAR_COMMON_H
#define FREERDP_CHANNEL_RDPEAR_COMMON_H
#include <winpr/stream.h>
#include <winpr/asn1.h>
#include <winpr/wlog.h>
#include <winpr/sspi.h>
#include <freerdp/api.h>
#include <rdpear-common/ndr.h>
typedef enum
{
RDPEAR_PACKAGE_KERBEROS,
RDPEAR_PACKAGE_NTLM,
RDPEAR_PACKAGE_UNKNOWN
} RdpEarPackageType;
/* RDPEAR 2.2.1.1 */
typedef enum
{
// Start Kerberos remote calls
RemoteCallKerbMinimum = 0x100,
RemoteCallKerbNegotiateVersion = 0x100,
RemoteCallKerbBuildAsReqAuthenticator,
RemoteCallKerbVerifyServiceTicket,
RemoteCallKerbCreateApReqAuthenticator,
RemoteCallKerbDecryptApReply,
RemoteCallKerbUnpackKdcReplyBody,
RemoteCallKerbComputeTgsChecksum,
RemoteCallKerbBuildEncryptedAuthData,
RemoteCallKerbPackApReply,
RemoteCallKerbHashS4UPreauth,
RemoteCallKerbSignS4UPreauthData,
RemoteCallKerbVerifyChecksum,
RemoteCallKerbReserved1,
RemoteCallKerbReserved2,
RemoteCallKerbReserved3,
RemoteCallKerbReserved4,
RemoteCallKerbReserved5,
RemoteCallKerbReserved6,
RemoteCallKerbReserved7,
RemoteCallKerbDecryptPacCredentials,
RemoteCallKerbCreateECDHKeyAgreement,
RemoteCallKerbCreateDHKeyAgreement,
RemoteCallKerbDestroyKeyAgreement,
RemoteCallKerbKeyAgreementGenerateNonce,
RemoteCallKerbFinalizeKeyAgreement,
RemoteCallKerbMaximum = 0x1ff,
// End Kerberos remote calls
// Start NTLM remote calls
RemoteCallNtlmMinimum = 0x200,
RemoteCallNtlmNegotiateVersion = 0x200,
RemoteCallNtlmLm20GetNtlm3ChallengeResponse,
RemoteCallNtlmCalculateNtResponse,
RemoteCallNtlmCalculateUserSessionKeyNt,
RemoteCallNtlmCompareCredentials,
RemoteCallNtlmMaximum = 0x2ff,
// End NTLM remote calls
} RemoteGuardCallId;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL RdpEarPackageType rdpear_packageType_from_name(const WinPrAsn1_OctetString* package);
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* rdpear_encodePayload(BOOL isKerb, wStream* payload);
#define RDPEAR_COMMON_MESSAGE_DECL(V) \
WINPR_ATTR_NODISCARD \
FREERDP_LOCAL BOOL ndr_read_##V(NdrContext* context, wStream* s, const void* hints, V* obj); \
WINPR_ATTR_NODISCARD \
FREERDP_LOCAL BOOL ndr_write_##V(NdrContext* context, wStream* s, const void* hints, \
const V* obj); \
FREERDP_LOCAL void ndr_destroy_##V(NdrContext* context, const void* hints, V* obj); \
FREERDP_LOCAL void ndr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const V* obj); \
WINPR_ATTR_NODISCARD \
FREERDP_LOCAL NdrMessageType ndr_##V##_descr(void)
/** @brief 2.2.1.2.2 KERB_RPC_OCTET_STRING */
typedef struct
{
UINT32 length;
BYTE* value;
} KERB_RPC_OCTET_STRING;
RDPEAR_COMMON_MESSAGE_DECL(KERB_RPC_OCTET_STRING);
/** @brief 2.2.1.2.1 KERB_ASN1_DATA */
typedef struct
{
UINT32 Pdu;
NdrArrayHints Asn1BufferHints;
BYTE* Asn1Buffer;
} KERB_ASN1_DATA;
RDPEAR_COMMON_MESSAGE_DECL(KERB_ASN1_DATA);
/** @brief 2.3.10 RPC_UNICODE_STRING (MS-DTYP) */
typedef struct
{
NdrVaryingArrayHints lenHints;
UINT32 strLength;
WCHAR* Buffer;
} RPC_UNICODE_STRING;
RDPEAR_COMMON_MESSAGE_DECL(RPC_UNICODE_STRING);
/** @brief 2.2.1.2.3 KERB_RPC_INTERNAL_NAME */
typedef struct
{
UINT16 NameType;
NdrArrayHints nameHints;
RPC_UNICODE_STRING* Names;
} KERB_RPC_INTERNAL_NAME;
RDPEAR_COMMON_MESSAGE_DECL(KERB_RPC_INTERNAL_NAME);
/** @brief 2.2.1.2.8 KERB_RPC_ENCRYPTION_KEY */
typedef struct
{
UINT32 reserved1;
UINT32 reserved2;
KERB_RPC_OCTET_STRING reserved3;
} KERB_RPC_ENCRYPTION_KEY;
RDPEAR_COMMON_MESSAGE_DECL(KERB_RPC_ENCRYPTION_KEY);
/** @brief 2.2.2.1.8 BuildEncryptedAuthData */
typedef struct
{
UINT32 KeyUsage;
KERB_RPC_ENCRYPTION_KEY* Key;
KERB_ASN1_DATA* PlainAuthData;
} BuildEncryptedAuthDataReq;
RDPEAR_COMMON_MESSAGE_DECL(BuildEncryptedAuthDataReq);
/** @brief 2.2.2.1.7 ComputeTgsChecksum */
typedef struct
{
KERB_ASN1_DATA* requestBody;
KERB_RPC_ENCRYPTION_KEY* Key;
UINT32 ChecksumType;
} ComputeTgsChecksumReq;
RDPEAR_COMMON_MESSAGE_DECL(ComputeTgsChecksumReq);
/** @brief 2.2.2.1.4 CreateApReqAuthenticator */
typedef struct
{
KERB_RPC_ENCRYPTION_KEY* EncryptionKey;
ULONG SequenceNumber;
KERB_RPC_INTERNAL_NAME* ClientName;
RPC_UNICODE_STRING* ClientRealm;
PLARGE_INTEGER SkewTime;
KERB_RPC_ENCRYPTION_KEY* SubKey; // optional
KERB_ASN1_DATA* AuthData; // optional
KERB_ASN1_DATA* GssChecksum; // optional
ULONG KeyUsage;
} CreateApReqAuthenticatorReq;
RDPEAR_COMMON_MESSAGE_DECL(CreateApReqAuthenticatorReq);
/** @brief 2.2.2.1.4 CreateApReqAuthenticator */
typedef struct
{
LARGE_INTEGER AuthenticatorTime;
KERB_ASN1_DATA Authenticator;
LONG KerbProtocolError;
} CreateApReqAuthenticatorResp;
RDPEAR_COMMON_MESSAGE_DECL(CreateApReqAuthenticatorResp);
/** @brief 2.2.2.1.6 UnpackKdcReplyBody */
typedef struct
{
KERB_ASN1_DATA* EncryptedData;
KERB_RPC_ENCRYPTION_KEY* Key;
KERB_RPC_ENCRYPTION_KEY* StrengthenKey;
ULONG Pdu;
ULONG KeyUsage;
} UnpackKdcReplyBodyReq;
RDPEAR_COMMON_MESSAGE_DECL(UnpackKdcReplyBodyReq);
/** @brief 2.2.2.1.6 UnpackKdcReplyBody */
typedef struct
{
LONG KerbProtocolError;
KERB_ASN1_DATA ReplyBody;
} UnpackKdcReplyBodyResp;
RDPEAR_COMMON_MESSAGE_DECL(UnpackKdcReplyBodyResp);
typedef struct
{
KERB_ASN1_DATA* EncryptedReply;
KERB_RPC_ENCRYPTION_KEY* Key;
} DecryptApReplyReq;
RDPEAR_COMMON_MESSAGE_DECL(DecryptApReplyReq);
typedef struct
{
KERB_ASN1_DATA* Reply;
KERB_ASN1_DATA* ReplyBody;
KERB_RPC_ENCRYPTION_KEY* SessionKey;
} PackApReplyReq;
RDPEAR_COMMON_MESSAGE_DECL(PackApReplyReq);
typedef struct
{
NdrArrayHints PackedReplyHints;
BYTE* PackedReply;
} PackApReplyResp;
RDPEAR_COMMON_MESSAGE_DECL(PackApReplyResp);
#undef RDPEAR_COMMON_MESSAGE_DECL
#endif /* FREERDP_CHANNEL_RDPEAR_COMMON_H */

View File

@@ -0,0 +1,104 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* ASN1 routines for RDPEAR
*
* Copyright 2024 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <rdpear-common/rdpear_asn1.h>
#include <winpr/asn1.h>
wStream* rdpear_enc_Checksum(UINT32 cksumtype, krb5_checksum* csum)
{
/**
* Checksum ::= SEQUENCE {
* cksumtype [0] Int32,
* checksum [1] OCTET STRING
* }
*/
wStream* ret = nullptr;
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
if (!enc)
return nullptr;
if (!WinPrAsn1EncSeqContainer(enc))
goto out;
if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)cksumtype))
goto out;
WinPrAsn1_OctetString octets;
octets.data = (BYTE*)csum->contents;
octets.len = csum->length;
if (!WinPrAsn1EncContextualOctetString(enc, 1, &octets) || !WinPrAsn1EncEndContainer(enc))
goto out;
ret = Stream_New(nullptr, 1024);
if (!ret)
goto out;
if (!WinPrAsn1EncToStream(enc, ret))
{
Stream_Free(ret, TRUE);
ret = nullptr;
goto out;
}
out:
WinPrAsn1Encoder_Free(&enc);
return ret;
}
wStream* rdpear_enc_EncryptedData(UINT32 encType, krb5_data* payload)
{
/**
* EncryptedData ::= SEQUENCE {
* etype [0] Int32 -- EncryptionType --,
* kvno [1] UInt32 OPTIONAL,
* cipher [2] OCTET STRING -- ciphertext
* }
*/
wStream* ret = nullptr;
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
if (!enc)
return nullptr;
if (!WinPrAsn1EncSeqContainer(enc))
goto out;
if (!WinPrAsn1EncContextualInteger(enc, 0, (WinPrAsn1_INTEGER)encType))
goto out;
WinPrAsn1_OctetString octets;
octets.data = (BYTE*)payload->data;
octets.len = payload->length;
if (!WinPrAsn1EncContextualOctetString(enc, 2, &octets) || !WinPrAsn1EncEndContainer(enc))
goto out;
ret = Stream_New(nullptr, 1024);
if (!ret)
goto out;
if (!WinPrAsn1EncToStream(enc, ret))
{
Stream_Free(ret, TRUE);
ret = nullptr;
goto out;
}
out:
WinPrAsn1Encoder_Free(&enc);
return ret;
}

View File

@@ -0,0 +1,572 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2023 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <rdpear-common/rdpear_common.h>
#include <rdpear-common/rdpear_asn1.h>
#include <rdpear-common/ndr.h>
#include <stddef.h>
#include <winpr/print.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("rdpear")
static char kerberosPackageName[] = {
'K', 0, 'e', 0, 'r', 0, 'b', 0, 'e', 0, 'r', 0, 'o', 0, 's', 0
};
static char ntlmPackageName[] = { 'N', 0, 'T', 0, 'L', 0, 'M', 0 };
RdpEarPackageType rdpear_packageType_from_name(const WinPrAsn1_OctetString* package)
{
if (package->len == sizeof(kerberosPackageName) &&
memcmp(package->data, kerberosPackageName, package->len) == 0)
return RDPEAR_PACKAGE_KERBEROS;
if (package->len == sizeof(ntlmPackageName) &&
memcmp(package->data, ntlmPackageName, package->len) == 0)
return RDPEAR_PACKAGE_NTLM;
return RDPEAR_PACKAGE_UNKNOWN;
}
wStream* rdpear_encodePayload(BOOL isKerb, wStream* payload)
{
wStream* ret = nullptr;
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
if (!enc)
return nullptr;
/* TSRemoteGuardInnerPacket ::= SEQUENCE { */
if (!WinPrAsn1EncSeqContainer(enc))
goto out;
/* packageName [1] OCTET STRING */
WinPrAsn1_OctetString packageOctetString;
if (isKerb)
{
packageOctetString.data = (BYTE*)kerberosPackageName;
packageOctetString.len = sizeof(kerberosPackageName);
}
else
{
packageOctetString.data = (BYTE*)ntlmPackageName;
packageOctetString.len = sizeof(ntlmPackageName);
}
if (!WinPrAsn1EncContextualOctetString(enc, 1, &packageOctetString))
goto out;
/* buffer [2] OCTET STRING*/
WinPrAsn1_OctetString payloadOctetString = { Stream_GetPosition(payload),
Stream_Buffer(payload) };
if (!WinPrAsn1EncContextualOctetString(enc, 2, &payloadOctetString))
goto out;
/* } */
if (!WinPrAsn1EncEndContainer(enc))
goto out;
ret = Stream_New(nullptr, 100);
if (!ret)
goto out;
if (!WinPrAsn1EncToStream(enc, ret))
{
Stream_Free(ret, TRUE);
ret = nullptr;
goto out;
}
out:
WinPrAsn1Encoder_Free(&enc);
return ret;
}
#define RDPEAR_SIMPLE_MESSAGE_TYPE(V) \
BOOL ndr_read_##V(NdrContext* context, wStream* s, const void* hints, V* obj) \
{ \
WINPR_UNUSED(hints); \
return ndr_struct_read_fromDescr(context, s, &V##_struct, obj); \
} \
BOOL ndr_write_##V(NdrContext* context, wStream* s, const void* hints, const V* obj) \
{ \
WINPR_UNUSED(hints); \
return ndr_struct_write_fromDescr(context, s, &V##_struct, obj); \
} \
void ndr_destroy_##V(NdrContext* context, const void* hints, V* obj) \
{ \
WINPR_UNUSED(hints); \
ndr_struct_destroy(context, &V##_struct, obj); \
} \
void ndr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const V* obj) \
{ \
ndr_struct_dump_fromDescr(logger, lvl, indentLevel, &V##_struct, obj); \
} \
\
static BOOL ndr_descr_read_##V(NdrContext* context, wStream* s, const void* hints, void* obj) \
{ \
WINPR_UNUSED(hints); \
return ndr_struct_read_fromDescr(context, s, &V##_struct, obj); \
} \
static BOOL ndr_descr_write_##V(NdrContext* context, wStream* s, const void* hints, \
const void* obj) \
{ \
WINPR_UNUSED(hints); \
return ndr_struct_write_fromDescr(context, s, &V##_struct, obj); \
} \
static void ndr_descr_destroy_##V(NdrContext* context, const void* hints, void* obj) \
{ \
WINPR_UNUSED(hints); \
ndr_struct_destroy(context, &V##_struct, obj); \
} \
static void ndr_descr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const void* obj) \
{ \
ndr_struct_dump_fromDescr(logger, lvl, indentLevel, &V##_struct, obj); \
} \
\
static NdrMessageDescr ndr_##V##_descr_s = { \
NDR_ARITY_SIMPLE, sizeof(V), ndr_descr_read_##V, ndr_descr_write_##V, \
ndr_descr_destroy_##V, ndr_descr_dump_##V, \
}; \
\
NdrMessageType ndr_##V##_descr(void) \
{ \
return &ndr_##V##_descr_s; \
}
static const NdrFieldStruct KERB_RPC_OCTET_STRING_fields[] = {
{ "Length", offsetof(KERB_RPC_OCTET_STRING, length), NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
{ "value", offsetof(KERB_RPC_OCTET_STRING, value), NDR_POINTER_NON_NULL, 0,
&ndr_uint8Array_descr_s }
};
static const NdrStructDescr KERB_RPC_OCTET_STRING_struct = { "KERB_RPC_OCTET_STRING", 2,
KERB_RPC_OCTET_STRING_fields };
RDPEAR_SIMPLE_MESSAGE_TYPE(KERB_RPC_OCTET_STRING)
/* ============================= KERB_ASN1_DATA ============================== */
static const NdrFieldStruct KERB_ASN1_DATA_fields[] = {
{ "Pdu", offsetof(KERB_ASN1_DATA, Pdu), NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
{ "Count", offsetof(KERB_ASN1_DATA, Asn1BufferHints.count), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "Asn1Buffer", offsetof(KERB_ASN1_DATA, Asn1Buffer), NDR_POINTER_NON_NULL, 1,
&ndr_uint8Array_descr_s }
};
static const NdrStructDescr KERB_ASN1_DATA_struct = { "KERB_ASN1_DATA",
ARRAYSIZE(KERB_ASN1_DATA_fields),
KERB_ASN1_DATA_fields };
RDPEAR_SIMPLE_MESSAGE_TYPE(KERB_ASN1_DATA)
/* ============================ RPC_UNICODE_STRING ========================== */
BOOL ndr_read_RPC_UNICODE_STRING(NdrContext* context, wStream* s, const void* hints,
RPC_UNICODE_STRING* res)
{
NdrDeferredEntry bufferDesc = { NDR_PTR_NULL, "RPC_UNICODE_STRING.Buffer", &res->lenHints,
(void*)&res->Buffer, ndr_uint16VaryingArray_descr() };
UINT16 Length = 0;
UINT16 MaximumLength = 0;
WINPR_UNUSED(hints);
if (!ndr_read_uint16(context, s, &Length) || !ndr_read_uint16(context, s, &MaximumLength) ||
!ndr_read_refpointer(context, s, &bufferDesc.ptrId) || Length > MaximumLength)
return FALSE;
res->lenHints.length = Length;
res->lenHints.maxLength = MaximumLength;
res->strLength = Length / 2;
return ndr_push_deferreds(context, &bufferDesc, 1);
}
static BOOL ndr_descr_read_RPC_UNICODE_STRING(NdrContext* context, wStream* s, const void* hints,
void* res)
{
return ndr_read_RPC_UNICODE_STRING(context, s, hints, res);
}
BOOL ndr_write_RPC_UNICODE_STRING(NdrContext* context, wStream* s,
WINPR_ATTR_UNUSED const void* hints,
const RPC_UNICODE_STRING* res)
{
WINPR_ASSERT(res);
if (!ndr_write_uint32(context, s, res->lenHints.length))
return FALSE;
if (!ndr_write_uint32(context, s, res->lenHints.maxLength))
return FALSE;
return ndr_write_data(context, s, res->Buffer, res->strLength);
}
static BOOL ndr_write_RPC_UNICODE_STRING_(NdrContext* context, wStream* s, const void* hints,
const void* pvres)
{
const RPC_UNICODE_STRING* res = pvres;
return ndr_write_RPC_UNICODE_STRING(context, s, hints, res);
}
void ndr_dump_RPC_UNICODE_STRING(wLog* logger, UINT32 lvl, size_t indentLevel,
const RPC_UNICODE_STRING* obj)
{
WINPR_UNUSED(indentLevel);
WLog_Print(logger, lvl, "\tLength=%u MaximumLength=%u", obj->lenHints.length,
obj->lenHints.maxLength);
winpr_HexLogDump(logger, lvl, obj->Buffer, obj->lenHints.length);
}
static void ndr_descr_dump_RPC_UNICODE_STRING(wLog* logger, UINT32 lvl, size_t indentLevel,
const void* obj)
{
ndr_dump_RPC_UNICODE_STRING(logger, lvl, indentLevel, obj);
}
void ndr_destroy_RPC_UNICODE_STRING(NdrContext* context, const void* hints, RPC_UNICODE_STRING* obj)
{
WINPR_UNUSED(context);
WINPR_UNUSED(hints);
if (!obj)
return;
free(obj->Buffer);
obj->Buffer = nullptr;
}
static void ndr_descr_destroy_RPC_UNICODE_STRING(NdrContext* context, const void* hints, void* obj)
{
ndr_destroy_RPC_UNICODE_STRING(context, hints, obj);
}
static const NdrMessageDescr RPC_UNICODE_STRING_descr_s = { NDR_ARITY_SIMPLE,
sizeof(RPC_UNICODE_STRING),
ndr_descr_read_RPC_UNICODE_STRING,
ndr_write_RPC_UNICODE_STRING_,
ndr_descr_destroy_RPC_UNICODE_STRING,
ndr_descr_dump_RPC_UNICODE_STRING };
NdrMessageType ndr_RPC_UNICODE_STRING_descr(void)
{
return &RPC_UNICODE_STRING_descr_s;
}
/* ========================= RPC_UNICODE_STRING_Array ======================== */
static BOOL ndr_read_RPC_UNICODE_STRING_Array(NdrContext* context, wStream* s, const void* hints,
void* v)
{
WINPR_ASSERT(context);
WINPR_ASSERT(s);
WINPR_ASSERT(hints);
return ndr_read_uconformant_array(context, s, hints, ndr_RPC_UNICODE_STRING_descr(), v);
}
static BOOL ndr_write_RPC_UNICODE_STRING_Array(NdrContext* context, wStream* s, const void* ghints,
const void* v)
{
WINPR_ASSERT(context);
WINPR_ASSERT(s);
WINPR_ASSERT(ghints);
const NdrArrayHints* hints = (const NdrArrayHints*)ghints;
return ndr_write_uconformant_array(context, s, hints->count, ndr_RPC_UNICODE_STRING_descr(), v);
}
static const NdrMessageDescr RPC_UNICODE_STRING_Array_descr_s = {
NDR_ARITY_ARRAYOF,
sizeof(RPC_UNICODE_STRING),
ndr_read_RPC_UNICODE_STRING_Array,
ndr_write_RPC_UNICODE_STRING_Array,
nullptr,
nullptr
};
static NdrMessageType ndr_RPC_UNICODE_STRING_Array_descr(void)
{
return &RPC_UNICODE_STRING_Array_descr_s;
}
/* ========================== KERB_RPC_INTERNAL_NAME ======================== */
BOOL ndr_read_KERB_RPC_INTERNAL_NAME(NdrContext* context, wStream* s, const void* hints,
KERB_RPC_INTERNAL_NAME* res)
{
WINPR_ASSERT(res);
union
{
RPC_UNICODE_STRING** ppstr;
void* pv;
} cnv;
cnv.ppstr = &res->Names;
NdrDeferredEntry names = { NDR_PTR_NULL, "KERB_RPC_INTERNAL_NAME.Names", &res->nameHints,
cnv.pv, ndr_RPC_UNICODE_STRING_Array_descr() };
UINT16 nameCount = 0;
WINPR_UNUSED(hints);
if (!ndr_read_uint16(context, s, &res->NameType) || !ndr_read_uint16(context, s, &nameCount))
return FALSE;
res->nameHints.count = nameCount;
return ndr_read_refpointer(context, s, &names.ptrId) && ndr_push_deferreds(context, &names, 1);
}
static BOOL ndr_descr_read_KERB_RPC_INTERNAL_NAME(NdrContext* context, wStream* s,
const void* hints, void* res)
{
return ndr_read_KERB_RPC_INTERNAL_NAME(context, s, hints, res);
}
BOOL ndr_write_KERB_RPC_INTERNAL_NAME(NdrContext* context, wStream* s, const void* hints,
const KERB_RPC_INTERNAL_NAME* res)
{
WINPR_UNUSED(context);
WINPR_UNUSED(s);
WINPR_UNUSED(hints);
WINPR_UNUSED(res);
WLog_ERR(TAG, "TODO: implement this");
return FALSE;
}
void ndr_dump_KERB_RPC_INTERNAL_NAME(wLog* logger, UINT32 lvl, size_t indentLevel,
const KERB_RPC_INTERNAL_NAME* obj)
{
WINPR_UNUSED(indentLevel);
WINPR_UNUSED(obj);
WLog_Print(logger, lvl, "TODO: implement this");
}
static void ndr_descr_dump_KERB_RPC_INTERNAL_NAME(wLog* logger, UINT32 lvl, size_t indentLevel,
const void* obj)
{
ndr_dump_KERB_RPC_INTERNAL_NAME(logger, lvl, indentLevel, obj);
}
void ndr_destroy_KERB_RPC_INTERNAL_NAME(NdrContext* context, const void* hints,
KERB_RPC_INTERNAL_NAME* obj)
{
WINPR_UNUSED(hints);
if (!obj)
return;
for (UINT32 i = 0; i < obj->nameHints.count; i++)
ndr_destroy_RPC_UNICODE_STRING(context, nullptr, &obj->Names[i]);
free(obj->Names);
obj->Names = nullptr;
}
static void ndr_descr_destroy_KERB_RPC_INTERNAL_NAME(NdrContext* context, const void* hints,
void* obj)
{
ndr_destroy_KERB_RPC_INTERNAL_NAME(context, hints, obj);
}
static NdrMessageDescr KERB_RPC_INTERNAL_NAME_descr_s = { NDR_ARITY_SIMPLE,
sizeof(KERB_RPC_INTERNAL_NAME),
ndr_descr_read_KERB_RPC_INTERNAL_NAME,
nullptr,
ndr_descr_destroy_KERB_RPC_INTERNAL_NAME,
ndr_descr_dump_KERB_RPC_INTERNAL_NAME };
NdrMessageType ndr_KERB_RPC_INTERNAL_NAME_descr(void)
{
return &KERB_RPC_INTERNAL_NAME_descr_s;
}
/* ========================== KERB_RPC_ENCRYPTION_KEY ======================== */
static const NdrFieldStruct KERB_RPC_ENCRYPTION_KEY_fields[] = {
{ "reserved1", offsetof(KERB_RPC_ENCRYPTION_KEY, reserved1), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "reserved2", offsetof(KERB_RPC_ENCRYPTION_KEY, reserved2), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "reserved3", offsetof(KERB_RPC_ENCRYPTION_KEY, reserved3), NDR_NOT_POINTER, -1,
&ndr_KERB_RPC_OCTET_STRING_descr_s }
};
static const NdrStructDescr KERB_RPC_ENCRYPTION_KEY_struct = {
"KERB_RPC_ENCRYPTION_KEY", ARRAYSIZE(KERB_RPC_ENCRYPTION_KEY_fields),
KERB_RPC_ENCRYPTION_KEY_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(KERB_RPC_ENCRYPTION_KEY)
/* ========================== BuildEncryptedAuthDataReq ======================== */
static const NdrFieldStruct BuildEncryptedAuthDataReq_fields[] = {
{ "KeyUsage", offsetof(BuildEncryptedAuthDataReq, KeyUsage), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "key", offsetof(BuildEncryptedAuthDataReq, Key), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
{ "plainAuthData", offsetof(BuildEncryptedAuthDataReq, PlainAuthData), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s }
};
static const NdrStructDescr BuildEncryptedAuthDataReq_struct = {
"BuildEncryptedAuthDataReq", ARRAYSIZE(BuildEncryptedAuthDataReq_fields),
BuildEncryptedAuthDataReq_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(BuildEncryptedAuthDataReq)
/* ========================== ComputeTgsChecksumReq ======================== */
static const NdrFieldStruct ComputeTgsChecksumReq_fields[] = {
{ "requestBody", offsetof(ComputeTgsChecksumReq, requestBody), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "key", offsetof(ComputeTgsChecksumReq, Key), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
{ "ChecksumType", offsetof(ComputeTgsChecksumReq, ChecksumType), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s }
};
static const NdrStructDescr ComputeTgsChecksumReq_struct = {
"ComputeTgsChecksumReq", ARRAYSIZE(ComputeTgsChecksumReq_fields), ComputeTgsChecksumReq_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(ComputeTgsChecksumReq)
/* ========================== CreateApReqAuthenticatorReq ======================== */
static const NdrFieldStruct CreateApReqAuthenticatorReq_fields[] = {
{ "EncryptionKey", offsetof(CreateApReqAuthenticatorReq, EncryptionKey), NDR_POINTER_NON_NULL,
-1, &ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
{ "SequenceNumber", offsetof(CreateApReqAuthenticatorReq, SequenceNumber), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "ClientName", offsetof(CreateApReqAuthenticatorReq, ClientName), NDR_POINTER_NON_NULL, -1,
&KERB_RPC_INTERNAL_NAME_descr_s },
{ "ClientRealm", offsetof(CreateApReqAuthenticatorReq, ClientRealm), NDR_POINTER_NON_NULL, -1,
&RPC_UNICODE_STRING_descr_s },
{ "SkewTime", offsetof(CreateApReqAuthenticatorReq, SkewTime), NDR_POINTER_NON_NULL, -1,
&ndr_uint64_descr_s },
{ "SubKey", offsetof(CreateApReqAuthenticatorReq, SubKey), NDR_POINTER, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
{ "AuthData", offsetof(CreateApReqAuthenticatorReq, AuthData), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "GssChecksum", offsetof(CreateApReqAuthenticatorReq, GssChecksum), NDR_POINTER, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "KeyUsage", offsetof(CreateApReqAuthenticatorReq, KeyUsage), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
};
static const NdrStructDescr CreateApReqAuthenticatorReq_struct = {
"CreateApReqAuthenticatorReq", ARRAYSIZE(CreateApReqAuthenticatorReq_fields),
CreateApReqAuthenticatorReq_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(CreateApReqAuthenticatorReq)
/* ========================== CreateApReqAuthenticatorResp ======================== */
static const NdrFieldStruct CreateApReqAuthenticatorResp_fields[] = {
{ "AuthenticatorTime", offsetof(CreateApReqAuthenticatorResp, AuthenticatorTime),
NDR_NOT_POINTER, -1, &ndr_uint64_descr_s },
{ "Authenticator", offsetof(CreateApReqAuthenticatorResp, Authenticator), NDR_NOT_POINTER, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "KerbProtocolError", offsetof(CreateApReqAuthenticatorResp, KerbProtocolError),
NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
};
static const NdrStructDescr CreateApReqAuthenticatorResp_struct = {
"CreateApReqAuthenticatorResp", ARRAYSIZE(CreateApReqAuthenticatorResp_fields),
CreateApReqAuthenticatorResp_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(CreateApReqAuthenticatorResp)
/* ========================== UnpackKdcReplyBodyReq ======================== */
static const NdrFieldStruct UnpackKdcReplyBodyReq_fields[] = {
{ "EncryptedData", offsetof(UnpackKdcReplyBodyReq, EncryptedData), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "Key", offsetof(UnpackKdcReplyBodyReq, Key), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
{ "StrenghtenKey", offsetof(UnpackKdcReplyBodyReq, StrengthenKey), NDR_POINTER, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s },
{ "Pdu", offsetof(UnpackKdcReplyBodyReq, Pdu), NDR_NOT_POINTER, -1, &ndr_uint32_descr_s },
{ "KeyUsage", offsetof(UnpackKdcReplyBodyReq, KeyUsage), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
};
static const NdrStructDescr UnpackKdcReplyBodyReq_struct = {
"UnpackKdcReplyBodyReq", ARRAYSIZE(UnpackKdcReplyBodyReq_fields), UnpackKdcReplyBodyReq_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(UnpackKdcReplyBodyReq)
/* ========================== UnpackKdcReplyBodyResp ======================== */
static const NdrFieldStruct UnpackKdcReplyBodyResp_fields[] = {
{ "KerbProtocolError", offsetof(UnpackKdcReplyBodyResp, KerbProtocolError), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "ReplyBody", offsetof(UnpackKdcReplyBodyResp, ReplyBody), NDR_NOT_POINTER, -1,
&ndr_KERB_ASN1_DATA_descr_s }
};
static const NdrStructDescr UnpackKdcReplyBodyResp_struct = {
"UnpackKdcReplyBodyResp", ARRAYSIZE(UnpackKdcReplyBodyResp_fields),
UnpackKdcReplyBodyResp_fields
};
RDPEAR_SIMPLE_MESSAGE_TYPE(UnpackKdcReplyBodyResp)
/* ========================== DecryptApReplyReq ======================== */
static const NdrFieldStruct DecryptApReplyReq_fields[] = {
{ "EncryptedReply", offsetof(DecryptApReplyReq, EncryptedReply), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "Key", offsetof(DecryptApReplyReq, Key), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s }
};
static const NdrStructDescr DecryptApReplyReq_struct = { "DecryptApReplyReq",
ARRAYSIZE(DecryptApReplyReq_fields),
DecryptApReplyReq_fields };
RDPEAR_SIMPLE_MESSAGE_TYPE(DecryptApReplyReq)
/* ========================== PackApReplyReq ======================== */
static const NdrFieldStruct PackApReplyReq_fields[] = {
{ "Reply", offsetof(PackApReplyReq, Reply), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "ReplyBody", offsetof(PackApReplyReq, ReplyBody), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_ASN1_DATA_descr_s },
{ "SessionKey", offsetof(PackApReplyReq, SessionKey), NDR_POINTER_NON_NULL, -1,
&ndr_KERB_RPC_ENCRYPTION_KEY_descr_s }
};
static const NdrStructDescr PackApReplyReq_struct = { "PackApReplyReq",
ARRAYSIZE(PackApReplyReq_fields),
PackApReplyReq_fields };
RDPEAR_SIMPLE_MESSAGE_TYPE(PackApReplyReq)
/* ========================== PackApReplyResp ======================== */
static const NdrFieldStruct PackApReplyResp_fields[] = {
{ "PackedReplySize", offsetof(PackApReplyResp, PackedReplyHints), NDR_NOT_POINTER, -1,
&ndr_uint32_descr_s },
{ "PackedReply", offsetof(PackApReplyResp, PackedReply), NDR_POINTER_NON_NULL, 0,
&ndr_uint8Array_descr_s },
};
static const NdrStructDescr PackApReplyResp_struct = { "PackApReplyResp",
ARRAYSIZE(PackApReplyResp_fields),
PackApReplyResp_fields };
RDPEAR_SIMPLE_MESSAGE_TYPE(PackApReplyResp)

View File

@@ -0,0 +1,30 @@
set(MODULE_NAME "TestRdpear")
set(MODULE_PREFIX "TEST_RDPEAR")
set(TEST_RDPEAR_DRIVER TestRdpear.c)
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(TEST_RDPEAR_TESTS TestNdr.c)
if(BUILD_TESTING_INTERNAL)
list(APPEND TEST_RDPEAR_TESTS TestNdrEar.c)
endif()
create_test_sourcelist(TEST_RDPEAR_SRCS TestRdpear.c ${TEST_RDPEAR_TESTS})
add_executable(${MODULE_NAME} ${TEST_RDPEAR_SRCS})
add_compile_definitions(TESTING_OUTPUT_DIRECTORY="${PROJECT_BINARY_DIR}")
add_compile_definitions(TESTING_SRC_DIRECTORY="${PROJECT_SOURCE_DIR}")
target_link_libraries(${MODULE_NAME} freerdp winpr freerdp-client rdpear-common)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Rdpear/Test")

View File

@@ -0,0 +1,40 @@
#include <rdpear-common/ndr.h>
int TestNdr(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
int retCode = -2;
NdrContext* context = ndr_context_new(FALSE, 1);
if (!context)
return -1;
BYTE payload[] = {
// == conformant array ==
0x02, 0x00, 0x00, 0x00, // (nitems)
0x30, 0x00, // content
0x00, 0x00 // (padding)
};
wStream staticS;
wStream* s = Stream_StaticInit(&staticS, payload, sizeof(payload));
BYTE* target = nullptr;
NdrArrayHints hints = { 2 };
NdrDeferredEntry e = { 0x020028, "arrayContent", &hints, (void*)&target,
ndr_uint8Array_descr() };
if (!ndr_push_deferreds(context, &e, 1))
goto out;
if (!ndr_treat_deferred_read(context, s))
goto out;
NdrMessageType descr = ndr_uint8Array_descr();
descr->destroyFn(context, &hints, target);
free(target);
retCode = 0;
out:
ndr_context_destroy(&context);
return retCode;
}

View File

@@ -0,0 +1,417 @@
#include <winpr/print.h>
#include <rdpear-common/ndr.h>
#include <rdpear-common/rdpear_common.h>
#ifndef MAX
#define MAX(a, b) ((a) > (b)) ? (a) : (b)
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b)) ? (a) : (b)
#endif
static BYTE nextValue(BYTE old, INT32 offset, char symbol, char startSymbol)
{
const INT32 uold = 16 * old;
const INT32 diff = symbol - startSymbol;
const INT32 res = uold + diff + offset;
return (BYTE)MIN(MAX(0, res), UINT8_MAX);
}
static BYTE* parseHexBlock(const char* str, size_t* plen)
{
WINPR_ASSERT(str);
WINPR_ASSERT(plen);
BYTE* ret = malloc(strlen(str) / 2);
BYTE* dest = ret;
const char* ptr = str;
BYTE tmp = 0;
size_t nchars = 0;
size_t len = 0;
for (; *ptr; ptr++)
{
switch (*ptr)
{
case ' ':
case '\n':
case '\t':
if (nchars)
{
WLog_ERR("", "error parsing hex block, unpaired char");
free(ret);
return nullptr;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
tmp = nextValue(tmp, 0, *ptr, '0');
nchars++;
if (nchars == 2)
{
*dest = tmp;
dest++;
len++;
tmp = 0;
nchars = 0;
}
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
tmp = nextValue(tmp, 10, *ptr, 'a');
nchars++;
if (nchars == 2)
{
*dest = tmp;
dest++;
len++;
tmp = 0;
nchars = 0;
}
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
tmp = nextValue(tmp, 10, *ptr, 'A');
nchars++;
if (nchars == 2)
{
*dest = tmp;
dest++;
len++;
tmp = 0;
nchars = 0;
}
break;
default:
WLog_ERR("", "invalid char in hex block");
free(ret);
return nullptr;
}
}
*plen = len;
return ret;
}
static int TestNdrEarWrite(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
int rc = -1;
BYTE buffer[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
KERB_ASN1_DATA asn1 = { 7, { 16 }, buffer };
wStream* s = Stream_New(nullptr, 100);
if (!s)
return -1;
NdrContext* context = ndr_context_new(FALSE, 1);
if (!context)
goto fail;
if (!ndr_write_KERB_ASN1_DATA(context, s, nullptr, &asn1))
goto fail;
if (!ndr_treat_deferred_write(context, s))
goto fail;
// winpr_HexDump("", WLOG_DEBUG, Stream_Buffer(s), Stream_GetPosition(s));
rc = 0;
fail:
ndr_context_destroy(&context);
Stream_Free(s, TRUE);
return rc;
}
static BOOL run_payload(NdrContext* context, const BYTE* payload4, size_t sizeofPayload4)
{
WINPR_ASSERT(context);
if (!payload4)
return FALSE;
CreateApReqAuthenticatorReq createApReqAuthenticatorReq = WINPR_C_ARRAY_INIT;
wStream staticS = WINPR_C_ARRAY_INIT;
wStream* s = Stream_StaticInit(&staticS, payload4, sizeofPayload4);
if (!ndr_skip_bytes(context, s, 4)) /* skip union id */
return FALSE;
if (!ndr_read_CreateApReqAuthenticatorReq(context, s, nullptr, &createApReqAuthenticatorReq))
return FALSE;
if (!ndr_treat_deferred_read(context, s))
return FALSE;
if (createApReqAuthenticatorReq.KeyUsage != 7)
return FALSE;
if (!createApReqAuthenticatorReq.EncryptionKey)
return FALSE;
if (createApReqAuthenticatorReq.SubKey)
return FALSE;
if (!createApReqAuthenticatorReq.ClientName)
return FALSE;
if (createApReqAuthenticatorReq.ClientName->nameHints.count != 1)
return FALSE;
if (!createApReqAuthenticatorReq.ClientRealm)
return FALSE;
if (!createApReqAuthenticatorReq.AuthData)
return FALSE;
if (createApReqAuthenticatorReq.AuthData->Asn1BufferHints.count != 2)
return FALSE;
if (!createApReqAuthenticatorReq.SkewTime)
return FALSE;
if (createApReqAuthenticatorReq.SkewTime->QuadPart != 0)
return FALSE;
ndr_destroy_CreateApReqAuthenticatorReq(context, nullptr, &createApReqAuthenticatorReq);
ndr_context_reset(context);
return TRUE;
}
static int TestNdrEarRead(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
int retCode = -1;
/* ====================================================================== */
NdrContext* context = ndr_context_new(FALSE, 1);
if (!context)
return -1;
{
retCode = -2;
const BYTE payload[] = {
0x00, 0x00, 0x00, 0x00, // (PduType)
0x02, 0x00, 0x00, 0x00, // (Length)
0x28, 0x00, 0x02, 0x00, // (Asn1Buffer)
// == conformant array ==
0x02, 0x00, 0x00, 0x00, // (nitems)
0x30, 0x00, // content
0x00, 0x00 // (padding)
};
wStream staticS = WINPR_C_ARRAY_INIT;
wStream* s = Stream_StaticInit(&staticS, payload, sizeof(payload));
KERB_ASN1_DATA asn1 = WINPR_C_ARRAY_INIT;
if (!ndr_read_KERB_ASN1_DATA(context, s, nullptr, &asn1) ||
!ndr_treat_deferred_read(context, s) || asn1.Asn1BufferHints.count != 2 ||
*asn1.Asn1Buffer != 0x30)
goto out;
ndr_destroy_KERB_ASN1_DATA(context, nullptr, &asn1);
ndr_context_reset(context);
/* ====================================================================== */
}
{
retCode = -3;
const BYTE payload2[] = {
// ------------ a RPC_UNICODE_STRING: Administrateur -------------------------
0x1c, 0x00, // (Length)
0x1e, 0x00, // (MaximumLength)
0x1c, 0x00, 0x02, 0x00, // (Buffer ptr)
// == conformant array ==
0x0f, 0x00, 0x00, 0x00, // (maximum count)
0x00, 0x00, 0x00, 0x00, // (offset)
0x0e, 0x00, 0x00, 0x00, // (length)
0x48, 0x00, 0x41, 0x00, 0x52, 0x00, 0x44, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x49, 0x00,
0x4e, 0x00, 0x47, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4d, 0x00,
0x00, 0x00,
0x00, 0x00
};
wStream staticS = WINPR_C_ARRAY_INIT;
wStream* s = Stream_StaticInit(&staticS, payload2, sizeof(payload2));
RPC_UNICODE_STRING unicode = WINPR_C_ARRAY_INIT;
if (!ndr_read_RPC_UNICODE_STRING(context, s, nullptr, &unicode) ||
!ndr_treat_deferred_read(context, s))
goto out;
ndr_destroy_RPC_UNICODE_STRING(context, nullptr, &unicode);
ndr_context_reset(context);
}
{
retCode = -4;
/* ====================================================================== */
const BYTE payload3[] = {
// ------------ an KERB_RPC_INTERNAL_NAME: HARDENING3.COM -------------------------
0x01, 0x00, // (NameType)
0x01, 0x00, // (NameCount)
0x10, 0x00, 0x02, 0x00, // (Names)
// == conformant array ==
0x01, 0x00, 0x00, 0x00, // (nitems)
// = RPC_UNICODE_STRING =
0x1c, 0x00, // (Length)
0x1e, 0x00, // (MaximumLength)
0x14, 0x00, 0x02, 0x00, /// (Buffer ptr)
// == Uni-dimensional Conformant-varying Array ==
0x0f, 0x00, 0x00, 0x00, // (maximum count)
0x00, 0x00, 0x00, 0x00, // (offset)
0x0e, 0x00, 0x00, 0x00, // (length)
0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00,
0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x75, 0x00, 0x72, 0x00,
0x00, 0x00,
0x00, 0x00
};
KERB_RPC_INTERNAL_NAME intName = WINPR_C_ARRAY_INIT;
wStream staticS = WINPR_C_ARRAY_INIT;
wStream* s = Stream_StaticInit(&staticS, payload3, sizeof(payload3));
if (!ndr_read_KERB_RPC_INTERNAL_NAME(context, s, nullptr, &intName) ||
!ndr_treat_deferred_read(context, s))
goto out;
ndr_destroy_KERB_RPC_INTERNAL_NAME(context, nullptr, &intName);
ndr_context_reset(context);
}
/* ====================================================================== */
{
retCode = -5;
const BYTE payload4[] = {
0x03, 0x01, 0x03, 0x01, // unionId / unionId
0x04, 0x00, 0x02, 0x00, // (EncryptionKey ptr)
0xf8, 0xca, 0x95, 0x11, // (SequenceNumber)
0x0c, 0x00, 0x02, 0x00, // (ClientName ptr)
0x18, 0x00, 0x02, 0x00, // (ClientRealm ptr)
0x20, 0x00, 0x02, 0x00, // (SkewTime ptr)
0x00, 0x00, 0x00, 0x00, // (SubKey ptr)
0x24, 0x00, 0x02, 0x00, // (AuthData ptr)
0x2c, 0x00, 0x02, 0x00, // (GssChecksum ptr)
0x07, 0x00, 0x00, 0x00, // (KeyUsage)
// === EncryptionKey ===
0x40, 0xe9, 0x12, 0xdf, // reserved1
0x12, 0x00, 0x00, 0x00, // reserved2
// KERB_RPC_OCTET_STRING
0x4c, 0x00, 0x00, 0x00, // (length)
0x08, 0x00, 0x02, 0x00, // (value ptr)
// == conformant array ==
0x4c, 0x00, 0x00, 0x00, // (length)
0xc4, 0x41, 0xee, 0x34, 0x82, 0x2b, 0x29, 0x61, 0xe2, 0x96, 0xb5, 0x75, 0x61, 0x2d,
0xbf, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x89, 0x08, 0x60, 0x2e, 0x30, 0x3e, 0xfe, 0x56, 0x11, 0xf0,
0x31, 0xf2, 0xd6, 0x2e, 0x3d, 0x33, 0xfe, 0xce, 0x56, 0x12, 0xbf, 0xb2, 0xe5, 0x86,
0x29, 0x8d, 0x29, 0x74, 0x1f, 0x8a, 0xf9, 0xb9, 0x8c, 0xd4, 0x86, 0x3a, 0x21, 0x92,
0xb2, 0x07, 0x95, 0x4b, 0xea, 0xee,
//=== ClientName - KERB_RPC_INTERNAL_NAME ===
0x01, 0x00, // (NameType)
0x01, 0x00, // (NameCount)
0x10, 0x00, 0x02, 0x00, // (Names)
0x01, 0x00, 0x00, 0x00, // (nitems)
// = RPC_UNICODE_STRING =
0x1c, 0x00, // (Length)
0x1e, 0x00, // (MaximumLength)
0x14, 0x00, 0x02, 0x00, //(Buffer ptr)
// == Uni-dimensional Conformant-varying Array ==
0x0f, 0x00, 0x00, 0x00, // (maximum count)
0x00, 0x00, 0x00, 0x00, // (offset)
0x0e, 0x00, 0x00, 0x00, // (length)
0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00,
0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x75, 0x00, 0x72, 0x00,
// === ClientRealm - RPC_UNICODE_STRING ===
0x1c, 0x00, // (Length)
0x1e, 0x00, // (MaximumLength)
0x1c, 0x00, 0x02, 0x00, // (Buffer ptr)
// == Uni-dimensional conformant varying array ==
0x0f, 0x00, 0x00, 0x00, // (maximum count)
0x00, 0x00, 0x00, 0x00, // (offset)
0x0e, 0x00, 0x00, 0x00, // (length)
0x48, 0x00, 0x41, 0x00, 0x52, 0x00, 0x44, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x49, 0x00,
0x4e, 0x00, 0x47, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4d, 0x00,
0x00, 0x00, 0x00, 0x00, // padding
// == SkewTime ==
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// === AuthData - KERB_ASN1_DATA ==
0x00, 0x00, 0x00, 0x00, // (PduType)
0x02, 0x00, 0x00, 0x00, // (Length)
0x28, 0x00, 0x02, 0x00, // (Asn1Buffer)
// == conformant array ==
0x02, 0x00, 0x00, 0x00, // (nitems)
0x30, 0x00, 0x00, 0x00, // (padding)
// === GssChecksum - KERB_ASN1_DATA ===
0x08, 0x00, 0x00, 0x00, // (PduType)
0x1b, 0x00, 0x00, 0x00, // (Length)
0x30, 0x00, 0x02, 0x00, // (Asn1Buffer)
// == conformant array ==
0x1b, 0x00, 0x00, 0x00, // (length)
0x30, 0x19, 0xa0, 0x03, 0x02, 0x01, 0x07, 0xa1, 0x12, 0x04, 0x10, 0xb9, 0x4f, 0xcd,
0xae, 0xd9, 0xa8, 0xff, 0x49, 0x69, 0x5a, 0xd1, 0x1d, 0x38, 0x49, 0xb6, 0x92, 0x00
};
if (!run_payload(context, payload4, sizeof(payload4)))
goto out;
}
{
retCode = -6;
size_t sizeofPayload4 = 0;
BYTE* payload4 = parseHexBlock("03 01 03 01 \
04 00 02 00 38 9e ef 6b 0c 00 02 00 18 00 02 00 \
20 00 02 00 00 00 00 00 24 00 02 00 2c 00 02 00 \
07 00 00 00 13 8a a5 a8 12 00 00 00 20 00 00 00 \
08 00 02 00 20 00 00 00 c9 03 42 a8 17 8f d9 c4 \
9b d2 c4 6e 73 64 98 7b 90 f5 9a 28 77 8e ca de \
29 2e a3 8d 8a 56 36 d5 01 00 01 00 10 00 02 00 \
01 00 00 00 1c 00 1e 00 14 00 02 00 0f 00 00 00 \
00 00 00 00 0e 00 00 00 41 00 64 00 6d 00 69 00 \
6e 00 69 00 73 00 74 00 72 00 61 00 74 00 65 00 \
75 00 72 00 1c 00 1e 00 1c 00 02 00 0f 00 00 00 \
00 00 00 00 0e 00 00 00 48 00 41 00 52 00 44 00 \
45 00 4e 00 49 00 4e 00 47 00 33 00 2e 00 43 00 \
4f 00 4d 00 00 00 00 00 00 00 00 00 00 00 00 00 \
02 00 00 00 28 00 02 00 02 00 00 00 30 00 00 00 \
08 00 00 00 1b 00 00 00 30 00 02 00 1b 00 00 00 \
30 19 a0 03 02 01 07 a1 12 04 10 e4 aa ff 2b 93 \
97 4c f2 5c 0b 49 85 72 92 94 54 00",
&sizeofPayload4);
const BOOL rc = run_payload(context, payload4, sizeofPayload4);
free(payload4);
if (!rc)
goto out;
}
/* ============ successful end of test =============== */
retCode = 0;
out:
ndr_context_destroy(&context);
return retCode;
}
int TestNdrEar(int argc, char* argv[])
{
const int rc = TestNdrEarWrite(argc, argv);
if (rc)
return rc;
return TestNdrEarRead(argc, argv);
}