FreeRDP
Loading...
Searching...
No Matches
ber.c
1
20#include <freerdp/config.h>
21
22#include <stdio.h>
23#include <winpr/assert.h>
24#include <winpr/cast.h>
25#include <winpr/crt.h>
26#include <winpr/string.h>
27
28#include <freerdp/log.h>
29#include <freerdp/crypto/ber.h>
30
31#define TAG FREERDP_TAG("crypto")
32
33BOOL ber_read_length(wStream* s, size_t* length)
34{
35 BYTE byte = 0;
36
37 WINPR_ASSERT(s);
38 WINPR_ASSERT(length);
39
40 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
41 return FALSE;
42
43 Stream_Read_UINT8(s, byte);
44
45 if (byte & 0x80)
46 {
47 byte &= ~(0x80);
48
49 if (!Stream_CheckAndLogRequiredLength(TAG, s, byte))
50 return FALSE;
51
52 if (byte == 1)
53 Stream_Read_UINT8(s, *length);
54 else if (byte == 2)
55 Stream_Read_UINT16_BE(s, *length);
56 else
57 {
58 WLog_ERR(TAG, "ber: unexpected byte 0x%02" PRIx8 ", expected [1,2]", byte);
59 return FALSE;
60 }
61 }
62 else
63 {
64 *length = byte;
65 }
66
67 return TRUE;
68}
69
76size_t ber_write_length(wStream* s, size_t length)
77{
78 WINPR_ASSERT(s);
79
80 if (length > 0xFF)
81 {
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);
86 return 3;
87 }
88
89 WINPR_ASSERT(length <= UINT8_MAX);
90 if (length > 0x7F)
91 {
92 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
93 Stream_Write_UINT8(s, 0x80 ^ 1);
94 Stream_Write_UINT8(s, (UINT8)length);
95 return 2;
96 }
97
98 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
99 Stream_Write_UINT8(s, (UINT8)length);
100 return 1;
101}
102
103size_t _ber_sizeof_length(size_t length)
104{
105 if (length > 0xFF)
106 return 3;
107
108 if (length > 0x7F)
109 return 2;
110
111 return 1;
112}
113
123BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
124{
125 BYTE byte = 0;
126 const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
127
128 WINPR_ASSERT(s);
129
130 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
131 return FALSE;
132
133 Stream_Read_UINT8(s, byte);
134
135 if (byte != expect)
136 {
137 WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
138 return FALSE;
139 }
140
141 return TRUE;
142}
143
151size_t ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
152{
153 WINPR_ASSERT(s);
154 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
155 return 1;
156}
157
165BOOL ber_read_application_tag(wStream* s, BYTE tag, size_t* length)
166{
167 BYTE byte = 0;
168
169 WINPR_ASSERT(s);
170 WINPR_ASSERT(length);
171
172 if (tag > 30)
173 {
174 const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
175
176 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
177 return FALSE;
178
179 Stream_Read_UINT8(s, byte);
180
181 if (byte != expect)
182 {
183 WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
184 return FALSE;
185 }
186
187 Stream_Read_UINT8(s, byte);
188
189 if (byte != tag)
190 {
191 WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, tag);
192 return FALSE;
193 }
194
195 return ber_read_length(s, length);
196 }
197 else
198 {
199 const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
200
201 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
202 return FALSE;
203
204 Stream_Read_UINT8(s, byte);
205
206 if (byte != expect)
207 {
208 WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
209 return FALSE;
210 }
211
212 return ber_read_length(s, length);
213 }
214
215 return TRUE;
216}
217
225void ber_write_application_tag(wStream* s, BYTE tag, size_t length)
226{
227 WINPR_ASSERT(s);
228
229 if (tag > 30)
230 {
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);
235 }
236 else
237 {
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);
241 }
242}
243
244BOOL ber_read_contextual_tag(wStream* s, BYTE tag, size_t* length, BOOL pc)
245{
246 const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
247 BYTE byte = 0;
248
249 WINPR_ASSERT(s);
250 WINPR_ASSERT(length);
251
252 if (Stream_GetRemainingLength(s) < 1)
253 {
254 WLog_VRB(TAG, "short data, got %" PRIuz ", expected %u", Stream_GetRemainingLength(s), 1u);
255 return FALSE;
256 }
257
258 Stream_Read_UINT8(s, byte);
259
260 if (byte != expect)
261 {
262 WLog_VRB(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
263 Stream_Rewind(s, 1);
264 return FALSE;
265 }
266
267 return ber_read_length(s, length);
268}
269
270size_t ber_write_contextual_tag(wStream* s, BYTE tag, size_t length, BOOL pc)
271{
272 WINPR_ASSERT(s);
273 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
274 Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
275 return 1 + ber_write_length(s, length);
276}
277
278size_t ber_sizeof_contextual_tag(size_t length)
279{
280 return 1 + _ber_sizeof_length(length);
281}
282
283BOOL ber_read_sequence_tag(wStream* s, size_t* length)
284{
285 const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
286 BYTE byte = 0;
287
288 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
289 return FALSE;
290
291 Stream_Read_UINT8(s, byte);
292
293 if (byte != expect)
294 {
295 WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
296 return FALSE;
297 }
298
299 return ber_read_length(s, length);
300}
301
308size_t ber_write_sequence_tag(wStream* s, size_t length)
309{
310 Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
311 return 1 + ber_write_length(s, length);
312}
313
314size_t ber_sizeof_sequence(size_t length)
315{
316 return 1 + _ber_sizeof_length(length) + length;
317}
318
319size_t ber_sizeof_sequence_tag(size_t length)
320{
321 return 1 + _ber_sizeof_length(length);
322}
323
324BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
325{
326 size_t length = 0;
327
328 WINPR_ASSERT(enumerated);
329
330 if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
331 return FALSE;
332
333 if (length != 1)
334 {
335 WLog_WARN(TAG, "short data, got %" PRIuz ", expected %u", length, 1u);
336 return FALSE;
337 }
338 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
339 return FALSE;
340
341 Stream_Read_UINT8(s, *enumerated);
342
343 /* check that enumerated value falls within expected range */
344 if (*enumerated + 1 > count)
345 {
346 WLog_WARN(TAG, "invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
347 return FALSE;
348 }
349
350 return TRUE;
351}
352
353void ber_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
354{
355 ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
356 ber_write_length(s, 1);
357 Stream_Write_UINT8(s, enumerated);
358}
359
360BOOL ber_read_bit_string(wStream* s, size_t* length, BYTE* padding)
361{
362 if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
363 return FALSE;
364
365 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
366 return FALSE;
367
368 Stream_Read_UINT8(s, *padding);
369 return TRUE;
370}
371
379size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length)
380{
381 size_t size = 0;
382
383 WINPR_ASSERT(oct_str || (length == 0));
384 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
385 size += ber_write_length(s, length);
386 Stream_Write(s, oct_str, length);
387 size += length;
388 return size;
389}
390
391size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, size_t length)
392{
393 size_t inner = ber_sizeof_octet_string(length);
394 size_t ret = 0;
395 size_t r = 0;
396
397 ret = ber_write_contextual_tag(s, tag, inner, TRUE);
398 if (!ret)
399 return 0;
400
401 r = ber_write_octet_string(s, oct_str, length);
402 if (!r)
403 return 0;
404 return ret + r;
405}
406
407size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str)
408{
409 WINPR_ASSERT(str);
410 size_t size = 0;
411 size_t length = strlen(str) + 1;
412 size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
413 size += ber_write_length(s, length * sizeof(WCHAR));
414
415 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
416 return 0;
417 return size + length * sizeof(WCHAR);
418}
419
420size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str)
421{
422 WINPR_ASSERT(str);
423 size_t len = _wcslen(str) * sizeof(WCHAR);
424 size_t inner_len = ber_sizeof_octet_string(len);
425 size_t ret = 0;
426
427 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
428 return ret + ber_write_octet_string(s, (const BYTE*)str, len);
429}
430
431size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, const char* str)
432{
433 size_t ret = 0;
434 size_t len = strlen(str);
435 size_t inner_len = ber_sizeof_octet_string(len * 2);
436
437 WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
438
439 ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
440 ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
441 ret += ber_write_length(s, len * sizeof(WCHAR));
442
443 if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
444 return 0;
445
446 return ret + len;
447}
448
449BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str)
450{
451 LPWSTR ret = NULL;
452 size_t length = 0;
453
454 if (!ber_read_octet_string_tag(s, &length))
455 return FALSE;
456
457 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
458 return FALSE;
459
460 ret = calloc(1, length + 2);
461 if (!ret)
462 return FALSE;
463
464 memcpy(ret, Stream_ConstPointer(s), length);
465 ret[length / 2] = 0;
466 Stream_Seek(s, length);
467 *str = ret;
468 return TRUE;
469}
470
471BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str)
472{
473 size_t length = 0;
474 char* ptr = NULL;
475
476 *str = NULL;
477 if (!ber_read_octet_string_tag(s, &length))
478 return FALSE;
479
480 ptr = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), NULL);
481 if (!ptr)
482 return FALSE;
483 *str = ptr;
484 return TRUE;
485}
486
487BOOL ber_read_octet_string_tag(wStream* s, size_t* length)
488{
489 return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
490}
491
492BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length)
493{
494 BYTE* ret = NULL;
495
496 WINPR_ASSERT(s);
497 WINPR_ASSERT(content);
498 WINPR_ASSERT(length);
499
500 if (!ber_read_octet_string_tag(s, length))
501 return FALSE;
502 if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
503 return FALSE;
504
505 ret = malloc(*length);
506 if (!ret)
507 return FALSE;
508
509 Stream_Read(s, ret, *length);
510 *content = ret;
511 return TRUE;
512}
513
514size_t ber_write_octet_string_tag(wStream* s, size_t length)
515{
516 ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
517 ber_write_length(s, length);
518 return 1 + _ber_sizeof_length(length);
519}
520
521size_t ber_sizeof_octet_string(size_t length)
522{
523 return 1 + _ber_sizeof_length(length) + length;
524}
525
526size_t ber_sizeof_contextual_octet_string(size_t length)
527{
528 size_t ret = ber_sizeof_octet_string(length);
529 return ber_sizeof_contextual_tag(ret) + ret;
530}
531
540BOOL ber_read_BOOL(wStream* s, BOOL* value)
541{
542 size_t length = 0;
543 BYTE v = 0;
544
545 WINPR_ASSERT(value);
546 if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
547 return FALSE;
548
549 if (length != 1)
550 {
551 WLog_WARN(TAG, "short data, got %" PRIuz ", expected %u", length, 1u);
552 return FALSE;
553 }
554 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
555 return FALSE;
556
557 Stream_Read_UINT8(s, v);
558 *value = (v ? TRUE : FALSE);
559 return TRUE;
560}
561
569void ber_write_BOOL(wStream* s, BOOL value)
570{
571 ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
572 ber_write_length(s, 1);
573 Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
574}
575
576BOOL ber_read_integer(wStream* s, UINT32* value)
577{
578 size_t length = 0;
579
580 WINPR_ASSERT(s);
581
582 if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
583 return FALSE;
584 if (!ber_read_length(s, &length))
585 return FALSE;
586 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
587 return FALSE;
588
589 if (value == NULL)
590 {
591 // even if we don't care the integer value, check the announced size
592 return Stream_SafeSeek(s, length);
593 }
594
595 if (length == 1)
596 {
597 Stream_Read_UINT8(s, *value);
598 }
599 else if (length == 2)
600 {
601 Stream_Read_UINT16_BE(s, *value);
602 }
603 else if (length == 3)
604 {
605 BYTE byte = 0;
606 Stream_Read_UINT8(s, byte);
607 Stream_Read_UINT16_BE(s, *value);
608 *value += (byte << 16) & 0xFF0000;
609 }
610 else if (length == 4)
611 {
612 Stream_Read_UINT32_BE(s, *value);
613 }
614 else if (length == 8)
615 {
616 WLog_ERR(TAG, "should implement reading an 8 bytes integer");
617 return FALSE;
618 }
619 else
620 {
621 WLog_ERR(TAG, "should implement reading an integer with length=%" PRIuz, length);
622 return FALSE;
623 }
624
625 return TRUE;
626}
627
637size_t ber_write_integer(wStream* s, UINT32 value)
638{
639 WINPR_ASSERT(s);
640
641 if (value < 0x80)
642 {
643 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
644 ber_write_length(s, 1);
645
646 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
647 return 3;
648 }
649 else if (value < 0x8000)
650 {
651 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
652 ber_write_length(s, 2);
653
654 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
655 return 4;
656 }
657 else if (value < 0x800000)
658 {
659 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
660 ber_write_length(s, 3);
661
662 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
663 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
664 return 5;
665 }
666 else if (value < 0x80000000)
667 {
668 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
669 ber_write_length(s, 4);
670
671 Stream_Write_UINT32_BE(s, value);
672 return 6;
673 }
674 else
675 {
676 /* treat as signed integer i.e. NT/HRESULT error codes */
677 ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
678 ber_write_length(s, 4);
679
680 Stream_Write_UINT32_BE(s, value);
681 return 6;
682 }
683}
684
685size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
686{
687 size_t len = ber_sizeof_integer(value);
688
689 WINPR_ASSERT(s);
690
691 WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
692
693 len += ber_write_contextual_tag(s, tag, len, TRUE);
694 ber_write_integer(s, value);
695 return len;
696}
697
698size_t ber_sizeof_integer(UINT32 value)
699{
700 if (value < 0x80)
701 {
702 return 3;
703 }
704 else if (value < 0x8000)
705 {
706 return 4;
707 }
708 else if (value < 0x800000)
709 {
710 return 5;
711 }
712 else if (value < 0x80000000)
713 {
714 return 6;
715 }
716 else
717 {
718 /* treat as signed integer i.e. NT/HRESULT error codes */
719 return 6;
720 }
721}
722
723size_t ber_sizeof_contextual_integer(UINT32 value)
724{
725 size_t intSize = ber_sizeof_integer(value);
726 return ber_sizeof_contextual_tag(intSize) + intSize;
727}
728
729BOOL ber_read_integer_length(wStream* s, size_t* length)
730{
731 return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
732}