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