FreeRDP
ber.c
1 
20 #include <freerdp/config.h>
21 
22 #include <stdio.h>
23 #include <winpr/assert.h>
24 #include <winpr/crt.h>
25 #include <winpr/string.h>
26 
27 #include <freerdp/log.h>
28 #include <freerdp/crypto/ber.h>
29 
30 #define TAG FREERDP_TAG("crypto")
31 
32 BOOL ber_read_length(wStream* s, size_t* length)
33 {
34  BYTE byte = 0;
35 
36  WINPR_ASSERT(s);
37  WINPR_ASSERT(length);
38 
39  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
40  return FALSE;
41 
42  Stream_Read_UINT8(s, byte);
43 
44  if (byte & 0x80)
45  {
46  byte &= ~(0x80);
47 
48  if (!Stream_CheckAndLogRequiredLength(TAG, s, byte))
49  return FALSE;
50 
51  if (byte == 1)
52  Stream_Read_UINT8(s, *length);
53  else if (byte == 2)
54  Stream_Read_UINT16_BE(s, *length);
55  else
56  {
57  WLog_ERR(TAG, "ber: unexpected byte 0x%02" PRIx8 ", expected [1,2]", byte);
58  return FALSE;
59  }
60  }
61  else
62  {
63  *length = byte;
64  }
65 
66  return TRUE;
67 }
68 
75 size_t ber_write_length(wStream* s, size_t length)
76 {
77  WINPR_ASSERT(s);
78 
79  if (length > 0xFF)
80  {
81  WINPR_ASSERT(length <= UINT16_MAX);
82  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 3);
83  Stream_Write_UINT8(s, 0x80 ^ 2);
84  Stream_Write_UINT16_BE(s, (UINT16)length);
85  return 3;
86  }
87 
88  WINPR_ASSERT(length <= UINT8_MAX);
89  if (length > 0x7F)
90  {
91  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
92  Stream_Write_UINT8(s, 0x80 ^ 1);
93  Stream_Write_UINT8(s, (UINT8)length);
94  return 2;
95  }
96 
97  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
98  Stream_Write_UINT8(s, (UINT8)length);
99  return 1;
100 }
101 
102 size_t _ber_sizeof_length(size_t length)
103 {
104  if (length > 0xFF)
105  return 3;
106 
107  if (length > 0x7F)
108  return 2;
109 
110  return 1;
111 }
112 
122 BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
123 {
124  BYTE byte = 0;
125  const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
126 
127  WINPR_ASSERT(s);
128 
129  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
130  return FALSE;
131 
132  Stream_Read_UINT8(s, byte);
133 
134  if (byte != expect)
135  {
136  WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
137  return FALSE;
138  }
139 
140  return TRUE;
141 }
142 
150 size_t ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
151 {
152  WINPR_ASSERT(s);
153  Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
154  return 1;
155 }
156 
164 BOOL ber_read_application_tag(wStream* s, BYTE tag, size_t* length)
165 {
166  BYTE byte = 0;
167 
168  WINPR_ASSERT(s);
169  WINPR_ASSERT(length);
170 
171  if (tag > 30)
172  {
173  const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
174 
175  if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
176  return FALSE;
177 
178  Stream_Read_UINT8(s, byte);
179 
180  if (byte != expect)
181  {
182  WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
183  return FALSE;
184  }
185 
186  Stream_Read_UINT8(s, byte);
187 
188  if (byte != tag)
189  {
190  WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, tag);
191  return FALSE;
192  }
193 
194  return ber_read_length(s, length);
195  }
196  else
197  {
198  const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
199 
200  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
201  return FALSE;
202 
203  Stream_Read_UINT8(s, byte);
204 
205  if (byte != expect)
206  {
207  WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
208  return FALSE;
209  }
210 
211  return ber_read_length(s, length);
212  }
213 
214  return TRUE;
215 }
216 
224 void ber_write_application_tag(wStream* s, BYTE tag, size_t length)
225 {
226  WINPR_ASSERT(s);
227 
228  if (tag > 30)
229  {
230  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
231  Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
232  Stream_Write_UINT8(s, tag);
233  ber_write_length(s, length);
234  }
235  else
236  {
237  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
238  Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
239  ber_write_length(s, length);
240  }
241 }
242 
243 BOOL ber_read_contextual_tag(wStream* s, BYTE tag, size_t* length, BOOL pc)
244 {
245  const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
246  BYTE byte = 0;
247 
248  WINPR_ASSERT(s);
249  WINPR_ASSERT(length);
250 
251  if (Stream_GetRemainingLength(s) < 1)
252  {
253  WLog_VRB(TAG, "short data, got %" PRIuz ", expected %" PRIuz, Stream_GetRemainingLength(s),
254  1);
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 
270 size_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 
278 size_t ber_sizeof_contextual_tag(size_t length)
279 {
280  return 1 + _ber_sizeof_length(length);
281 }
282 
283 BOOL 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 
308 size_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 
314 size_t ber_sizeof_sequence(size_t length)
315 {
316  return 1 + _ber_sizeof_length(length) + length;
317 }
318 
319 size_t ber_sizeof_sequence_tag(size_t length)
320 {
321  return 1 + _ber_sizeof_length(length);
322 }
323 
324 BOOL 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 %" PRIuz, length, 1);
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 
353 void ber_write_enumerated(wStream* s, BYTE enumerated, 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 
360 BOOL 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 
379 size_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 
391 size_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 
407 size_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 
420 size_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 
431 size_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 
449 BOOL 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 
471 BOOL 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 
487 BOOL 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 
492 BOOL 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 
514 size_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 
521 size_t ber_sizeof_octet_string(size_t length)
522 {
523  return 1 + _ber_sizeof_length(length) + length;
524 }
525 
526 size_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 
540 BOOL 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 %" PRIuz, length, 1);
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 
569 void 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 
576 BOOL 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);
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 
637 size_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, 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, 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, (value >> 16));
663  Stream_Write_UINT16_BE(s, (value & 0xFFFF));
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 
685 size_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 
698 size_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 
723 size_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 
729 BOOL 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 }