]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/snmp/asn1_dec.c
5e04b38e0dbbe84d41b8a06eb67bf3224e0485c6
[freertos] / Demo / Common / ethernet / lwIP / 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
40 #include "lwip/snmp_asn1.h"
41
42 /**
43  * Retrieves type field from incoming pbuf chain.
44  *
45  * @param p points to a pbuf holding an ASN1 coded type field
46  * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
47  * @param type return ASN1 type
48  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
49  */
50 err_t
51 snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
52 {
53   u16_t plen, base;
54   u8_t *msg_ptr;
55
56   plen = 0;
57   while (p != NULL)
58   {
59     base = plen;
60     plen += p->len;
61     if (ofs < plen)
62     {
63       msg_ptr = p->payload;
64       msg_ptr += ofs - base;
65       *type = *msg_ptr;
66       return ERR_OK;
67     }
68     p = p->next;
69   }
70   /* p == NULL, ofs >= plen */
71   return ERR_ARG;
72 }
73
74 /**
75  * Decodes length field from incoming pbuf chain into host length.
76  *
77  * @param p points to a pbuf holding an ASN1 coded length
78  * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
79  * @param octets_used returns number of octets used by the length code
80  * @param length return host order length, upto 64k
81  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
82  */
83 err_t
84 snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
85 {
86   u16_t plen, base;
87   u8_t *msg_ptr;
88
89   plen = 0;
90   while (p != NULL)
91   {
92     base = plen;
93     plen += p->len;
94     if (ofs < plen)
95     {
96       msg_ptr = p->payload;
97       msg_ptr += ofs - base;
98
99       if (*msg_ptr < 0x80)
100       {
101         /* primitive definite length format */
102         *octets_used = 1;
103         *length = *msg_ptr;
104         return ERR_OK;
105       }
106       else if (*msg_ptr == 0x80)
107       {
108         /* constructed indefinite length format, termination with two zero octets */
109         u8_t zeros;
110         u8_t i;
111
112         *length = 0;
113         zeros = 0;
114         while (zeros != 2)
115         {
116           i = 2;
117           while (i > 0)
118           {
119             i--;
120             (*length) += 1;
121             ofs += 1;
122             if (ofs >= plen)
123             {
124               /* next octet in next pbuf */
125               p = p->next;
126               if (p == NULL) { return ERR_ARG; }
127               msg_ptr = p->payload;
128               plen += p->len;
129             }
130             else
131             {
132               /* next octet in same pbuf */
133               msg_ptr++;
134             }
135             if (*msg_ptr == 0)
136             {
137               zeros++;
138               if (zeros == 2)
139               {
140                 /* stop while (i > 0) */
141                 i = 0;
142               }
143             }
144             else
145             {
146               zeros = 0;
147             }
148           }
149         }
150         *octets_used = 1;
151         return ERR_OK;
152       }
153       else if (*msg_ptr == 0x81)
154       {
155         /* constructed definite length format, one octet */
156         ofs += 1;
157         if (ofs >= plen)
158         {
159           /* next octet in next pbuf */
160           p = p->next;
161           if (p == NULL) { return ERR_ARG; }
162           msg_ptr = p->payload;
163         }
164         else
165         {
166           /* next octet in same pbuf */
167           msg_ptr++;
168         }
169         *length = *msg_ptr;
170         *octets_used = 2;
171         return ERR_OK;
172       }
173       else if (*msg_ptr == 0x82)
174       {
175         u8_t i;
176
177         /* constructed definite length format, two octets */
178         i = 2;
179         while (i > 0)
180         {
181           i--;
182           ofs += 1;
183           if (ofs >= plen)
184           {
185             /* next octet in next pbuf */
186             p = p->next;
187             if (p == NULL) { return ERR_ARG; }
188             msg_ptr = p->payload;
189             plen += p->len;
190           }
191           else
192           {
193             /* next octet in same pbuf */
194             msg_ptr++;
195           }
196           if (i == 0)
197           {
198             /* least significant length octet */
199             *length |= *msg_ptr;
200           }
201           else
202           {
203             /* most significant length octet */
204             *length = (*msg_ptr) << 8;
205           }
206         }
207         *octets_used = 3;
208         return ERR_OK;
209       }
210       else
211       {
212         /* constructed definite length format 3..127 octets, this is too big (>64k) */
213         /**  @todo: do we need to accept inefficient codings with many leading zero's? */
214         *octets_used = 1 + ((*msg_ptr) & 0x7f);
215         return ERR_ARG;
216       }
217     }
218     p = p->next;
219   }
220
221   /* p == NULL, ofs >= plen */
222   return ERR_ARG;
223 }
224
225 /**
226  * Decodes positive integer (counter, gauge, timeticks) into u32_t.
227  *
228  * @param p points to a pbuf holding an ASN1 coded integer
229  * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
230  * @param len length of the coded integer field
231  * @param value return host order integer
232  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
233  *
234  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
235  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
236  * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
237  */
238 err_t
239 snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
240 {
241   u16_t plen, base;
242   u8_t *msg_ptr;
243
244   plen = 0;
245   while (p != NULL)
246   {
247     base = plen;
248     plen += p->len;
249     if (ofs < plen)
250     {
251       msg_ptr = p->payload;
252       msg_ptr += ofs - base;
253       if ((len > 0) && (len < 6))
254       {
255         /* start from zero */
256         *value = 0;
257         if (*msg_ptr & 0x80)
258         {
259           /* negative, expecting zero sign bit! */
260           return ERR_ARG;
261         }
262         else
263         {
264           /* positive */
265           if ((len > 1) && (*msg_ptr == 0))
266           {
267             /* skip leading "sign byte" octet 0x00 */
268             len--;
269             ofs += 1;
270             if (ofs >= plen)
271             {
272               /* next octet in next pbuf */
273               p = p->next;
274               if (p == NULL) { return ERR_ARG; }
275               msg_ptr = p->payload;
276               plen += p->len;
277             }
278             else
279             {
280               /* next octet in same pbuf */
281               msg_ptr++;
282             }
283           }
284         }
285         /* OR octets with value */
286         while (len > 1)
287         {
288           len--;
289           *value |= *msg_ptr;
290           *value <<= 8;
291           ofs += 1;
292           if (ofs >= plen)
293           {
294             /* next octet in next pbuf */
295             p = p->next;
296             if (p == NULL) { return ERR_ARG; }
297             msg_ptr = p->payload;
298             plen += p->len;
299           }
300           else
301           {
302             /* next octet in same pbuf */
303             msg_ptr++;
304           }
305         }
306         *value |= *msg_ptr;
307         return ERR_OK;
308       }
309       else
310       {
311         return ERR_ARG;
312       }
313     }
314     p = p->next;
315   }
316   /* p == NULL, ofs >= plen */
317   return ERR_ARG;
318 }
319
320 /**
321  * Decodes integer into s32_t.
322  *
323  * @param p points to a pbuf holding an ASN1 coded integer
324  * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
325  * @param len length of the coded integer field
326  * @param value return host order integer
327  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
328  *
329  * @note ASN coded integers are _always_ signed!
330  */
331 err_t
332 snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
333 {
334   u16_t plen, base;
335   u8_t *msg_ptr;
336   u8_t *lsb_ptr = (u8_t*)value;
337   u8_t sign;
338
339   plen = 0;
340   while (p != NULL)
341   {
342     base = plen;
343     plen += p->len;
344     if (ofs < plen)
345     {
346       msg_ptr = p->payload;
347       msg_ptr += ofs - base;
348       if ((len > 0) && (len < 5))
349       {
350         if (*msg_ptr & 0x80)
351         {
352           /* negative, start from -1 */
353           *value = -1;
354           sign = 1;
355         }
356         else
357         {
358           /* positive, start from 0 */
359           *value = 0;
360           sign = 0;
361         }
362         /* OR/AND octets with value */
363         while (len > 1)
364         {
365           len--;
366           if (sign)
367           {
368             *lsb_ptr &= *msg_ptr;
369             *value <<= 8;
370             *lsb_ptr |= 255;
371           }
372           else
373           {
374             *lsb_ptr |= *msg_ptr;
375             *value <<= 8;
376           }
377           ofs += 1;
378           if (ofs >= plen)
379           {
380             /* next octet in next pbuf */
381             p = p->next;
382             if (p == NULL) { return ERR_ARG; }
383             msg_ptr = p->payload;
384             plen += p->len;
385           }
386           else
387           {
388             /* next octet in same pbuf */
389             msg_ptr++;
390           }
391         }
392         if (sign)
393         {
394           *lsb_ptr &= *msg_ptr;
395         }
396         else
397         {
398           *lsb_ptr |= *msg_ptr;
399         }
400         return ERR_OK;
401       }
402       else
403       {
404         return ERR_ARG;
405       }
406     }
407     p = p->next;
408   }
409   /* p == NULL, ofs >= plen */
410   return ERR_ARG;
411 }
412
413 /**
414  * Decodes object identifier from incoming message into array of s32_t.
415  *
416  * @param p points to a pbuf holding an ASN1 coded object identifier
417  * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
418  * @param len length of the coded object identifier
419  * @param oid return object identifier struct
420  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
421  */
422 err_t
423 snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
424 {
425   u16_t plen, base;
426   u8_t *msg_ptr;
427   s32_t *oid_ptr;
428
429   plen = 0;
430   while (p != NULL)
431   {
432     base = plen;
433     plen += p->len;
434     if (ofs < plen)
435     {
436       msg_ptr = p->payload;
437       msg_ptr += ofs - base;
438
439       oid->len = 0;
440       oid_ptr = &oid->id[0];
441       if (len > 0)
442       {
443         /* first compressed octet */
444         if (*msg_ptr == 0x2B)
445         {
446           /* (most) common case 1.3 (iso.org) */
447           *oid_ptr = 1;
448           oid_ptr++;
449           *oid_ptr = 3;
450           oid_ptr++;
451         }
452         else if (*msg_ptr < 40)
453         {
454           *oid_ptr = 0;
455           oid_ptr++;
456           *oid_ptr = *msg_ptr;
457           oid_ptr++;
458         }
459         else if (*msg_ptr < 80)
460         {
461           *oid_ptr = 1;
462           oid_ptr++;
463           *oid_ptr = (*msg_ptr) - 40;
464           oid_ptr++;
465         }
466         else
467         {
468           *oid_ptr = 2;
469           oid_ptr++;
470           *oid_ptr = (*msg_ptr) - 80;
471           oid_ptr++;
472         }
473         oid->len = 2;
474       }
475       else
476       {
477         /* accepting zero length identifiers e.g. for
478            getnext operation. uncommon but valid */
479         return ERR_OK;
480       }
481       len--;
482       if (len > 0)
483       {
484         ofs += 1;
485         if (ofs >= plen)
486         {
487           /* next octet in next pbuf */
488           p = p->next;
489           if (p == NULL) { return ERR_ARG; }
490           msg_ptr = p->payload;
491           plen += p->len;
492         }
493         else
494         {
495           /* next octet in same pbuf */
496           msg_ptr++;
497         }
498       }
499       while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
500       {
501         /* sub-identifier uses multiple octets */
502         if (*msg_ptr & 0x80)
503         {
504           s32_t sub_id = 0;
505
506           while ((*msg_ptr & 0x80) && (len > 1))
507           {
508             len--;
509             sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
510             ofs += 1;
511             if (ofs >= plen)
512             {
513               /* next octet in next pbuf */
514               p = p->next;
515               if (p == NULL) { return ERR_ARG; }
516               msg_ptr = p->payload;
517               plen += p->len;
518             }
519             else
520             {
521               /* next octet in same pbuf */
522               msg_ptr++;
523             }
524           }
525           if (!(*msg_ptr & 0x80) && (len > 0))
526           {
527             /* last octet sub-identifier */
528             len--;
529             sub_id = (sub_id << 7) + *msg_ptr;
530             *oid_ptr = sub_id;
531           }
532         }
533         else
534         {
535           /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
536           len--;
537           *oid_ptr = *msg_ptr;
538         }
539         if (len > 0)
540         {
541           /* remaining oid bytes available ... */
542           ofs += 1;
543           if (ofs >= plen)
544           {
545             /* next octet in next pbuf */
546             p = p->next;
547             if (p == NULL) { return ERR_ARG; }
548             msg_ptr = p->payload;
549             plen += p->len;
550           }
551           else
552           {
553             /* next octet in same pbuf */
554             msg_ptr++;
555           }
556         }
557         oid_ptr++;
558         oid->len++;
559       }
560       if (len == 0)
561       {
562         /* len == 0, end of oid */
563         return ERR_OK;
564       }
565       else
566       {
567         /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
568         return ERR_ARG;
569       }
570
571     }
572     p = p->next;
573   }
574   /* p == NULL, ofs >= plen */
575   return ERR_ARG;
576 }
577
578 /**
579  * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
580  * from incoming message into array.
581  *
582  * @param p points to a pbuf holding an ASN1 coded raw data
583  * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
584  * @param len length of the coded raw data (zero is valid, e.g. empty string!)
585  * @param raw_len length of the raw return value
586  * @param raw return raw bytes
587  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
588  */
589 err_t
590 snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
591 {
592   u16_t plen, base;
593   u8_t *msg_ptr;
594
595   if (len > 0)
596   {
597     plen = 0;
598     while (p != NULL)
599     {
600       base = plen;
601       plen += p->len;
602       if (ofs < plen)
603       {
604         msg_ptr = p->payload;
605         msg_ptr += ofs - base;
606         if (raw_len >= len)
607         {
608           while (len > 1)
609           {
610             /* copy len - 1 octets */
611             len--;
612             *raw = *msg_ptr;
613             raw++;
614             ofs += 1;
615             if (ofs >= plen)
616             {
617               /* next octet in next pbuf */
618               p = p->next;
619               if (p == NULL) { return ERR_ARG; }
620               msg_ptr = p->payload;
621               plen += p->len;
622             }
623             else
624             {
625               /* next octet in same pbuf */
626               msg_ptr++;
627             }
628           }
629           /* copy last octet */
630           *raw = *msg_ptr;
631           return ERR_OK;
632         }
633         else
634         {
635           /* raw_len < len, not enough dst space */
636           return ERR_ARG;
637         }
638       }
639       p = p->next;
640     }
641     /* p == NULL, ofs >= plen */
642     return ERR_ARG;
643   }
644   else
645   {
646     /* len == 0, empty string */
647     return ERR_OK;
648   }
649 }
650
651 #endif /* LWIP_SNMP */
652