Coverage Report

Created: 2023-09-25 06:56

/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/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
0
{
34
0
  BYTE byte;
35
36
0
  WINPR_ASSERT(s);
37
0
  WINPR_ASSERT(length);
38
39
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
40
0
    return FALSE;
41
42
0
  Stream_Read_UINT8(s, byte);
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;
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;
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;
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 %" PRIuz, Stream_GetRemainingLength(s),
254
0
             1);
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;
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;
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 %" PRIuz, length, 1);
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, 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, r;
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;
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;
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 = NULL;
451
0
  size_t length;
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;
473
0
  char* ptr;
474
475
0
  *str = NULL;
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), NULL);
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;
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
  ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
516
0
  ber_write_length(s, length);
517
0
  return 1 + _ber_sizeof_length(length);
518
0
}
519
520
size_t ber_sizeof_octet_string(size_t length)
521
0
{
522
0
  return 1 + _ber_sizeof_length(length) + length;
523
0
}
524
525
size_t ber_sizeof_contextual_octet_string(size_t length)
526
0
{
527
0
  size_t ret = ber_sizeof_octet_string(length);
528
0
  return ber_sizeof_contextual_tag(ret) + ret;
529
0
}
530
531
/** \brief Read a BER BOOLEAN
532
 *
533
 * @param s The stream to read from.
534
 * @param value A pointer to the value read, must not be NULL
535
 *
536
 * \return \b TRUE for success, \b FALSE for any failure
537
 */
538
539
BOOL ber_read_BOOL(wStream* s, BOOL* value)
540
0
{
541
0
  size_t length;
542
0
  BYTE v;
543
544
0
  WINPR_ASSERT(value);
545
0
  if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
546
0
    return FALSE;
547
548
0
  if (length != 1)
549
0
  {
550
0
    WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
551
0
    return FALSE;
552
0
  }
553
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
554
0
    return FALSE;
555
556
0
  Stream_Read_UINT8(s, v);
557
0
  *value = (v ? TRUE : FALSE);
558
0
  return TRUE;
559
0
}
560
561
/**
562
 * Write a BER BOOLEAN
563
 *
564
 * @param s A pointer to the stream to write to
565
 * @param value The value to write
566
 */
567
568
void ber_write_BOOL(wStream* s, BOOL value)
569
0
{
570
0
  ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
571
0
  ber_write_length(s, 1);
572
0
  Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
573
0
}
574
575
BOOL ber_read_integer(wStream* s, UINT32* value)
576
0
{
577
0
  size_t length;
578
579
0
  WINPR_ASSERT(s);
580
581
0
  if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
582
0
    return FALSE;
583
0
  if (!ber_read_length(s, &length))
584
0
    return FALSE;
585
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
586
0
    return FALSE;
587
588
0
  if (value == NULL)
589
0
  {
590
    // even if we don't care the integer value, check the announced size
591
0
    return Stream_SafeSeek(s, length);
592
0
  }
593
594
0
  if (length == 1)
595
0
  {
596
0
    Stream_Read_UINT8(s, *value);
597
0
  }
598
0
  else if (length == 2)
599
0
  {
600
0
    Stream_Read_UINT16_BE(s, *value);
601
0
  }
602
0
  else if (length == 3)
603
0
  {
604
0
    BYTE byte;
605
0
    Stream_Read_UINT8(s, byte);
606
0
    Stream_Read_UINT16_BE(s, *value);
607
0
    *value += (byte << 16);
608
0
  }
609
0
  else if (length == 4)
610
0
  {
611
0
    Stream_Read_UINT32_BE(s, *value);
612
0
  }
613
0
  else if (length == 8)
614
0
  {
615
0
    WLog_ERR(TAG, "should implement reading an 8 bytes integer");
616
0
    return FALSE;
617
0
  }
618
0
  else
619
0
  {
620
0
    WLog_ERR(TAG, "should implement reading an integer with length=%" PRIuz, length);
621
0
    return FALSE;
622
0
  }
623
624
0
  return TRUE;
625
0
}
626
627
/**
628
 * Write a BER INTEGER
629
 *
630
 * @param s A pointer to the stream to write to
631
 * @param value The value to write
632
 *
633
 * @return The size in bytes that were written
634
 */
635
636
size_t ber_write_integer(wStream* s, UINT32 value)
637
0
{
638
0
  WINPR_ASSERT(s);
639
640
0
  if (value < 0x80)
641
0
  {
642
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
643
0
    ber_write_length(s, 1);
644
645
0
    Stream_Write_UINT8(s, value);
646
0
    return 3;
647
0
  }
648
0
  else if (value < 0x8000)
649
0
  {
650
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
651
0
    ber_write_length(s, 2);
652
653
0
    Stream_Write_UINT16_BE(s, value);
654
0
    return 4;
655
0
  }
656
0
  else if (value < 0x800000)
657
0
  {
658
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
659
0
    ber_write_length(s, 3);
660
661
0
    Stream_Write_UINT8(s, (value >> 16));
662
0
    Stream_Write_UINT16_BE(s, (value & 0xFFFF));
663
0
    return 5;
664
0
  }
665
0
  else if (value < 0x80000000)
666
0
  {
667
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
668
0
    ber_write_length(s, 4);
669
670
0
    Stream_Write_UINT32_BE(s, value);
671
0
    return 6;
672
0
  }
673
0
  else
674
0
  {
675
    /* treat as signed integer i.e. NT/HRESULT error codes */
676
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
677
0
    ber_write_length(s, 4);
678
679
0
    Stream_Write_UINT32_BE(s, value);
680
0
    return 6;
681
0
  }
682
0
}
683
684
size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
685
0
{
686
0
  size_t len = ber_sizeof_integer(value);
687
688
0
  WINPR_ASSERT(s);
689
690
0
  WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
691
692
0
  len += ber_write_contextual_tag(s, tag, len, TRUE);
693
0
  ber_write_integer(s, value);
694
0
  return len;
695
0
}
696
697
size_t ber_sizeof_integer(UINT32 value)
698
0
{
699
0
  if (value < 0x80)
700
0
  {
701
0
    return 3;
702
0
  }
703
0
  else if (value < 0x8000)
704
0
  {
705
0
    return 4;
706
0
  }
707
0
  else if (value < 0x800000)
708
0
  {
709
0
    return 5;
710
0
  }
711
0
  else if (value < 0x80000000)
712
0
  {
713
0
    return 6;
714
0
  }
715
0
  else
716
0
  {
717
    /* treat as signed integer i.e. NT/HRESULT error codes */
718
0
    return 6;
719
0
  }
720
0
}
721
722
size_t ber_sizeof_contextual_integer(UINT32 value)
723
0
{
724
0
  size_t intSize = ber_sizeof_integer(value);
725
0
  return ber_sizeof_contextual_tag(intSize) + intSize;
726
0
}
727
728
BOOL ber_read_integer_length(wStream* s, size_t* length)
729
0
{
730
0
  return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
731
0
}