FreeRDP
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 
39 BOOL 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 
75 BOOL 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 
100 BOOL 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 
117 BOOL 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 
133 BOOL 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 
151 BOOL 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 
167 BOOL 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 
186 BOOL 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 
203 BOOL 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 
220 BOOL 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 
236 BOOL 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 
268 BOOL 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 
307 BOOL 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 
335 BOOL 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 
355 BOOL 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 
383 BOOL per_write_enumerated(wStream* s, BYTE enumerated, BYTE count)
384 {
385  if (!Stream_EnsureRemainingCapacity(s, 1))
386  return FALSE;
387  Stream_Write_UINT8(s, enumerated);
388  return TRUE;
389 }
390 
391 static 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 
419 BOOL 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 
458 BOOL 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 
479 static void per_write_string(wStream* s, BYTE* str, int length)
480 {
481  for (int i = 0; i < length; i++)
482  Stream_Write_UINT8(s, str[i]);
483 }
484 
496 BOOL per_read_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
497 {
498  UINT16 mlength = 0;
499 
500  if (!per_read_length(s, &mlength))
501  return FALSE;
502 
503  if (mlength + min != length)
504  {
505  WLog_ERR(TAG, "length mismatch: %" PRIu16 "!= %" PRIu16, mlength + min, length);
506  return FALSE;
507  }
508 
509  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
510  return FALSE;
511 
512  const BYTE* a_oct_str = Stream_ConstPointer(s);
513  Stream_Seek(s, length);
514 
515  return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
516 }
517 
528 BOOL per_write_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
529 {
530  UINT16 mlength = 0;
531 
532  mlength = (length >= min) ? length - min : min;
533 
534  if (!per_write_length(s, mlength))
535  return FALSE;
536 
537  if (!Stream_EnsureRemainingCapacity(s, length))
538  return FALSE;
539  for (UINT16 i = 0; i < length; i++)
540  Stream_Write_UINT8(s, oct_str[i]);
541  return TRUE;
542 }
543 
552 BOOL per_read_numeric_string(wStream* s, UINT16 min)
553 {
554  size_t length = 0;
555  UINT16 mlength = 0;
556 
557  if (!per_read_length(s, &mlength))
558  return FALSE;
559 
560  length = (mlength + min + 1) / 2;
561 
562  if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
563  return FALSE;
564 
565  Stream_Seek(s, length);
566  return TRUE;
567 }
568 
579 BOOL per_write_numeric_string(wStream* s, const BYTE* num_str, UINT16 length, UINT16 min)
580 {
581  WINPR_ASSERT(num_str || (length == 0));
582 
583  const UINT16 mlength = (length >= min) ? length - min : min;
584 
585  if (!per_write_length(s, mlength))
586  return FALSE;
587 
588  if (!Stream_EnsureRemainingCapacity(s, length))
589  return FALSE;
590  for (UINT16 i = 0; i < length; i += 2)
591  {
592  BYTE c1 = num_str[i];
593  BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
594 
595  if ((c1 < 0x30) || (c2 < 0x30))
596  return FALSE;
597 
598  c1 = (c1 - 0x30) % 10;
599  c2 = (c2 - 0x30) % 10;
600  const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
601 
602  Stream_Write_UINT8(s, num); /* string */
603  }
604  return TRUE;
605 }