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
" > %d", *integer, UINT16_MAX - min);
334BOOL per_write_integer16(
wStream* s, UINT16 integer, UINT16 min)
338 if (!Stream_EnsureRemainingCapacity(s, 2))
340 Stream_Write_UINT16_BE(s, integer - min);
354BOOL per_read_enumerated(
wStream* s, BYTE* enumerated, BYTE count)
356 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
359 WINPR_ASSERT(enumerated);
360 Stream_Read_UINT8(s, *enumerated);
363 if (*enumerated + 1 > count)
365 WLog_WARN(TAG,
"PER invalid data, expected %" PRIu8
" < %" PRIu8, *enumerated, count);
382BOOL per_write_enumerated(
wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
384 if (!Stream_EnsureRemainingCapacity(s, 1))
386 Stream_Write_UINT8(s, enumerated);
390static BOOL per_check_oid_and_log_mismatch(
const BYTE* got,
const BYTE* expect,
size_t length)
392 if (memcmp(got, expect, length) == 0)
398 char* got_str = winpr_BinToHexString(got, length, TRUE);
399 char* expect_str = winpr_BinToHexString(expect, length, TRUE);
401 WLog_WARN(TAG,
"PER OID mismatch, got %s, expected %s", got_str, expect_str);
418BOOL per_read_object_identifier(
wStream* s,
const BYTE oid[6])
422 BYTE a_oid[6] = { 0 };
424 if (!per_read_length(s, &length))
429 WLog_WARN(TAG,
"PER length, got %" PRIu16
", expected 5", length);
433 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
436 Stream_Read_UINT8(s, t12);
440 Stream_Read_UINT8(s, a_oid[2]);
441 Stream_Read_UINT8(s, a_oid[3]);
442 Stream_Read_UINT8(s, a_oid[4]);
443 Stream_Read_UINT8(s, a_oid[5]);
445 return per_check_oid_and_log_mismatch(a_oid, oid,
sizeof(a_oid));
457BOOL per_write_object_identifier(
wStream* s,
const BYTE oid[6])
459 BYTE t12 = oid[0] * 40 + oid[1];
460 if (!Stream_EnsureRemainingCapacity(s, 6))
462 Stream_Write_UINT8(s, 5);
463 Stream_Write_UINT8(s, t12);
464 Stream_Write_UINT8(s, oid[2]);
465 Stream_Write_UINT8(s, oid[3]);
466 Stream_Write_UINT8(s, oid[4]);
467 Stream_Write_UINT8(s, oid[5]);
482BOOL per_read_octet_string(
wStream* s,
const BYTE* oct_str, UINT16 length, UINT16 min)
486 if (!per_read_length(s, &mlength))
489 if (mlength + min != length)
491 WLog_ERR(TAG,
"length mismatch: %d!= %" PRIu16, mlength + min, length);
495 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
498 const BYTE* a_oct_str = Stream_ConstPointer(s);
499 Stream_Seek(s, length);
501 return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
514BOOL per_write_octet_string(
wStream* s,
const BYTE* oct_str, UINT16 length, UINT16 min)
518 mlength = (length >= min) ? length - min : min;
520 if (!per_write_length(s, mlength))
523 if (!Stream_EnsureRemainingCapacity(s, length))
525 for (UINT16 i = 0; i < length; i++)
526 Stream_Write_UINT8(s, oct_str[i]);
538BOOL per_read_numeric_string(
wStream* s, UINT16 min)
543 if (!per_read_length(s, &mlength))
546 length = (mlength + min + 1) / 2;
548 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
551 Stream_Seek(s, length);
565BOOL per_write_numeric_string(
wStream* s,
const BYTE* num_str, UINT16 length, UINT16 min)
567 WINPR_ASSERT(num_str || (length == 0));
569 const UINT16 mlength = (length >= min) ? length - min : min;
571 if (!per_write_length(s, mlength))
574 if (!Stream_EnsureRemainingCapacity(s, length))
576 for (UINT16 i = 0; i < length; i += 2)
578 BYTE c1 = num_str[i];
579 BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
581 if ((c1 < 0x30) || (c2 < 0x30))
584 c1 = (c1 - 0x30) % 10;
585 c2 = (c2 - 0x30) % 10;
586 const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
588 Stream_Write_UINT8(s, num);