Coverage Report

Created: 2026-02-26 06:50

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