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)
40 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
43 Stream_Read_UINT8(s,
byte);
49 if (!Stream_CheckAndLogRequiredLength(TAG, s,
byte))
53 Stream_Read_UINT8(s, *length);
55 Stream_Read_UINT16_BE(s, *length);
58 WLog_ERR(TAG,
"ber: unexpected byte 0x%02" PRIx8
", expected [1,2]",
byte);
76size_t ber_write_length(
wStream* s,
size_t length)
82 WINPR_ASSERT(length <= UINT16_MAX);
83 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 3);
84 Stream_Write_UINT8(s, 0x80 ^ 2);
85 Stream_Write_UINT16_BE(s, (UINT16)length);
89 WINPR_ASSERT(length <= UINT8_MAX);
92 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
93 Stream_Write_UINT8(s, 0x80 ^ 1);
94 Stream_Write_UINT8(s, (UINT8)length);
98 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
99 Stream_Write_UINT8(s, (UINT8)length);
103size_t _ber_sizeof_length(
size_t length)
123BOOL ber_read_universal_tag(
wStream* s, BYTE tag, BOOL pc)
126 const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
130 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
133 Stream_Read_UINT8(s,
byte);
137 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
151size_t ber_write_universal_tag(
wStream* s, BYTE tag, BOOL pc)
154 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
165BOOL ber_read_application_tag(
wStream* s, BYTE tag,
size_t* length)
170 WINPR_ASSERT(length);
174 const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
176 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
179 Stream_Read_UINT8(s,
byte);
183 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
187 Stream_Read_UINT8(s,
byte);
191 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, tag);
195 return ber_read_length(s, length);
199 const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
201 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
204 Stream_Read_UINT8(s,
byte);
208 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
212 return ber_read_length(s, length);
225void ber_write_application_tag(
wStream* s, BYTE tag,
size_t length)
231 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
232 Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
233 Stream_Write_UINT8(s, tag);
234 ber_write_length(s, length);
238 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
239 Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
240 ber_write_length(s, length);
244BOOL ber_read_contextual_tag(
wStream* s, BYTE tag,
size_t* length, BOOL pc)
246 const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
250 WINPR_ASSERT(length);
252 if (Stream_GetRemainingLength(s) < 1)
254 WLog_VRB(TAG,
"short data, got %" PRIuz
", expected %u", Stream_GetRemainingLength(s), 1u);
258 Stream_Read_UINT8(s,
byte);
262 WLog_VRB(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
267 return ber_read_length(s, length);
270size_t ber_write_contextual_tag(
wStream* s, BYTE tag,
size_t length, BOOL pc)
273 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
274 Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
275 return 1 + ber_write_length(s, length);
278size_t ber_sizeof_contextual_tag(
size_t length)
280 return 1 + _ber_sizeof_length(length);
283BOOL ber_read_sequence_tag(
wStream* s,
size_t* length)
285 const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
288 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
291 Stream_Read_UINT8(s,
byte);
295 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
299 return ber_read_length(s, length);
308size_t ber_write_sequence_tag(
wStream* s,
size_t length)
310 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
311 return 1 + ber_write_length(s, length);
314size_t ber_sizeof_sequence(
size_t length)
316 return 1 + _ber_sizeof_length(length) + length;
319size_t ber_sizeof_sequence_tag(
size_t length)
321 return 1 + _ber_sizeof_length(length);
324BOOL ber_read_enumerated(
wStream* s, BYTE* enumerated, BYTE count)
328 WINPR_ASSERT(enumerated);
330 if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
335 WLog_WARN(TAG,
"short data, got %" PRIuz
", expected %u", length, 1u);
338 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
341 Stream_Read_UINT8(s, *enumerated);
344 if (*enumerated + 1 > count)
346 WLog_WARN(TAG,
"invalid data, expected %" PRIu8
" < %" PRIu8, *enumerated, count);
353void ber_write_enumerated(
wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
355 ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
356 ber_write_length(s, 1);
357 Stream_Write_UINT8(s, enumerated);
360BOOL ber_read_bit_string(
wStream* s,
size_t* length, BYTE* padding)
362 if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
365 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
368 Stream_Read_UINT8(s, *padding);
379size_t ber_write_octet_string(
wStream* s,
const BYTE* oct_str,
size_t length)
383 WINPR_ASSERT(oct_str || (length == 0));
384 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
385 size += ber_write_length(s, length);
386 Stream_Write(s, oct_str, length);
391size_t ber_write_contextual_octet_string(
wStream* s, BYTE tag,
const BYTE* oct_str,
size_t length)
393 size_t inner = ber_sizeof_octet_string(length);
397 ret = ber_write_contextual_tag(s, tag, inner, TRUE);
401 r = ber_write_octet_string(s, oct_str, length);
407size_t ber_write_char_to_unicode_octet_string(
wStream* s,
const char* str)
411 size_t length = strlen(str) + 1;
412 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
413 size += ber_write_length(s, length *
sizeof(WCHAR));
415 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
417 return size + length *
sizeof(WCHAR);
420size_t ber_write_contextual_unicode_octet_string(
wStream* s, BYTE tag, LPWSTR str)
423 size_t len = _wcslen(str) *
sizeof(WCHAR);
424 size_t inner_len = ber_sizeof_octet_string(len);
427 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
428 return ret + ber_write_octet_string(s, (
const BYTE*)str, len);
431size_t ber_write_contextual_char_to_unicode_octet_string(
wStream* s, BYTE tag,
const char* str)
434 size_t len = strlen(str);
435 size_t inner_len = ber_sizeof_octet_string(len * 2);
437 WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
439 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
440 ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
441 ret += ber_write_length(s, len *
sizeof(WCHAR));
443 if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
449BOOL ber_read_unicode_octet_string(
wStream* s, LPWSTR* str)
454 if (!ber_read_octet_string_tag(s, &length))
457 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
460 ret = calloc(1, length + 2);
464 memcpy(ret, Stream_ConstPointer(s), length);
466 Stream_Seek(s, length);
471BOOL ber_read_char_from_unicode_octet_string(
wStream* s,
char** str)
477 if (!ber_read_octet_string_tag(s, &length))
480 ptr = Stream_Read_UTF16_String_As_UTF8(s, length /
sizeof(WCHAR), NULL);
487BOOL ber_read_octet_string_tag(
wStream* s,
size_t* length)
489 return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
492BOOL ber_read_octet_string(
wStream* s, BYTE** content,
size_t* length)
497 WINPR_ASSERT(content);
498 WINPR_ASSERT(length);
500 if (!ber_read_octet_string_tag(s, length))
502 if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
505 ret = malloc(*length);
509 Stream_Read(s, ret, *length);
514size_t ber_write_octet_string_tag(
wStream* s,
size_t length)
516 ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
517 ber_write_length(s, length);
518 return 1 + _ber_sizeof_length(length);
521size_t ber_sizeof_octet_string(
size_t length)
523 return 1 + _ber_sizeof_length(length) + length;
526size_t ber_sizeof_contextual_octet_string(
size_t length)
528 size_t ret = ber_sizeof_octet_string(length);
529 return ber_sizeof_contextual_tag(ret) + ret;
540BOOL ber_read_BOOL(
wStream* s, BOOL* value)
546 if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
551 WLog_WARN(TAG,
"short data, got %" PRIuz
", expected %u", length, 1u);
554 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
557 Stream_Read_UINT8(s, v);
558 *value = (v ? TRUE : FALSE);
569void ber_write_BOOL(
wStream* s, BOOL value)
571 ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
572 ber_write_length(s, 1);
573 Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
576BOOL ber_read_integer(
wStream* s, UINT32* value)
582 if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
584 if (!ber_read_length(s, &length))
586 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
592 return Stream_SafeSeek(s, length);
597 Stream_Read_UINT8(s, *value);
599 else if (length == 2)
601 Stream_Read_UINT16_BE(s, *value);
603 else if (length == 3)
606 Stream_Read_UINT8(s,
byte);
607 Stream_Read_UINT16_BE(s, *value);
608 *value += (
byte << 16) & 0xFF0000;
610 else if (length == 4)
612 Stream_Read_UINT32_BE(s, *value);
614 else if (length == 8)
616 WLog_ERR(TAG,
"should implement reading an 8 bytes integer");
621 WLog_ERR(TAG,
"should implement reading an integer with length=%" PRIuz, length);
637size_t ber_write_integer(
wStream* s, UINT32 value)
643 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
644 ber_write_length(s, 1);
646 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
649 else if (value < 0x8000)
651 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
652 ber_write_length(s, 2);
654 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
657 else if (value < 0x800000)
659 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
660 ber_write_length(s, 3);
662 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
663 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
666 else if (value < 0x80000000)
668 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
669 ber_write_length(s, 4);
671 Stream_Write_UINT32_BE(s, value);
677 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
678 ber_write_length(s, 4);
680 Stream_Write_UINT32_BE(s, value);
685size_t ber_write_contextual_integer(
wStream* s, BYTE tag, UINT32 value)
687 size_t len = ber_sizeof_integer(value);
691 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
693 len += ber_write_contextual_tag(s, tag, len, TRUE);
694 ber_write_integer(s, value);
698size_t ber_sizeof_integer(UINT32 value)
704 else if (value < 0x8000)
708 else if (value < 0x800000)
712 else if (value < 0x80000000)
723size_t ber_sizeof_contextual_integer(UINT32 value)
725 size_t intSize = ber_sizeof_integer(value);
726 return ber_sizeof_contextual_tag(intSize) + intSize;
729BOOL ber_read_integer_length(
wStream* s,
size_t* length)
731 return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);