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