20 #include <freerdp/config.h>
23 #include <winpr/assert.h>
24 #include <winpr/cast.h>
25 #include <winpr/crt.h>
26 #include <winpr/string.h>
28 #include <freerdp/log.h>
29 #include <freerdp/crypto/ber.h>
31 #define TAG FREERDP_TAG("crypto")
33 BOOL 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);
76 size_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);
103 size_t _ber_sizeof_length(
size_t length)
123 BOOL 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);
151 size_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));
165 BOOL 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);
225 void 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);
244 BOOL 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 %" PRIuz, Stream_GetRemainingLength(s),
259 Stream_Read_UINT8(s,
byte);
263 WLog_VRB(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
268 return ber_read_length(s, length);
271 size_t ber_write_contextual_tag(
wStream* s, BYTE tag,
size_t length, BOOL pc)
274 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
275 Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
276 return 1 + ber_write_length(s, length);
279 size_t ber_sizeof_contextual_tag(
size_t length)
281 return 1 + _ber_sizeof_length(length);
284 BOOL ber_read_sequence_tag(
wStream* s,
size_t* length)
286 const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
289 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
292 Stream_Read_UINT8(s,
byte);
296 WLog_WARN(TAG,
"invalid tag, got 0x%02" PRIx8
", expected 0x%02" PRIx8,
byte, expect);
300 return ber_read_length(s, length);
309 size_t ber_write_sequence_tag(
wStream* s,
size_t length)
311 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
312 return 1 + ber_write_length(s, length);
315 size_t ber_sizeof_sequence(
size_t length)
317 return 1 + _ber_sizeof_length(length) + length;
320 size_t ber_sizeof_sequence_tag(
size_t length)
322 return 1 + _ber_sizeof_length(length);
325 BOOL ber_read_enumerated(
wStream* s, BYTE* enumerated, BYTE count)
329 WINPR_ASSERT(enumerated);
331 if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
336 WLog_WARN(TAG,
"short data, got %" PRIuz
", expected %" PRIuz, length, 1);
339 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
342 Stream_Read_UINT8(s, *enumerated);
345 if (*enumerated + 1 > count)
347 WLog_WARN(TAG,
"invalid data, expected %" PRIu8
" < %" PRIu8, *enumerated, count);
354 void ber_write_enumerated(
wStream* s, BYTE enumerated, BYTE count)
356 ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
357 ber_write_length(s, 1);
358 Stream_Write_UINT8(s, enumerated);
361 BOOL ber_read_bit_string(
wStream* s,
size_t* length, BYTE* padding)
363 if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
366 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
369 Stream_Read_UINT8(s, *padding);
380 size_t ber_write_octet_string(
wStream* s,
const BYTE* oct_str,
size_t length)
384 WINPR_ASSERT(oct_str || (length == 0));
385 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
386 size += ber_write_length(s, length);
387 Stream_Write(s, oct_str, length);
392 size_t ber_write_contextual_octet_string(
wStream* s, BYTE tag,
const BYTE* oct_str,
size_t length)
394 size_t inner = ber_sizeof_octet_string(length);
398 ret = ber_write_contextual_tag(s, tag, inner, TRUE);
402 r = ber_write_octet_string(s, oct_str, length);
408 size_t ber_write_char_to_unicode_octet_string(
wStream* s,
const char* str)
412 size_t length = strlen(str) + 1;
413 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
414 size += ber_write_length(s, length *
sizeof(WCHAR));
416 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
418 return size + length *
sizeof(WCHAR);
421 size_t ber_write_contextual_unicode_octet_string(
wStream* s, BYTE tag, LPWSTR str)
424 size_t len = _wcslen(str) *
sizeof(WCHAR);
425 size_t inner_len = ber_sizeof_octet_string(len);
428 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
429 return ret + ber_write_octet_string(s, (
const BYTE*)str, len);
432 size_t ber_write_contextual_char_to_unicode_octet_string(
wStream* s, BYTE tag,
const char* str)
435 size_t len = strlen(str);
436 size_t inner_len = ber_sizeof_octet_string(len * 2);
438 WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
440 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
441 ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
442 ret += ber_write_length(s, len *
sizeof(WCHAR));
444 if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
450 BOOL ber_read_unicode_octet_string(
wStream* s, LPWSTR* str)
455 if (!ber_read_octet_string_tag(s, &length))
458 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
461 ret = calloc(1, length + 2);
465 memcpy(ret, Stream_ConstPointer(s), length);
467 Stream_Seek(s, length);
472 BOOL ber_read_char_from_unicode_octet_string(
wStream* s,
char** str)
478 if (!ber_read_octet_string_tag(s, &length))
481 ptr = Stream_Read_UTF16_String_As_UTF8(s, length /
sizeof(WCHAR), NULL);
488 BOOL ber_read_octet_string_tag(
wStream* s,
size_t* length)
490 return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
493 BOOL ber_read_octet_string(
wStream* s, BYTE** content,
size_t* length)
498 WINPR_ASSERT(content);
499 WINPR_ASSERT(length);
501 if (!ber_read_octet_string_tag(s, length))
503 if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
506 ret = malloc(*length);
510 Stream_Read(s, ret, *length);
515 size_t ber_write_octet_string_tag(
wStream* s,
size_t length)
517 ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
518 ber_write_length(s, length);
519 return 1 + _ber_sizeof_length(length);
522 size_t ber_sizeof_octet_string(
size_t length)
524 return 1 + _ber_sizeof_length(length) + length;
527 size_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;
541 BOOL 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 %" PRIuz, length, 1);
555 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
558 Stream_Read_UINT8(s, v);
559 *value = (v ? TRUE : FALSE);
570 void 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);
577 BOOL 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))
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);
638 size_t ber_write_integer(
wStream* s, UINT32 value)
644 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
645 ber_write_length(s, 1);
647 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
650 else if (value < 0x8000)
652 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
653 ber_write_length(s, 2);
655 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
658 else if (value < 0x800000)
660 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
661 ber_write_length(s, 3);
663 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
664 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
667 else if (value < 0x80000000)
669 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
670 ber_write_length(s, 4);
672 Stream_Write_UINT32_BE(s, value);
678 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
679 ber_write_length(s, 4);
681 Stream_Write_UINT32_BE(s, value);
686 size_t ber_write_contextual_integer(
wStream* s, BYTE tag, UINT32 value)
688 size_t len = ber_sizeof_integer(value);
692 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
694 len += ber_write_contextual_tag(s, tag, len, TRUE);
695 ber_write_integer(s, value);
699 size_t ber_sizeof_integer(UINT32 value)
705 else if (value < 0x8000)
709 else if (value < 0x800000)
713 else if (value < 0x80000000)
724 size_t ber_sizeof_contextual_integer(UINT32 value)
726 size_t intSize = ber_sizeof_integer(value);
727 return ber_sizeof_contextual_tag(intSize) + intSize;
730 BOOL ber_read_integer_length(
wStream* s,
size_t* length)
732 return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);