FreeRDP
Loading...
Searching...
No Matches
per.c
1
20#include <winpr/assert.h>
21#include <winpr/cast.h>
22#include <winpr/print.h>
23
24#include <freerdp/config.h>
25#include <freerdp/crypto/per.h>
26
27#include <freerdp/log.h>
28#define TAG FREERDP_TAG("crypto.per")
29
39BOOL per_read_length(wStream* s, UINT16* length)
40{
41 BYTE byte = 0;
42
43 WINPR_ASSERT(length);
44 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
45 return FALSE;
46
47 Stream_Read_UINT8(s, byte);
48
49 if (byte & 0x80)
50 {
51 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
52 return FALSE;
53
54 byte &= ~(0x80);
55 *length = WINPR_ASSERTING_INT_CAST(UINT16, byte << 8);
56 Stream_Read_UINT8(s, byte);
57 *length += byte;
58 }
59 else
60 {
61 *length = byte;
62 }
63
64 return TRUE;
65}
66
75BOOL per_write_length(wStream* s, UINT16 length)
76{
77 if (length > 0x7F)
78 {
79 if (!Stream_EnsureRemainingCapacity(s, 2))
80 return FALSE;
81 Stream_Write_UINT16_BE(s, (length | 0x8000));
82 }
83 else
84 {
85 if (!Stream_EnsureRemainingCapacity(s, 1))
86 return FALSE;
87 Stream_Write_UINT8(s, (UINT8)length);
88 }
89 return TRUE;
90}
91
100BOOL per_read_choice(wStream* s, BYTE* choice)
101{
102 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
103 return FALSE;
104
105 Stream_Read_UINT8(s, *choice);
106 return TRUE;
107}
108
117BOOL per_write_choice(wStream* s, BYTE choice)
118{
119 if (!Stream_EnsureRemainingCapacity(s, 1))
120 return FALSE;
121 Stream_Write_UINT8(s, choice);
122 return TRUE;
123}
124
133BOOL per_read_selection(wStream* s, BYTE* selection)
134{
135 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
136 return FALSE;
137
138 WINPR_ASSERT(selection);
139 Stream_Read_UINT8(s, *selection);
140 return TRUE;
141}
142
151BOOL per_write_selection(wStream* s, BYTE selection)
152{
153 if (!Stream_EnsureRemainingCapacity(s, 1))
154 return FALSE;
155 Stream_Write_UINT8(s, selection);
156 return TRUE;
157}
158
167BOOL per_read_number_of_sets(wStream* s, BYTE* number)
168{
169 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
170 return FALSE;
171
172 WINPR_ASSERT(number);
173 Stream_Read_UINT8(s, *number);
174 return TRUE;
175}
176
186BOOL per_write_number_of_sets(wStream* s, BYTE number)
187{
188 if (!Stream_EnsureRemainingCapacity(s, 1))
189 return FALSE;
190 Stream_Write_UINT8(s, number);
191 return TRUE;
192}
193
203BOOL per_read_padding(wStream* s, UINT16 length)
204{
205 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
206 return FALSE;
207
208 Stream_Seek(s, length);
209 return TRUE;
210}
211
220BOOL per_write_padding(wStream* s, UINT16 length)
221{
222 if (!Stream_EnsureRemainingCapacity(s, length))
223 return FALSE;
224 Stream_Zero(s, length);
225 return TRUE;
226}
227
236BOOL per_read_integer(wStream* s, UINT32* integer)
237{
238 UINT16 length = 0;
239
240 WINPR_ASSERT(integer);
241
242 if (!per_read_length(s, &length))
243 return FALSE;
244
245 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
246 return FALSE;
247
248 if (length == 0)
249 *integer = 0;
250 else if (length == 1)
251 Stream_Read_UINT8(s, *integer);
252 else if (length == 2)
253 Stream_Read_UINT16_BE(s, *integer);
254 else
255 return FALSE;
256
257 return TRUE;
258}
259
268BOOL per_write_integer(wStream* s, UINT32 integer)
269{
270 if (integer <= UINT8_MAX)
271 {
272 if (!per_write_length(s, 1))
273 return FALSE;
274 if (!Stream_EnsureRemainingCapacity(s, 1))
275 return FALSE;
276 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, integer));
277 }
278 else if (integer <= UINT16_MAX)
279 {
280 if (!per_write_length(s, 2))
281 return FALSE;
282 if (!Stream_EnsureRemainingCapacity(s, 2))
283 return FALSE;
284 Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, integer));
285 }
286 else if (integer <= UINT32_MAX)
287 {
288 if (!per_write_length(s, 4))
289 return FALSE;
290 if (!Stream_EnsureRemainingCapacity(s, 4))
291 return FALSE;
292 Stream_Write_UINT32_BE(s, integer);
293 }
294 return TRUE;
295}
296
307BOOL per_read_integer16(wStream* s, UINT16* integer, UINT16 min)
308{
309 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
310 return FALSE;
311
312 Stream_Read_UINT16_BE(s, *integer);
313
314 if (*integer > UINT16_MAX - min)
315 {
316 WLog_WARN(TAG, "PER uint16 invalid value %" PRIu16 " > %d", *integer, UINT16_MAX - min);
317 return FALSE;
318 }
319
320 *integer += min;
321
322 return TRUE;
323}
324
334BOOL per_write_integer16(wStream* s, UINT16 integer, UINT16 min)
335{
336 if (min > integer)
337 return FALSE;
338 if (!Stream_EnsureRemainingCapacity(s, 2))
339 return FALSE;
340 Stream_Write_UINT16_BE(s, integer - min);
341 return TRUE;
342}
343
354BOOL per_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
355{
356 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
357 return FALSE;
358
359 WINPR_ASSERT(enumerated);
360 Stream_Read_UINT8(s, *enumerated);
361
362 /* check that enumerated value falls within expected range */
363 if (*enumerated + 1 > count)
364 {
365 WLog_WARN(TAG, "PER invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
366 return FALSE;
367 }
368
369 return TRUE;
370}
371
382BOOL per_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
383{
384 if (!Stream_EnsureRemainingCapacity(s, 1))
385 return FALSE;
386 Stream_Write_UINT8(s, enumerated);
387 return TRUE;
388}
389
390static BOOL per_check_oid_and_log_mismatch(const BYTE* got, const BYTE* expect, size_t length)
391{
392 if (memcmp(got, expect, length) == 0)
393 {
394 return TRUE;
395 }
396 else
397 {
398 char* got_str = winpr_BinToHexString(got, length, TRUE);
399 char* expect_str = winpr_BinToHexString(expect, length, TRUE);
400
401 WLog_WARN(TAG, "PER OID mismatch, got %s, expected %s", got_str, expect_str);
402 free(got_str);
403 free(expect_str);
404 return FALSE;
405 }
406}
407
418BOOL per_read_object_identifier(wStream* s, const BYTE oid[6])
419{
420 BYTE t12 = 0;
421 UINT16 length = 0;
422 BYTE a_oid[6] = { 0 };
423
424 if (!per_read_length(s, &length))
425 return FALSE;
426
427 if (length != 5)
428 {
429 WLog_WARN(TAG, "PER length, got %" PRIu16 ", expected 5", length);
430 return FALSE;
431 }
432
433 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
434 return FALSE;
435
436 Stream_Read_UINT8(s, t12); /* first two tuples */
437 a_oid[0] = t12 / 40;
438 a_oid[1] = t12 % 40;
439
440 Stream_Read_UINT8(s, a_oid[2]); /* tuple 3 */
441 Stream_Read_UINT8(s, a_oid[3]); /* tuple 4 */
442 Stream_Read_UINT8(s, a_oid[4]); /* tuple 5 */
443 Stream_Read_UINT8(s, a_oid[5]); /* tuple 6 */
444
445 return per_check_oid_and_log_mismatch(a_oid, oid, sizeof(a_oid));
446}
447
457BOOL per_write_object_identifier(wStream* s, const BYTE oid[6])
458{
459 BYTE t12 = oid[0] * 40 + oid[1];
460 if (!Stream_EnsureRemainingCapacity(s, 6))
461 return FALSE;
462 Stream_Write_UINT8(s, 5); /* length */
463 Stream_Write_UINT8(s, t12); /* first two tuples */
464 Stream_Write_UINT8(s, oid[2]); /* tuple 3 */
465 Stream_Write_UINT8(s, oid[3]); /* tuple 4 */
466 Stream_Write_UINT8(s, oid[4]); /* tuple 5 */
467 Stream_Write_UINT8(s, oid[5]); /* tuple 6 */
468 return TRUE;
469}
470
482BOOL per_read_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
483{
484 UINT16 mlength = 0;
485
486 if (!per_read_length(s, &mlength))
487 return FALSE;
488
489 if (mlength + min != length)
490 {
491 WLog_ERR(TAG, "length mismatch: %d!= %" PRIu16, mlength + min, length);
492 return FALSE;
493 }
494
495 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
496 return FALSE;
497
498 const BYTE* a_oct_str = Stream_ConstPointer(s);
499 Stream_Seek(s, length);
500
501 return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
502}
503
514BOOL per_write_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
515{
516 UINT16 mlength = 0;
517
518 mlength = (length >= min) ? length - min : min;
519
520 if (!per_write_length(s, mlength))
521 return FALSE;
522
523 if (!Stream_EnsureRemainingCapacity(s, length))
524 return FALSE;
525 for (UINT16 i = 0; i < length; i++)
526 Stream_Write_UINT8(s, oct_str[i]);
527 return TRUE;
528}
529
538BOOL per_read_numeric_string(wStream* s, UINT16 min)
539{
540 size_t length = 0;
541 UINT16 mlength = 0;
542
543 if (!per_read_length(s, &mlength))
544 return FALSE;
545
546 length = (mlength + min + 1) / 2;
547
548 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
549 return FALSE;
550
551 Stream_Seek(s, length);
552 return TRUE;
553}
554
565BOOL per_write_numeric_string(wStream* s, const BYTE* num_str, UINT16 length, UINT16 min)
566{
567 WINPR_ASSERT(num_str || (length == 0));
568
569 const UINT16 mlength = (length >= min) ? length - min : min;
570
571 if (!per_write_length(s, mlength))
572 return FALSE;
573
574 if (!Stream_EnsureRemainingCapacity(s, length))
575 return FALSE;
576 for (UINT16 i = 0; i < length; i += 2)
577 {
578 BYTE c1 = num_str[i];
579 BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
580
581 if ((c1 < 0x30) || (c2 < 0x30))
582 return FALSE;
583
584 c1 = (c1 - 0x30) % 10;
585 c2 = (c2 - 0x30) % 10;
586 const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
587
588 Stream_Write_UINT8(s, num); /* string */
589 }
590 return TRUE;
591}