File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_asn1.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:11:38 2023 UTC (9 months, 1 week ago) by misho
Branches: libnet, MAIN
CVS tags: v1_2p1, HEAD
Version 1.2p1

    1: /*
    2:  *  $Id: libnet_asn1.c,v 1.1.1.3 2023/09/27 11:11:38 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: #include "common.h"
   57: 
   58: uint8_t *
   59: libnet_build_asn1_int(uint8_t *data, int *datalen, uint8_t type, int32_t *int_p,
   60:             int int_s)
   61: {
   62:     /*
   63:      *  ASN.1 integer ::= 0x02 asnlength byte {byte}*
   64:      */
   65:      register int32_t integer;
   66:      register uint32_t mask;
   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:      */
   79:     mask = ((uint32_t) 0x1FF) << ((8 * (sizeof (int32_t) - 1)) - 1);
   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: 
   97:     mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1));
   98:     /* mask is 0xFF000000 on a big-endian machine */
   99: 
  100:     while (int_s--)
  101:     {
  102:         *data++ = (uint8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1)));
  103:         integer <<= 8;
  104:     }
  105:     return (data);
  106: }
  107: 
  108: 
  109: uint8_t *
  110: libnet_build_asn1_uint(uint8_t *data, int *datalen, uint8_t type, uint32_t *int_p,
  111:             int int_s)
  112: {
  113:     /*
  114:      *  ASN.1 integer ::= 0x02 asnlength byte {byte}*
  115:      */
  116:     register uint32_t integer;
  117:     register uint32_t mask;
  118:     int add_null_byte = 0;
  119: 
  120:     if (int_s != sizeof (int32_t))
  121:     {
  122:         return (NULL);
  123:     }
  124:     integer = *int_p;
  125: 
  126:     mask = ((uint32_t) 0xFF) << (8 * (sizeof (int32_t) - 1));
  127:     /* mask is 0xFF000000 on a big-endian machine */
  128: 
  129:     if ((uint8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1))) & 0x80)
  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:          */
  143:         mask = ((uint32_t) 0x1FF) << ((8 * (sizeof(int32_t) - 1)) - 1);
  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: 
  168:     mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1));
  169:     /* mask is 0xFF000000 on a big-endian machine */
  170: 
  171:     while (int_s--)
  172:     {
  173:         *data++ = (uint8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1)));
  174:         integer <<= 8;
  175:     }
  176:     return (data);
  177: }
  178: 
  179: 
  180: uint8_t *
  181: libnet_build_asn1_string(uint8_t *data, int *datalen, uint8_t type,
  182:             uint8_t *string, int str_s)
  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: 
  204: uint8_t *
  205: libnet_build_asn1_header(uint8_t *data, int *datalen, uint8_t type, int len)
  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: 
  218: uint8_t *
  219: libnet_build_asn1_sequence(uint8_t *data, int *datalen, uint8_t type, int len)
  220: {
  221:     *datalen -= 4;
  222:     if (*datalen < 0)
  223:     {
  224:         *datalen += 4;       /* fix up before punting */
  225:         return (NULL);
  226:     }
  227:     *data++ = type;
  228:     *data++ = (uint8_t)(0x02 | ASN_LONG_LEN);
  229:     *data++ = (uint8_t)((len >> 8) & 0xFF);
  230:     *data++ = (uint8_t)(len & 0xFF);
  231:     return (data);
  232: }
  233: 
  234: 
  235: uint8_t *
  236: libnet_build_asn1_length(uint8_t *data, int *datalen, int len)
  237: {
  238:     uint8_t *start_data = data;
  239: 
  240:     /* no indefinite lengths sent */
  241:     if (len < 0x80)
  242:     {
  243:         if (*datalen < 1)
  244:         {
  245:             return (NULL);
  246:         }
  247:         *data++ = (uint8_t)len;
  248:     }
  249:     else if (len <= 0xFF)
  250:     {
  251:         if (*datalen < 2)
  252:         {
  253:             return (NULL);
  254:         }
  255:         *data++ = (uint8_t)(0x01 | ASN_LONG_LEN);
  256:         *data++ = (uint8_t)len;
  257:     }
  258:     else    /* 0xFF < len <= 0xFFFF */
  259:     {
  260:         if (*datalen < 3)
  261:         {
  262:             return (NULL);
  263:         }
  264:         *data++ = (uint8_t)(0x02 | ASN_LONG_LEN);
  265:         *data++ = (uint8_t)((len >> 8) & 0xFF);
  266:         *data++ = (uint8_t)(len & 0xFF);
  267:     }
  268:     *datalen -= (int)(data - start_data);
  269:     return (data);
  270: }
  271: 
  272: 
  273: uint8_t *
  274: libnet_build_asn1_objid(uint8_t *data, int *datalen, uint8_t type, oid *objid,
  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;
  285:     uint8_t objid_size[MAX_OID_LEN];
  286:     register uint32_t objid_val;
  287:     uint32_t first_objid_val;
  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:
  358:                 *data++ = (uint8_t)objid_val;
  359:                 break;
  360: 
  361:             case 2:
  362:                 *data++ = (uint8_t)((objid_val >> 7) | 0x80);
  363:                 *data++ = (uint8_t)(objid_val & 0x07f);
  364:                 break;
  365:             case 3:
  366:                 *data++ = (uint8_t)((objid_val >> 14) | 0x80);
  367:                 *data++ = (uint8_t)((objid_val >> 7 & 0x7f) | 0x80);
  368:                 *data++ = (uint8_t)(objid_val & 0x07f);
  369:                 break;
  370: 
  371:             case 4:
  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);
  376:                 break;
  377: 
  378:             case 5:
  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);
  384:                 break;
  385:         }
  386:     }
  387: 
  388:     /* return the length and data ptagr */
  389:     *datalen -= asnlen;
  390:     return (data);
  391: }
  392: 
  393: 
  394: uint8_t *
  395: libnet_build_asn1_null(uint8_t *data, int *datalen, uint8_t type)
  396: {
  397:     /*
  398:      *  ASN.1 null ::= 0x05 0x00
  399:      */       
  400:     return (libnet_build_asn1_header(data, datalen, type, 0));
  401: }
  402: 
  403: 
  404: uint8_t *
  405: libnet_build_asn1_bitstring(uint8_t *data, int *datalen, uint8_t type,
  406:             uint8_t *string, int str_s)
  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: 
  429: /**
  430:  * Local Variables:
  431:  *  indent-tabs-mode: nil
  432:  *  c-file-style: "stroustrup"
  433:  * End:
  434:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>