/*++ Copyright (c) 1992-1996 Microsoft Corporation Module Name: berapi.c Abstract: ASN.1 BER Encode/Decode APIs Environment: User Mode - Win32 Revision History: 10-May-1996 DonRyan Removed banner from Technology Dynamics, Inc. --*/ //--------------------------- WINDOWS DEPENDENCIES -------------------------- //--------------------------- STANDARD DEPENDENCIES -- #include ---- #include //--------------------------- MODULE DEPENDENCIES -- #include"xxxxx.h" ------ #include #include #include "authapi.h" //--------------------------- SELF-DEPENDENCY -- ONE #include"module.h" ----- #include "berapi.h" //--------------------------- PUBLIC VARIABLES --(same as in module.h file)-- //--------------------------- PRIVATE CONSTANTS ----------------------------- // BER limits #define BER_OCTET_LEN 8 // 8 bits in an octet #define BER_OCTET_SIZE 256 // 8 bits make an octet #define BER_MAX_INT_OCTETS 4 // 4 octets - 32 bit integer #define BER_MAX_LEN_OCTETS 2 // 2 octets - 16 bit integer length #define BER_MAX_STREAM_LEN 0xffff // 16 bit unsigned integer #define BER_MIN_HEADER_LEN 2 // 2 octets #define BER_MAX_SIMPLE_LEN 127 // SNMP BER definition // Buffer offsets for info. #define BER_TAG_OFFSET 0 #define BER_LENGTH_OFFSET 1 // Meaningful bit definitions #define BER_EXTENDED_TAG 0x1f // 00011111 #define BER_OCTET_CONT_BIT 0x80 // 10000000 // BER OBJECTIDENTIFIER limits #define BER_MAX_FIRST_ELEM 2 // Obj Id's 1st element must be 0-2 #define BER_MAX_SECOND_ELEM 39 // Obj Id's 2nd element must be 0-40 #define BER_SUBOID_BLK_SIZE 20 // Number of Sub OID's to alloc at once. //--------------------------- PRIVATE STRUCTS ------------------------------- //--------------------------- PRIVATE VARIABLES ----------------------------- //--------------------------- PRIVATE MACROS -------------------------------- // This macro requires that a label named 'Exit' exists in the function // and handles any cleanup procedures the function needs to do // before exiting. #define BERAPI_ERROR( X ) \ SetLastError( X ); \ nResult = SNMPAPI_ERROR; \ goto Exit \ //--------------------------- PRIVATE PROTOTYPES ---------------------------- SNMPAPI BER_CreateHeader( IN BYTE nTag, IN UINT nObjLen, IN OUT BYTE **pBuffer, IN OUT UINT *nStart ); SNMPAPI BER_ProcessHeader( IN BYTE nTag, IN BYTE *BufPtr, IN UINT BufLen, OUT UINT *StrLen, OUT UINT *HeadLen ); SNMPAPI BER_DecodeAsnInteger( IN BYTE nTag, // Expect type of integer IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded integer and specific type ); SNMPAPI BER_DecodeAsnOctetStr( IN BYTE nTag, // Expect type of OctetStr IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded OctetStr and specific type ); SNMPAPI BER_DecodeAsnNull( IN BYTE nTag, // Expect type of NULL IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded NULL and specific type ); SNMPAPI BER_DecodeAsnObjectId( IN BYTE nTag, // Expect type of ObjectId IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded ObjectId and specific type ); SNMPAPI BER_DecodeAsnImplicitSeq( IN BYTE nTag, // Expected type of sequence IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded sequence and specific type ); //--------------------------- PRIVATE PROCEDURES ---------------------------- //--------------------------- PUBLIC PROCEDURES ----------------------------- // // SnmpBerDecodeAsnStream // Will decode next object in stream, based on expected type. // // Notes: // If expected type does not match what is in buffer, an error is generated. // // "Extended Tags" (tags requiring more than one octet) are invalid. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_BERAPI_INVALID_TAG // SNMPAPI SnmpBerDecodeAsnStream( IN BYTE idExpectedAsnType, // Expected type of ASN object IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer OUT AsnAny *pResult // Contains decoded object and type ) { SNMPAPI nResult; // Call appropriate routine to convert ASN.1 type switch ( idExpectedAsnType ) { case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: case ASN_INTEGER: nResult = BER_DecodeAsnInteger( idExpectedAsnType, pBuffer, nLength, pResult ); break; case ASN_RFC1155_IPADDRESS: case ASN_RFC1155_OPAQUE: case ASN_OCTETSTRING: nResult = BER_DecodeAsnOctetStr( idExpectedAsnType, pBuffer, nLength, pResult ); break; case ASN_NULL: nResult = BER_DecodeAsnNull( idExpectedAsnType, pBuffer, nLength, pResult ); break; case ASN_OBJECTIDENTIFIER: nResult = BER_DecodeAsnObjectId( idExpectedAsnType, pBuffer, nLength, pResult ); break; case ASN_SEQUENCE: case ASN_RFC1157_GETREQUEST: case ASN_RFC1157_GETNEXTREQUEST: case ASN_RFC1157_GETRESPONSE: case ASN_RFC1157_SETREQUEST: case ASN_RFC1157_TRAP: case ASN_RFCxxxx_PRIVDATA: nResult = BER_DecodeAsnImplicitSeq( idExpectedAsnType, pBuffer, nLength, pResult ); break; default: BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG ); } Exit: return nResult; } // end SnmpBerDecodeAsnStream() // // SnmpBerEncodeAsnAny // Encodes any ASN type, except sequences, implicit or normal. // // Notes: // "Extended Tags" are invalid. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_BERAPI_INVALID_TAG // SNMPAPI SnmpBerEncodeAsnAny( IN AsnAny *pItem, IN OUT BYTE **pBuffer, IN OUT UINT *nLength ) { SNMPAPI nResult; // Call appropriate routine to convert ASN.1 type switch ( pItem->asnType ) { case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: case ASN_INTEGER: nResult = SnmpBerEncodeAsnInteger( pItem->asnType, pItem->asnValue.number, pBuffer, nLength ); break; case ASN_RFC1155_IPADDRESS: case ASN_RFC1155_OPAQUE: case ASN_OCTETSTRING: nResult = SnmpBerEncodeAsnOctetStr( pItem->asnType, &pItem->asnValue.string, pBuffer, nLength ); break; case ASN_NULL: nResult = SnmpBerEncodeAsnNull( pItem->asnType, pBuffer, nLength ); break; case ASN_OBJECTIDENTIFIER: nResult = SnmpBerEncodeAsnObjectId( pItem->asnType, &pItem->asnValue.object, pBuffer, nLength ); break; default: BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG ); } Exit: return nResult; } // SnmpBerEncodeAsnAny // // BER_CreateHeader // // Notes: // If an error occurs during this routine, it is the responsibility of // the calling routine to free any memory that may or may not have // been realloc'ed by BER_CreateHeader. // // The buffer information must be initialized before calling this routine. // If this is the first routine to alloc memory for the buffer, it must be // initialized to NULL. // SNMPAPI BER_CreateHeader( IN BYTE nTag, IN UINT nObjLen, IN OUT BYTE **pBuffer, IN OUT UINT *nStart ) { UINT nHeadLen; UINT nStrLen; BYTE nExtLen; SNMPAPI nResult; UINT tLen; // Check for extended length nExtLen = 0; if ( nObjLen > BER_MAX_SIMPLE_LEN ) { tLen = nObjLen; while (tLen > 0) { nExtLen++; tLen /= BER_OCTET_SIZE; } } // Calculate the length of the header nHeadLen = BER_MIN_HEADER_LEN + nExtLen; // Re-Alloc the buffer to hold the header *pBuffer = SnmpUtilMemReAlloc( *pBuffer, (*nStart + nObjLen + nHeadLen) ); if ( *pBuffer == NULL ) { BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR ); } // Save start position of buffer nStrLen = *nStart + nObjLen; // Adjust overall length of buffer *nStart += nObjLen + nHeadLen; // Put Tag at end of buffer (*pBuffer)[nStrLen+nHeadLen-BER_TAG_OFFSET-1] = nTag; // Place Extended length indicator in stream if needed if ( nExtLen > 0 ) { (*pBuffer)[nStrLen+nHeadLen-BER_LENGTH_OFFSET-1] = (BYTE) (nExtLen | BER_OCTET_CONT_BIT); } // Put stream length in buffer (reverse order) (*pBuffer)[nStrLen] = 0; while ( nObjLen > 0 ) { (*pBuffer)[nStrLen++] = (BYTE) (nObjLen % BER_OCTET_SIZE); nObjLen /= BER_OCTET_SIZE; } nResult = SNMPAPI_NOERROR; Exit: // Memory is released if 'realloc' fails, leaving buffer pointing to NULL. return nResult; } // CreateHeader // // BER_ProcessHeader: // Calculates the length of the ASN.1 object. Does not change any // buffer information. // // Notes: // If an error occurs, the values of StrLen and HeadLen are // invalid. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_INVALID_TAG // SNMP_BERAPI_OVERFLOW // SNMP_BERAPI_SHORT_BUFFER // // // SNMPAPI BER_ProcessHeader( IN BYTE nTag, IN BYTE *BufPtr, IN UINT BufLen, OUT UINT *StrLen, OUT UINT *HeadLen ) { UINT ExtLen; UINT I; SNMPAPI nResult; // Check for short buffer if ( BufLen < BER_MIN_HEADER_LEN ) { BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER ); } // Check for correct tag if ( BufPtr[BER_TAG_OFFSET] != nTag ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG ); } // Check for extended 'length' octets *StrLen = BufPtr[BER_LENGTH_OFFSET] & ~BER_OCTET_CONT_BIT; // if extended length, calculate length if ( BufPtr[BER_LENGTH_OFFSET] & BER_OCTET_CONT_BIT ) { ExtLen = *StrLen; *StrLen = 0; // Check for short buffer if ( BufLen < (UINT)BER_MIN_HEADER_LEN+ExtLen ) { BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER ); } // Check for string length overflow if ( ExtLen > BER_MAX_LEN_OCTETS ) { BERAPI_ERROR( SNMP_BERAPI_OVERFLOW ); } // Build length for ( I=0;I < ExtLen;I++ ) { *StrLen = *StrLen * BER_OCTET_SIZE + BufPtr[I+BER_MIN_HEADER_LEN]; } } else { ExtLen = 0; } // Calculate header length *HeadLen = BER_MIN_HEADER_LEN + ExtLen; // Check for short buffer if ( (ULONG)BufLen < (ULONG)*HeadLen + (ULONG)*StrLen ) { BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER ); } // Signal success nResult = SNMPAPI_NOERROR; Exit: return nResult; } // BER_ProcessHeader // // SnmpBerEncodeAsnInteger // // Notes: // If an error occurs during this routine, it is the responsibility of // the calling routine to free any memory that may or may not have // been realloc'ed by this routine. // // The buffer information must be initialized before calling this routine. // If this is the first routine to alloc memory for the buffer, it must be // initialized to NULL. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_MEM_ALLOC_ERROR // SNMPAPI SnmpBerEncodeAsnInteger( IN BYTE nTag, IN AsnInteger lInteger, IN OUT BYTE **pBuffer, IN OUT UINT *nLength ) { BYTE *pTemp; UINT nIntLen; ULONG ULTemp; UINT I; SNMPAPI nResult; ULTemp = (ULONG) lInteger; switch ( nTag ) { case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: if ( (ULONG)0x80 > (ULONG)lInteger ) { nIntLen = 1; } else if ( (ULONG)0x8000 > (ULONG)lInteger ) { nIntLen = 2; } else if ( 0x800000 > (ULONG)lInteger ) { nIntLen = 3; } else if ( 0x80000000 > (ULONG)lInteger ) { nIntLen = 4; } else { nIntLen = 5; } break; default: if ( (AsnInteger)0 > lInteger ) { if ( (ULONG)0x80 >= -lInteger ) { nIntLen = 1; } else if ( (ULONG)0x8000 >= -lInteger ) { nIntLen = 2; } else if ( (ULONG)0x800000 >= -lInteger ) { nIntLen = 3; } else { nIntLen = 4; } } else { if ( (ULONG)0x80 > lInteger ) { nIntLen = 1; } else if ( (ULONG)0x8000 > lInteger ) { nIntLen = 2; } else if ( (ULONG)0x800000 > lInteger ) { nIntLen = 3; } else { nIntLen = 4; } } } // case // Alloc maximum memory for stream. BER_CreateHeader will adjust to fit *pBuffer = SnmpUtilMemReAlloc( *pBuffer, (*nLength + nIntLen + BER_MIN_HEADER_LEN) ); if ( *pBuffer == NULL ) { BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR ); } // Alias the start position in buffer pTemp = *pBuffer + *nLength; // Encode the ASN integer for ( I=0;I < min(nIntLen, BER_MAX_INT_OCTETS);I++ ) { pTemp[I] = (BYTE) (ULTemp % BER_OCTET_SIZE); ULTemp = ULTemp / BER_OCTET_SIZE; } // Check for the necessary fifth bit on unsigned integers if ( nIntLen > BER_MAX_INT_OCTETS ) { pTemp[BER_MAX_INT_OCTETS] = 0; } // Create header nResult = BER_CreateHeader( nTag, nIntLen, pBuffer, nLength ); Exit: // Memory is released if 'realloc' fails, leaving buffer pointing to NULL. return nResult; } // SnmpBerEncodeAsnInteger // // BER_DecodeAsnInteger: // Decodes an integer. If the integer cannot be decoded, an error message // is returned and the buffer information remains unchanged. // // Notes: Considers integers over 32 bits (4 Octets) as an error. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_INVALID_TAG // SNMP_BERAPI_OVERFLOW // SNMP_BERAPI_SHORT_BUFFER // SNMPAPI BER_DecodeAsnInteger( IN BYTE nTag, // Expect type of integer IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded integer and specific type ) { UINT StrLen; UINT HeadLen; UINT I; AsnInteger IntResult; SNMPAPI nResult; // Process header of ASN.1 INTEGER nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen ); if ( nResult != SNMPAPI_NOERROR ) { goto Exit; } // Check length based on signed or unsigned expected switch( nTag ) { case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: if ( StrLen > BER_MAX_INT_OCTETS+1 ) { BERAPI_ERROR( SNMP_BERAPI_OVERFLOW ); } break; default: if ( StrLen > BER_MAX_INT_OCTETS ) { BERAPI_ERROR( SNMP_BERAPI_OVERFLOW ); } break; } // Save sign information if ( (*pBuffer)[HeadLen] & 0x80 ) { IntResult = -1; } else { IntResult = 0; } // Convert integer for ( I=0;I < StrLen;I++ ) { IntResult = IntResult << BER_OCTET_LEN | (*pBuffer)[HeadLen+I]; } // Extend sign if necessary // Assign completed conversion to return structure pResult->asnType = nTag; pResult->asnValue.number = IntResult; // Adjust buffer info *nLength -= HeadLen + StrLen; *pBuffer += HeadLen + StrLen; // Signal successful conversion nResult = SNMPAPI_NOERROR; Exit: return nResult; } // BER_DecodeAsnInteger // // SnmpBerEncodeAsnOctetStr // // Notes: // If an error occurs during this routine, it is the responsibility of // the calling routine to free any memory that may or may not have // been realloc'ed by this routine. // // The buffer information must be initialized before calling this routine. // If this is the first routine to alloc memory for the buffer, it must be // initialized to NULL. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_MEM_ALLOC_ERROR // SNMPAPI SnmpBerEncodeAsnOctetStr( IN BYTE nTag, IN AsnOctetString *String, IN OUT BYTE **pBuffer, IN OUT UINT *nLength ) { BYTE *pTemp; SNMPAPI nResult; // Alloc maximum memory for stream. BER_CreateHeader will adjust to fit *pBuffer = SnmpUtilMemReAlloc( *pBuffer, (*nLength + String->length + BER_MIN_HEADER_LEN) ); if ( *pBuffer == NULL ) { BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR ); } // Alias the start position in buffer pTemp = *pBuffer + *nLength; // Encode stream (reverse order) SnmpSvcBufRevAndCpy( pTemp, String->stream, String->length ); // Create header nResult = BER_CreateHeader( nTag, String->length, pBuffer, nLength ); Exit: // Memory is released if 'realloc' fails, leaving buffer pointing to NULL. return nResult; } // SnmpBerEncodeAsnOctetStr // // BER_DecodeAsnOctetStr: // Decodes an octet string. If the octet string cannot be decoded, an // error message is returned and the buffer information remains unchanged. // Returns a pointer into the message buffer which points to the // octet string. This routine does not allocate any memory to hold the // octet string. // // Notes: Considers octet strings longer than 65535 as an an error. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_INVALID_TAG // SNMP_BERAPI_OVERFLOW // SNMP_BERAPI_SHORT_BUFFER // SNMPAPI BER_DecodeAsnOctetStr( IN BYTE nTag, // Expect type of OctetStr IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded OctetStr and specific type ) { UINT StrLen; UINT HeadLen; SNMPAPI nResult; // Process header of ASN.1 OCTET STRING nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen ); if ( nResult == SNMPAPI_ERROR ) { goto Exit; } // Set result type pResult->asnType = nTag; // Set return values pResult->asnValue.string.length = StrLen; pResult->asnValue.string.stream = *pBuffer + HeadLen; pResult->asnValue.string.dynamic = FALSE; // Adjust buffer info *nLength -= HeadLen + StrLen; *pBuffer += HeadLen + StrLen; // Signal successful conversion nResult = SNMPAPI_NOERROR; Exit: return nResult; } // BER_DecodeAsnOctetStr // // SnmpBerEncodeAsnNull // Encodes an ASN NULL into the buffer. // // Notes: // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_MEM_ALLOC_ERROR // SNMPAPI SnmpBerEncodeAsnNull( IN BYTE nTag, IN OUT BYTE **pBuffer, IN OUT UINT *nLength ) { // Create header return BER_CreateHeader( nTag, 0, pBuffer, nLength ); } // SnmpBerEncodeAsnNull // // BER_DecodeAsnNull: // Decodes an NULL. If the NULL cannot be decoded, an error message is // returned and the buffer information remains unchanged. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_INVALID_TAG // SNMP_BERAPI_OVERFLOW // SNMP_BERAPI_SHORT_BUFFER // SNMP_BERAPI_INVALID_LENGTH // // // SNMPAPI BER_DecodeAsnNull( IN BYTE nTag, // Expect type of NULL IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded NULL and specific type ) { UINT StrLen; UINT HeadLen; SNMPAPI nResult; // Get length of ASN.1 NULL nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen ); if ( nResult == SNMPAPI_ERROR ) { goto Exit; } // Check for correct length if ( StrLen != 0 ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH ); } // Set return type pResult->asnType = nTag; // Adjust buffer info *nLength -= HeadLen + StrLen; *pBuffer += HeadLen + StrLen; // Signal successful conversion nResult = SNMPAPI_NOERROR; Exit: return nResult; } // BER_DecodeAsnNull // // SnmpBerEncodeAsnObjectId // // Notes: // If an error occurs during this routine, it is the responsibility of // the calling routine to free any memory that may or may not have // been realloc'ed by this routine. // // The buffer information must be initialized before calling this routine. // If this is the first routine to alloc memory for the buffer, it must be // initialized to NULL. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_MEM_ALLOC_ERROR // SNMP_BERAPI_INVALID_OBJELEM // SNMPAPI SnmpBerEncodeAsnObjectId( IN BYTE nTag, IN AsnObjectIdentifier *ObjectId, IN OUT BYTE **pBuffer, IN OUT UINT *nLength ) { UINT nObjIdLen; UINT nTemp; BYTE *pTemp; UINT I; SNMPAPI nResult; // Check for error on number of SUB ID's if ( ObjectId->idLength < 2 ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH ); } // Alloc maximum memory for stream. BER_CreateHeader will adjust to fit *pBuffer = SnmpUtilMemReAlloc( *pBuffer, (*nLength + ObjectId->idLength*3 + BER_MIN_HEADER_LEN) ); if ( *pBuffer == NULL ) { BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR ); } // Alias start position in buffer pTemp = *pBuffer + *nLength; // Encode stream (reverse order) and calculate length nObjIdLen = 0; I = ObjectId->idLength; while ( I - 2 > 0 ) { nTemp = ObjectId->ids[--I]; if ( nTemp ) { pTemp[nObjIdLen] = 0; while ( nTemp ) { pTemp[nObjIdLen++] |= nTemp % BER_OCTET_CONT_BIT; if ( nTemp /= BER_OCTET_CONT_BIT ) { pTemp[nObjIdLen] = BER_OCTET_CONT_BIT; } } } else { pTemp[nObjIdLen++] = 0; } } // Check for invalid first and second element if ( (ObjectId->ids[0] > BER_MAX_FIRST_ELEM) || (ObjectId->idLength > 1 && ObjectId->ids[1] > BER_MAX_SECOND_ELEM) ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_OBJELEM ); } // Setup the first two elements of the object ID pTemp[nObjIdLen++] = (BYTE) (ObjectId->ids[0] * 40 + ObjectId->ids[1]); // Create header nResult = BER_CreateHeader( nTag, nObjIdLen, pBuffer, nLength ); Exit: if ( nResult == SNMPAPI_ERROR ) { SnmpUtilMemFree( *pBuffer ); *pBuffer = NULL; *nLength = 0; } return nResult; } // SnmpBerEncodeAsnObjectId #define MAX_SNMPOID 0XFFFFFFFF // // BER_DecodeAsnObjectId: // Decodes an object identifier. If the object identifier cannot be // decoded, an error message is returned and the buffer information // remains unchanged. // // Notes: Considers object identifiers that have over 65535 elements // as an error. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_INVALID_TAG // SNMP_BERAPI_OVERFLOW // SNMP_BERAPI_SHORT_BUFFER // SNMP_BERAPI_INVALID_LENGTH // SNMPAPI BER_DecodeAsnObjectId( IN BYTE nTag, // Expect type of ObjectId IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded ObjectId and specific type ) { UINT StrLen; UINT HeadLen; UINT I; UINT *TempObjId; UINT ElemTemp; UINT nLen; SNMPAPI nResult; // Initialize TempObjId = pResult->asnValue.object.ids = NULL; // Get length of ASN.1 OBJECT IDENTIFIER nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen ); if ( nResult == SNMPAPI_ERROR ) { goto Exit; } // Check for invalid length if ( StrLen < 1 ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH ); } // Alloc space for at least 2 elements if ( NULL == (TempObjId = SnmpUtilMemAlloc((BER_SUBOID_BLK_SIZE*sizeof(UINT)))) ) { BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR ); } // Get first two elements of the object identifier I = HeadLen; TempObjId[0] = (*pBuffer)[I] / 40; TempObjId[1] = (*pBuffer)[I] % 40; nLen = 2; // Check first element for error if ( TempObjId[0] > BER_MAX_FIRST_ELEM ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_OBJELEM ); } // Get rest of elements I++; while ( I < (UINT)HeadLen+StrLen && nLen < SNMP_MAX_OID_LEN ) { ElemTemp = 0; do { ElemTemp = (ElemTemp << 7) | ((*pBuffer)[I] & ~BER_OCTET_CONT_BIT); ++I; // Check for invalid length if ( I > StrLen + HeadLen ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH ); } } while((*pBuffer)[I - 1] & BER_OCTET_CONT_BIT); // Check for 32 bit overflow if ( (ElemTemp > MAX_SNMPOID) ) { BERAPI_ERROR( SNMP_BERAPI_OVERFLOW ); } #if 0 ElemTemp = (*pBuffer)[I] & ~BER_OCTET_CONT_BIT; // Check for 16 bit element if ( (*pBuffer)[I++] & BER_OCTET_CONT_BIT ) { // Check for invalid length if ( I == StrLen + HeadLen ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH ); } // Check for 16 bit overflow if ( (*pBuffer)[I] & BER_OCTET_CONT_BIT ) { BERAPI_ERROR( SNMP_BERAPI_OVERFLOW ); } // Build element ElemTemp = ElemTemp * BER_OCTET_CONT_BIT + (*pBuffer)[I++]; } #endif // alloc memory for object ids if ( !(nLen % BER_SUBOID_BLK_SIZE) ) { if ( NULL == (TempObjId = SnmpUtilMemReAlloc(TempObjId, ((UINT)(nLen+BER_SUBOID_BLK_SIZE) * sizeof(UINT)))) ) { BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR ); } } // Assign element to the object id struct TempObjId[nLen++] = ElemTemp; } // Check for object id too long - overflow if ( I < (UINT)StrLen+HeadLen ) { BERAPI_ERROR( SNMP_BERAPI_OVERFLOW ); } // Set result type pResult->asnType = nTag; // Set result - Realloc to perfect fit pResult->asnValue.object.ids = SnmpUtilMemReAlloc( TempObjId, (nLen * sizeof(UINT)) ); pResult->asnValue.object.idLength = nLen; // Adjust buffer info *nLength -= HeadLen + StrLen; *pBuffer += HeadLen + StrLen; // Signal successful conversion nResult = SNMPAPI_NOERROR; Exit: if ( nResult == SNMPAPI_ERROR ) { SnmpUtilMemFree( TempObjId ); } return nResult; } // BER_DecodeAsnObjectId // // SnmpBerEncodeAsnImplicitSeq // // Notes: // The buffer passed as the encoding buffer is considered as the data to // be encoded as a sequence. The data must already be in reverse order // (probably from a previous call to an encoding routine.) The encoding // algorithm will fool the 'BER_CreateHeader' routine into thinking that the // information in the buffer has just been encoded, just like the // other encoding routines. The result will be 'BER_CreateHeader' appending // the header (in reverse order) onto the buffer referenced by *pBuffer. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // None. // SNMPAPI SnmpBerEncodeAsnImplicitSeq( IN BYTE nTag, IN UINT nSeqLen, IN OUT BYTE **pBuffer, IN OUT UINT *nLength ) { // Fool CreateHeader into thinking that this routine just encoded // the items in the sequence *nLength -= nSeqLen; // Create header return BER_CreateHeader( nTag, nSeqLen, pBuffer, nLength ); } // SnmpBerEncodeAsnImplicitSeq // // BER_DecodeAsnImplicitSeq: // Decodes a sequence. Returns a pointer into the message buffer which // which points to the first object in the sequence. NO new memory is // allocated to hold the sequence objects. If an error occurs, one of // the following error codes is returned and the buffer information // remains unchanged. // // Notes: // To decode the individual objects, call the main decode routine passing // the sequence buffer pointer (stream) and the sequence length. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_INVALID_TAG // SNMP_BERAPI_OVERFLOW // SNMP_BERAPI_SHORT_BUFFER // SNMPAPI BER_DecodeAsnImplicitSeq( IN BYTE nTag, // Expected type of sequence IN OUT BYTE **pBuffer, // Buffer to decode IN OUT UINT *nLength, // Length of buffer IN OUT AsnAny *pResult // Contains decoded sequence and specific type ) { UINT StrLen; UINT HeadLen; SNMPAPI nResult; // Process header of IMPLICIT SEQUENCE nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen ); if ( nResult == SNMPAPI_ERROR ) { goto Exit; } // Set result type pResult->asnType = nTag; // Set return values pResult->asnValue.sequence.length = StrLen; pResult->asnValue.sequence.stream = *pBuffer + HeadLen; // Adjust buffer info *nLength -= HeadLen + StrLen; *pBuffer += HeadLen + StrLen; // Signal successful conversion nResult = SNMPAPI_NOERROR; Exit: return nResult; } // BER_DecodeAsnImplicitSeq // // SnmpBerQueryAsnType: // Examines the buffer to determine the type of the next object // in the buffer. // // Notes: // If any of the ASN types are equal to SNMPAPI_ERROR or SNMPAPI_NOERROR, // then this routine will fail to perform accurately. // // Return codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error codes: // SNMP_BERAPI_SHORT_BUFFER // SNMP_BERAPI_INVALID_TAG // SNMPAPI SnmpBerQueryAsnType( BYTE *pBuffer, /* in */ UINT nLength /* in */ ) { SNMPAPI nResult; // Check for short buffer if ( !nLength ) { BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER ); } // Check for extended tag if ( (pBuffer[BER_TAG_OFFSET] & BER_EXTENDED_TAG) == BER_EXTENDED_TAG ) { BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG ); } nResult = pBuffer[BER_TAG_OFFSET]; Exit: return nResult; } // SnmpBerQueryAsnType //-------------------------------- END --------------------------------------