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