Coverage Report

Created: 2024-05-20 06:11

/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
6.65k
{
34
6.65k
  BYTE byte = 0;
35
36
6.65k
  WINPR_ASSERT(s);
37
6.65k
  WINPR_ASSERT(length);
38
39
6.65k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
40
27
    return FALSE;
41
42
6.62k
  Stream_Read_UINT8(s, byte);
43
44
6.62k
  if (byte & 0x80)
45
196
  {
46
196
    byte &= ~(0x80);
47
48
196
    if (!Stream_CheckAndLogRequiredLength(TAG, s, byte))
49
20
      return FALSE;
50
51
176
    if (byte == 1)
52
55
      Stream_Read_UINT8(s, *length);
53
121
    else if (byte == 2)
54
65
      Stream_Read_UINT16_BE(s, *length);
55
56
    else
56
56
    {
57
56
      WLog_ERR(TAG, "ber: unexpected byte 0x%02" PRIx8 ", expected [1,2]", byte);
58
56
      return FALSE;
59
56
    }
60
176
  }
61
6.43k
  else
62
6.43k
  {
63
6.43k
    *length = byte;
64
6.43k
  }
65
66
6.55k
  return TRUE;
67
6.62k
}
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
5.48k
{
124
5.48k
  BYTE byte = 0;
125
5.48k
  const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
126
127
5.48k
  WINPR_ASSERT(s);
128
129
5.48k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
130
53
    return FALSE;
131
132
5.43k
  Stream_Read_UINT8(s, byte);
133
134
5.43k
  if (byte != expect)
135
201
  {
136
201
    WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
137
201
    return FALSE;
138
201
  }
139
140
5.23k
  return TRUE;
141
5.43k
}
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
1.89k
{
166
1.89k
  BYTE byte = 0;
167
168
1.89k
  WINPR_ASSERT(s);
169
1.89k
  WINPR_ASSERT(length);
170
171
1.89k
  if (tag > 30)
172
1.89k
  {
173
1.89k
    const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
174
175
1.89k
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
176
4
      return FALSE;
177
178
1.88k
    Stream_Read_UINT8(s, byte);
179
180
1.88k
    if (byte != expect)
181
60
    {
182
60
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
183
60
      return FALSE;
184
60
    }
185
186
1.82k
    Stream_Read_UINT8(s, byte);
187
188
1.82k
    if (byte != tag)
189
933
    {
190
933
      WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, tag);
191
933
      return FALSE;
192
933
    }
193
194
893
    return ber_read_length(s, length);
195
1.82k
  }
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
1.89k
}
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 %" 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
752
{
285
752
  const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
286
752
  BYTE byte = 0;
287
288
752
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
289
22
    return FALSE;
290
291
730
  Stream_Read_UINT8(s, byte);
292
293
730
  if (byte != expect)
294
197
  {
295
197
    WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
296
197
    return FALSE;
297
197
  }
298
299
533
  return ber_read_length(s, length);
300
730
}
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
389
{
326
389
  size_t length = 0;
327
328
389
  WINPR_ASSERT(enumerated);
329
330
389
  if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
331
36
    return FALSE;
332
333
353
  if (length != 1)
334
23
  {
335
23
    WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
336
23
    return FALSE;
337
23
  }
338
330
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
339
2
    return FALSE;
340
341
328
  Stream_Read_UINT8(s, *enumerated);
342
343
  /* check that enumerated value falls within expected range */
344
328
  if (*enumerated + 1 > count)
345
15
  {
346
15
    WLog_WARN(TAG, "invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
347
15
    return FALSE;
348
15
  }
349
350
313
  return TRUE;
351
328
}
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 = 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
1.01k
{
489
1.01k
  return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
490
1.01k
}
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
  ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
517
0
  ber_write_length(s, length);
518
0
  return 1 + _ber_sizeof_length(length);
519
0
}
520
521
size_t ber_sizeof_octet_string(size_t length)
522
0
{
523
0
  return 1 + _ber_sizeof_length(length) + length;
524
0
}
525
526
size_t ber_sizeof_contextual_octet_string(size_t length)
527
0
{
528
0
  size_t ret = ber_sizeof_octet_string(length);
529
0
  return ber_sizeof_contextual_tag(ret) + ret;
530
0
}
531
532
/** \brief Read a BER BOOLEAN
533
 *
534
 * @param s The stream to read from.
535
 * @param value A pointer to the value read, must not be NULL
536
 *
537
 * \return \b TRUE for success, \b FALSE for any failure
538
 */
539
540
BOOL ber_read_BOOL(wStream* s, BOOL* value)
541
368
{
542
368
  size_t length = 0;
543
368
  BYTE v = 0;
544
545
368
  WINPR_ASSERT(value);
546
368
  if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
547
47
    return FALSE;
548
549
321
  if (length != 1)
550
33
  {
551
33
    WLog_WARN(TAG, "short data, got %" PRIuz ", expected %" PRIuz, length, 1);
552
33
    return FALSE;
553
33
  }
554
288
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
555
2
    return FALSE;
556
557
286
  Stream_Read_UINT8(s, v);
558
286
  *value = (v ? TRUE : FALSE);
559
286
  return TRUE;
560
288
}
561
562
/**
563
 * Write a BER BOOLEAN
564
 *
565
 * @param s A pointer to the stream to write to
566
 * @param value The value to write
567
 */
568
569
void ber_write_BOOL(wStream* s, BOOL value)
570
0
{
571
0
  ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
572
0
  ber_write_length(s, 1);
573
0
  Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
574
0
}
575
576
BOOL ber_read_integer(wStream* s, UINT32* value)
577
3.70k
{
578
3.70k
  size_t length = 0;
579
580
3.70k
  WINPR_ASSERT(s);
581
582
3.70k
  if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
583
118
    return FALSE;
584
3.59k
  if (!ber_read_length(s, &length))
585
25
    return FALSE;
586
3.56k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
587
8
    return FALSE;
588
589
3.55k
  if (value == NULL)
590
0
  {
591
    // even if we don't care the integer value, check the announced size
592
0
    return Stream_SafeSeek(s, length);
593
0
  }
594
595
3.55k
  if (length == 1)
596
117
  {
597
117
    Stream_Read_UINT8(s, *value);
598
117
  }
599
3.44k
  else if (length == 2)
600
3.01k
  {
601
3.01k
    Stream_Read_UINT16_BE(s, *value);
602
3.01k
  }
603
427
  else if (length == 3)
604
83
  {
605
83
    BYTE byte = 0;
606
83
    Stream_Read_UINT8(s, byte);
607
83
    Stream_Read_UINT16_BE(s, *value);
608
83
    *value += (byte << 16);
609
83
  }
610
344
  else if (length == 4)
611
280
  {
612
280
    Stream_Read_UINT32_BE(s, *value);
613
280
  }
614
64
  else if (length == 8)
615
6
  {
616
6
    WLog_ERR(TAG, "should implement reading an 8 bytes integer");
617
6
    return FALSE;
618
6
  }
619
58
  else
620
58
  {
621
58
    WLog_ERR(TAG, "should implement reading an integer with length=%" PRIuz, length);
622
58
    return FALSE;
623
58
  }
624
625
3.49k
  return TRUE;
626
3.55k
}
627
628
/**
629
 * Write a BER INTEGER
630
 *
631
 * @param s A pointer to the stream to write to
632
 * @param value The value to write
633
 *
634
 * @return The size in bytes that were written
635
 */
636
637
size_t ber_write_integer(wStream* s, UINT32 value)
638
0
{
639
0
  WINPR_ASSERT(s);
640
641
0
  if (value < 0x80)
642
0
  {
643
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
644
0
    ber_write_length(s, 1);
645
646
0
    Stream_Write_UINT8(s, value);
647
0
    return 3;
648
0
  }
649
0
  else if (value < 0x8000)
650
0
  {
651
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
652
0
    ber_write_length(s, 2);
653
654
0
    Stream_Write_UINT16_BE(s, value);
655
0
    return 4;
656
0
  }
657
0
  else if (value < 0x800000)
658
0
  {
659
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
660
0
    ber_write_length(s, 3);
661
662
0
    Stream_Write_UINT8(s, (value >> 16));
663
0
    Stream_Write_UINT16_BE(s, (value & 0xFFFF));
664
0
    return 5;
665
0
  }
666
0
  else if (value < 0x80000000)
667
0
  {
668
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
669
0
    ber_write_length(s, 4);
670
671
0
    Stream_Write_UINT32_BE(s, value);
672
0
    return 6;
673
0
  }
674
0
  else
675
0
  {
676
    /* treat as signed integer i.e. NT/HRESULT error codes */
677
0
    ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE);
678
0
    ber_write_length(s, 4);
679
680
0
    Stream_Write_UINT32_BE(s, value);
681
0
    return 6;
682
0
  }
683
0
}
684
685
size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
686
0
{
687
0
  size_t len = ber_sizeof_integer(value);
688
689
0
  WINPR_ASSERT(s);
690
691
0
  WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
692
693
0
  len += ber_write_contextual_tag(s, tag, len, TRUE);
694
0
  ber_write_integer(s, value);
695
0
  return len;
696
0
}
697
698
size_t ber_sizeof_integer(UINT32 value)
699
0
{
700
0
  if (value < 0x80)
701
0
  {
702
0
    return 3;
703
0
  }
704
0
  else if (value < 0x8000)
705
0
  {
706
0
    return 4;
707
0
  }
708
0
  else if (value < 0x800000)
709
0
  {
710
0
    return 5;
711
0
  }
712
0
  else if (value < 0x80000000)
713
0
  {
714
0
    return 6;
715
0
  }
716
0
  else
717
0
  {
718
    /* treat as signed integer i.e. NT/HRESULT error codes */
719
0
    return 6;
720
0
  }
721
0
}
722
723
size_t ber_sizeof_contextual_integer(UINT32 value)
724
0
{
725
0
  size_t intSize = ber_sizeof_integer(value);
726
0
  return ber_sizeof_contextual_tag(intSize) + intSize;
727
0
}
728
729
BOOL ber_read_integer_length(wStream* s, size_t* length)
730
0
{
731
0
  return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
732
0
}