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")
39 BOOL 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);
75 BOOL 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);
100 BOOL per_read_choice(
wStream* s, BYTE* choice)
102 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
105 Stream_Read_UINT8(s, *choice);
117 BOOL per_write_choice(
wStream* s, BYTE choice)
119 if (!Stream_EnsureRemainingCapacity(s, 1))
121 Stream_Write_UINT8(s, choice);
133 BOOL per_read_selection(
wStream* s, BYTE* selection)
135 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
138 WINPR_ASSERT(selection);
139 Stream_Read_UINT8(s, *selection);
151 BOOL per_write_selection(
wStream* s, BYTE selection)
153 if (!Stream_EnsureRemainingCapacity(s, 1))
155 Stream_Write_UINT8(s, selection);
167 BOOL 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);
186 BOOL per_write_number_of_sets(
wStream* s, BYTE number)
188 if (!Stream_EnsureRemainingCapacity(s, 1))
190 Stream_Write_UINT8(s, number);
203 BOOL per_read_padding(
wStream* s, UINT16 length)
205 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
208 Stream_Seek(s, length);
220 BOOL per_write_padding(
wStream* s, UINT16 length)
222 if (!Stream_EnsureRemainingCapacity(s, length))
224 Stream_Zero(s, length);
236 BOOL 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);
268 BOOL 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);
307 BOOL 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,
335 BOOL per_write_integer16(
wStream* s, UINT16 integer, UINT16 min)
339 if (!Stream_EnsureRemainingCapacity(s, 2))
341 Stream_Write_UINT16_BE(s, integer - min);
355 BOOL 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);
383 BOOL per_write_enumerated(
wStream* s, BYTE enumerated, BYTE count)
385 if (!Stream_EnsureRemainingCapacity(s, 1))
387 Stream_Write_UINT8(s, enumerated);
391 static 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);
419 BOOL 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));
458 BOOL 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]);
479 static void per_write_string(
wStream* s, BYTE* str,
int length)
481 for (
int i = 0; i < length; i++)
482 Stream_Write_UINT8(s, str[i]);
496 BOOL per_read_octet_string(
wStream* s,
const BYTE* oct_str, UINT16 length, UINT16 min)
500 if (!per_read_length(s, &mlength))
503 if (mlength + min != length)
505 WLog_ERR(TAG,
"length mismatch: %" PRIu16
"!= %" PRIu16, mlength + min, length);
509 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
512 const BYTE* a_oct_str = Stream_ConstPointer(s);
513 Stream_Seek(s, length);
515 return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
528 BOOL per_write_octet_string(
wStream* s,
const BYTE* oct_str, UINT16 length, UINT16 min)
532 mlength = (length >= min) ? length - min : min;
534 if (!per_write_length(s, mlength))
537 if (!Stream_EnsureRemainingCapacity(s, length))
539 for (UINT16 i = 0; i < length; i++)
540 Stream_Write_UINT8(s, oct_str[i]);
552 BOOL per_read_numeric_string(
wStream* s, UINT16 min)
557 if (!per_read_length(s, &mlength))
560 length = (mlength + min + 1) / 2;
562 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
565 Stream_Seek(s, length);
579 BOOL per_write_numeric_string(
wStream* s,
const BYTE* num_str, UINT16 length, UINT16 min)
581 WINPR_ASSERT(num_str || (length == 0));
583 const UINT16 mlength = (length >= min) ? length - min : min;
585 if (!per_write_length(s, mlength))
588 if (!Stream_EnsureRemainingCapacity(s, length))
590 for (UINT16 i = 0; i < length; i += 2)
592 BYTE c1 = num_str[i];
593 BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
595 if ((c1 < 0x30) || (c2 < 0x30))
598 c1 = (c1 - 0x30) % 10;
599 c2 = (c2 - 0x30) % 10;
600 const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
602 Stream_Write_UINT8(s, num);