- Fix the stupid mess we created when making this from the cmake branch
[reactos.git] / lib / drivers / lwip / src / core / snmp / asn1_dec.c
1 /**
2 * @file
3 * Abstract Syntax Notation One (ISO 8824, 8825) decoding
4 *
5 * @todo not optimised (yet), favor correctness over speed, favor speed over size
6 */
7
8 /*
9 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 *
34 * Author: Christiaan Simons <christiaan.simons@axon.tv>
35 */
36
37 #include "lwip/opt.h"
38
39 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
40
41 #include "lwip/snmp_asn1.h"
42
43 /**
44 * Retrieves type field from incoming pbuf chain.
45 *
46 * @param p points to a pbuf holding an ASN1 coded type field
47 * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
48 * @param type return ASN1 type
49 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
50 */
51 err_t
52 snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
53 {
54 u16_t plen, base;
55 u8_t *msg_ptr;
56
57 plen = 0;
58 while (p != NULL)
59 {
60 base = plen;
61 plen += p->len;
62 if (ofs < plen)
63 {
64 msg_ptr = (u8_t*)p->payload;
65 msg_ptr += ofs - base;
66 *type = *msg_ptr;
67 return ERR_OK;
68 }
69 p = p->next;
70 }
71 /* p == NULL, ofs >= plen */
72 return ERR_ARG;
73 }
74
75 /**
76 * Decodes length field from incoming pbuf chain into host length.
77 *
78 * @param p points to a pbuf holding an ASN1 coded length
79 * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
80 * @param octets_used returns number of octets used by the length code
81 * @param length return host order length, upto 64k
82 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
83 */
84 err_t
85 snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
86 {
87 u16_t plen, base;
88 u8_t *msg_ptr;
89
90 plen = 0;
91 while (p != NULL)
92 {
93 base = plen;
94 plen += p->len;
95 if (ofs < plen)
96 {
97 msg_ptr = (u8_t*)p->payload;
98 msg_ptr += ofs - base;
99
100 if (*msg_ptr < 0x80)
101 {
102 /* primitive definite length format */
103 *octets_used = 1;
104 *length = *msg_ptr;
105 return ERR_OK;
106 }
107 else if (*msg_ptr == 0x80)
108 {
109 /* constructed indefinite length format, termination with two zero octets */
110 u8_t zeros;
111 u8_t i;
112
113 *length = 0;
114 zeros = 0;
115 while (zeros != 2)
116 {
117 i = 2;
118 while (i > 0)
119 {
120 i--;
121 (*length) += 1;
122 ofs += 1;
123 if (ofs >= plen)
124 {
125 /* next octet in next pbuf */
126 p = p->next;
127 if (p == NULL) { return ERR_ARG; }
128 msg_ptr = (u8_t*)p->payload;
129 plen += p->len;
130 }
131 else
132 {
133 /* next octet in same pbuf */
134 msg_ptr++;
135 }
136 if (*msg_ptr == 0)
137 {
138 zeros++;
139 if (zeros == 2)
140 {
141 /* stop while (i > 0) */
142 i = 0;
143 }
144 }
145 else
146 {
147 zeros = 0;
148 }
149 }
150 }
151 *octets_used = 1;
152 return ERR_OK;
153 }
154 else if (*msg_ptr == 0x81)
155 {
156 /* constructed definite length format, one octet */
157 ofs += 1;
158 if (ofs >= plen)
159 {
160 /* next octet in next pbuf */
161 p = p->next;
162 if (p == NULL) { return ERR_ARG; }
163 msg_ptr = (u8_t*)p->payload;
164 }
165 else
166 {
167 /* next octet in same pbuf */
168 msg_ptr++;
169 }
170 *length = *msg_ptr;
171 *octets_used = 2;
172 return ERR_OK;
173 }
174 else if (*msg_ptr == 0x82)
175 {
176 u8_t i;
177
178 /* constructed definite length format, two octets */
179 i = 2;
180 while (i > 0)
181 {
182 i--;
183 ofs += 1;
184 if (ofs >= plen)
185 {
186 /* next octet in next pbuf */
187 p = p->next;
188 if (p == NULL) { return ERR_ARG; }
189 msg_ptr = (u8_t*)p->payload;
190 plen += p->len;
191 }
192 else
193 {
194 /* next octet in same pbuf */
195 msg_ptr++;
196 }
197 if (i == 0)
198 {
199 /* least significant length octet */
200 *length |= *msg_ptr;
201 }
202 else
203 {
204 /* most significant length octet */
205 *length = (*msg_ptr) << 8;
206 }
207 }
208 *octets_used = 3;
209 return ERR_OK;
210 }
211 else
212 {
213 /* constructed definite length format 3..127 octets, this is too big (>64k) */
214 /** @todo: do we need to accept inefficient codings with many leading zero's? */
215 *octets_used = 1 + ((*msg_ptr) & 0x7f);
216 return ERR_ARG;
217 }
218 }
219 p = p->next;
220 }
221
222 /* p == NULL, ofs >= plen */
223 return ERR_ARG;
224 }
225
226 /**
227 * Decodes positive integer (counter, gauge, timeticks) into u32_t.
228 *
229 * @param p points to a pbuf holding an ASN1 coded integer
230 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
231 * @param len length of the coded integer field
232 * @param value return host order integer
233 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
234 *
235 * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
236 * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
237 * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
238 */
239 err_t
240 snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
241 {
242 u16_t plen, base;
243 u8_t *msg_ptr;
244
245 plen = 0;
246 while (p != NULL)
247 {
248 base = plen;
249 plen += p->len;
250 if (ofs < plen)
251 {
252 msg_ptr = (u8_t*)p->payload;
253 msg_ptr += ofs - base;
254 if ((len > 0) && (len < 6))
255 {
256 /* start from zero */
257 *value = 0;
258 if (*msg_ptr & 0x80)
259 {
260 /* negative, expecting zero sign bit! */
261 return ERR_ARG;
262 }
263 else
264 {
265 /* positive */
266 if ((len > 1) && (*msg_ptr == 0))
267 {
268 /* skip leading "sign byte" octet 0x00 */
269 len--;
270 ofs += 1;
271 if (ofs >= plen)
272 {
273 /* next octet in next pbuf */
274 p = p->next;
275 if (p == NULL) { return ERR_ARG; }
276 msg_ptr = (u8_t*)p->payload;
277 plen += p->len;
278 }
279 else
280 {
281 /* next octet in same pbuf */
282 msg_ptr++;
283 }
284 }
285 }
286 /* OR octets with value */
287 while (len > 1)
288 {
289 len--;
290 *value |= *msg_ptr;
291 *value <<= 8;
292 ofs += 1;
293 if (ofs >= plen)
294 {
295 /* next octet in next pbuf */
296 p = p->next;
297 if (p == NULL) { return ERR_ARG; }
298 msg_ptr = (u8_t*)p->payload;
299 plen += p->len;
300 }
301 else
302 {
303 /* next octet in same pbuf */
304 msg_ptr++;
305 }
306 }
307 *value |= *msg_ptr;
308 return ERR_OK;
309 }
310 else
311 {
312 return ERR_ARG;
313 }
314 }
315 p = p->next;
316 }
317 /* p == NULL, ofs >= plen */
318 return ERR_ARG;
319 }
320
321 /**
322 * Decodes integer into s32_t.
323 *
324 * @param p points to a pbuf holding an ASN1 coded integer
325 * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
326 * @param len length of the coded integer field
327 * @param value return host order integer
328 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
329 *
330 * @note ASN coded integers are _always_ signed!
331 */
332 err_t
333 snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
334 {
335 u16_t plen, base;
336 u8_t *msg_ptr;
337 #if BYTE_ORDER == LITTLE_ENDIAN
338 u8_t *lsb_ptr = (u8_t*)value;
339 #endif
340 #if BYTE_ORDER == BIG_ENDIAN
341 u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
342 #endif
343 u8_t sign;
344
345 plen = 0;
346 while (p != NULL)
347 {
348 base = plen;
349 plen += p->len;
350 if (ofs < plen)
351 {
352 msg_ptr = (u8_t*)p->payload;
353 msg_ptr += ofs - base;
354 if ((len > 0) && (len < 5))
355 {
356 if (*msg_ptr & 0x80)
357 {
358 /* negative, start from -1 */
359 *value = -1;
360 sign = 1;
361 }
362 else
363 {
364 /* positive, start from 0 */
365 *value = 0;
366 sign = 0;
367 }
368 /* OR/AND octets with value */
369 while (len > 1)
370 {
371 len--;
372 if (sign)
373 {
374 *lsb_ptr &= *msg_ptr;
375 *value <<= 8;
376 *lsb_ptr |= 255;
377 }
378 else
379 {
380 *lsb_ptr |= *msg_ptr;
381 *value <<= 8;
382 }
383 ofs += 1;
384 if (ofs >= plen)
385 {
386 /* next octet in next pbuf */
387 p = p->next;
388 if (p == NULL) { return ERR_ARG; }
389 msg_ptr = (u8_t*)p->payload;
390 plen += p->len;
391 }
392 else
393 {
394 /* next octet in same pbuf */
395 msg_ptr++;
396 }
397 }
398 if (sign)
399 {
400 *lsb_ptr &= *msg_ptr;
401 }
402 else
403 {
404 *lsb_ptr |= *msg_ptr;
405 }
406 return ERR_OK;
407 }
408 else
409 {
410 return ERR_ARG;
411 }
412 }
413 p = p->next;
414 }
415 /* p == NULL, ofs >= plen */
416 return ERR_ARG;
417 }
418
419 /**
420 * Decodes object identifier from incoming message into array of s32_t.
421 *
422 * @param p points to a pbuf holding an ASN1 coded object identifier
423 * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
424 * @param len length of the coded object identifier
425 * @param oid return object identifier struct
426 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
427 */
428 err_t
429 snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
430 {
431 u16_t plen, base;
432 u8_t *msg_ptr;
433 s32_t *oid_ptr;
434
435 plen = 0;
436 while (p != NULL)
437 {
438 base = plen;
439 plen += p->len;
440 if (ofs < plen)
441 {
442 msg_ptr = (u8_t*)p->payload;
443 msg_ptr += ofs - base;
444
445 oid->len = 0;
446 oid_ptr = &oid->id[0];
447 if (len > 0)
448 {
449 /* first compressed octet */
450 if (*msg_ptr == 0x2B)
451 {
452 /* (most) common case 1.3 (iso.org) */
453 *oid_ptr = 1;
454 oid_ptr++;
455 *oid_ptr = 3;
456 oid_ptr++;
457 }
458 else if (*msg_ptr < 40)
459 {
460 *oid_ptr = 0;
461 oid_ptr++;
462 *oid_ptr = *msg_ptr;
463 oid_ptr++;
464 }
465 else if (*msg_ptr < 80)
466 {
467 *oid_ptr = 1;
468 oid_ptr++;
469 *oid_ptr = (*msg_ptr) - 40;
470 oid_ptr++;
471 }
472 else
473 {
474 *oid_ptr = 2;
475 oid_ptr++;
476 *oid_ptr = (*msg_ptr) - 80;
477 oid_ptr++;
478 }
479 oid->len = 2;
480 }
481 else
482 {
483 /* accepting zero length identifiers e.g. for
484 getnext operation. uncommon but valid */
485 return ERR_OK;
486 }
487 len--;
488 if (len > 0)
489 {
490 ofs += 1;
491 if (ofs >= plen)
492 {
493 /* next octet in next pbuf */
494 p = p->next;
495 if (p == NULL) { return ERR_ARG; }
496 msg_ptr = (u8_t*)p->payload;
497 plen += p->len;
498 }
499 else
500 {
501 /* next octet in same pbuf */
502 msg_ptr++;
503 }
504 }
505 while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
506 {
507 /* sub-identifier uses multiple octets */
508 if (*msg_ptr & 0x80)
509 {
510 s32_t sub_id = 0;
511
512 while ((*msg_ptr & 0x80) && (len > 1))
513 {
514 len--;
515 sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
516 ofs += 1;
517 if (ofs >= plen)
518 {
519 /* next octet in next pbuf */
520 p = p->next;
521 if (p == NULL) { return ERR_ARG; }
522 msg_ptr = (u8_t*)p->payload;
523 plen += p->len;
524 }
525 else
526 {
527 /* next octet in same pbuf */
528 msg_ptr++;
529 }
530 }
531 if (!(*msg_ptr & 0x80) && (len > 0))
532 {
533 /* last octet sub-identifier */
534 len--;
535 sub_id = (sub_id << 7) + *msg_ptr;
536 *oid_ptr = sub_id;
537 }
538 }
539 else
540 {
541 /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
542 len--;
543 *oid_ptr = *msg_ptr;
544 }
545 if (len > 0)
546 {
547 /* remaining oid bytes available ... */
548 ofs += 1;
549 if (ofs >= plen)
550 {
551 /* next octet in next pbuf */
552 p = p->next;
553 if (p == NULL) { return ERR_ARG; }
554 msg_ptr = (u8_t*)p->payload;
555 plen += p->len;
556 }
557 else
558 {
559 /* next octet in same pbuf */
560 msg_ptr++;
561 }
562 }
563 oid_ptr++;
564 oid->len++;
565 }
566 if (len == 0)
567 {
568 /* len == 0, end of oid */
569 return ERR_OK;
570 }
571 else
572 {
573 /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
574 return ERR_ARG;
575 }
576
577 }
578 p = p->next;
579 }
580 /* p == NULL, ofs >= plen */
581 return ERR_ARG;
582 }
583
584 /**
585 * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
586 * from incoming message into array.
587 *
588 * @param p points to a pbuf holding an ASN1 coded raw data
589 * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
590 * @param len length of the coded raw data (zero is valid, e.g. empty string!)
591 * @param raw_len length of the raw return value
592 * @param raw return raw bytes
593 * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
594 */
595 err_t
596 snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
597 {
598 u16_t plen, base;
599 u8_t *msg_ptr;
600
601 if (len > 0)
602 {
603 plen = 0;
604 while (p != NULL)
605 {
606 base = plen;
607 plen += p->len;
608 if (ofs < plen)
609 {
610 msg_ptr = (u8_t*)p->payload;
611 msg_ptr += ofs - base;
612 if (raw_len >= len)
613 {
614 while (len > 1)
615 {
616 /* copy len - 1 octets */
617 len--;
618 *raw = *msg_ptr;
619 raw++;
620 ofs += 1;
621 if (ofs >= plen)
622 {
623 /* next octet in next pbuf */
624 p = p->next;
625 if (p == NULL) { return ERR_ARG; }
626 msg_ptr = (u8_t*)p->payload;
627 plen += p->len;
628 }
629 else
630 {
631 /* next octet in same pbuf */
632 msg_ptr++;
633 }
634 }
635 /* copy last octet */
636 *raw = *msg_ptr;
637 return ERR_OK;
638 }
639 else
640 {
641 /* raw_len < len, not enough dst space */
642 return ERR_ARG;
643 }
644 }
645 p = p->next;
646 }
647 /* p == NULL, ofs >= plen */
648 return ERR_ARG;
649 }
650 else
651 {
652 /* len == 0, empty string */
653 return ERR_OK;
654 }
655 }
656
657 #endif /* LWIP_SNMP */