20#include <freerdp/config.h>
23#include <winpr/assert.h>
24#include <winpr/cast.h>
26#include <winpr/string.h>
28#include <freerdp/log.h>
29#include <freerdp/crypto/ber.h>
31#define TAG FREERDP_TAG("crypto")
33BOOL ber_read_length(
wStream* s,
size_t* length)
39 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
42 BYTE
byte = Stream_Get_UINT8(s);
48 if (!Stream_CheckAndLogRequiredLength(TAG, s,
byte))
52 Stream_Read_UINT8(s, *length);
54 Stream_Read_UINT16_BE(s, *length);
57 WLog_ERR(TAG,
"ber: unexpected byte 0x%02" PRIx8
", expected [1,2]",
byte);
75size_t ber_write_length(
wStream* s,
size_t length)
81 WINPR_ASSERT(length <= UINT16_MAX);
82 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 3);
83 Stream_Write_UINT8(s, 0x80 ^ 2);
84 Stream_Write_UINT16_BE(s, (UINT16)length);
88 WINPR_ASSERT(length <= UINT8_MAX);
91 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
92 Stream_Write_UINT8(s, 0x80 ^ 1);
93 Stream_Write_UINT8(s, (UINT8)length);
97 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
98 Stream_Write_UINT8(s, (UINT8)length);
102size_t _ber_sizeof_length(
size_t length)
122BOOL ber_read_universal_tag(
wStream* s, BYTE tag, BOOL pc)
125 const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
129 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
132 Stream_Read_UINT8(s,
byte);
136 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
150size_t ber_write_universal_tag(
wStream* s, BYTE tag, BOOL pc)
153 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
164BOOL ber_read_application_tag(
wStream* s, BYTE tag,
size_t* length)
169 WINPR_ASSERT(length);
173 const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
175 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
178 Stream_Read_UINT8(s,
byte);
182 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
186 Stream_Read_UINT8(s,
byte);
190 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, tag);
194 return ber_read_length(s, length);
198 const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
200 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
203 Stream_Read_UINT8(s,
byte);
207 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
211 return ber_read_length(s, length);
224void ber_write_application_tag(
wStream* s, BYTE tag,
size_t length)
230 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
231 Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
232 Stream_Write_UINT8(s, tag);
233 ber_write_length(s, length);
237 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
238 Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
239 ber_write_length(s, length);
243BOOL ber_read_contextual_tag(
wStream* s, BYTE tag,
size_t* length, BOOL pc)
245 const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
249 WINPR_ASSERT(length);
251 if (Stream_GetRemainingLength(s) < 1)
253 WLog_VRB(TAG,
"short data, got %" PRIuz
", expected %u", Stream_GetRemainingLength(s), 1u);
257 Stream_Read_UINT8(s,
byte);
261 WLog_VRB(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
266 return ber_read_length(s, length);
269size_t ber_write_contextual_tag(
wStream* s, BYTE tag,
size_t length, BOOL pc)
272 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
273 Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
274 return 1 + ber_write_length(s, length);
277size_t ber_sizeof_contextual_tag(
size_t length)
279 return 1 + _ber_sizeof_length(length);
282BOOL ber_read_sequence_tag(
wStream* s,
size_t* length)
284 const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
287 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
290 Stream_Read_UINT8(s,
byte);
294 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
298 return ber_read_length(s, length);
307size_t ber_write_sequence_tag(
wStream* s,
size_t length)
309 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
310 return 1 + ber_write_length(s, length);
313size_t ber_sizeof_sequence(
size_t length)
315 return 1 + _ber_sizeof_length(length) + length;
318size_t ber_sizeof_sequence_tag(
size_t length)
320 return 1 + _ber_sizeof_length(length);
323BOOL ber_read_enumerated(
wStream* s, BYTE* enumerated, BYTE count)
327 WINPR_ASSERT(enumerated);
329 if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
334 WLog_WARN(TAG,
"short data, got %" PRIuz
", expected %u", length, 1u);
337 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
340 Stream_Read_UINT8(s, *enumerated);
343 if (*enumerated + 1 > count)
345 WLog_WARN(TAG,
"invalid data, expected %" PRIu8
" < %" PRIu8, *enumerated, count);
352void ber_write_enumerated(
wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
354 ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
355 ber_write_length(s, 1);
356 Stream_Write_UINT8(s, enumerated);
359BOOL ber_read_bit_string(
wStream* s,
size_t* length, BYTE* padding)
361 if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
364 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
367 Stream_Read_UINT8(s, *padding);
378size_t ber_write_octet_string(
wStream* s,
const BYTE* oct_str,
size_t length)
382 WINPR_ASSERT(oct_str || (length == 0));
383 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
384 size += ber_write_length(s, length);
385 Stream_Write(s, oct_str, length);
390size_t ber_write_contextual_octet_string(
wStream* s, BYTE tag,
const BYTE* oct_str,
size_t length)
392 size_t inner = ber_sizeof_octet_string(length);
396 ret = ber_write_contextual_tag(s, tag, inner, TRUE);
400 r = ber_write_octet_string(s, oct_str, length);
406size_t ber_write_char_to_unicode_octet_string(
wStream* s,
const char* str)
411 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(str,
nullptr, 0);
414 const size_t length = WINPR_ASSERTING_INT_CAST(
size_t, devNameWLen) + 1;
415 const size_t slen = strlen(str);
416 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
417 size += ber_write_length(s, length *
sizeof(WCHAR));
419 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, slen, TRUE) < 0)
421 return size + length *
sizeof(WCHAR);
424size_t ber_write_contextual_unicode_octet_string(
wStream* s, BYTE tag, LPWSTR str)
427 size_t len = _wcslen(str) *
sizeof(WCHAR);
428 size_t inner_len = ber_sizeof_octet_string(len);
431 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
432 return ret + ber_write_octet_string(s, (
const BYTE*)str, len);
435size_t ber_write_contextual_char_to_unicode_octet_string(
wStream* s, BYTE tag,
const char* str)
438 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(str,
nullptr, 0);
441 const size_t len = WINPR_ASSERTING_INT_CAST(
size_t, devNameWLen);
442 const size_t slen = strlen(str);
443 const size_t inner_len = ber_sizeof_octet_string(len *
sizeof(WCHAR));
445 WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
447 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
448 ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
449 ret += ber_write_length(s, len *
sizeof(WCHAR));
451 if (Stream_Write_UTF16_String_From_UTF8(s, len, str, slen, TRUE) < 0)
457BOOL ber_read_unicode_octet_string(
wStream* s, LPWSTR* str)
459 LPWSTR ret =
nullptr;
462 if (!ber_read_octet_string_tag(s, &length))
465 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
468 ret = calloc(1, length + 2);
472 memcpy(ret, Stream_ConstPointer(s), length);
474 Stream_Seek(s, length);
479BOOL ber_read_char_from_unicode_octet_string(
wStream* s,
char** str)
485 if (!ber_read_octet_string_tag(s, &length))
488 ptr = Stream_Read_UTF16_String_As_UTF8(s, length /
sizeof(WCHAR),
nullptr);
495BOOL ber_read_octet_string_tag(
wStream* s,
size_t* length)
497 return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
500BOOL ber_read_octet_string(
wStream* s, BYTE** content,
size_t* length)
505 WINPR_ASSERT(content);
506 WINPR_ASSERT(length);
508 if (!ber_read_octet_string_tag(s, length))
510 if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
513 ret = malloc(*length);
517 Stream_Read(s, ret, *length);
522size_t ber_write_octet_string_tag(
wStream* s,
size_t length)
524 if (ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) == 0)
526 if (ber_write_length(s, length) == 0)
528 return 1 + _ber_sizeof_length(length);
531size_t ber_sizeof_octet_string(
size_t length)
533 return 1 + _ber_sizeof_length(length) + length;
536size_t ber_sizeof_contextual_octet_string(
size_t length)
538 size_t ret = ber_sizeof_octet_string(length);
539 return ber_sizeof_contextual_tag(ret) + ret;
550BOOL ber_read_BOOL(
wStream* s, BOOL* value)
556 if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
561 WLog_WARN(TAG,
"short data, got %" PRIuz
", expected %u", length, 1u);
564 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
567 Stream_Read_UINT8(s, v);
579void ber_write_BOOL(
wStream* s, BOOL value)
581 ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
582 ber_write_length(s, 1);
583 Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
586BOOL ber_read_integer(
wStream* s, UINT32* value)
592 if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
594 if (!ber_read_length(s, &length))
596 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
599 if (value ==
nullptr)
602 return Stream_SafeSeek(s, length);
607 Stream_Read_UINT8(s, *value);
609 else if (length == 2)
611 Stream_Read_UINT16_BE(s, *value);
613 else if (length == 3)
616 Stream_Read_UINT8(s,
byte);
617 Stream_Read_UINT16_BE(s, *value);
618 *value += (
byte << 16) & 0xFF0000;
620 else if (length == 4)
622 Stream_Read_UINT32_BE(s, *value);
624 else if (length == 8)
626 WLog_ERR(TAG,
"should implement reading an 8 bytes integer");
631 WLog_ERR(TAG,
"should implement reading an integer with length=%" PRIuz, length);
647size_t ber_write_integer(
wStream* s, UINT32 value)
653 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
655 if (ber_write_length(s, 1) == 0)
658 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
661 else if (value < 0x8000)
663 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
665 if (ber_write_length(s, 2) == 0)
668 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
671 else if (value < 0x800000)
673 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
675 if (ber_write_length(s, 3) == 0)
678 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
679 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
682 else if (value < 0x80000000)
684 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
686 if (ber_write_length(s, 4) == 0)
689 Stream_Write_UINT32_BE(s, value);
695 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
697 if (ber_write_length(s, 4) == 0)
700 Stream_Write_UINT32_BE(s, value);
705size_t ber_write_contextual_integer(
wStream* s, BYTE tag, UINT32 value)
707 size_t len = ber_sizeof_integer(value);
711 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
713 len += ber_write_contextual_tag(s, tag, len, TRUE);
714 if (ber_write_integer(s, value) == 0)
719size_t ber_sizeof_integer(UINT32 value)
725 else if (value < 0x8000)
729 else if (value < 0x800000)
733 else if (value < 0x80000000)
744size_t ber_sizeof_contextual_integer(UINT32 value)
746 size_t intSize = ber_sizeof_integer(value);
747 return ber_sizeof_contextual_tag(intSize) + intSize;
750BOOL ber_read_integer_length(
wStream* s,
size_t* length)
752 return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);