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)
410 size_t length = strlen(str) + 1;
411 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
412 size += ber_write_length(s, length *
sizeof(WCHAR));
414 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
416 return size + length *
sizeof(WCHAR);
419size_t ber_write_contextual_unicode_octet_string(
wStream* s, BYTE tag, LPWSTR str)
422 size_t len = _wcslen(str) *
sizeof(WCHAR);
423 size_t inner_len = ber_sizeof_octet_string(len);
426 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
427 return ret + ber_write_octet_string(s, (
const BYTE*)str, len);
430size_t ber_write_contextual_char_to_unicode_octet_string(
wStream* s, BYTE tag,
const char* str)
433 size_t len = strlen(str);
434 size_t inner_len = ber_sizeof_octet_string(len * 2);
436 WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
438 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
439 ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
440 ret += ber_write_length(s, len *
sizeof(WCHAR));
442 if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
448BOOL ber_read_unicode_octet_string(
wStream* s, LPWSTR* str)
450 LPWSTR ret =
nullptr;
453 if (!ber_read_octet_string_tag(s, &length))
456 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
459 ret = calloc(1, length + 2);
463 memcpy(ret, Stream_ConstPointer(s), length);
465 Stream_Seek(s, length);
470BOOL ber_read_char_from_unicode_octet_string(
wStream* s,
char** str)
476 if (!ber_read_octet_string_tag(s, &length))
479 ptr = Stream_Read_UTF16_String_As_UTF8(s, length /
sizeof(WCHAR),
nullptr);
486BOOL ber_read_octet_string_tag(
wStream* s,
size_t* length)
488 return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
491BOOL ber_read_octet_string(
wStream* s, BYTE** content,
size_t* length)
496 WINPR_ASSERT(content);
497 WINPR_ASSERT(length);
499 if (!ber_read_octet_string_tag(s, length))
501 if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
504 ret = malloc(*length);
508 Stream_Read(s, ret, *length);
513size_t ber_write_octet_string_tag(
wStream* s,
size_t length)
515 if (ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) == 0)
517 if (ber_write_length(s, length) == 0)
519 return 1 + _ber_sizeof_length(length);
522size_t ber_sizeof_octet_string(
size_t length)
524 return 1 + _ber_sizeof_length(length) + length;
527size_t ber_sizeof_contextual_octet_string(
size_t length)
529 size_t ret = ber_sizeof_octet_string(length);
530 return ber_sizeof_contextual_tag(ret) + ret;
541BOOL ber_read_BOOL(
wStream* s, BOOL* value)
547 if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
552 WLog_WARN(TAG,
"short data, got %" PRIuz
", expected %u", length, 1u);
555 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
558 Stream_Read_UINT8(s, v);
570void ber_write_BOOL(
wStream* s, BOOL value)
572 ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
573 ber_write_length(s, 1);
574 Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
577BOOL ber_read_integer(
wStream* s, UINT32* value)
583 if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
585 if (!ber_read_length(s, &length))
587 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
590 if (value ==
nullptr)
593 return Stream_SafeSeek(s, length);
598 Stream_Read_UINT8(s, *value);
600 else if (length == 2)
602 Stream_Read_UINT16_BE(s, *value);
604 else if (length == 3)
607 Stream_Read_UINT8(s,
byte);
608 Stream_Read_UINT16_BE(s, *value);
609 *value += (
byte << 16) & 0xFF0000;
611 else if (length == 4)
613 Stream_Read_UINT32_BE(s, *value);
615 else if (length == 8)
617 WLog_ERR(TAG,
"should implement reading an 8 bytes integer");
622 WLog_ERR(TAG,
"should implement reading an integer with length=%" PRIuz, length);
638size_t ber_write_integer(
wStream* s, UINT32 value)
644 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
646 if (ber_write_length(s, 1) == 0)
649 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
652 else if (value < 0x8000)
654 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
656 if (ber_write_length(s, 2) == 0)
659 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
662 else if (value < 0x800000)
664 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
666 if (ber_write_length(s, 3) == 0)
669 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
670 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
673 else if (value < 0x80000000)
675 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
677 if (ber_write_length(s, 4) == 0)
680 Stream_Write_UINT32_BE(s, value);
686 if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
688 if (ber_write_length(s, 4) == 0)
691 Stream_Write_UINT32_BE(s, value);
696size_t ber_write_contextual_integer(
wStream* s, BYTE tag, UINT32 value)
698 size_t len = ber_sizeof_integer(value);
702 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
704 len += ber_write_contextual_tag(s, tag, len, TRUE);
705 if (ber_write_integer(s, value) == 0)
710size_t ber_sizeof_integer(UINT32 value)
716 else if (value < 0x8000)
720 else if (value < 0x800000)
724 else if (value < 0x80000000)
735size_t ber_sizeof_contextual_integer(UINT32 value)
737 size_t intSize = ber_sizeof_integer(value);
738 return ber_sizeof_contextual_tag(intSize) + intSize;
741BOOL ber_read_integer_length(
wStream* s,
size_t* length)
743 return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);