OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / Libnet / src / libnet_asn1.c
1 /*
2  *  $Id: libnet_asn1.c,v 1.1.1.1 2000/05/25 00:28:49 route Exp $
3  *
4  *  libnet
5  *  libnet_asn1.c -  Abstract Syntax Notation One routines
6  *
7  *  Abstract Syntax Notation One, ASN.1
8  *  As defined in ISO/IS 8824 and ISO/IS 8825
9  *  This implements a subset of the above International Standards that
10  *  is sufficient to implement SNMP.
11  *
12  *  Encodes abstract data types into a machine independent stream of bytes.
13  *
14  *  Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
15  *  All rights reserved.
16  *
17  *  Permission to use, copy, modify, and distribute this software and its
18  *  documentation for any purpose and without fee is hereby granted,
19  *  provided that the above copyright notice appear in all copies and that
20  *  both that copyright notice and this permission notice appear in
21  *  supporting documentation, and that the name of CMU not be
22  *  used in advertising or publicity pertaining to distribution of the
23  *  software without specific, written prior permission.
24  *
25  *  CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
26  *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
27  *  CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
28  *  ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
29  *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
30  *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
31  *  SOFTWARE.
32  *
33  *  Copyright (c) 1998 - 2001 Mike D. Schiffman <mike@infonexus.com>
34  *  All rights reserved.
35  *
36  * Copyright (c) 1993, 1994, 1995, 1996, 1998
37  *      The Regents of the University of California.  All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that: (1) source code distributions
41  * retain the above copyright notice and this paragraph in its entirety, (2)
42  * distributions including binary code include the above copyright notice and
43  * this paragraph in its entirety in the documentation or other materials
44  * provided with the distribution, and (3) all advertising materials mentioning
45  * features or use of this software display the following acknowledgement:
46  * ``This product includes software developed by the University of California,
47  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
48  * the University nor the names of its contributors may be used to endorse
49  * or promote products derived from this software without specific prior
50  * written permission.
51  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
52  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
53  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
54  */
55
56 #if (HAVE_CONFIG_H)
57 #include "../include/config.h"
58 #endif
59 #include "../include/libnet.h"
60
61 u_char *
62 libnet_build_asn1_int(u_char *data, int *datalen, u_char type, long *int_p,
63             int int_s)
64 {
65     /*
66      *  ASN.1 integer ::= 0x02 asnlength byte {byte}*
67      */
68      register long integer;
69      register u_long mask;
70
71     if (int_s != sizeof (long))
72     {
73         return (NULL);
74     }
75     integer = *int_p;
76
77     /*
78      *  Truncate "unnecessary" bytes off of the most significant end of this
79      *  2's complement integer.  There should be no sequence of 9 consecutive
80      *  1's or 0's at the most significant end of the integer.
81      */
82     mask = ((u_long) 0x1FF) << ((8 * (sizeof (long) - 1)) - 1);
83     /* mask is 0xFF800000 on a big-endian machine */
84
85     while ((((integer & mask) == 0) || ((integer & mask) == mask)) && int_s > 1)
86     {
87         int_s--;
88         integer <<= 8;
89     }
90
91     data = libnet_build_asn1_header(data, datalen, type, int_s);
92
93     if (data == NULL || *datalen < int_s)
94     {
95         return (NULL);
96     }
97
98     *datalen -= int_s;
99
100     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
101     /* mask is 0xFF000000 on a big-endian machine */
102
103     while (int_s--)
104     {
105         *data++ = (u_char)((integer & mask) >> (8 * (sizeof (long) - 1)));
106         integer <<= 8;
107     }
108     return (data);
109 }
110
111
112 u_char *
113 libnet_build_asn1_uint(u_char *data, int *datalen, u_char type, u_long *int_p,
114             int int_s)
115 {
116     /*
117      *  ASN.1 integer ::= 0x02 asnlength byte {byte}*
118      */
119     register u_long integer;
120     register u_long mask;
121     int add_null_byte = 0;
122
123     if (int_s != sizeof (long))
124     {
125         return (NULL);
126     }
127     integer = *int_p;
128
129     mask = ((u_long) 0xFF) << (8 * (sizeof (long) - 1));
130     /* mask is 0xFF000000 on a big-endian machine */
131
132     if ((u_char)((integer & mask) >> (8 * (sizeof (long) - 1))) & 0x80)
133     {
134         /* if MSB is set */
135         add_null_byte = 1;
136         int_s++;
137     }
138     else
139     {
140         /*
141          * Truncate "unnecessary" bytes off of the most significant end of this
142          * 2's complement integer.  There should be no sequence of 9
143          * consecutive 1's or 0's at the most significant end of the
144          * integer.
145          */
146         mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
147         /* mask is 0xFF800000 on a big-endian machine */
148
149         while (((integer & mask) == 0) && int_s > 1)
150         {
151             int_s--;
152             integer <<= 8;
153         }
154     }
155
156     data = libnet_build_asn1_header(data, datalen, type, int_s);
157
158     if (data == NULL || *datalen < int_s)
159     {
160         return (NULL);
161     }
162
163     *datalen -= int_s;
164
165     if (add_null_byte == 1)
166     {
167         *data++ = '\0';
168         int_s--;
169     }
170
171     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
172     /* mask is 0xFF000000 on a big-endian machine */
173
174     while (int_s--)
175     {
176         *data++ = (u_char)((integer & mask) >> (8 * (sizeof (long) - 1)));
177         integer <<= 8;
178     }
179     return (data);
180 }
181
182
183 u_char *
184 libnet_build_asn1_string(u_char *data, int *datalen, u_char type,
185             u_char *string, int str_s)
186 {
187
188     /*
189      *  ASN.1 octet string ::= primstring | cmpdstring
190      *  primstring ::= 0x04 asnlength byte {byte}*
191      *  cmpdstring ::= 0x24 asnlength string {string}*
192      *  This code will never send a compound string.
193      */
194     data = libnet_build_asn1_header(data, datalen, type, str_s);
195
196     if (data == NULL || *datalen < str_s)
197     {
198         return (NULL);
199     }
200     memmove(data, string, str_s);
201     *datalen -= str_s;
202
203     return (data + str_s);
204 }
205
206
207 u_char *
208 libnet_build_asn1_header(u_char *data, int *datalen, u_char type, int len)
209 {
210     if (*datalen < 1)
211     {
212         return (NULL);
213     }
214     *data++ = type;
215     (*datalen)--;
216
217     return (libnet_build_asn1_length(data, datalen, len));
218 }
219
220
221 u_char *
222 libnet_build_asn1_sequence(u_char *data, int *datalen, u_char type, int len)
223 {
224     *datalen -= 4;
225     if (*datalen < 0)
226     {
227         *datalen += 4;       /* fix up before punting */
228         return (NULL);
229     }
230     *data++ = type;
231     *data++ = (u_char)(0x02 | ASN_LONG_LEN);
232     *data++ = (u_char)((len >> 8) & 0xFF);
233     *data++ = (u_char)(len & 0xFF);
234     return (data);
235 }
236
237
238 u_char *
239 libnet_build_asn1_length(u_char *data, int *datalen, int len)
240 {
241     u_char *start_data = data;
242
243     /* no indefinite lengths sent */
244     if (len < 0x80)
245     {
246         if (*datalen < 1)
247         {
248             return (NULL);
249         }
250         *data++ = (u_char)len;
251     }
252     else if (len <= 0xFF)
253     {
254         if (*datalen < 2)
255         {
256             return (NULL);
257         }
258         *data++ = (u_char)(0x01 | ASN_LONG_LEN);
259         *data++ = (u_char)len;
260     }
261     else    /* 0xFF < len <= 0xFFFF */
262     {
263         if (*datalen < 3)
264         {
265             return (NULL);
266         }
267         *data++ = (u_char)(0x02 | ASN_LONG_LEN);
268         *data++ = (u_char)((len >> 8) & 0xFF);
269         *data++ = (u_char)(len & 0xFF);
270     }
271     *datalen -= (data - start_data);
272     return (data);
273 }
274
275
276 u_char *
277 libnet_build_asn1_objid(u_char *data, int *datalen, u_char type, oid *objid,
278             int objidlen)
279 {
280     /*
281      *  ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
282      *  subidentifier ::= {leadingbyte}* lastbyte
283      *  leadingbyte ::= 1 7bitvalue
284      *  lastbyte ::= 0 7bitvalue
285      */
286     int asnlen;
287     register oid *op = objid;
288     u_char objid_size[MAX_OID_LEN];
289     register u_long objid_val;
290     u_long first_objid_val;
291     register int i;
292
293     /* check if there are at least 2 sub-identifiers */
294     if (objidlen < 2)
295     {
296         /* there are not, so make OID have two with value of zero */
297         objid_val = 0;
298         objidlen  = 2;
299     }
300     else
301     {
302         /* combine the first two values */
303         objid_val = (op[0] * 40) + op[1];
304         op += 2;
305     }
306     first_objid_val = objid_val;
307
308     /* calculate the number of bytes needed to store the encoded value */
309     for (i = 1, asnlen = 0;;)
310     {
311         if (objid_val < (unsigned)0x80)
312         {
313             objid_size[i] = 1;
314             asnlen += 1;
315         }
316         else if (objid_val < (unsigned)0x4000)
317         {
318             objid_size[i] = 2;
319             asnlen += 2;
320         }
321         else if (objid_val < (unsigned)0x200000)
322         {
323             objid_size[i] = 3;
324             asnlen += 3;
325         }
326         else if (objid_val < (unsigned)0x10000000)
327         {
328             objid_size[i] = 4;
329             asnlen += 4;
330         }
331         else
332         {
333             objid_size[i] = 5;
334             asnlen += 5;
335         }
336         i++;
337         if (i >= objidlen)
338         {
339             break;
340         }
341         objid_val = *op++;
342     }
343
344     /* store the ASN.1 tag and length */
345     data = libnet_build_asn1_header(data, datalen, type, asnlen);
346     if (data == NULL || *datalen < asnlen)
347     {
348         return (NULL);
349     }
350
351     /* store the encoded OID value */
352     for (i = 1, objid_val = first_objid_val, op = objid + 2; i < objidlen; i++)
353     {
354         if (i != 1)
355         {
356             objid_val = *op++;
357         }
358         switch (objid_size[i])
359         {
360             case 1:
361                 *data++ = (u_char)objid_val;
362                 break;
363
364             case 2:
365                 *data++ = (u_char)((objid_val >> 7) | 0x80);
366                 *data++ = (u_char)(objid_val & 0x07f);
367                 break;
368             case 3:
369                 *data++ = (u_char)((objid_val >> 14) | 0x80);
370                 *data++ = (u_char)((objid_val >> 7 & 0x7f) | 0x80);
371                 *data++ = (u_char)(objid_val & 0x07f);
372                 break;
373
374             case 4:
375                 *data++ = (u_char)((objid_val >> 21) | 0x80);
376                 *data++ = (u_char)((objid_val >> 14 & 0x7f) | 0x80);
377                 *data++ = (u_char)((objid_val >> 7 & 0x7f) | 0x80);
378                 *data++ = (u_char)(objid_val & 0x07f);
379                 break;
380
381             case 5:
382                 *data++ = (u_char)((objid_val >> 28) | 0x80);
383                 *data++ = (u_char)((objid_val >> 21 & 0x7f) | 0x80);
384                 *data++ = (u_char)((objid_val >> 14 & 0x7f) | 0x80);
385                 *data++ = (u_char)((objid_val >> 7 & 0x7f) | 0x80);
386                 *data++ = (u_char)(objid_val & 0x07f);
387                 break;
388         }
389     }
390
391     /* return the length and data ptr */
392     *datalen -= asnlen;
393     return (data);
394 }
395
396
397 u_char *
398 libnet_build_asn1_null(u_char *data, int *datalen, u_char type)
399 {
400     /*
401      *  ASN.1 null ::= 0x05 0x00
402      */       
403     return (libnet_build_asn1_header(data, datalen, type, 0));
404 }
405
406
407 u_char *
408 libnet_build_asn1_bitstring(u_char *data, int *datalen, u_char type,
409             u_char *string, int str_s)
410 {
411
412     /*
413      *  ASN.1 bit string ::= 0x03 asnlength unused {byte}*
414      */
415     if (str_s < 1 || *string > 7)
416     {
417         return (NULL);
418     }
419     data = libnet_build_asn1_header(data, datalen, type, str_s);
420
421     if (data == NULL || *datalen < str_s)
422     {
423         return (NULL);
424     }
425
426     memmove(data, string, str_s);
427     *datalen -= str_s;
428
429     return (data + str_s);
430 }
431
432 /* EOF */