1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * ASN.1 Packed 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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <freerdp/crypto/per.h>
25
26 /**
27 * Read PER length.
28 * @param s stream
29 * @param length length
30 * @return
31 */
32
per_read_length(wStream * s,UINT16 * length)33 BOOL per_read_length(wStream* s, UINT16* length)
34 {
35 BYTE byte;
36
37 if (Stream_GetRemainingLength(s) < 1)
38 return FALSE;
39
40 Stream_Read_UINT8(s, byte);
41
42 if (byte & 0x80)
43 {
44 if (Stream_GetRemainingLength(s) < 1)
45 return FALSE;
46
47 byte &= ~(0x80);
48 *length = (byte << 8);
49 Stream_Read_UINT8(s, byte);
50 *length += byte;
51 }
52 else
53 {
54 *length = byte;
55 }
56
57 return TRUE;
58 }
59
60 /**
61 * Write PER length.
62 * @param s stream
63 * @param length length
64 */
65
per_write_length(wStream * s,int length)66 void per_write_length(wStream* s, int length)
67 {
68 if (length > 0x7F)
69 Stream_Write_UINT16_BE(s, (length | 0x8000));
70 else
71 Stream_Write_UINT8(s, length);
72 }
73
74 /**
75 * Read PER choice.
76 * @param s stream
77 * @param choice choice
78 * @return
79 */
80
per_read_choice(wStream * s,BYTE * choice)81 BOOL per_read_choice(wStream* s, BYTE* choice)
82 {
83 if (Stream_GetRemainingLength(s) < 1)
84 return FALSE;
85
86 Stream_Read_UINT8(s, *choice);
87 return TRUE;
88 }
89
90 /**
91 * Write PER CHOICE.
92 * @param s stream
93 * @param choice index of chosen field
94 */
95
per_write_choice(wStream * s,BYTE choice)96 void per_write_choice(wStream* s, BYTE choice)
97 {
98 Stream_Write_UINT8(s, choice);
99 }
100
101 /**
102 * Read PER selection.
103 * @param s stream
104 * @param selection selection
105 * @return
106 */
107
per_read_selection(wStream * s,BYTE * selection)108 BOOL per_read_selection(wStream* s, BYTE* selection)
109 {
110 if (Stream_GetRemainingLength(s) < 1)
111 return FALSE;
112
113 Stream_Read_UINT8(s, *selection);
114 return TRUE;
115 }
116
117 /**
118 * Write PER selection for OPTIONAL fields.
119 * @param s stream
120 * @param selection bit map of selected fields
121 */
122
per_write_selection(wStream * s,BYTE selection)123 void per_write_selection(wStream* s, BYTE selection)
124 {
125 Stream_Write_UINT8(s, selection);
126 }
127
128 /**
129 * Read PER number of sets.
130 * @param s stream
131 * @param number number of sets
132 * @return
133 */
134
per_read_number_of_sets(wStream * s,BYTE * number)135 BOOL per_read_number_of_sets(wStream* s, BYTE* number)
136 {
137 if (Stream_GetRemainingLength(s) < 1)
138 return FALSE;
139
140 Stream_Read_UINT8(s, *number);
141 return TRUE;
142 }
143
144 /**
145 * Write PER number of sets for SET OF.
146 * @param s stream
147 * @param number number of sets
148 */
149
per_write_number_of_sets(wStream * s,BYTE number)150 void per_write_number_of_sets(wStream* s, BYTE number)
151 {
152 Stream_Write_UINT8(s, number);
153 }
154
155 /**
156 * Read PER padding with zeros.
157 * @param s stream
158 * @param length
159 */
160
per_read_padding(wStream * s,int length)161 BOOL per_read_padding(wStream* s, int length)
162 {
163 if (((int)Stream_GetRemainingLength(s)) < length)
164 return FALSE;
165
166 Stream_Seek(s, length);
167 return TRUE;
168 }
169
170 /**
171 * Write PER padding with zeros.
172 * @param s stream
173 * @param length
174 */
175
per_write_padding(wStream * s,int length)176 void per_write_padding(wStream* s, int length)
177 {
178 int i;
179
180 for (i = 0; i < length; i++)
181 Stream_Write_UINT8(s, 0);
182 }
183
184 /**
185 * Read PER INTEGER.
186 * @param s stream
187 * @param integer integer
188 * @return
189 */
190
per_read_integer(wStream * s,UINT32 * integer)191 BOOL per_read_integer(wStream* s, UINT32* integer)
192 {
193 UINT16 length;
194
195 if (!per_read_length(s, &length))
196 return FALSE;
197
198 if (Stream_GetRemainingLength(s) < length)
199 return FALSE;
200
201 if (length == 0)
202 *integer = 0;
203 else if (length == 1)
204 Stream_Read_UINT8(s, *integer);
205 else if (length == 2)
206 Stream_Read_UINT16_BE(s, *integer);
207 else
208 return FALSE;
209
210 return TRUE;
211 }
212
213 /**
214 * Write PER INTEGER.
215 * @param s stream
216 * @param integer integer
217 */
218
per_write_integer(wStream * s,UINT32 integer)219 void per_write_integer(wStream* s, UINT32 integer)
220 {
221 if (integer <= 0xFF)
222 {
223 per_write_length(s, 1);
224 Stream_Write_UINT8(s, integer);
225 }
226 else if (integer <= 0xFFFF)
227 {
228 per_write_length(s, 2);
229 Stream_Write_UINT16_BE(s, integer);
230 }
231 else if (integer <= 0xFFFFFFFF)
232 {
233 per_write_length(s, 4);
234 Stream_Write_UINT32_BE(s, integer);
235 }
236 }
237
238 /**
239 * Read PER INTEGER (UINT16).
240 * @param s stream
241 * @param integer integer
242 * @param min minimum value
243 * @return
244 */
245
per_read_integer16(wStream * s,UINT16 * integer,UINT16 min)246 BOOL per_read_integer16(wStream* s, UINT16* integer, UINT16 min)
247 {
248 if (Stream_GetRemainingLength(s) < 2)
249 return FALSE;
250
251 Stream_Read_UINT16_BE(s, *integer);
252
253 if (*integer + min > 0xFFFF)
254 return FALSE;
255
256 *integer += min;
257
258 return TRUE;
259 }
260
261 /**
262 * Write PER INTEGER (UINT16).
263 * @param s stream
264 * @param integer integer
265 * @param min minimum value
266 */
267
per_write_integer16(wStream * s,UINT16 integer,UINT16 min)268 void per_write_integer16(wStream* s, UINT16 integer, UINT16 min)
269 {
270 Stream_Write_UINT16_BE(s, integer - min);
271 }
272
273 /**
274 * Read PER ENUMERATED.
275 * @param s stream
276 * @param enumerated enumerated
277 * @param count enumeration count
278 * @return
279 */
280
per_read_enumerated(wStream * s,BYTE * enumerated,BYTE count)281 BOOL per_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
282 {
283 if (Stream_GetRemainingLength(s) < 1)
284 return FALSE;
285
286 Stream_Read_UINT8(s, *enumerated);
287
288 /* check that enumerated value falls within expected range */
289 if (*enumerated + 1 > count)
290 return FALSE;
291
292 return TRUE;
293 }
294
295 /**
296 * Write PER ENUMERATED.
297 * @param s stream
298 * @param enumerated enumerated
299 * @param count enumeration count
300 * @return
301 */
302
per_write_enumerated(wStream * s,BYTE enumerated,BYTE count)303 void per_write_enumerated(wStream* s, BYTE enumerated, BYTE count)
304 {
305 Stream_Write_UINT8(s, enumerated);
306 }
307
308 /**
309 * Read PER OBJECT_IDENTIFIER (OID).
310 * @param s stream
311 * @param oid object identifier (OID)
312 * @warning It works correctly only for limited set of OIDs.
313 * @return
314 */
315
per_read_object_identifier(wStream * s,BYTE oid[6])316 BOOL per_read_object_identifier(wStream* s, BYTE oid[6])
317 {
318 BYTE t12;
319 UINT16 length;
320 BYTE a_oid[6];
321
322 if (!per_read_length(s, &length))
323 return FALSE;
324
325 if (length != 5)
326 return FALSE;
327
328 if (Stream_GetRemainingLength(s) < length)
329 return FALSE;
330
331 Stream_Read_UINT8(s, t12); /* first two tuples */
332 a_oid[0] = t12 / 40;
333 a_oid[1] = t12 % 40;
334
335 Stream_Read_UINT8(s, a_oid[2]); /* tuple 3 */
336 Stream_Read_UINT8(s, a_oid[3]); /* tuple 4 */
337 Stream_Read_UINT8(s, a_oid[4]); /* tuple 5 */
338 Stream_Read_UINT8(s, a_oid[5]); /* tuple 6 */
339
340 if ((a_oid[0] == oid[0]) && (a_oid[1] == oid[1]) && (a_oid[2] == oid[2]) &&
341 (a_oid[3] == oid[3]) && (a_oid[4] == oid[4]) && (a_oid[5] == oid[5]))
342 {
343 return TRUE;
344 }
345 else
346 {
347 return FALSE;
348 }
349 }
350
351 /**
352 * Write PER OBJECT_IDENTIFIER (OID)
353 * @param s stream
354 * @param oid object identifier (oid)
355 * @warning It works correctly only for limited set of OIDs.
356 */
357
per_write_object_identifier(wStream * s,BYTE oid[6])358 void per_write_object_identifier(wStream* s, BYTE oid[6])
359 {
360 BYTE t12 = oid[0] * 40 + oid[1];
361 Stream_Write_UINT8(s, 5); /* length */
362 Stream_Write_UINT8(s, t12); /* first two tuples */
363 Stream_Write_UINT8(s, oid[2]); /* tuple 3 */
364 Stream_Write_UINT8(s, oid[3]); /* tuple 4 */
365 Stream_Write_UINT8(s, oid[4]); /* tuple 5 */
366 Stream_Write_UINT8(s, oid[5]); /* tuple 6 */
367 }
368
369 /**
370 * Write PER string.
371 * @param s stream
372 * @param str string
373 * @param length string length
374 */
375
per_write_string(wStream * s,BYTE * str,int length)376 static void per_write_string(wStream* s, BYTE* str, int length)
377 {
378 int i;
379
380 for (i = 0; i < length; i++)
381 Stream_Write_UINT8(s, str[i]);
382 }
383
384 /**
385 * Read PER OCTET_STRING.
386 * @param s stream
387 * @param oct_str octet string
388 * @param length string length
389 * @param min minimum length
390 * @return
391 */
392
per_read_octet_string(wStream * s,BYTE * oct_str,int length,int min)393 BOOL per_read_octet_string(wStream* s, BYTE* oct_str, int length, int min)
394 {
395 int i;
396 UINT16 mlength;
397 BYTE* a_oct_str;
398
399 if (!per_read_length(s, &mlength))
400 return FALSE;
401
402 if (mlength + min != length)
403 return FALSE;
404
405 if (((int)Stream_GetRemainingLength(s)) < length)
406 return FALSE;
407
408 a_oct_str = Stream_Pointer(s);
409 Stream_Seek(s, length);
410
411 for (i = 0; i < length; i++)
412 {
413 if (a_oct_str[i] != oct_str[i])
414 return FALSE;
415 }
416
417 return TRUE;
418 }
419
420 /**
421 * Write PER OCTET_STRING
422 * @param s stream
423 * @param oct_str octet string
424 * @param length string length
425 * @param min minimum string length
426 */
427
per_write_octet_string(wStream * s,BYTE * oct_str,int length,int min)428 void per_write_octet_string(wStream* s, BYTE* oct_str, int length, int min)
429 {
430 int i;
431 int mlength;
432
433 mlength = (length - min >= 0) ? length - min : min;
434
435 per_write_length(s, mlength);
436
437 for (i = 0; i < length; i++)
438 Stream_Write_UINT8(s, oct_str[i]);
439 }
440
441 /**
442 * Read PER NumericString.
443 * @param s stream
444 * @param num_str numeric string
445 * @param length string length
446 * @param min minimum string length
447 */
448
per_read_numeric_string(wStream * s,int min)449 BOOL per_read_numeric_string(wStream* s, int min)
450 {
451 int length;
452 UINT16 mlength;
453
454 if (!per_read_length(s, &mlength))
455 return FALSE;
456
457 length = (mlength + min + 1) / 2;
458
459 if (((int)Stream_GetRemainingLength(s)) < length)
460 return FALSE;
461
462 Stream_Seek(s, length);
463 return TRUE;
464 }
465
466 /**
467 * Write PER NumericString.
468 * @param s stream
469 * @param num_str numeric string
470 * @param length string length
471 * @param min minimum string length
472 */
473
per_write_numeric_string(wStream * s,BYTE * num_str,int length,int min)474 void per_write_numeric_string(wStream* s, BYTE* num_str, int length, int min)
475 {
476 int i;
477 int mlength;
478 BYTE num, c1, c2;
479
480 mlength = (length - min >= 0) ? length - min : min;
481
482 per_write_length(s, mlength);
483
484 for (i = 0; i < length; i += 2)
485 {
486 c1 = num_str[i];
487 c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
488
489 c1 = (c1 - 0x30) % 10;
490 c2 = (c2 - 0x30) % 10;
491 num = (c1 << 4) | c2;
492
493 Stream_Write_UINT8(s, num); /* string */
494 }
495 }
496