2 * $Id: libnet_asn1.c,v 1.1.1.1 2000/05/25 00:28:49 route Exp $
5 * libnet_asn1.c - Abstract Syntax Notation One routines
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.
12 * Encodes abstract data types into a machine independent stream of bytes.
14 * Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
15 * All rights reserved.
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.
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
33 * Copyright (c) 1998 - 2001 Mike D. Schiffman <mike@infonexus.com>
34 * All rights reserved.
36 * Copyright (c) 1993, 1994, 1995, 1996, 1998
37 * The Regents of the University of California. All rights reserved.
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
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.
57 #include "../include/config.h"
59 #include "../include/libnet.h"
62 libnet_build_asn1_int(u_char *data, int *datalen, u_char type, long *int_p,
66 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
68 register long integer;
71 if (int_s != sizeof (long))
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.
82 mask = ((u_long) 0x1FF) << ((8 * (sizeof (long) - 1)) - 1);
83 /* mask is 0xFF800000 on a big-endian machine */
85 while ((((integer & mask) == 0) || ((integer & mask) == mask)) && int_s > 1)
91 data = libnet_build_asn1_header(data, datalen, type, int_s);
93 if (data == NULL || *datalen < int_s)
100 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
101 /* mask is 0xFF000000 on a big-endian machine */
105 *data++ = (u_char)((integer & mask) >> (8 * (sizeof (long) - 1)));
113 libnet_build_asn1_uint(u_char *data, int *datalen, u_char type, u_long *int_p,
117 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
119 register u_long integer;
120 register u_long mask;
121 int add_null_byte = 0;
123 if (int_s != sizeof (long))
129 mask = ((u_long) 0xFF) << (8 * (sizeof (long) - 1));
130 /* mask is 0xFF000000 on a big-endian machine */
132 if ((u_char)((integer & mask) >> (8 * (sizeof (long) - 1))) & 0x80)
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
146 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
147 /* mask is 0xFF800000 on a big-endian machine */
149 while (((integer & mask) == 0) && int_s > 1)
156 data = libnet_build_asn1_header(data, datalen, type, int_s);
158 if (data == NULL || *datalen < int_s)
165 if (add_null_byte == 1)
171 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
172 /* mask is 0xFF000000 on a big-endian machine */
176 *data++ = (u_char)((integer & mask) >> (8 * (sizeof (long) - 1)));
184 libnet_build_asn1_string(u_char *data, int *datalen, u_char type,
185 u_char *string, int str_s)
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.
194 data = libnet_build_asn1_header(data, datalen, type, str_s);
196 if (data == NULL || *datalen < str_s)
200 memmove(data, string, str_s);
203 return (data + str_s);
208 libnet_build_asn1_header(u_char *data, int *datalen, u_char type, int len)
217 return (libnet_build_asn1_length(data, datalen, len));
222 libnet_build_asn1_sequence(u_char *data, int *datalen, u_char type, int len)
227 *datalen += 4; /* fix up before punting */
231 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
232 *data++ = (u_char)((len >> 8) & 0xFF);
233 *data++ = (u_char)(len & 0xFF);
239 libnet_build_asn1_length(u_char *data, int *datalen, int len)
241 u_char *start_data = data;
243 /* no indefinite lengths sent */
250 *data++ = (u_char)len;
252 else if (len <= 0xFF)
258 *data++ = (u_char)(0x01 | ASN_LONG_LEN);
259 *data++ = (u_char)len;
261 else /* 0xFF < len <= 0xFFFF */
267 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
268 *data++ = (u_char)((len >> 8) & 0xFF);
269 *data++ = (u_char)(len & 0xFF);
271 *datalen -= (data - start_data);
277 libnet_build_asn1_objid(u_char *data, int *datalen, u_char type, oid *objid,
281 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
282 * subidentifier ::= {leadingbyte}* lastbyte
283 * leadingbyte ::= 1 7bitvalue
284 * lastbyte ::= 0 7bitvalue
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;
293 /* check if there are at least 2 sub-identifiers */
296 /* there are not, so make OID have two with value of zero */
302 /* combine the first two values */
303 objid_val = (op[0] * 40) + op[1];
306 first_objid_val = objid_val;
308 /* calculate the number of bytes needed to store the encoded value */
309 for (i = 1, asnlen = 0;;)
311 if (objid_val < (unsigned)0x80)
316 else if (objid_val < (unsigned)0x4000)
321 else if (objid_val < (unsigned)0x200000)
326 else if (objid_val < (unsigned)0x10000000)
344 /* store the ASN.1 tag and length */
345 data = libnet_build_asn1_header(data, datalen, type, asnlen);
346 if (data == NULL || *datalen < asnlen)
351 /* store the encoded OID value */
352 for (i = 1, objid_val = first_objid_val, op = objid + 2; i < objidlen; i++)
358 switch (objid_size[i])
361 *data++ = (u_char)objid_val;
365 *data++ = (u_char)((objid_val >> 7) | 0x80);
366 *data++ = (u_char)(objid_val & 0x07f);
369 *data++ = (u_char)((objid_val >> 14) | 0x80);
370 *data++ = (u_char)((objid_val >> 7 & 0x7f) | 0x80);
371 *data++ = (u_char)(objid_val & 0x07f);
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);
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);
391 /* return the length and data ptr */
398 libnet_build_asn1_null(u_char *data, int *datalen, u_char type)
401 * ASN.1 null ::= 0x05 0x00
403 return (libnet_build_asn1_header(data, datalen, type, 0));
408 libnet_build_asn1_bitstring(u_char *data, int *datalen, u_char type,
409 u_char *string, int str_s)
413 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
415 if (str_s < 1 || *string > 7)
419 data = libnet_build_asn1_header(data, datalen, type, str_s);
421 if (data == NULL || *datalen < str_s)
426 memmove(data, string, str_s);
429 return (data + str_s);