Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/libfreerdp/crypto/ber.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * ASN.1 Basic Encoding Rules (BER)
4
 *
5
 * Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
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
0
{
35
0
  BYTE byte = 0;
36
37
0
  WINPR_ASSERT(s);
38
0
  WINPR_ASSERT(length);
39
40
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
41
0
    return FALSE;
42
43
0
  Stream_Read_UINT8(s, byte);
44
45
0
  if (byte & 0x80)
46
0
  {
47
0
    byte &= ~(0x80);
48
49
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, byte))
50
0
      return FALSE;
51
52
0
    if (byte == 1)
53
0
      Stream_Read_UINT8(s, *length);
54
0
    else if (byte == 2)
55
0
      Stream_Read_UINT16_BE(s, *length);
56
0
    else
57
0
    {
58
0
      WLog_ERR(TAG, "ber: unexpected byte 0x%02" PRIx8 ", expected [1,2]", byte);
59
0
      return FALSE;
60
0
    }
61
0
  }
62
0
  else
63
0
  {
64
0
    *length = byte;
65
0
  }
66
67
0
  return TRUE;
68
0
}
69
70
/**
71
 * Write BER length.
72
 * @param s stream
73
 * @param length length
74
 */
75
76
size_t ber_write_length(wStream* s, size_t length)
77
0
{
78
0
  WINPR_ASSERT(s);
79
80
0
  if (length > 0xFF)
81
0
  {
82
0
    WINPR_ASSERT(length <= UINT16_MAX);
83
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 3);
84
0
    Stream_Write_UINT8(s, 0x80 ^ 2);
85
0
    Stream_Write_UINT16_BE(s, (UINT16)length);
86
0
    return 3;
87
0
  }
88
89
0
  WINPR_ASSERT(length <= UINT8_MAX);
90
0
  if (length > 0x7F)
91
0
  {
92
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
93
0
    Stream_Write_UINT8(s, 0x80 ^ 1);
94
0
    Stream_Write_UINT8(s, (UINT8)length);
95
0
    return 2;
96
0
  }
97
98
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
99
0
  Stream_Write_UINT8(s, (UINT8)length);
100
0
  return 1;
101
0
}
102
103
size_t _ber_sizeof_length(size_t length)
104
0
{
105
0
  if (length > 0xFF)
106
0
    return 3;
107
108
0
  if (length > 0x7F)
109
0
    return 2;
110
111
0
  return 1;
112
0
}
113
114
/**
115
 * Read BER Universal tag.
116
 *
117
 * @param s The stream to read from
118
 * @param tag BER universally-defined tag
119
 *
120
 * @return \b TRUE for success, \b FALSE otherwise
121
 */
122
123
BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
124
0
{
125
0
  BYTE byte = 0;
126
0
  const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
127
128
0
  WINPR_ASSERT(s);
129
130
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
131
0
    return FALSE;
132
133
0
  Stream_Read_UINT8(s, byte);
134
135
0
  if (byte != expect)
136
0
  {
137
0
    WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
138
0
    return FALSE;
139
0
  }
140
141
0
  return TRUE;
142
0
}
143
144
/**
145
 * Write BER Universal tag.
146
 * @param s stream
147
 * @param tag BER universally-defined tag
148
 * @param pc primitive (FALSE) or constructed (TRUE)
149
 */
150
151
size_t ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
152
0
{
153
0
  WINPR_ASSERT(s);
154
0
  Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
155
0
  return 1;
156
0
}
157
158
/**
159
 * Read BER Application tag.
160
 * @param s stream
161
 * @param tag BER application-defined tag
162
 * @param length length
163
 */
164
165
BOOL ber_read_application_tag(wStream* s, BYTE tag, size_t* length)
166
0
{
167
0
  BYTE byte = 0;
168
169
0
  WINPR_ASSERT(s);
170
0
  WINPR_ASSERT(length);
171
172
0
  if (tag > 30)
173
0
  {
174
0
    const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
175
176
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
177
0
      return FALSE;
178
179
0
    Stream_Read_UINT8(s, byte);
180
181
0
    if (byte != expect)
182
0
    {
183
0
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
184
0
      return FALSE;
185
0
    }
186
187
0
    Stream_Read_UINT8(s, byte);
188
189
0
    if (byte != tag)
190
0
    {
191
0
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, tag);
192
0
      return FALSE;
193
0
    }
194
195
0
    return ber_read_length(s, length);
196
0
  }
197
0
  else
198
0
  {
199
0
    const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
200
201
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
202
0
      return FALSE;
203
204
0
    Stream_Read_UINT8(s, byte);
205
206
0
    if (byte != expect)
207
0
    {
208
0
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
209
0
      return FALSE;
210
0
    }
211
212
0
    return ber_read_length(s, length);
213
0
  }
214
215
0
  return TRUE;
216
0
}
217
218
/**
219
 * Write BER Application tag.
220
 * @param s stream
221
 * @param tag BER application-defined tag
222
 * @param length length
223
 */
224
225
void ber_write_application_tag(wStream* s, BYTE tag, size_t length)
226
0
{
227
0
  WINPR_ASSERT(s);
228
229
0
  if (tag > 30)
230
0
  {
231
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
232
0
    Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
233
0
    Stream_Write_UINT8(s, tag);
234
0
    ber_write_length(s, length);
235
0
  }
236
0
  else
237
0
  {
238
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
239
0
    Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
240
0
    ber_write_length(s, length);
241
0
  }
242
0
}
243
244
BOOL ber_read_contextual_tag(wStream* s, BYTE tag, size_t* length, BOOL pc)
245
0
{
246
0
  const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
247
0
  BYTE byte = 0;
248
249
0
  WINPR_ASSERT(s);
250
0
  WINPR_ASSERT(length);
251
252
0
  if (Stream_GetRemainingLength(s) < 1)
253
0
  {
254
0
    WLog_VRB(TAG, "short data, got %" PRIuz ", expected %" PRIuz, Stream_GetRemainingLength(s),
255
0
             1);
256
0
    return FALSE;
257
0
  }
258
259
0
  Stream_Read_UINT8(s, byte);
260
261
0
  if (byte != expect)
262
0
  {
263
0
    WLog_VRB(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
264
0
    Stream_Rewind(s, 1);
265
0
    return FALSE;
266
0
  }
267
268
0
  return ber_read_length(s, length);
269
0
}
270
271
size_t ber_write_contextual_tag(wStream* s, BYTE tag, size_t length, BOOL pc)
272
0
{
273
0
  WINPR_ASSERT(s);
274
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
275
0
  Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
276
0
  return 1 + ber_write_length(s, length);
277
0
}
278
279
size_t ber_sizeof_contextual_tag(size_t length)
280
0
{
281
0
  return 1 + _ber_sizeof_length(length);
282
0
}
283
284
BOOL ber_read_sequence_tag(wStream* s, size_t* length)
285
0
{
286
0
  const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
287
0
  BYTE byte = 0;
288
289
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
290
0
    return FALSE;
291
292
0
  Stream_Read_UINT8(s, byte);
293
294
0
  if (byte != expect)
295
0
  {
296
0
    WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
297
0
    return FALSE;
298
0
  }
299
300
0
  return ber_read_length(s, length);
301
0
}
302
303
/**
304
 * Write BER SEQUENCE tag.
305
 * @param s stream
306
 * @param length length
307
 */
308
309
size_t ber_write_sequence_tag(wStream* s, size_t length)
310
0
{
311
0
  Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
312
0
  return 1 + ber_write_length(s, length);
313
0
}
314
315
size_t ber_sizeof_sequence(size_t length)
316
0
{
317
0
  return 1 + _ber_sizeof_length(length) + length;
318
0
}
319
320
size_t ber_sizeof_sequence_tag(size_t length)
321
0
{
322
0
  return 1 + _ber_sizeof_length(length);
323
0
}
324
325
BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
326
0
{
327
0
  size_t length = 0;
328
329
0
  WINPR_ASSERT(enumerated);
330
331
0
  if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
332
0
    return FALSE;
333
334
0
  if (length != 1)
335
0
  {
336
0
    WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
337
0
    return FALSE;
338
0
  }
339
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
340
0
    return FALSE;
341
342
0
  Stream_Read_UINT8(s, *enumerated);
343
344
  /* check that enumerated value falls within expected range */
345
0
  if (*enumerated + 1 > count)
346
0
  {
347
0
    WLog_WARN(TAG, "invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
348
0
    return FALSE;
349
0
  }
350
351
0
  return TRUE;
352
0
}
353
354
void ber_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
355
0
{
356
0
  ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
357
0
  ber_write_length(s, 1);
358
0
  Stream_Write_UINT8(s, enumerated);
359
0
}
360
361
BOOL ber_read_bit_string(wStream* s, size_t* length, BYTE* padding)
362
0
{
363
0
  if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
364
0
    return FALSE;
365
366
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
367
0
    return FALSE;
368
369
0
  Stream_Read_UINT8(s, *padding);
370
0
  return TRUE;
371
0
}
372
373
/**
374
 * Write a BER OCTET_STRING
375
 * @param s stream
376
 * @param oct_str octet string
377
 * @param length string length
378
 */
379
380
size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length)
381
0
{
382
0
  size_t size = 0;
383
384
0
  WINPR_ASSERT(oct_str || (length == 0));
385
0
  size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
386
0
  size += ber_write_length(s, length);
387
0
  Stream_Write(s, oct_str, length);
388
0
  size += length;
389
0
  return size;
390
0
}
391
392
size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, size_t length)
393
0
{
394
0
  size_t inner = ber_sizeof_octet_string(length);
395
0
  size_t ret = 0;
396
0
  size_t r = 0;
397
398
0
  ret = ber_write_contextual_tag(s, tag, inner, TRUE);
399
0
  if (!ret)
400
0
    return 0;
401
402
0
  r = ber_write_octet_string(s, oct_str, length);
403
0
  if (!r)
404
0
    return 0;
405
0
  return ret + r;
406
0
}
407
408
size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str)
409
0
{
410
0
  WINPR_ASSERT(str);
411
0
  size_t size = 0;
412
0
  size_t length = strlen(str) + 1;
413
0
  size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
414
0
  size += ber_write_length(s, length * sizeof(WCHAR));
415
416
0
  if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
417
0
    return 0;
418
0
  return size + length * sizeof(WCHAR);
419
0
}
420
421
size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str)
422
0
{
423
0
  WINPR_ASSERT(str);
424
0
  size_t len = _wcslen(str) * sizeof(WCHAR);
425
0
  size_t inner_len = ber_sizeof_octet_string(len);
426
0
  size_t ret = 0;
427
428
0
  ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
429
0
  return ret + ber_write_octet_string(s, (const BYTE*)str, len);
430
0
}
431
432
size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, const char* str)
433
0
{
434
0
  size_t ret = 0;
435
0
  size_t len = strlen(str);
436
0
  size_t inner_len = ber_sizeof_octet_string(len * 2);
437
438
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
439
440
0
  ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
441
0
  ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
442
0
  ret += ber_write_length(s, len * sizeof(WCHAR));
443
444
0
  if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
445
0
    return 0;
446
447
0
  return ret + len;
448
0
}
449
450
BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str)
451
0
{
452
0
  LPWSTR ret = NULL;
453
0
  size_t length = 0;
454
455
0
  if (!ber_read_octet_string_tag(s, &length))
456
0
    return FALSE;
457
458
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
459
0
    return FALSE;
460
461
0
  ret = calloc(1, length + 2);
462
0
  if (!ret)
463
0
    return FALSE;
464
465
0
  memcpy(ret, Stream_ConstPointer(s), length);
466
0
  ret[length / 2] = 0;
467
0
  Stream_Seek(s, length);
468
0
  *str = ret;
469
0
  return TRUE;
470
0
}
471
472
BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str)
473
0
{
474
0
  size_t length = 0;
475
0
  char* ptr = NULL;
476
477
0
  *str = NULL;
478
0
  if (!ber_read_octet_string_tag(s, &length))
479
0
    return FALSE;
480
481
0
  ptr = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), NULL);
482
0
  if (!ptr)
483
0
    return FALSE;
484
0
  *str = ptr;
485
0
  return TRUE;
486
0
}
487
488
BOOL ber_read_octet_string_tag(wStream* s, size_t* length)
489
0
{
490
0
  return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
491
0
}
492
493
BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length)
494
0
{
495
0
  BYTE* ret = NULL;
496
497
0
  WINPR_ASSERT(s);
498
0
  WINPR_ASSERT(content);
499
0
  WINPR_ASSERT(length);
500
501
0
  if (!ber_read_octet_string_tag(s, length))
502
0
    return FALSE;
503
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
504
0
    return FALSE;
505
506
0
  ret = malloc(*length);
507
0
  if (!ret)
508
0
    return FALSE;
509
510
0
  Stream_Read(s, ret, *length);
511
0
  *content = ret;
512
0
  return TRUE;
513
0
}
514
515
size_t ber_write_octet_string_tag(wStream* s, size_t length)
516
0
{
517
0
  ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
518
0
  ber_write_length(s, length);
519
0
  return 1 + _ber_sizeof_length(length);
520
0
}
521
522
size_t ber_sizeof_octet_string(size_t length)
523
0
{
524
0
  return 1 + _ber_sizeof_length(length) + length;
525
0
}
526
527
size_t ber_sizeof_contextual_octet_string(size_t length)
528
0
{
529
0
  size_t ret = ber_sizeof_octet_string(length);
530
0
  return ber_sizeof_contextual_tag(ret) + ret;
531
0
}
532
533
/** \brief Read a BER BOOLEAN
534
 *
535
 * @param s The stream to read from.
536
 * @param value A pointer to the value read, must not be NULL
537
 *
538
 * \return \b TRUE for success, \b FALSE for any failure
539
 */
540
541
BOOL ber_read_BOOL(wStream* s, BOOL* value)
542
0
{
543
0
  size_t length = 0;
544
0
  BYTE v = 0;
545
546
0
  WINPR_ASSERT(value);
547
0
  if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
548
0
    return FALSE;
549
550
0
  if (length != 1)
551
0
  {
552
0
    WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
553
0
    return FALSE;
554
0
  }
555
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
556
0
    return FALSE;
557
558
0
  Stream_Read_UINT8(s, v);
559
0
  *value = (v ? TRUE : FALSE);
560
0
  return TRUE;
561
0
}
562
563
/**
564
 * Write a BER BOOLEAN
565
 *
566
 * @param s A pointer to the stream to write to
567
 * @param value The value to write
568
 */
569
570
void ber_write_BOOL(wStream* s, BOOL value)
571
0
{
572
0
  ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
573
0
  ber_write_length(s, 1);
574
0
  Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
575
0
}
576
577
BOOL ber_read_integer(wStream* s, UINT32* value)
578
0
{
579
0
  size_t length = 0;
580
581
0
  WINPR_ASSERT(s);
582
583
0
  if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
584
0
    return FALSE;
585
0
  if (!ber_read_length(s, &length))
586
0
    return FALSE;
587
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
588
0
    return FALSE;
589
590
0
  if (value == NULL)
591
0
  {
592
    // even if we don't care the integer value, check the announced size
593
0
    return Stream_SafeSeek(s, length);
594
0
  }
595
596
0
  if (length == 1)
597
0
  {
598
0
    Stream_Read_UINT8(s, *value);
599
0
  }
600
0
  else if (length == 2)
601
0
  {
602
0
    Stream_Read_UINT16_BE(s, *value);
603
0
  }
604
0
  else if (length == 3)
605
0
  {
606
0
    BYTE byte = 0;
607
0
    Stream_Read_UINT8(s, byte);
608
0
    Stream_Read_UINT16_BE(s, *value);
609
0
    *value += (byte << 16) & 0xFF0000;
610
0
  }
611
0
  else if (length == 4)
612
0
  {
613
0
    Stream_Read_UINT32_BE(s, *value);
614
0
  }
615
0
  else if (length == 8)
616
0
  {
617
0
    WLog_ERR(TAG, "should implement reading an 8 bytes integer");
618
0
    return FALSE;
619
0
  }
620
0
  else
621
0
  {
622
0
    WLog_ERR(TAG, "should implement reading an integer with length=%" PRIuz, length);
623
0
    return FALSE;
624
0
  }
625
626
0
  return TRUE;
627
0
}
628
629
/**
630
 * Write a BER INTEGER
631
 *
632
 * @param s A pointer to the stream to write to
633
 * @param value The value to write
634
 *
635
 * @return The size in bytes that were written
636
 */
637
638
size_t ber_write_integer(wStream* s, UINT32 value)
639
0
{
640
0
  WINPR_ASSERT(s);
641
642
0
  if (value < 0x80)
643
0
  {
644
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
645
0
    ber_write_length(s, 1);
646
647
0
    Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
648
0
    return 3;
649
0
  }
650
0
  else if (value < 0x8000)
651
0
  {
652
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
653
0
    ber_write_length(s, 2);
654
655
0
    Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
656
0
    return 4;
657
0
  }
658
0
  else if (value < 0x800000)
659
0
  {
660
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
661
0
    ber_write_length(s, 3);
662
663
0
    Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
664
0
    Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
665
0
    return 5;
666
0
  }
667
0
  else if (value < 0x80000000)
668
0
  {
669
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
670
0
    ber_write_length(s, 4);
671
672
0
    Stream_Write_UINT32_BE(s, value);
673
0
    return 6;
674
0
  }
675
0
  else
676
0
  {
677
    /* treat as signed integer i.e. NT/HRESULT error codes */
678
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
679
0
    ber_write_length(s, 4);
680
681
0
    Stream_Write_UINT32_BE(s, value);
682
0
    return 6;
683
0
  }
684
0
}
685
686
size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
687
0
{
688
0
  size_t len = ber_sizeof_integer(value);
689
690
0
  WINPR_ASSERT(s);
691
692
0
  WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
693
694
0
  len += ber_write_contextual_tag(s, tag, len, TRUE);
695
0
  ber_write_integer(s, value);
696
0
  return len;
697
0
}
698
699
size_t ber_sizeof_integer(UINT32 value)
700
0
{
701
0
  if (value < 0x80)
702
0
  {
703
0
    return 3;
704
0
  }
705
0
  else if (value < 0x8000)
706
0
  {
707
0
    return 4;
708
0
  }
709
0
  else if (value < 0x800000)
710
0
  {
711
0
    return 5;
712
0
  }
713
0
  else if (value < 0x80000000)
714
0
  {
715
0
    return 6;
716
0
  }
717
0
  else
718
0
  {
719
    /* treat as signed integer i.e. NT/HRESULT error codes */
720
0
    return 6;
721
0
  }
722
0
}
723
724
size_t ber_sizeof_contextual_integer(UINT32 value)
725
0
{
726
0
  size_t intSize = ber_sizeof_integer(value);
727
0
  return ber_sizeof_contextual_tag(intSize) + intSize;
728
0
}
729
730
BOOL ber_read_integer_length(wStream* s, size_t* length)
731
0
{
732
0
  return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
733
0
}