Coverage Report

Created: 2026-05-30 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/crypto/ber.c
Line
Count
Source
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
  WINPR_ASSERT(s);
36
0
  WINPR_ASSERT(length);
37
38
0
  *length = 0;
39
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
40
0
    return FALSE;
41
42
0
  BYTE byte = Stream_Get_UINT8(s);
43
44
0
  if (byte & 0x80)
45
0
  {
46
0
    byte &= ~(0x80);
47
48
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, byte))
49
0
      return FALSE;
50
51
0
    if (byte == 1)
52
0
      Stream_Read_UINT8(s, *length);
53
0
    else if (byte == 2)
54
0
      Stream_Read_UINT16_BE(s, *length);
55
0
    else
56
0
    {
57
0
      WLog_ERR(TAG, "ber: unexpected byte 0x%02" PRIx8 ", expected [1,2]", byte);
58
0
      return FALSE;
59
0
    }
60
0
  }
61
0
  else
62
0
  {
63
0
    *length = byte;
64
0
  }
65
66
0
  return TRUE;
67
0
}
68
69
/**
70
 * Write BER length.
71
 * @param s stream
72
 * @param length length
73
 */
74
75
size_t ber_write_length(wStream* s, size_t length)
76
0
{
77
0
  WINPR_ASSERT(s);
78
79
0
  if (length > 0xFF)
80
0
  {
81
0
    WINPR_ASSERT(length <= UINT16_MAX);
82
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 3);
83
0
    Stream_Write_UINT8(s, 0x80 ^ 2);
84
0
    Stream_Write_UINT16_BE(s, (UINT16)length);
85
0
    return 3;
86
0
  }
87
88
0
  WINPR_ASSERT(length <= UINT8_MAX);
89
0
  if (length > 0x7F)
90
0
  {
91
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
92
0
    Stream_Write_UINT8(s, 0x80 ^ 1);
93
0
    Stream_Write_UINT8(s, (UINT8)length);
94
0
    return 2;
95
0
  }
96
97
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
98
0
  Stream_Write_UINT8(s, (UINT8)length);
99
0
  return 1;
100
0
}
101
102
size_t _ber_sizeof_length(size_t length)
103
0
{
104
0
  if (length > 0xFF)
105
0
    return 3;
106
107
0
  if (length > 0x7F)
108
0
    return 2;
109
110
0
  return 1;
111
0
}
112
113
/**
114
 * Read BER Universal tag.
115
 *
116
 * @param s The stream to read from
117
 * @param tag BER universally-defined tag
118
 *
119
 * @return \b TRUE for success, \b FALSE otherwise
120
 */
121
122
BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
123
0
{
124
0
  BYTE byte = 0;
125
0
  const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
126
127
0
  WINPR_ASSERT(s);
128
129
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
130
0
    return FALSE;
131
132
0
  Stream_Read_UINT8(s, byte);
133
134
0
  if (byte != expect)
135
0
  {
136
0
    WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
137
0
    return FALSE;
138
0
  }
139
140
0
  return TRUE;
141
0
}
142
143
/**
144
 * Write BER Universal tag.
145
 * @param s stream
146
 * @param tag BER universally-defined tag
147
 * @param pc primitive (FALSE) or constructed (TRUE)
148
 */
149
150
size_t ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
151
0
{
152
0
  WINPR_ASSERT(s);
153
0
  Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
154
0
  return 1;
155
0
}
156
157
/**
158
 * Read BER Application tag.
159
 * @param s stream
160
 * @param tag BER application-defined tag
161
 * @param length length
162
 */
163
164
BOOL ber_read_application_tag(wStream* s, BYTE tag, size_t* length)
165
0
{
166
0
  BYTE byte = 0;
167
168
0
  WINPR_ASSERT(s);
169
0
  WINPR_ASSERT(length);
170
171
0
  if (tag > 30)
172
0
  {
173
0
    const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
174
175
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
176
0
      return FALSE;
177
178
0
    Stream_Read_UINT8(s, byte);
179
180
0
    if (byte != expect)
181
0
    {
182
0
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
183
0
      return FALSE;
184
0
    }
185
186
0
    Stream_Read_UINT8(s, byte);
187
188
0
    if (byte != tag)
189
0
    {
190
0
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, tag);
191
0
      return FALSE;
192
0
    }
193
194
0
    return ber_read_length(s, length);
195
0
  }
196
0
  else
197
0
  {
198
0
    const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
199
200
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
201
0
      return FALSE;
202
203
0
    Stream_Read_UINT8(s, byte);
204
205
0
    if (byte != expect)
206
0
    {
207
0
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
208
0
      return FALSE;
209
0
    }
210
211
0
    return ber_read_length(s, length);
212
0
  }
213
214
0
  return TRUE;
215
0
}
216
217
/**
218
 * Write BER Application tag.
219
 * @param s stream
220
 * @param tag BER application-defined tag
221
 * @param length length
222
 */
223
224
void ber_write_application_tag(wStream* s, BYTE tag, size_t length)
225
0
{
226
0
  WINPR_ASSERT(s);
227
228
0
  if (tag > 30)
229
0
  {
230
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
231
0
    Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
232
0
    Stream_Write_UINT8(s, tag);
233
0
    ber_write_length(s, length);
234
0
  }
235
0
  else
236
0
  {
237
0
    WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
238
0
    Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
239
0
    ber_write_length(s, length);
240
0
  }
241
0
}
242
243
BOOL ber_read_contextual_tag(wStream* s, BYTE tag, size_t* length, BOOL pc)
244
0
{
245
0
  const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
246
0
  BYTE byte = 0;
247
248
0
  WINPR_ASSERT(s);
249
0
  WINPR_ASSERT(length);
250
251
0
  if (Stream_GetRemainingLength(s) < 1)
252
0
  {
253
0
    WLog_VRB(TAG, "short data, got %" PRIuz ", expected %u", Stream_GetRemainingLength(s), 1u);
254
0
    return FALSE;
255
0
  }
256
257
0
  Stream_Read_UINT8(s, byte);
258
259
0
  if (byte != expect)
260
0
  {
261
0
    WLog_VRB(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
262
0
    Stream_Rewind(s, 1);
263
0
    return FALSE;
264
0
  }
265
266
0
  return ber_read_length(s, length);
267
0
}
268
269
size_t ber_write_contextual_tag(wStream* s, BYTE tag, size_t length, BOOL pc)
270
0
{
271
0
  WINPR_ASSERT(s);
272
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
273
0
  Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
274
0
  return 1 + ber_write_length(s, length);
275
0
}
276
277
size_t ber_sizeof_contextual_tag(size_t length)
278
0
{
279
0
  return 1 + _ber_sizeof_length(length);
280
0
}
281
282
BOOL ber_read_sequence_tag(wStream* s, size_t* length)
283
0
{
284
0
  const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
285
0
  BYTE byte = 0;
286
287
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
288
0
    return FALSE;
289
290
0
  Stream_Read_UINT8(s, byte);
291
292
0
  if (byte != expect)
293
0
  {
294
0
    WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
295
0
    return FALSE;
296
0
  }
297
298
0
  return ber_read_length(s, length);
299
0
}
300
301
/**
302
 * Write BER SEQUENCE tag.
303
 * @param s stream
304
 * @param length length
305
 */
306
307
size_t ber_write_sequence_tag(wStream* s, size_t length)
308
0
{
309
0
  Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
310
0
  return 1 + ber_write_length(s, length);
311
0
}
312
313
size_t ber_sizeof_sequence(size_t length)
314
0
{
315
0
  return 1 + _ber_sizeof_length(length) + length;
316
0
}
317
318
size_t ber_sizeof_sequence_tag(size_t length)
319
0
{
320
0
  return 1 + _ber_sizeof_length(length);
321
0
}
322
323
BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
324
0
{
325
0
  size_t length = 0;
326
327
0
  WINPR_ASSERT(enumerated);
328
329
0
  if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
330
0
    return FALSE;
331
332
0
  if (length != 1)
333
0
  {
334
0
    WLog_WARN(TAG, "short data, got %" PRIuz ", expected %u", length, 1u);
335
0
    return FALSE;
336
0
  }
337
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
338
0
    return FALSE;
339
340
0
  Stream_Read_UINT8(s, *enumerated);
341
342
  /* check that enumerated value falls within expected range */
343
0
  if (*enumerated + 1 > count)
344
0
  {
345
0
    WLog_WARN(TAG, "invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
346
0
    return FALSE;
347
0
  }
348
349
0
  return TRUE;
350
0
}
351
352
void ber_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
353
0
{
354
0
  ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
355
0
  ber_write_length(s, 1);
356
0
  Stream_Write_UINT8(s, enumerated);
357
0
}
358
359
BOOL ber_read_bit_string(wStream* s, size_t* length, BYTE* padding)
360
0
{
361
0
  if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
362
0
    return FALSE;
363
364
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
365
0
    return FALSE;
366
367
0
  Stream_Read_UINT8(s, *padding);
368
0
  return TRUE;
369
0
}
370
371
/**
372
 * Write a BER OCTET_STRING
373
 * @param s stream
374
 * @param oct_str octet string
375
 * @param length string length
376
 */
377
378
size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length)
379
0
{
380
0
  size_t size = 0;
381
382
0
  WINPR_ASSERT(oct_str || (length == 0));
383
0
  size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
384
0
  size += ber_write_length(s, length);
385
0
  Stream_Write(s, oct_str, length);
386
0
  size += length;
387
0
  return size;
388
0
}
389
390
size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, size_t length)
391
0
{
392
0
  size_t inner = ber_sizeof_octet_string(length);
393
0
  size_t ret = 0;
394
0
  size_t r = 0;
395
396
0
  ret = ber_write_contextual_tag(s, tag, inner, TRUE);
397
0
  if (!ret)
398
0
    return 0;
399
400
0
  r = ber_write_octet_string(s, oct_str, length);
401
0
  if (!r)
402
0
    return 0;
403
0
  return ret + r;
404
0
}
405
406
size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str)
407
0
{
408
0
  WINPR_ASSERT(str);
409
0
  size_t size = 0;
410
0
  size_t length = strlen(str) + 1;
411
0
  size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
412
0
  size += ber_write_length(s, length * sizeof(WCHAR));
413
414
0
  if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
415
0
    return 0;
416
0
  return size + length * sizeof(WCHAR);
417
0
}
418
419
size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str)
420
0
{
421
0
  WINPR_ASSERT(str);
422
0
  size_t len = _wcslen(str) * sizeof(WCHAR);
423
0
  size_t inner_len = ber_sizeof_octet_string(len);
424
0
  size_t ret = 0;
425
426
0
  ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
427
0
  return ret + ber_write_octet_string(s, (const BYTE*)str, len);
428
0
}
429
430
size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, const char* str)
431
0
{
432
0
  size_t ret = 0;
433
0
  size_t len = strlen(str);
434
0
  size_t inner_len = ber_sizeof_octet_string(len * 2);
435
436
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
437
438
0
  ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
439
0
  ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
440
0
  ret += ber_write_length(s, len * sizeof(WCHAR));
441
442
0
  if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
443
0
    return 0;
444
445
0
  return ret + len;
446
0
}
447
448
BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str)
449
0
{
450
0
  LPWSTR ret = nullptr;
451
0
  size_t length = 0;
452
453
0
  if (!ber_read_octet_string_tag(s, &length))
454
0
    return FALSE;
455
456
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
457
0
    return FALSE;
458
459
0
  ret = calloc(1, length + 2);
460
0
  if (!ret)
461
0
    return FALSE;
462
463
0
  memcpy(ret, Stream_ConstPointer(s), length);
464
0
  ret[length / 2] = 0;
465
0
  Stream_Seek(s, length);
466
0
  *str = ret;
467
0
  return TRUE;
468
0
}
469
470
BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str)
471
0
{
472
0
  size_t length = 0;
473
0
  char* ptr = nullptr;
474
475
0
  *str = nullptr;
476
0
  if (!ber_read_octet_string_tag(s, &length))
477
0
    return FALSE;
478
479
0
  ptr = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), nullptr);
480
0
  if (!ptr)
481
0
    return FALSE;
482
0
  *str = ptr;
483
0
  return TRUE;
484
0
}
485
486
BOOL ber_read_octet_string_tag(wStream* s, size_t* length)
487
0
{
488
0
  return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
489
0
}
490
491
BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length)
492
0
{
493
0
  BYTE* ret = nullptr;
494
495
0
  WINPR_ASSERT(s);
496
0
  WINPR_ASSERT(content);
497
0
  WINPR_ASSERT(length);
498
499
0
  if (!ber_read_octet_string_tag(s, length))
500
0
    return FALSE;
501
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
502
0
    return FALSE;
503
504
0
  ret = malloc(*length);
505
0
  if (!ret)
506
0
    return FALSE;
507
508
0
  Stream_Read(s, ret, *length);
509
0
  *content = ret;
510
0
  return TRUE;
511
0
}
512
513
size_t ber_write_octet_string_tag(wStream* s, size_t length)
514
0
{
515
0
  if (ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) == 0)
516
0
    return 0;
517
0
  if (ber_write_length(s, length) == 0)
518
0
    return 0;
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 nullptr
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 %u", length, 1u);
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 != 0);
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 == nullptr)
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
    if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
645
0
      return 0;
646
0
    if (ber_write_length(s, 1) == 0)
647
0
      return 0;
648
649
0
    Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
650
0
    return 3;
651
0
  }
652
0
  else if (value < 0x8000)
653
0
  {
654
0
    if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
655
0
      return 0;
656
0
    if (ber_write_length(s, 2) == 0)
657
0
      return 0;
658
659
0
    Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
660
0
    return 4;
661
0
  }
662
0
  else if (value < 0x800000)
663
0
  {
664
0
    if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
665
0
      return 0;
666
0
    if (ber_write_length(s, 3) == 0)
667
0
      return 0;
668
669
0
    Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
670
0
    Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
671
0
    return 5;
672
0
  }
673
0
  else if (value < 0x80000000)
674
0
  {
675
0
    if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
676
0
      return 0;
677
0
    if (ber_write_length(s, 4) == 0)
678
0
      return 0;
679
680
0
    Stream_Write_UINT32_BE(s, value);
681
0
    return 6;
682
0
  }
683
0
  else
684
0
  {
685
    /* treat as signed integer i.e. NT/HRESULT error codes */
686
0
    if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
687
0
      return 0;
688
0
    if (ber_write_length(s, 4) == 0)
689
0
      return 0;
690
691
0
    Stream_Write_UINT32_BE(s, value);
692
0
    return 6;
693
0
  }
694
0
}
695
696
size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
697
0
{
698
0
  size_t len = ber_sizeof_integer(value);
699
700
0
  WINPR_ASSERT(s);
701
702
0
  WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
703
704
0
  len += ber_write_contextual_tag(s, tag, len, TRUE);
705
0
  if (ber_write_integer(s, value) == 0)
706
0
    return 0;
707
0
  return len;
708
0
}
709
710
size_t ber_sizeof_integer(UINT32 value)
711
0
{
712
0
  if (value < 0x80)
713
0
  {
714
0
    return 3;
715
0
  }
716
0
  else if (value < 0x8000)
717
0
  {
718
0
    return 4;
719
0
  }
720
0
  else if (value < 0x800000)
721
0
  {
722
0
    return 5;
723
0
  }
724
0
  else if (value < 0x80000000)
725
0
  {
726
0
    return 6;
727
0
  }
728
0
  else
729
0
  {
730
    /* treat as signed integer i.e. NT/HRESULT error codes */
731
0
    return 6;
732
0
  }
733
0
}
734
735
size_t ber_sizeof_contextual_integer(UINT32 value)
736
0
{
737
0
  size_t intSize = ber_sizeof_integer(value);
738
0
  return ber_sizeof_contextual_tag(intSize) + intSize;
739
0
}
740
741
BOOL ber_read_integer_length(wStream* s, size_t* length)
742
0
{
743
0
  return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
744
0
}