* $Id: libnet_asn1.c,v 1.19 2005/11/29 22:53:41 carlosc Exp $
* libnet_asn1.c - Abstract Syntax Notation One routines
* Abstract Syntax Notation One, ASN.1
* As defined in ISO/IS 8824 and ISO/IS 8825
* This implements a subset of the above International Standards that
* is sufficient to implement SNMP.
* Encodes abstract data types into a machine independent stream of bytes.
* Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of CMU not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
* CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
* Copyright (c) 1993, 1994, 1995, 1996, 1998
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#include "../include/config.h"
#if (!(_WIN32) || (__CYGWIN__))
#include "../include/libnet.h"
#include "../include/win32/libnet.h"
libnet_build_asn1_int(u_int8_t
*data
, int *datalen
, u_int8_t type
, int32_t *int_p
,
* ASN.1 integer ::= 0x02 asnlength byte {byte}*
register int32_t integer
;
if (int_s
!= sizeof (int32_t))
* Truncate "unnecessary" bytes off of the most significant end of this
* 2's complement integer. There should be no sequence of 9 consecutive
* 1's or 0's at the most significant end of the integer.
mask
= ((u_int32_t
) 0x1FF) << ((8 * (sizeof (int32_t) - 1)) - 1);
/* mask is 0xFF800000 on a big-endian machine */
while ((((integer
& mask
) == 0) || ((integer
& mask
) == mask
)) && int_s
> 1)
data
= libnet_build_asn1_header(data
, datalen
, type
, int_s
);
if (data
== NULL
|| *datalen
< int_s
)
mask
= ((u_int32_t
) 0xFF) << (8 * (sizeof(int32_t) - 1));
/* mask is 0xFF000000 on a big-endian machine */
*data
++ = (u_int8_t
)((integer
& mask
) >> (8 * (sizeof (int32_t) - 1)));
libnet_build_asn1_uint(u_int8_t
*data
, int *datalen
, u_int8_t type
, u_int32_t
*int_p
,
* ASN.1 integer ::= 0x02 asnlength byte {byte}*
register u_int32_t integer
;
if (int_s
!= sizeof (int32_t))
mask
= ((u_int32_t
) 0xFF) << (8 * (sizeof (int32_t) - 1));
/* mask is 0xFF000000 on a big-endian machine */
if ((u_int8_t
)((integer
& mask
) >> (8 * (sizeof (int32_t) - 1))) & 0x80)
* Truncate "unnecessary" bytes off of the most significant end of this
* 2's complement integer. There should be no sequence of 9
* consecutive 1's or 0's at the most significant end of the
mask
= ((u_int32_t
) 0x1FF) << ((8 * (sizeof(int32_t) - 1)) - 1);
/* mask is 0xFF800000 on a big-endian machine */
while (((integer
& mask
) == 0) && int_s
> 1)
data
= libnet_build_asn1_header(data
, datalen
, type
, int_s
);
if (data
== NULL
|| *datalen
< int_s
)
mask
= ((u_int32_t
) 0xFF) << (8 * (sizeof(int32_t) - 1));
/* mask is 0xFF000000 on a big-endian machine */
*data
++ = (u_int8_t
)((integer
& mask
) >> (8 * (sizeof (int32_t) - 1)));
libnet_build_asn1_string(u_int8_t
*data
, int *datalen
, u_int8_t type
,
u_int8_t
*string
, int str_s
)
* ASN.1 octet string ::= primstring | cmpdstring
* primstring ::= 0x04 asnlength byte {byte}*
* cmpdstring ::= 0x24 asnlength string {string}*
* This code will never send a compound string.
data
= libnet_build_asn1_header(data
, datalen
, type
, str_s
);
if (data
== NULL
|| *datalen
< str_s
)
memmove(data
, string
, str_s
);
libnet_build_asn1_header(u_int8_t
*data
, int *datalen
, u_int8_t type
, int len
)
return (libnet_build_asn1_length(data
, datalen
, len
));
libnet_build_asn1_sequence(u_int8_t
*data
, int *datalen
, u_int8_t type
, int len
)
*datalen
+= 4; /* fix up before punting */
*data
++ = (u_int8_t
)(0x02 | ASN_LONG_LEN
);
*data
++ = (u_int8_t
)((len
>> 8) & 0xFF);
*data
++ = (u_int8_t
)(len
& 0xFF);
libnet_build_asn1_length(u_int8_t
*data
, int *datalen
, int len
)
u_int8_t
*start_data
= data
;
/* no indefinite lengths sent */
*data
++ = (u_int8_t
)(0x01 | ASN_LONG_LEN
);
else /* 0xFF < len <= 0xFFFF */
*data
++ = (u_int8_t
)(0x02 | ASN_LONG_LEN
);
*data
++ = (u_int8_t
)((len
>> 8) & 0xFF);
*data
++ = (u_int8_t
)(len
& 0xFF);
*datalen
-= (data
- start_data
);
libnet_build_asn1_objid(u_int8_t
*data
, int *datalen
, u_int8_t type
, oid
*objid
,
* ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
* subidentifier ::= {leadingbyte}* lastbyte
* leadingbyte ::= 1 7bitvalue
* lastbyte ::= 0 7bitvalue
register oid
*op
= objid
;
u_int8_t objid_size
[MAX_OID_LEN
];
register u_int32_t objid_val
;
u_int32_t first_objid_val
;
/* check if there are at least 2 sub-identifiers */
/* there are not, so make OID have two with value of zero */
/* combine the first two values */
objid_val
= (op
[0] * 40) + op
[1];
first_objid_val
= objid_val
;
/* calculate the number of bytes needed to store the encoded value */
for (i
= 1, asnlen
= 0;;)
if (objid_val
< (unsigned)0x80)
else if (objid_val
< (unsigned)0x4000)
else if (objid_val
< (unsigned)0x200000)
else if (objid_val
< (unsigned)0x10000000)
/* store the ASN.1 tag and length */
data
= libnet_build_asn1_header(data
, datalen
, type
, asnlen
);
if (data
== NULL
|| *datalen
< asnlen
)
/* store the encoded OID value */
for (i
= 1, objid_val
= first_objid_val
, op
= objid
+ 2; i
< objidlen
; i
++)
*data
++ = (u_int8_t
)objid_val
;
*data
++ = (u_int8_t
)((objid_val
>> 7) | 0x80);
*data
++ = (u_int8_t
)(objid_val
& 0x07f);
*data
++ = (u_int8_t
)((objid_val
>> 14) | 0x80);
*data
++ = (u_int8_t
)((objid_val
>> 7 & 0x7f) | 0x80);
*data
++ = (u_int8_t
)(objid_val
& 0x07f);
*data
++ = (u_int8_t
)((objid_val
>> 21) | 0x80);
*data
++ = (u_int8_t
)((objid_val
>> 14 & 0x7f) | 0x80);
*data
++ = (u_int8_t
)((objid_val
>> 7 & 0x7f) | 0x80);
*data
++ = (u_int8_t
)(objid_val
& 0x07f);
*data
++ = (u_int8_t
)((objid_val
>> 28) | 0x80);
*data
++ = (u_int8_t
)((objid_val
>> 21 & 0x7f) | 0x80);
*data
++ = (u_int8_t
)((objid_val
>> 14 & 0x7f) | 0x80);
*data
++ = (u_int8_t
)((objid_val
>> 7 & 0x7f) | 0x80);
*data
++ = (u_int8_t
)(objid_val
& 0x07f);
/* return the length and data ptagr */
libnet_build_asn1_null(u_int8_t
*data
, int *datalen
, u_int8_t type
)
* ASN.1 null ::= 0x05 0x00
return (libnet_build_asn1_header(data
, datalen
, type
, 0));
libnet_build_asn1_bitstring(u_int8_t
*data
, int *datalen
, u_int8_t type
,
u_int8_t
*string
, int str_s
)
* ASN.1 bit string ::= 0x03 asnlength unused {byte}*
if (str_s
< 1 || *string
> 7)
data
= libnet_build_asn1_header(data
, datalen
, type
, str_s
);
if (data
== NULL
|| *datalen
< str_s
)
memmove(data
, string
, str_s
);