Annotation of embedaddon/libnet/src/libnet_asn1.c, revision 1.1.1.3
1.1 misho 1: /*
2: * $Id: libnet_asn1.c,v 1.5 2004/01/03 20:31:01 mike Exp $
3: *
4: * libnet 1.1
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 - 2004 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:
1.1.1.3 ! misho 56: #include "common.h"
1.1 misho 57:
1.1.1.2 misho 58: uint8_t *
59: libnet_build_asn1_int(uint8_t *data, int *datalen, uint8_t type, int32_t *int_p,
1.1 misho 60: int int_s)
61: {
62: /*
63: * ASN.1 integer ::= 0x02 asnlength byte {byte}*
64: */
65: register int32_t integer;
1.1.1.2 misho 66: register uint32_t mask;
1.1 misho 67:
68: if (int_s != sizeof (int32_t))
69: {
70: return (NULL);
71: }
72: integer = *int_p;
73:
74: /*
75: * Truncate "unnecessary" bytes off of the most significant end of this
76: * 2's complement integer. There should be no sequence of 9 consecutive
77: * 1's or 0's at the most significant end of the integer.
78: */
1.1.1.2 misho 79: mask = ((uint32_t) 0x1FF) << ((8 * (sizeof (int32_t) - 1)) - 1);
1.1 misho 80: /* mask is 0xFF800000 on a big-endian machine */
81:
82: while ((((integer & mask) == 0) || ((integer & mask) == mask)) && int_s > 1)
83: {
84: int_s--;
85: integer <<= 8;
86: }
87:
88: data = libnet_build_asn1_header(data, datalen, type, int_s);
89:
90: if (data == NULL || *datalen < int_s)
91: {
92: return (NULL);
93: }
94:
95: *datalen -= int_s;
96:
1.1.1.2 misho 97: mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1));
1.1 misho 98: /* mask is 0xFF000000 on a big-endian machine */
99:
100: while (int_s--)
101: {
1.1.1.2 misho 102: *data++ = (uint8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1)));
1.1 misho 103: integer <<= 8;
104: }
105: return (data);
106: }
107:
108:
1.1.1.2 misho 109: uint8_t *
110: libnet_build_asn1_uint(uint8_t *data, int *datalen, uint8_t type, uint32_t *int_p,
1.1 misho 111: int int_s)
112: {
113: /*
114: * ASN.1 integer ::= 0x02 asnlength byte {byte}*
115: */
1.1.1.2 misho 116: register uint32_t integer;
117: register uint32_t mask;
1.1 misho 118: int add_null_byte = 0;
119:
120: if (int_s != sizeof (int32_t))
121: {
122: return (NULL);
123: }
124: integer = *int_p;
125:
1.1.1.2 misho 126: mask = ((uint32_t) 0xFF) << (8 * (sizeof (int32_t) - 1));
1.1 misho 127: /* mask is 0xFF000000 on a big-endian machine */
128:
1.1.1.2 misho 129: if ((uint8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1))) & 0x80)
1.1 misho 130: {
131: /* if MSB is set */
132: add_null_byte = 1;
133: int_s++;
134: }
135: else
136: {
137: /*
138: * Truncate "unnecessary" bytes off of the most significant end of this
139: * 2's complement integer. There should be no sequence of 9
140: * consecutive 1's or 0's at the most significant end of the
141: * integer.
142: */
1.1.1.2 misho 143: mask = ((uint32_t) 0x1FF) << ((8 * (sizeof(int32_t) - 1)) - 1);
1.1 misho 144: /* mask is 0xFF800000 on a big-endian machine */
145:
146: while (((integer & mask) == 0) && int_s > 1)
147: {
148: int_s--;
149: integer <<= 8;
150: }
151: }
152:
153: data = libnet_build_asn1_header(data, datalen, type, int_s);
154:
155: if (data == NULL || *datalen < int_s)
156: {
157: return (NULL);
158: }
159:
160: *datalen -= int_s;
161:
162: if (add_null_byte == 1)
163: {
164: *data++ = '\0';
165: int_s--;
166: }
167:
1.1.1.2 misho 168: mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1));
1.1 misho 169: /* mask is 0xFF000000 on a big-endian machine */
170:
171: while (int_s--)
172: {
1.1.1.2 misho 173: *data++ = (uint8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1)));
1.1 misho 174: integer <<= 8;
175: }
176: return (data);
177: }
178:
179:
1.1.1.2 misho 180: uint8_t *
181: libnet_build_asn1_string(uint8_t *data, int *datalen, uint8_t type,
182: uint8_t *string, int str_s)
1.1 misho 183: {
184:
185: /*
186: * ASN.1 octet string ::= primstring | cmpdstring
187: * primstring ::= 0x04 asnlength byte {byte}*
188: * cmpdstring ::= 0x24 asnlength string {string}*
189: * This code will never send a compound string.
190: */
191: data = libnet_build_asn1_header(data, datalen, type, str_s);
192:
193: if (data == NULL || *datalen < str_s)
194: {
195: return (NULL);
196: }
197: memmove(data, string, str_s);
198: *datalen -= str_s;
199:
200: return (data + str_s);
201: }
202:
203:
1.1.1.2 misho 204: uint8_t *
205: libnet_build_asn1_header(uint8_t *data, int *datalen, uint8_t type, int len)
1.1 misho 206: {
207: if (*datalen < 1)
208: {
209: return (NULL);
210: }
211: *data++ = type;
212: (*datalen)--;
213:
214: return (libnet_build_asn1_length(data, datalen, len));
215: }
216:
217:
1.1.1.2 misho 218: uint8_t *
219: libnet_build_asn1_sequence(uint8_t *data, int *datalen, uint8_t type, int len)
1.1 misho 220: {
221: *datalen -= 4;
222: if (*datalen < 0)
223: {
224: *datalen += 4; /* fix up before punting */
225: return (NULL);
226: }
227: *data++ = type;
1.1.1.2 misho 228: *data++ = (uint8_t)(0x02 | ASN_LONG_LEN);
229: *data++ = (uint8_t)((len >> 8) & 0xFF);
230: *data++ = (uint8_t)(len & 0xFF);
1.1 misho 231: return (data);
232: }
233:
234:
1.1.1.2 misho 235: uint8_t *
236: libnet_build_asn1_length(uint8_t *data, int *datalen, int len)
1.1 misho 237: {
1.1.1.2 misho 238: uint8_t *start_data = data;
1.1 misho 239:
240: /* no indefinite lengths sent */
241: if (len < 0x80)
242: {
243: if (*datalen < 1)
244: {
245: return (NULL);
246: }
1.1.1.2 misho 247: *data++ = (uint8_t)len;
1.1 misho 248: }
249: else if (len <= 0xFF)
250: {
251: if (*datalen < 2)
252: {
253: return (NULL);
254: }
1.1.1.2 misho 255: *data++ = (uint8_t)(0x01 | ASN_LONG_LEN);
256: *data++ = (uint8_t)len;
1.1 misho 257: }
258: else /* 0xFF < len <= 0xFFFF */
259: {
260: if (*datalen < 3)
261: {
262: return (NULL);
263: }
1.1.1.2 misho 264: *data++ = (uint8_t)(0x02 | ASN_LONG_LEN);
265: *data++ = (uint8_t)((len >> 8) & 0xFF);
266: *data++ = (uint8_t)(len & 0xFF);
1.1 misho 267: }
1.1.1.3 ! misho 268: *datalen -= (int)(data - start_data);
1.1 misho 269: return (data);
270: }
271:
272:
1.1.1.2 misho 273: uint8_t *
274: libnet_build_asn1_objid(uint8_t *data, int *datalen, uint8_t type, oid *objid,
1.1 misho 275: int objidlen)
276: {
277: /*
278: * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
279: * subidentifier ::= {leadingbyte}* lastbyte
280: * leadingbyte ::= 1 7bitvalue
281: * lastbyte ::= 0 7bitvalue
282: */
283: int asnlen;
284: register oid *op = objid;
1.1.1.2 misho 285: uint8_t objid_size[MAX_OID_LEN];
286: register uint32_t objid_val;
287: uint32_t first_objid_val;
1.1 misho 288: register int i;
289:
290: /* check if there are at least 2 sub-identifiers */
291: if (objidlen < 2)
292: {
293: /* there are not, so make OID have two with value of zero */
294: objid_val = 0;
295: objidlen = 2;
296: }
297: else
298: {
299: /* combine the first two values */
300: objid_val = (op[0] * 40) + op[1];
301: op += 2;
302: }
303: first_objid_val = objid_val;
304:
305: /* calculate the number of bytes needed to store the encoded value */
306: for (i = 1, asnlen = 0;;)
307: {
308: if (objid_val < (unsigned)0x80)
309: {
310: objid_size[i] = 1;
311: asnlen += 1;
312: }
313: else if (objid_val < (unsigned)0x4000)
314: {
315: objid_size[i] = 2;
316: asnlen += 2;
317: }
318: else if (objid_val < (unsigned)0x200000)
319: {
320: objid_size[i] = 3;
321: asnlen += 3;
322: }
323: else if (objid_val < (unsigned)0x10000000)
324: {
325: objid_size[i] = 4;
326: asnlen += 4;
327: }
328: else
329: {
330: objid_size[i] = 5;
331: asnlen += 5;
332: }
333: i++;
334: if (i >= objidlen)
335: {
336: break;
337: }
338: objid_val = *op++;
339: }
340:
341: /* store the ASN.1 tag and length */
342: data = libnet_build_asn1_header(data, datalen, type, asnlen);
343: if (data == NULL || *datalen < asnlen)
344: {
345: return (NULL);
346: }
347:
348: /* store the encoded OID value */
349: for (i = 1, objid_val = first_objid_val, op = objid + 2; i < objidlen; i++)
350: {
351: if (i != 1)
352: {
353: objid_val = *op++;
354: }
355: switch (objid_size[i])
356: {
357: case 1:
1.1.1.2 misho 358: *data++ = (uint8_t)objid_val;
1.1 misho 359: break;
360:
361: case 2:
1.1.1.2 misho 362: *data++ = (uint8_t)((objid_val >> 7) | 0x80);
363: *data++ = (uint8_t)(objid_val & 0x07f);
1.1 misho 364: break;
365: case 3:
1.1.1.2 misho 366: *data++ = (uint8_t)((objid_val >> 14) | 0x80);
367: *data++ = (uint8_t)((objid_val >> 7 & 0x7f) | 0x80);
368: *data++ = (uint8_t)(objid_val & 0x07f);
1.1 misho 369: break;
370:
371: case 4:
1.1.1.2 misho 372: *data++ = (uint8_t)((objid_val >> 21) | 0x80);
373: *data++ = (uint8_t)((objid_val >> 14 & 0x7f) | 0x80);
374: *data++ = (uint8_t)((objid_val >> 7 & 0x7f) | 0x80);
375: *data++ = (uint8_t)(objid_val & 0x07f);
1.1 misho 376: break;
377:
378: case 5:
1.1.1.2 misho 379: *data++ = (uint8_t)((objid_val >> 28) | 0x80);
380: *data++ = (uint8_t)((objid_val >> 21 & 0x7f) | 0x80);
381: *data++ = (uint8_t)((objid_val >> 14 & 0x7f) | 0x80);
382: *data++ = (uint8_t)((objid_val >> 7 & 0x7f) | 0x80);
383: *data++ = (uint8_t)(objid_val & 0x07f);
1.1 misho 384: break;
385: }
386: }
387:
388: /* return the length and data ptagr */
389: *datalen -= asnlen;
390: return (data);
391: }
392:
393:
1.1.1.2 misho 394: uint8_t *
395: libnet_build_asn1_null(uint8_t *data, int *datalen, uint8_t type)
1.1 misho 396: {
397: /*
398: * ASN.1 null ::= 0x05 0x00
399: */
400: return (libnet_build_asn1_header(data, datalen, type, 0));
401: }
402:
403:
1.1.1.2 misho 404: uint8_t *
405: libnet_build_asn1_bitstring(uint8_t *data, int *datalen, uint8_t type,
406: uint8_t *string, int str_s)
1.1 misho 407: {
408:
409: /*
410: * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
411: */
412: if (str_s < 1 || *string > 7)
413: {
414: return (NULL);
415: }
416: data = libnet_build_asn1_header(data, datalen, type, str_s);
417:
418: if (data == NULL || *datalen < str_s)
419: {
420: return (NULL);
421: }
422:
423: memmove(data, string, str_s);
424: *datalen -= str_s;
425:
426: return (data + str_s);
427: }
428:
1.1.1.3 ! misho 429: /**
! 430: * Local Variables:
! 431: * indent-tabs-mode: nil
! 432: * c-file-style: "stroustrup"
! 433: * End:
! 434: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>