FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 " > %" PRIu16, *integer,
317 UINT16_MAX - min);
318 return FALSE;
319 }
320
321 *integer += min;
322
323 return TRUE;
324}
325
335BOOL per_write_integer16(wStream* s, UINT16 integer, UINT16 min)
336{
337 if (min > integer)
338 return FALSE;
339 if (!Stream_EnsureRemainingCapacity(s, 2))
340 return FALSE;
341 Stream_Write_UINT16_BE(s, integer - min);
342 return TRUE;
343}
344
355BOOL per_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
356{
357 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
358 return FALSE;
359
360 WINPR_ASSERT(enumerated);
361 Stream_Read_UINT8(s, *enumerated);
362
363 /* check that enumerated value falls within expected range */
364 if (*enumerated + 1 > count)
365 {
366 WLog_WARN(TAG, "PER invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
367 return FALSE;
368 }
369
370 return TRUE;
371}
372
383BOOL per_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
384{
385 if (!Stream_EnsureRemainingCapacity(s, 1))
386 return FALSE;
387 Stream_Write_UINT8(s, enumerated);
388 return TRUE;
389}
390
391static BOOL per_check_oid_and_log_mismatch(const BYTE* got, const BYTE* expect, size_t length)
392{
393 if (memcmp(got, expect, length) == 0)
394 {
395 return TRUE;
396 }
397 else
398 {
399 char* got_str = winpr_BinToHexString(got, length, TRUE);
400 char* expect_str = winpr_BinToHexString(expect, length, TRUE);
401
402 WLog_WARN(TAG, "PER OID mismatch, got %s, expected %s", got_str, expect_str);
403 free(got_str);
404 free(expect_str);
405 return FALSE;
406 }
407}
408
419BOOL per_read_object_identifier(wStream* s, const BYTE oid[6])
420{
421 BYTE t12 = 0;
422 UINT16 length = 0;
423 BYTE a_oid[6] = { 0 };
424
425 if (!per_read_length(s, &length))
426 return FALSE;
427
428 if (length != 5)
429 {
430 WLog_WARN(TAG, "PER length, got %" PRIu16 ", expected 5", length);
431 return FALSE;
432 }
433
434 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
435 return FALSE;
436
437 Stream_Read_UINT8(s, t12); /* first two tuples */
438 a_oid[0] = t12 / 40;
439 a_oid[1] = t12 % 40;
440
441 Stream_Read_UINT8(s, a_oid[2]); /* tuple 3 */
442 Stream_Read_UINT8(s, a_oid[3]); /* tuple 4 */
443 Stream_Read_UINT8(s, a_oid[4]); /* tuple 5 */
444 Stream_Read_UINT8(s, a_oid[5]); /* tuple 6 */
445
446 return per_check_oid_and_log_mismatch(a_oid, oid, sizeof(a_oid));
447}
448
458BOOL per_write_object_identifier(wStream* s, const BYTE oid[6])
459{
460 BYTE t12 = oid[0] * 40 + oid[1];
461 if (!Stream_EnsureRemainingCapacity(s, 6))
462 return FALSE;
463 Stream_Write_UINT8(s, 5); /* length */
464 Stream_Write_UINT8(s, t12); /* first two tuples */
465 Stream_Write_UINT8(s, oid[2]); /* tuple 3 */
466 Stream_Write_UINT8(s, oid[3]); /* tuple 4 */
467 Stream_Write_UINT8(s, oid[4]); /* tuple 5 */
468 Stream_Write_UINT8(s, oid[5]); /* tuple 6 */
469 return TRUE;
470}
471
483BOOL per_read_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
484{
485 UINT16 mlength = 0;
486
487 if (!per_read_length(s, &mlength))
488 return FALSE;
489
490 if (mlength + min != length)
491 {
492 WLog_ERR(TAG, "length mismatch: %" PRIu16 "!= %" PRIu16, mlength + min, length);
493 return FALSE;
494 }
495
496 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
497 return FALSE;
498
499 const BYTE* a_oct_str = Stream_ConstPointer(s);
500 Stream_Seek(s, length);
501
502 return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
503}
504
515BOOL per_write_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
516{
517 UINT16 mlength = 0;
518
519 mlength = (length >= min) ? length - min : min;
520
521 if (!per_write_length(s, mlength))
522 return FALSE;
523
524 if (!Stream_EnsureRemainingCapacity(s, length))
525 return FALSE;
526 for (UINT16 i = 0; i < length; i++)
527 Stream_Write_UINT8(s, oct_str[i]);
528 return TRUE;
529}
530
539BOOL per_read_numeric_string(wStream* s, UINT16 min)
540{
541 size_t length = 0;
542 UINT16 mlength = 0;
543
544 if (!per_read_length(s, &mlength))
545 return FALSE;
546
547 length = (mlength + min + 1) / 2;
548
549 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
550 return FALSE;
551
552 Stream_Seek(s, length);
553 return TRUE;
554}
555
566BOOL per_write_numeric_string(wStream* s, const BYTE* num_str, UINT16 length, UINT16 min)
567{
568 WINPR_ASSERT(num_str || (length == 0));
569
570 const UINT16 mlength = (length >= min) ? length - min : min;
571
572 if (!per_write_length(s, mlength))
573 return FALSE;
574
575 if (!Stream_EnsureRemainingCapacity(s, length))
576 return FALSE;
577 for (UINT16 i = 0; i < length; i += 2)
578 {
579 BYTE c1 = num_str[i];
580 BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
581
582 if ((c1 < 0x30) || (c2 < 0x30))
583 return FALSE;
584
585 c1 = (c1 - 0x30) % 10;
586 c2 = (c2 - 0x30) % 10;
587 const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
588
589 Stream_Write_UINT8(s, num); /* string */
590 }
591 return TRUE;
592}