FreeRDP
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 
33 BOOL 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 
76 size_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 
103 size_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 
123 BOOL 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 
151 size_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 
165 BOOL 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 
225 void 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 
244 BOOL 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 %" PRIuz, Stream_GetRemainingLength(s),
255  1);
256  return FALSE;
257  }
258 
259  Stream_Read_UINT8(s, byte);
260 
261  if (byte != expect)
262  {
263  WLog_VRB(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
264  Stream_Rewind(s, 1);
265  return FALSE;
266  }
267 
268  return ber_read_length(s, length);
269 }
270 
271 size_t ber_write_contextual_tag(wStream* s, BYTE tag, size_t length, BOOL pc)
272 {
273  WINPR_ASSERT(s);
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);
277 }
278 
279 size_t ber_sizeof_contextual_tag(size_t length)
280 {
281  return 1 + _ber_sizeof_length(length);
282 }
283 
284 BOOL ber_read_sequence_tag(wStream* s, size_t* length)
285 {
286  const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
287  BYTE byte = 0;
288 
289  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
290  return FALSE;
291 
292  Stream_Read_UINT8(s, byte);
293 
294  if (byte != expect)
295  {
296  WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
297  return FALSE;
298  }
299 
300  return ber_read_length(s, length);
301 }
302 
309 size_t ber_write_sequence_tag(wStream* s, size_t length)
310 {
311  Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
312  return 1 + ber_write_length(s, length);
313 }
314 
315 size_t ber_sizeof_sequence(size_t length)
316 {
317  return 1 + _ber_sizeof_length(length) + length;
318 }
319 
320 size_t ber_sizeof_sequence_tag(size_t length)
321 {
322  return 1 + _ber_sizeof_length(length);
323 }
324 
325 BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
326 {
327  size_t length = 0;
328 
329  WINPR_ASSERT(enumerated);
330 
331  if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
332  return FALSE;
333 
334  if (length != 1)
335  {
336  WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
337  return FALSE;
338  }
339  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
340  return FALSE;
341 
342  Stream_Read_UINT8(s, *enumerated);
343 
344  /* check that enumerated value falls within expected range */
345  if (*enumerated + 1 > count)
346  {
347  WLog_WARN(TAG, "invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
348  return FALSE;
349  }
350 
351  return TRUE;
352 }
353 
354 void ber_write_enumerated(wStream* s, BYTE enumerated, BYTE count)
355 {
356  ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
357  ber_write_length(s, 1);
358  Stream_Write_UINT8(s, enumerated);
359 }
360 
361 BOOL ber_read_bit_string(wStream* s, size_t* length, BYTE* padding)
362 {
363  if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
364  return FALSE;
365 
366  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
367  return FALSE;
368 
369  Stream_Read_UINT8(s, *padding);
370  return TRUE;
371 }
372 
380 size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length)
381 {
382  size_t size = 0;
383 
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);
388  size += length;
389  return size;
390 }
391 
392 size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, size_t length)
393 {
394  size_t inner = ber_sizeof_octet_string(length);
395  size_t ret = 0;
396  size_t r = 0;
397 
398  ret = ber_write_contextual_tag(s, tag, inner, TRUE);
399  if (!ret)
400  return 0;
401 
402  r = ber_write_octet_string(s, oct_str, length);
403  if (!r)
404  return 0;
405  return ret + r;
406 }
407 
408 size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str)
409 {
410  WINPR_ASSERT(str);
411  size_t size = 0;
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));
415 
416  if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
417  return 0;
418  return size + length * sizeof(WCHAR);
419 }
420 
421 size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str)
422 {
423  WINPR_ASSERT(str);
424  size_t len = _wcslen(str) * sizeof(WCHAR);
425  size_t inner_len = ber_sizeof_octet_string(len);
426  size_t ret = 0;
427 
428  ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
429  return ret + ber_write_octet_string(s, (const BYTE*)str, len);
430 }
431 
432 size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, const char* str)
433 {
434  size_t ret = 0;
435  size_t len = strlen(str);
436  size_t inner_len = ber_sizeof_octet_string(len * 2);
437 
438  WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
439 
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));
443 
444  if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
445  return 0;
446 
447  return ret + len;
448 }
449 
450 BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str)
451 {
452  LPWSTR ret = NULL;
453  size_t length = 0;
454 
455  if (!ber_read_octet_string_tag(s, &length))
456  return FALSE;
457 
458  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
459  return FALSE;
460 
461  ret = calloc(1, length + 2);
462  if (!ret)
463  return FALSE;
464 
465  memcpy(ret, Stream_ConstPointer(s), length);
466  ret[length / 2] = 0;
467  Stream_Seek(s, length);
468  *str = ret;
469  return TRUE;
470 }
471 
472 BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str)
473 {
474  size_t length = 0;
475  char* ptr = NULL;
476 
477  *str = NULL;
478  if (!ber_read_octet_string_tag(s, &length))
479  return FALSE;
480 
481  ptr = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), NULL);
482  if (!ptr)
483  return FALSE;
484  *str = ptr;
485  return TRUE;
486 }
487 
488 BOOL ber_read_octet_string_tag(wStream* s, size_t* length)
489 {
490  return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
491 }
492 
493 BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length)
494 {
495  BYTE* ret = NULL;
496 
497  WINPR_ASSERT(s);
498  WINPR_ASSERT(content);
499  WINPR_ASSERT(length);
500 
501  if (!ber_read_octet_string_tag(s, length))
502  return FALSE;
503  if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
504  return FALSE;
505 
506  ret = malloc(*length);
507  if (!ret)
508  return FALSE;
509 
510  Stream_Read(s, ret, *length);
511  *content = ret;
512  return TRUE;
513 }
514 
515 size_t ber_write_octet_string_tag(wStream* s, size_t length)
516 {
517  ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
518  ber_write_length(s, length);
519  return 1 + _ber_sizeof_length(length);
520 }
521 
522 size_t ber_sizeof_octet_string(size_t length)
523 {
524  return 1 + _ber_sizeof_length(length) + length;
525 }
526 
527 size_t ber_sizeof_contextual_octet_string(size_t length)
528 {
529  size_t ret = ber_sizeof_octet_string(length);
530  return ber_sizeof_contextual_tag(ret) + ret;
531 }
532 
541 BOOL ber_read_BOOL(wStream* s, BOOL* value)
542 {
543  size_t length = 0;
544  BYTE v = 0;
545 
546  WINPR_ASSERT(value);
547  if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
548  return FALSE;
549 
550  if (length != 1)
551  {
552  WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
553  return FALSE;
554  }
555  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
556  return FALSE;
557 
558  Stream_Read_UINT8(s, v);
559  *value = (v ? TRUE : FALSE);
560  return TRUE;
561 }
562 
570 void ber_write_BOOL(wStream* s, BOOL value)
571 {
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);
575 }
576 
577 BOOL ber_read_integer(wStream* s, UINT32* value)
578 {
579  size_t length = 0;
580 
581  WINPR_ASSERT(s);
582 
583  if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
584  return FALSE;
585  if (!ber_read_length(s, &length))
586  return FALSE;
587  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
588  return FALSE;
589 
590  if (value == NULL)
591  {
592  // even if we don't care the integer value, check the announced size
593  return Stream_SafeSeek(s, length);
594  }
595 
596  if (length == 1)
597  {
598  Stream_Read_UINT8(s, *value);
599  }
600  else if (length == 2)
601  {
602  Stream_Read_UINT16_BE(s, *value);
603  }
604  else if (length == 3)
605  {
606  BYTE byte = 0;
607  Stream_Read_UINT8(s, byte);
608  Stream_Read_UINT16_BE(s, *value);
609  *value += (byte << 16) & 0xFF0000;
610  }
611  else if (length == 4)
612  {
613  Stream_Read_UINT32_BE(s, *value);
614  }
615  else if (length == 8)
616  {
617  WLog_ERR(TAG, "should implement reading an 8 bytes integer");
618  return FALSE;
619  }
620  else
621  {
622  WLog_ERR(TAG, "should implement reading an integer with length=%" PRIuz, length);
623  return FALSE;
624  }
625 
626  return TRUE;
627 }
628 
638 size_t ber_write_integer(wStream* s, UINT32 value)
639 {
640  WINPR_ASSERT(s);
641 
642  if (value < 0x80)
643  {
644  ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
645  ber_write_length(s, 1);
646 
647  Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
648  return 3;
649  }
650  else if (value < 0x8000)
651  {
652  ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
653  ber_write_length(s, 2);
654 
655  Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
656  return 4;
657  }
658  else if (value < 0x800000)
659  {
660  ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
661  ber_write_length(s, 3);
662 
663  Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
664  Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
665  return 5;
666  }
667  else if (value < 0x80000000)
668  {
669  ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
670  ber_write_length(s, 4);
671 
672  Stream_Write_UINT32_BE(s, value);
673  return 6;
674  }
675  else
676  {
677  /* treat as signed integer i.e. NT/HRESULT error codes */
678  ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
679  ber_write_length(s, 4);
680 
681  Stream_Write_UINT32_BE(s, value);
682  return 6;
683  }
684 }
685 
686 size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
687 {
688  size_t len = ber_sizeof_integer(value);
689 
690  WINPR_ASSERT(s);
691 
692  WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
693 
694  len += ber_write_contextual_tag(s, tag, len, TRUE);
695  ber_write_integer(s, value);
696  return len;
697 }
698 
699 size_t ber_sizeof_integer(UINT32 value)
700 {
701  if (value < 0x80)
702  {
703  return 3;
704  }
705  else if (value < 0x8000)
706  {
707  return 4;
708  }
709  else if (value < 0x800000)
710  {
711  return 5;
712  }
713  else if (value < 0x80000000)
714  {
715  return 6;
716  }
717  else
718  {
719  /* treat as signed integer i.e. NT/HRESULT error codes */
720  return 6;
721  }
722 }
723 
724 size_t ber_sizeof_contextual_integer(UINT32 value)
725 {
726  size_t intSize = ber_sizeof_integer(value);
727  return ber_sizeof_contextual_tag(intSize) + intSize;
728 }
729 
730 BOOL ber_read_integer_length(wStream* s, size_t* length)
731 {
732  return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
733 }