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 %" 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);
 
  271size_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);
 
  279size_t ber_sizeof_contextual_tag(
size_t length)
 
  281  return 1 + _ber_sizeof_length(length);
 
  284BOOL 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);
 
  309size_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);
 
  315size_t ber_sizeof_sequence(
size_t length)
 
  317  return 1 + _ber_sizeof_length(length) + length;
 
  320size_t ber_sizeof_sequence_tag(
size_t length)
 
  322  return 1 + _ber_sizeof_length(length);
 
  325BOOL 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);
 
  354void ber_write_enumerated(
wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
 
  356  ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
 
  357  ber_write_length(s, 1);
 
  358  Stream_Write_UINT8(s, enumerated);
 
  361BOOL 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);
 
  380size_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);
 
  392size_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);
 
  408size_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);
 
  421size_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);
 
  432size_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)
 
  450BOOL 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);
 
  472BOOL 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);
 
  488BOOL 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);
 
  493BOOL 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);
 
  515size_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);
 
  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 %" PRIuz, length, 1);
 
  555  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  558  Stream_Read_UINT8(s, v);
 
  559  *value = (v ? TRUE : FALSE);
 
  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))
 
  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    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);
 
  686size_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);
 
  699size_t ber_sizeof_integer(UINT32 value)
 
  705  else if (value < 0x8000)
 
  709  else if (value < 0x800000)
 
  713  else if (value < 0x80000000)
 
  724size_t ber_sizeof_contextual_integer(UINT32 value)
 
  726  size_t intSize = ber_sizeof_integer(value);
 
  727  return ber_sizeof_contextual_tag(intSize) + intSize;
 
  730BOOL 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);