File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_asn1.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:14:23 2012 UTC (12 years, 4 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_2_1, HEAD
libnet

    1: /*
    2:  *  $Id: libnet_asn1.c,v 1.1.1.1 2012/02/21 22:14:23 misho 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>