Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-core / ber.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * ASN.1 Basic 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 "ber.h"
21
22 void ber_read_length(STREAM* s, int* length)
23 {
24         uint8 byte;
25
26         stream_read_uint8(s, byte);
27
28         if (byte & 0x80)
29         {
30                 byte &= ~(0x80);
31
32                 if (byte == 1)
33                         stream_read_uint8(s, *length);
34                 if (byte == 2)
35                         stream_read_uint16_be(s, *length);
36         }
37         else
38         {
39                 *length = byte;
40         }
41 }
42
43 /**
44  * Write BER length.
45  * @param s stream
46  * @param length length
47  */
48
49 int ber_write_length(STREAM* s, int length)
50 {
51         if (length > 0x7F)
52         {
53                 stream_write_uint8(s, 0x82);
54                 stream_write_uint16_be(s, length);
55                 return 3;
56         }
57         else
58         {
59                 stream_write_uint8(s, length);
60                 return 1;
61         }
62 }
63
64 int _ber_skip_length(int length)
65 {
66         if (length > 0x7F)
67                 return 3;
68         else
69                 return 1;
70 }
71
72 int ber_get_content_length(int length)
73 {
74         if (length - 1 > 0x7F)
75                 return length - 4;
76         else
77                 return length - 2;
78 }
79
80 /**
81  * Read BER Universal tag.
82  * @param s stream
83  * @param tag BER universally-defined tag
84  * @return
85  */
86
87 boolean ber_read_universal_tag(STREAM* s, uint8 tag, boolean pc)
88 {
89         uint8 byte;
90
91         stream_read_uint8(s, byte);
92
93         if (byte != (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag)))
94                 return false;
95
96         return true;
97 }
98
99 /**
100  * Write BER Universal tag.
101  * @param s stream
102  * @param tag BER universally-defined tag
103  * @param pc primitive (false) or constructed (true)
104  */
105
106 void ber_write_universal_tag(STREAM* s, uint8 tag, boolean pc)
107 {
108         stream_write_uint8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
109 }
110
111 /**
112  * Read BER Application tag.
113  * @param s stream
114  * @param tag BER application-defined tag
115  * @param length length
116  */
117
118 boolean ber_read_application_tag(STREAM* s, uint8 tag, int* length)
119 {
120         uint8 byte;
121
122         if (tag > 30)
123         {
124                 stream_read_uint8(s, byte);
125
126                 if (byte != ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK))
127                         return false;
128
129                 stream_read_uint8(s, byte);
130
131                 if (byte != tag)
132                         return false;
133
134                 ber_read_length(s, length);
135         }
136         else
137         {
138                 stream_read_uint8(s, byte);
139
140                 if (byte != ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag)))
141                         return false;
142
143                 ber_read_length(s, length);
144         }
145
146         return true;
147 }
148
149 /**
150  * Write BER Application tag.
151  * @param s stream
152  * @param tag BER application-defined tag
153  * @param length length
154  */
155
156 void ber_write_application_tag(STREAM* s, uint8 tag, int length)
157 {
158         if (tag > 30)
159         {
160                 stream_write_uint8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
161                 stream_write_uint8(s, tag);
162                 ber_write_length(s, length);
163         }
164         else
165         {
166                 stream_write_uint8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
167                 ber_write_length(s, length);
168         }
169 }
170
171 boolean ber_read_contextual_tag(STREAM* s, uint8 tag, int* length, boolean pc)
172 {
173         uint8 byte;
174
175         stream_read_uint8(s, byte);
176
177         if (byte != ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag)))
178         {
179                 stream_rewind(s, 1);
180                 return false;
181         }
182
183         ber_read_length(s, length);
184
185         return true;
186 }
187
188 int ber_write_contextual_tag(STREAM* s, uint8 tag, int length, boolean pc)
189 {
190         stream_write_uint8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
191         return ber_write_length(s, length) + 1;
192 }
193
194 int ber_skip_contextual_tag(int length)
195 {
196         return _ber_skip_length(length) + 1;
197 }
198
199 boolean ber_read_sequence_tag(STREAM* s, int* length)
200 {
201         uint8 byte;
202
203         stream_read_uint8(s, byte);
204
205         if (byte != ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF)))
206                 return false;
207
208         ber_read_length(s, length);
209
210         return true;
211 }
212
213 /**
214  * Write BER SEQUENCE tag.
215  * @param s stream
216  * @param length length
217  */
218
219 int ber_write_sequence_tag(STREAM* s, int length)
220 {
221         stream_write_uint8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
222         return ber_write_length(s, length) + 1;
223 }
224
225 int ber_skip_sequence(int length)
226 {
227         return 1 + _ber_skip_length(length) + length;
228 }
229
230 int ber_skip_sequence_tag(int length)
231 {
232         return 1 + _ber_skip_length(length);
233 }
234
235 boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 count)
236 {
237         int length;
238
239         ber_read_universal_tag(s, BER_TAG_ENUMERATED, false);
240         ber_read_length(s, &length);
241
242         if (length == 1)
243                 stream_read_uint8(s, *enumerated);
244         else
245                 return false;
246
247         /* check that enumerated value falls within expected range */
248         if (*enumerated + 1 > count)
249                 return false;
250
251         return true;
252 }
253
254 void ber_write_enumerated(STREAM* s, uint8 enumerated, uint8 count)
255 {
256         ber_write_universal_tag(s, BER_TAG_ENUMERATED, false);
257         ber_write_length(s, 1);
258         stream_write_uint8(s, enumerated);
259 }
260
261 boolean ber_read_bit_string(STREAM* s, int* length, uint8* padding)
262 {
263         ber_read_universal_tag(s, BER_TAG_BIT_STRING, false);
264         ber_read_length(s, length);
265         stream_read_uint8(s, *padding);
266
267         return true;
268 }
269
270 boolean ber_read_octet_string(STREAM* s, int* length)
271 {
272         ber_read_universal_tag(s, BER_TAG_OCTET_STRING, false);
273         ber_read_length(s, length);
274
275         return true;
276 }
277
278 /**
279  * Write a BER OCTET_STRING
280  * @param s stream
281  * @param oct_str octet string
282  * @param length string length
283  */
284
285 void ber_write_octet_string(STREAM* s, const uint8* oct_str, int length)
286 {
287         ber_write_universal_tag(s, BER_TAG_OCTET_STRING, false);
288         ber_write_length(s, length);
289         stream_write(s, oct_str, length);
290 }
291
292 int ber_write_octet_string_tag(STREAM* s, int length)
293 {
294         ber_write_universal_tag(s, BER_TAG_OCTET_STRING, false);
295         ber_write_length(s, length);
296         return 1 + _ber_skip_length(length);
297 }
298
299 int ber_skip_octet_string(int length)
300 {
301         return 1 + _ber_skip_length(length) + length;
302 }
303
304 /**
305  * Read a BER BOOLEAN
306  * @param s
307  * @param value
308  */
309
310 boolean ber_read_boolean(STREAM* s, boolean* value)
311 {
312         int length;
313         uint8 v;
314
315         if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, false))
316                 return false;
317         ber_read_length(s, &length);
318         if (length != 1)
319                 return false;
320         stream_read_uint8(s, v);
321         *value = (v ? true : false);
322         return true;
323 }
324
325 /**
326  * Write a BER BOOLEAN
327  * @param s
328  * @param value
329  */
330
331 void ber_write_boolean(STREAM* s, boolean value)
332 {
333         ber_write_universal_tag(s, BER_TAG_BOOLEAN, false);
334         ber_write_length(s, 1);
335         stream_write_uint8(s, (value == true) ? 0xFF : 0);
336 }
337
338 boolean ber_read_integer(STREAM* s, uint32* value)
339 {
340         int length;
341
342         ber_read_universal_tag(s, BER_TAG_INTEGER, false);
343         ber_read_length(s, &length);
344
345         if (value == NULL)
346         {
347                 stream_seek(s, length);
348                 return true;
349         }
350
351         if (length == 1)
352                 stream_read_uint8(s, *value);
353         else if (length == 2)
354                 stream_read_uint16_be(s, *value);
355         else if (length == 3)
356         {
357                 uint8 byte;
358                 stream_read_uint8(s, byte);
359                 stream_read_uint16_be(s, *value);
360                 *value += (byte << 16);
361         }
362         else if (length == 4)
363                 stream_read_uint32_be(s, *value);
364         else
365                 return false;
366
367         return true;
368 }
369
370 /**
371  * Write a BER INTEGER
372  * @param s
373  * @param value
374  */
375
376 int ber_write_integer(STREAM* s, uint32 value)
377 {
378         ber_write_universal_tag(s, BER_TAG_INTEGER, false);
379
380         if (value <= 0xFF)
381         {
382                 ber_write_length(s, 1);
383                 stream_write_uint8(s, value);
384                 return 2;
385         }
386         else if (value < 0xFF80)
387         {
388                 ber_write_length(s, 2);
389                 stream_write_uint16_be(s, value);
390                 return 3;
391         }
392         else if (value < 0xFF8000)
393         {
394                 ber_write_length(s, 3);
395                 stream_write_uint8(s, (value >> 16));
396                 stream_write_uint16_be(s, (value & 0xFFFF));
397                 return 4;
398         }
399         else if (value <= 0xFFFFFFFF)
400         {
401                 ber_write_length(s, 4);
402                 stream_write_uint32_be(s, value);
403                 return 5;
404         }
405
406         return 0;
407 }
408
409 int ber_skip_integer(uint32 value)
410 {
411         if (value <= 0xFF)
412         {
413                 return _ber_skip_length(1) + 2;
414         }
415         else if (value <= 0xFFFF)
416         {
417                 return _ber_skip_length(2) + 3;
418         }
419         else if (value <= 0xFFFFFFFF)
420         {
421                 return _ber_skip_length(4) + 5;
422         }
423
424         return 0;
425 }
426
427 boolean ber_read_integer_length(STREAM* s, int* length)
428 {
429         ber_read_universal_tag(s, BER_TAG_INTEGER, false);
430         ber_read_length(s, length);
431         return true;
432 }