/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ASN.1 encoding related routines
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asn1.h"
#include "pdu.h"
#include "debug.h"
/*
* This routine builds a 'SEQUENCE OF' ASN.1 object in the buffer
* using the 'id' and 'length' supplied. This is probably the place
* where using "reverse" asn encoding will help.
*/
uchar_t *
{
/*
* When rebuilding sequence (which we do many times), we'll
* simply pass NULL to bufsz_p to skip the error check.
*/
return (NULL);
if (bufsz_p)
*bufsz_p -= 4;
return (buf + 4);
}
/*
* The next two routines, asn_build_header() and asn_build_length(), build
* the header and length for an arbitrary object type into the buffer. The
* length of the object is encoded using as few length octets as possible.
*/
uchar_t *
{
if (*bufsz_p < 1)
return (NULL);
(*bufsz_p)--;
}
uchar_t *
{
if (length < 0x80) {
if (*bufsz_p < 1)
return (NULL);
(*bufsz_p)--;
return (buf + 1);
} else if (length <= 0xFF) {
if (*bufsz_p < 2)
return (NULL);
*bufsz_p -= 2;
return (buf + 2);
} else {
if (*bufsz_p < 3)
return (NULL);
*bufsz_p -= 3;
return (buf + 3);
}
}
/*
* Builds an ASN.1 encoded integer in the buffer using as few octets
* as possible.
*/
uchar_t *
{
int ival, i;
short sval;
char cval;
/*
* We need to "pack" the integer before sending it, so determine
* the minimum number of bytes in which we can pack the integer
*/
valsz = 1;
valsz = 2;
valsz = 3;
else
valsz = 4;
/*
* Prepare the ASN.1 header for the integer
*/
return (NULL);
/*
* If we have enough space left, encode the integer
*/
return (NULL);
else {
for (i = 0; i < valsz; i++)
return (p + valsz);
}
}
/*
* Builds an ASN.1 encoded octet string in the buffer. The source string
* need not be null-terminated.
*/
uchar_t *
{
uchar_t *p;
return (NULL);
return (NULL);
else {
if (str) {
} else {
}
return (p + slen);
}
}
/*
* Builds an Object Identifier into the buffer according to the OID
* packing and encoding rules.
*/
uchar_t *
{
uchar_t *p;
int i, ndx;
/*
* Eliminate invalid cases
*/
return (NULL);
return (NULL);
/*
* The BER encoding rule for the ASN.1 Object Identifier states
* that after packing the first two subids into one, each subsequent
* component is considered as the next subid. Each subidentifier is
* then encoded as a non-negative integer using as few 7-bit blocks
* as possible. The blocks are packed in octets with the first bit of
* each octet equal to 1, except for the last octet of each subid.
*/
oid_asnlen = 0;
if (i == 0) {
/*
* The packing formula for the first two subids
* of an OID is given by Z = (X * 40) + Y
*/
first_subid = subid;
i++; /* done with both subids 0 and 1 */
} else {
}
else {
}
}
return (NULL);
if (*bufsz_p < oid_asnlen)
return (NULL);
/*
* Store the encoded OID
*/
if (i == 0) {
subid = first_subid;
i++;
} else {
}
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
}
}
*bufsz_p -= oid_asnlen;
return (p);
}
/*
* Build an ASN_NULL object val into the request packet
*/
uchar_t *
{
uchar_t *p;
return (p);
}
/*
* This routine parses a 'SEQUENCE OF' object header from the input
* buffer stream. If the identifier tag (made up of class, constructed
* type and data type tag) does not match the expected identifier tag,
* returns failure.
*/
uchar_t *
{
uchar_t *p;
return (NULL);
return (NULL);
return (p);
}
/*
* Return the type identifier of the ASN object via 'id'
*/
uchar_t *
{
uchar_t *p;
/*
* Objects with extension tag type are not supported
*/
return (NULL);
/*
* Parse the length field of the ASN object in the header
*/
return (NULL);
/*
* Check if the rest of the msg packet is big enough for the
* full length of the object
*/
return (NULL);
return (p);
}
/*
* This routine parses the length of the object as specified in its
* header. The 'Indefinite' form of representing length is not supported.
*/
uchar_t *
{
uchar_t *p;
int n_length_octets;
/*
* First, check for the short-definite form. Length of
* the object is simply the least significant 7-bits of
* the first byte.
*/
if ((buf[0] & ASN_LONG_LEN) == 0) {
return (buf + 1);
}
/*
* Then, eliminate the indefinite form. The ASN_LONG_LEN
* bit of the first byte will be set and the least significant
* 7-bites of that byte will be zeros.
*/
return (NULL);
/*
* Then, eliminate the long-definite case when the number of
* follow-up octets is more than what the size var can hold.
*/
if (n_length_octets > sizeof (*asnobj_len_p))
return (NULL);
/*
* Finally gather the length
*/
p = buf + 1;
*asnobj_len_p = 0;
while (n_length_octets--) {
*asnobj_len_p <<= 8;
*asnobj_len_p |= *p++;
}
return (p);
}
/*
* Parses an integer out of the input buffer
*/
uchar_t *
{
uchar_t *p;
return (NULL);
/*
* Read in the length of the object; Note that integers are
* "packed" when sent from agent to manager and vice-versa,
* so the size of the object could be less than sizeof (int).
*/
return (NULL);
/*
* Is there sufficient space left in the packet to read the integer ?
*/
return (NULL);
/*
* Update space left in the buffer after the integer is read
*/
/*
* Read in the integer value
*/
while (asnobj_len--) {
*ival <<= 8;
*ival |= *p++;
}
return (p);
}
/*
* Parses an unsigned integer out of the input buffer
*/
uchar_t *
{
uchar_t *p;
return (NULL);
/*
* Read in the length of the object. Integers are sent the same
* way unsigned integers are sent. Except that, if the MSB was 1
* in the unsigned int value, a null-byte is attached to the front.
* Otherwise, packing rules are the same as for integer values.
*/
return (NULL);
/*
* Is there sufficient space left in the packet to read in the value ?
*/
return (NULL);
/*
* Update space left in the buffer after the uint is read
*/
/*
* Read in the unsigned integer (this should never get
* initialized to ~0 if it was sent right)
*/
while (asnobj_len--) {
*uival <<= 8;
*uival |= *p++;
}
return (p);
}
/*
* Parses a string (ASN_OCTET_STR or ASN_BIT_STR) out of the input buffer.
* The memory for the string is allocated inside the routine and must be
* freed by the caller when it is no longer needed. If the string type is
* ASN_OCTET_STR, the returned string is null-terminated, and the returned
* length indicates the strlen value. If the string type is ASN_BIT_STR,
* the returned string is not null-terminated, and the returned length
* indicates the number of bytes.
*/
uchar_t *
{
uchar_t *p;
/*
* Octet and bit strings are supported
*/
return (NULL);
/*
* Parse out the length of the object and verify source buf sz
*/
return (NULL);
return (NULL);
/*
* Allocate for and copy out the string
*/
return (NULL);
/*
* Terminate the octet string with a null
*/
(*str_p)[asnobj_len] = 0;
}
/*
* Update pointers and return
*/
*slen = asnobj_len;
return (p + asnobj_len);
}
/*
* Parses an object identifier out of the input packet buffer. Space for
* the oid object is allocated within this routine and must be freed by the
* caller when no longer needed.
*/
uchar_t *
{
uchar_t *p;
int i, ndx;
/*
* Check id
*/
return (NULL);
/*
* Read object length
*/
return (NULL);
/*
* Check space in input message
*/
return (NULL);
/*
* Since the OID subidentifiers are packed in 7-bit blocks with
* MSB set to 1 for all but the last octet, the number of subids
* is simply the number of octets with MSB equal to 0, plus 1
* (since the first two subids were packed into one subid and have
* to be expanded back to two).
*/
*n_subids = 1;
for (i = 0; i < asnobj_len; i++) {
if ((p[i] & ASN_BIT8) == 0)
(*n_subids)++;
}
/*
* Now allocate for the oid and parse the OID into it
*/
return (NULL);
subid = 0;
for (i = 0; i < asnobj_len; i++) {
if ((p[i] & ASN_BIT8) == 0) {
ndx++;
subid = 0;
}
}
/*
* Now unpack the first two subids from the subid at index 1.
*/
objid[0] = 0;
objid[0] = 1;
} else {
objid[0] = 2;
}
}
/*
* Parses the value of an OID object out of the input message buffer.
* Only type tags less than ASN_EXT_TAG (0x1f) are supported.
*/
uchar_t *
{
uchar_t *p;
return (NULL);
/*
* Currently we handle ASN_INTEGER, ASN_OCTET_STR, ASN_BIT_STR
* and ASN_TIMETICKS types.
*/
switch (msg[0]) {
return (NULL);
return (NULL);
}
break;
case ASN_COUNTER:
case ASN_TIMETICKS:
return (NULL);
return (NULL);
}
break;
if (p == NULL)
return (NULL);
break;
if (p == NULL)
return (NULL);
break;
case SNMP_NOSUCHOBJECT:
case SNMP_NOSUCHINSTANCE:
case SNMP_ENDOFMIBVIEW:
default:
if (p == NULL)
return (NULL);
return (NULL);
p += asnobj_len;
break;
}
return (p);
}