20#include <winpr/assert.h> 
   21#include <winpr/cast.h> 
   22#include <winpr/print.h> 
   24#include <freerdp/config.h> 
   25#include <freerdp/crypto/per.h> 
   27#include <freerdp/log.h> 
   28#define TAG FREERDP_TAG("crypto.per") 
   39BOOL per_read_length(
wStream* s, UINT16* length)
 
   44  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
   47  Stream_Read_UINT8(s, 
byte);
 
   51    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
   55    *length = WINPR_ASSERTING_INT_CAST(UINT16, 
byte << 8);
 
   56    Stream_Read_UINT8(s, 
byte);
 
   75BOOL per_write_length(
wStream* s, UINT16 length)
 
   79    if (!Stream_EnsureRemainingCapacity(s, 2))
 
   81    Stream_Write_UINT16_BE(s, (length | 0x8000));
 
   85    if (!Stream_EnsureRemainingCapacity(s, 1))
 
   87    Stream_Write_UINT8(s, (UINT8)length);
 
  100BOOL per_read_choice(
wStream* s, BYTE* choice)
 
  102  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  105  Stream_Read_UINT8(s, *choice);
 
  117BOOL per_write_choice(
wStream* s, BYTE choice)
 
  119  if (!Stream_EnsureRemainingCapacity(s, 1))
 
  121  Stream_Write_UINT8(s, choice);
 
  133BOOL per_read_selection(
wStream* s, BYTE* selection)
 
  135  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  138  WINPR_ASSERT(selection);
 
  139  Stream_Read_UINT8(s, *selection);
 
  151BOOL per_write_selection(
wStream* s, BYTE selection)
 
  153  if (!Stream_EnsureRemainingCapacity(s, 1))
 
  155  Stream_Write_UINT8(s, selection);
 
  167BOOL per_read_number_of_sets(
wStream* s, BYTE* number)
 
  169  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  172  WINPR_ASSERT(number);
 
  173  Stream_Read_UINT8(s, *number);
 
  186BOOL per_write_number_of_sets(
wStream* s, BYTE number)
 
  188  if (!Stream_EnsureRemainingCapacity(s, 1))
 
  190  Stream_Write_UINT8(s, number);
 
  203BOOL per_read_padding(
wStream* s, UINT16 length)
 
  205  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
 
  208  Stream_Seek(s, length);
 
  220BOOL per_write_padding(
wStream* s, UINT16 length)
 
  222  if (!Stream_EnsureRemainingCapacity(s, length))
 
  224  Stream_Zero(s, length);
 
  236BOOL per_read_integer(
wStream* s, UINT32* integer)
 
  240  WINPR_ASSERT(integer);
 
  242  if (!per_read_length(s, &length))
 
  245  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
 
  250  else if (length == 1)
 
  251    Stream_Read_UINT8(s, *integer);
 
  252  else if (length == 2)
 
  253    Stream_Read_UINT16_BE(s, *integer);
 
  268BOOL per_write_integer(
wStream* s, UINT32 integer)
 
  270  if (integer <= UINT8_MAX)
 
  272    if (!per_write_length(s, 1))
 
  274    if (!Stream_EnsureRemainingCapacity(s, 1))
 
  276    Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, integer));
 
  278  else if (integer <= UINT16_MAX)
 
  280    if (!per_write_length(s, 2))
 
  282    if (!Stream_EnsureRemainingCapacity(s, 2))
 
  284    Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, integer));
 
  286  else if (integer <= UINT32_MAX)
 
  288    if (!per_write_length(s, 4))
 
  290    if (!Stream_EnsureRemainingCapacity(s, 4))
 
  292    Stream_Write_UINT32_BE(s, integer);
 
  307BOOL per_read_integer16(
wStream* s, UINT16* integer, UINT16 min)
 
  309  if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
 
  312  Stream_Read_UINT16_BE(s, *integer);
 
  314  if (*integer > UINT16_MAX - min)
 
  316    WLog_WARN(TAG, 
"PER uint16 invalid value %" PRIu16 
" > %" PRIu16, *integer,
 
  335BOOL per_write_integer16(
wStream* s, UINT16 integer, UINT16 min)
 
  339  if (!Stream_EnsureRemainingCapacity(s, 2))
 
  341  Stream_Write_UINT16_BE(s, integer - min);
 
  355BOOL per_read_enumerated(
wStream* s, BYTE* enumerated, BYTE count)
 
  357  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  360  WINPR_ASSERT(enumerated);
 
  361  Stream_Read_UINT8(s, *enumerated);
 
  364  if (*enumerated + 1 > count)
 
  366    WLog_WARN(TAG, 
"PER invalid data, expected %" PRIu8 
" < %" PRIu8, *enumerated, count);
 
  383BOOL per_write_enumerated(
wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
 
  385  if (!Stream_EnsureRemainingCapacity(s, 1))
 
  387  Stream_Write_UINT8(s, enumerated);
 
  391static BOOL per_check_oid_and_log_mismatch(
const BYTE* got, 
const BYTE* expect, 
size_t length)
 
  393  if (memcmp(got, expect, length) == 0)
 
  399    char* got_str = winpr_BinToHexString(got, length, TRUE);
 
  400    char* expect_str = winpr_BinToHexString(expect, length, TRUE);
 
  402    WLog_WARN(TAG, 
"PER OID mismatch, got %s, expected %s", got_str, expect_str);
 
  419BOOL per_read_object_identifier(
wStream* s, 
const BYTE oid[6])
 
  423  BYTE a_oid[6] = { 0 };
 
  425  if (!per_read_length(s, &length))
 
  430    WLog_WARN(TAG, 
"PER length, got %" PRIu16 
", expected 5", length);
 
  434  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
 
  437  Stream_Read_UINT8(s, t12); 
 
  441  Stream_Read_UINT8(s, a_oid[2]); 
 
  442  Stream_Read_UINT8(s, a_oid[3]); 
 
  443  Stream_Read_UINT8(s, a_oid[4]); 
 
  444  Stream_Read_UINT8(s, a_oid[5]); 
 
  446  return per_check_oid_and_log_mismatch(a_oid, oid, 
sizeof(a_oid));
 
  458BOOL per_write_object_identifier(
wStream* s, 
const BYTE oid[6])
 
  460  BYTE t12 = oid[0] * 40 + oid[1];
 
  461  if (!Stream_EnsureRemainingCapacity(s, 6))
 
  463  Stream_Write_UINT8(s, 5);      
 
  464  Stream_Write_UINT8(s, t12);    
 
  465  Stream_Write_UINT8(s, oid[2]); 
 
  466  Stream_Write_UINT8(s, oid[3]); 
 
  467  Stream_Write_UINT8(s, oid[4]); 
 
  468  Stream_Write_UINT8(s, oid[5]); 
 
  483BOOL per_read_octet_string(
wStream* s, 
const BYTE* oct_str, UINT16 length, UINT16 min)
 
  487  if (!per_read_length(s, &mlength))
 
  490  if (mlength + min != length)
 
  492    WLog_ERR(TAG, 
"length mismatch: %" PRIu16 
"!= %" PRIu16, mlength + min, length);
 
  496  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
 
  499  const BYTE* a_oct_str = Stream_ConstPointer(s);
 
  500  Stream_Seek(s, length);
 
  502  return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
 
  515BOOL per_write_octet_string(
wStream* s, 
const BYTE* oct_str, UINT16 length, UINT16 min)
 
  519  mlength = (length >= min) ? length - min : min;
 
  521  if (!per_write_length(s, mlength))
 
  524  if (!Stream_EnsureRemainingCapacity(s, length))
 
  526  for (UINT16 i = 0; i < length; i++)
 
  527    Stream_Write_UINT8(s, oct_str[i]);
 
  539BOOL per_read_numeric_string(
wStream* s, UINT16 min)
 
  544  if (!per_read_length(s, &mlength))
 
  547  length = (mlength + min + 1) / 2;
 
  549  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
 
  552  Stream_Seek(s, length);
 
  566BOOL per_write_numeric_string(
wStream* s, 
const BYTE* num_str, UINT16 length, UINT16 min)
 
  568  WINPR_ASSERT(num_str || (length == 0));
 
  570  const UINT16 mlength = (length >= min) ? length - min : min;
 
  572  if (!per_write_length(s, mlength))
 
  575  if (!Stream_EnsureRemainingCapacity(s, length))
 
  577  for (UINT16 i = 0; i < length; i += 2)
 
  579    BYTE c1 = num_str[i];
 
  580    BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
 
  582    if ((c1 < 0x30) || (c2 < 0x30))
 
  585    c1 = (c1 - 0x30) % 10;
 
  586    c2 = (c2 - 0x30) % 10;
 
  587    const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
 
  589    Stream_Write_UINT8(s, num);