1452 lines
40 KiB
C++
1452 lines
40 KiB
C++
/**
|
|
* asn.cpp
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
*
|
|
* ASN.1 Library
|
|
*
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
|
* Copyright (C) 2004-2014 Null Team
|
|
*
|
|
* This software is distributed under multiple licenses;
|
|
* see the COPYING file in the main directory for licensing
|
|
* information for this specific distribution.
|
|
*
|
|
* This use of this software may be subject to additional restrictions.
|
|
* See the LEGAL file in the main directory for details.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#include "yateasn.h"
|
|
|
|
using namespace TelEngine;
|
|
|
|
static String s_libName = "ASNLib";
|
|
|
|
ASNLib::ASNLib()
|
|
{}
|
|
|
|
ASNLib::~ASNLib()
|
|
{}
|
|
|
|
int ASNLib::decodeLength(DataBlock& data) {
|
|
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeLength() - from data='%p'",&data);
|
|
int length = 0;
|
|
uint8_t lengthByte = data[0];
|
|
|
|
if (lengthByte & ASN_LONG_LENGTH) { // the length is represented on more than one byte
|
|
|
|
lengthByte &= ~ASN_LONG_LENGTH; /* turn MSB off */
|
|
if (lengthByte == 0) {
|
|
data.cut(-1);
|
|
return IndefiniteForm;
|
|
}
|
|
|
|
if (lengthByte > sizeof(int))
|
|
return InvalidLengthOrTag;
|
|
|
|
for (int i = 0 ; i < lengthByte ; i++)
|
|
length = (length << 8) + data[1 + i];
|
|
|
|
data.cut(-lengthByte - 1);
|
|
return length;
|
|
|
|
} else { // one byte for length
|
|
length = (int) lengthByte;
|
|
data.cut(-1);
|
|
return length;
|
|
}
|
|
}
|
|
|
|
DataBlock ASNLib::buildLength(DataBlock& data)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::buildLength() - encode length=%d",data.length());
|
|
DataBlock lenDb;
|
|
if (data.length() < 0)
|
|
return lenDb;
|
|
if (data.length() < ASN_LONG_LENGTH) {
|
|
uint8_t l = data.length();
|
|
lenDb.append(&l, 1);
|
|
return lenDb;
|
|
}
|
|
else {
|
|
uint8_t longLen = ASN_LONG_LENGTH;
|
|
int len = data.length();
|
|
while (len > 0) {
|
|
uint8_t v = len & 0xFF;
|
|
lenDb.insert(DataBlock(&v,1));
|
|
len >>= 8;
|
|
}
|
|
longLen |= lenDb.length();
|
|
lenDb.insert(DataBlock(&longLen,1));
|
|
return lenDb;
|
|
}
|
|
return lenDb;
|
|
}
|
|
|
|
int ASNLib::matchEOC(DataBlock& data)
|
|
{
|
|
/**
|
|
* EoC = 00 00
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,"::matchEOC() in data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
if (data[0] == 0 && data[1] == 0) {
|
|
data.cut(-2);
|
|
return 2;
|
|
}
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
|
|
int ASNLib::parseUntilEoC(DataBlock& data, int length)
|
|
{
|
|
if (length >= (int)data.length() || ASNLib::matchEOC(data) > 0)
|
|
return length;
|
|
while (data.length() && ASNLib::matchEOC(data) < 0) {
|
|
// compute tag portion length
|
|
AsnTag tag;
|
|
AsnTag::decode(tag,data);
|
|
length += tag.coding().length();
|
|
data.cut(-(int)tag.coding().length());
|
|
// compute length portion length
|
|
int initLen = data.length();
|
|
int len = ASNLib::decodeLength(data);
|
|
length += initLen - data.length();
|
|
|
|
bool checkEoC = (len == ASNLib::IndefiniteForm);
|
|
if (!checkEoC && len < 0)
|
|
return length;
|
|
|
|
if (checkEoC) {
|
|
length = parseUntilEoC(data,length);
|
|
if (ASNLib::matchEOC(data) > 0)
|
|
length += 2;
|
|
}
|
|
else {
|
|
length += len;
|
|
data.cut(-len);
|
|
}
|
|
}
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeBoolean(DataBlock& data, bool* val, bool tagCheck)
|
|
{
|
|
/**
|
|
* boolean = 0x01 length byte (byte == 0 => false, byte != 0 => true)
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
int type = data[0];
|
|
if ((type != BOOLEAN)) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length() || length != 1) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
if (!val) {
|
|
data.cut(-1);
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*val = false;
|
|
if ((data[0] & 0xFF) != 0)
|
|
*val = true;
|
|
data.cut(-1);
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeBoolean() - decoded boolean value from data='%p', consumed %u bytes",
|
|
&data, initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeInteger(DataBlock& data, u_int64_t& intVal, unsigned int bytes, bool tagCheck)
|
|
{
|
|
/**
|
|
* integer = 0x02 length byte {byte}*
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeInteger() from data='%p'",&data);
|
|
int64_t value = 0;
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
int type = data[0];
|
|
if ((type != INTEGER)) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length()) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
if ((unsigned int)length > bytes) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length: decoded length=%d greater than requested length=%u in data='%p'",
|
|
length,bytes,&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
if (data[0] & 0x80)
|
|
value = -1; /* integer is negative */
|
|
int j = 0;
|
|
while (j < length) {
|
|
value = (value << 8) | data[j];
|
|
j++;
|
|
}
|
|
intVal = (u_int64_t) value;
|
|
data.cut(-length);
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeInteger() - decoded integer value from data='%p', consumed %u bytes",
|
|
&data, initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeUINT8(DataBlock& data, u_int8_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUINT8()");
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(u_int8_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUINT8() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = (u_int8_t) val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeUINT16(DataBlock& data, u_int16_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUINT16() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(u_int16_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUINT16() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = (u_int16_t) val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeUINT32(DataBlock& data, u_int32_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUINT32() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(u_int32_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUINT32() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = (u_int32_t) val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeUINT64(DataBlock& data, u_int64_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUINT64() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(u_int64_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUINT64() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeINT8(DataBlock& data, int8_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeINT8() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(int8_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeINT8() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = (int8_t) val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeINT16(DataBlock& data, int16_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeINT16() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(int16_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeINT16() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = (int16_t) val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeINT32(DataBlock& data, int32_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeINT32() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(int32_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeINT32() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = (int32_t) val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeINT64(DataBlock& data, int64_t* intVal, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeINT64() from data='%p'",&data);
|
|
u_int64_t val;
|
|
int l = decodeInteger(data,val,sizeof(int64_t),tagCheck);
|
|
if (!intVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeINT64() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*intVal = val;
|
|
return l;
|
|
}
|
|
|
|
int ASNLib::decodeBitString(DataBlock& data, String* val, bool tagCheck)
|
|
{
|
|
/**
|
|
* bitstring ::= 0x03 asnlength unusedBytes {byte}*
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll, "::decodeBitString() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
int type = data[0];
|
|
if ((type != BIT_STRING)) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length()) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
if (data[0] > 7){
|
|
DDebug(s_libName.c_str(),DebugAll, "::decodeBitString() - Invalid bitstring, unused bytes > 7 in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
int unused = data[0];
|
|
data.cut(-1);
|
|
length--;
|
|
int j = 0;
|
|
if (!val) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid buffer for return data");
|
|
data.cut(-length);
|
|
return InvalidContentsError;
|
|
}
|
|
*val = "";
|
|
while (j < length) {
|
|
uint8_t byte = data[j];
|
|
for (int i = 7; i > -1; i--) {
|
|
int c = (byte >> i) % 2;
|
|
*val += c;
|
|
}
|
|
j++;
|
|
}
|
|
*val = val->substr(0, length * 8 - unused);
|
|
data.cut(-length);
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeBitString() - decoded bit string value from data='%p', consumed %u bytes",
|
|
&data, initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeOctetString(DataBlock& db, OctetString* strVal, bool tagCheck)
|
|
{
|
|
/**
|
|
* octet string ::= 0x04 asnlength {byte}*
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,":decodeOctetString() from data='%p'",&db);
|
|
if (db.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = db.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
int type = db[0];
|
|
if (type != OCTET_STRING) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Tag in data='%p'",&db);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
db.cut(-1);
|
|
}
|
|
int length = decodeLength(db);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Length in data='%p'",&db);
|
|
return length;
|
|
}
|
|
if ((unsigned int)length > db.length()) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Length in data='%p'",&db);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
if (!strVal) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
strVal->assign((void*)db.data(0,length),length);
|
|
db.cut(-length);
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeOctetString() - decoded octet string value from data='%p', consumed %u bytes",
|
|
&db, initLen - db.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeNull(DataBlock& data, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 null := 0x05 00
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeNull() from data='%p'",&data);
|
|
if (tagCheck) {
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
|
|
if (data[0] != NULL_ID) {
|
|
XDebug(s_libName.c_str(),DebugAll, "::decodeNull() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length != 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeNull() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;;
|
|
}
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeNull() - decoded null value from data='%p', consumed %u bytes",
|
|
&data, (tagCheck ? 2 : 1));
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeOID(DataBlock& data, ASNObjId* obj, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
|
|
* subidentifier ::= {leadingbyte}* lastbyte
|
|
* leadingbyte ::= 1 7bites
|
|
* lastbyte ::= 0 7bites
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeOID() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != OBJECT_ID) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length()) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
if (length == 0) {
|
|
obj = 0;
|
|
return length;
|
|
}
|
|
|
|
int j = 0;
|
|
String oid = "";
|
|
unsigned int longNo = 0;
|
|
while (j < length) {
|
|
// first byte contains 2 identifiers : x,y. The byte is 40 * x + y . x can only be 0,1,2 so if x > 2, x stays 2 and the rest goes into y
|
|
if (j == 0) {
|
|
unsigned int x = data[j] / 40;
|
|
unsigned int y = data[j] % 40;
|
|
if (x > 2) {
|
|
y = (x - 2) * 40 + y;
|
|
x = 2;
|
|
}
|
|
oid += x;
|
|
oid += ".";
|
|
oid += y;
|
|
oid += ".";
|
|
}
|
|
else {
|
|
uint8_t byte = data[j];
|
|
longNo += byte & ~ASN_BIT8;
|
|
if ((byte & ASN_BIT8) == ASN_BIT8)
|
|
longNo <<= 7;
|
|
else {
|
|
oid += longNo;
|
|
longNo = 0;
|
|
if (j != length -1)
|
|
oid += ".";
|
|
}
|
|
}
|
|
j++;
|
|
}
|
|
data.cut(-length);
|
|
if (!obj) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*obj = oid;
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeOID() - decoded object ID from data='%p', consumed %u bytes",
|
|
&data, initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeReal(DataBlock& db, float* realVal, bool tagCheck)
|
|
{
|
|
if (db.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
unsigned int initLen = db.length();
|
|
if (tagCheck) {
|
|
if (db[0] != REAL) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Tag in data='%p'",&db);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
db.cut(-1);
|
|
}
|
|
int length = decodeLength(db);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Length in data='%p'",&db);
|
|
return length;
|
|
}
|
|
if ((unsigned int)length > db.length()) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Length in data='%p'",&db);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
db.cut(-length);
|
|
Debug(s_libName.c_str(),DebugInfo,"::decodeReal() - real value decoding not implemented, skipping over the %u bytes of the encoding",
|
|
initLen - db.length());
|
|
return 0;
|
|
}
|
|
|
|
int ASNLib::decodeString(DataBlock& data, String* str, int* type, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeString() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != NUMERIC_STR ||
|
|
data[0] != PRINTABLE_STR ||
|
|
data[0] != IA5_STR ||
|
|
data[0] != VISIBLE_STR
|
|
) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeString() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
if (type)
|
|
*type = data[0];
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeString() -Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length()) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeString() -Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
String var = "";
|
|
for (int i = 0; i < length; i++)
|
|
var += (char) (data[i] & 0x7f);
|
|
data.cut(-length);
|
|
if (!str || !type) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeString() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*str = var;
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugInfo,"::decodeString() - decode string value from data='%p', consumed %u bytes",
|
|
&data,initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
|
|
int ASNLib::decodeUtf8(DataBlock& data, String* str, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != UTF8_STR) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() -Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length()) {
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeUtf8() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
|
|
String var = "";
|
|
for (int i = 0; i < length; i++)
|
|
var += (char) (data[i]);
|
|
data.cut(-length);
|
|
if (String::lenUtf8(var.c_str()) < 0)
|
|
return ParseError;
|
|
if (!str) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUTF8() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
*str = var;
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeUtf8() - decoded an UTF8 string value from data='%p', consumed %u bytes",&data,initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeGenTime(DataBlock& data, unsigned int* time, unsigned int* fractions, bool* utc, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != GENERALIZED_TIME) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length() || length < 14) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
String date = "";
|
|
for (int i = 0; i < length; i++)
|
|
date += (char) (data[i]);
|
|
data.cut(-length);
|
|
|
|
if (!(utc && fractions && time)) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
|
|
unsigned int year, month, day, hours, minutes, seconds;
|
|
int timeDiff = 0;
|
|
|
|
*utc = false;
|
|
*fractions = 0;
|
|
|
|
if (date[date.length() - 1] == 'Z') {
|
|
*utc = true;
|
|
date = date.substr(0,date.length() - 1);
|
|
}
|
|
else {
|
|
int pos = date.find('-');
|
|
if (pos < 0)
|
|
pos = date.find('+');
|
|
if (pos >0 && pos != (int)date.length() - 5)
|
|
return InvalidContentsError;
|
|
if (pos > 0) {
|
|
char sign = date.at(pos);
|
|
unsigned int hDiff = (unsigned int) date.substr(date.length() - 4,2).toInteger(-1,10);
|
|
if (hDiff > 11)
|
|
return InvalidContentsError;
|
|
unsigned int mDiff = (unsigned int) date.substr(date.length() - 2,2).toInteger(-1,10);
|
|
if (mDiff > 59)
|
|
return InvalidContentsError;
|
|
unsigned int diff = Time::toEpoch(1970,1,1,hDiff,mDiff,0);
|
|
if (sign == '-')
|
|
timeDiff = diff;
|
|
else
|
|
timeDiff -= diff;
|
|
*utc = true;
|
|
date = date.substr(0,date.length() - 5);
|
|
}
|
|
}
|
|
ObjList* list = date.split('.');
|
|
if (!list || list->count() > 2)
|
|
return InvalidContentsError;
|
|
if (list->count() == 2)
|
|
*fractions = (*list)[1]->toString().toInteger(0,10);
|
|
|
|
String dateTime = (*list)[0]->toString();
|
|
TelEngine::destruct(list);
|
|
|
|
year = dateTime.substr(0,4).toInteger(-1,10);
|
|
month = dateTime.substr(4,2).toInteger(-1,10);
|
|
day = dateTime.substr(6,2).toInteger(-1,10);
|
|
hours = dateTime.substr(8,2).toInteger(-1,10);
|
|
minutes = dateTime.substr(10,2).toInteger(-1,10);
|
|
seconds = dateTime.substr(12,2).toInteger(-1,10);
|
|
if (year < 1970 || month > 12 || day > 31 || hours > 23 || minutes > 59 || seconds > 59)
|
|
return InvalidContentsError;
|
|
|
|
unsigned int epochTime = Time::toEpoch(year,month,day,hours,minutes,seconds);
|
|
if (epochTime == (unsigned int) -1)
|
|
return InvalidContentsError;
|
|
*time = epochTime + timeDiff;
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeGenTime() - decoded time value from data='%p', consumed %u bytes",&data,initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeUTCTime(DataBlock& data, unsigned int* time, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != UTC_TIME) {
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Length in data='%p'",&data);
|
|
return length;
|
|
}
|
|
|
|
if ((unsigned int)length > data.length() || length < 11) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Length in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
String date = "";
|
|
for (int i = 0; i < length; i++)
|
|
date += (char) (data[i]);
|
|
data.cut(-length);
|
|
|
|
if (!time) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
unsigned int year = 0, month = 0, day = 0, hours = 0, minutes = 0, seconds = 0;
|
|
int timeDiff = 0;
|
|
|
|
int len = date.length();
|
|
if (date[date.length() - 1] == 'Z')
|
|
date = date.substr(0,len - 1);
|
|
else {
|
|
int pos = date.find('-');
|
|
if (pos < 0)
|
|
pos = date.find('+');
|
|
if ((pos >0 && pos != len - 5) || pos < 0)
|
|
return InvalidContentsError;
|
|
if (pos > 0) {
|
|
char sign = date.at(pos);
|
|
unsigned int hDiff = (unsigned int) date.substr(len - 4,2).toInteger(-1,10);
|
|
if (hDiff > 11)
|
|
return InvalidContentsError;
|
|
unsigned int mDiff = (unsigned int) date.substr(len - 2,2).toInteger(-1,10);
|
|
if (mDiff > 59)
|
|
return InvalidContentsError;
|
|
unsigned int diff = Time::toEpoch(1970,1,1,hDiff,mDiff,0);
|
|
if (sign == '-')
|
|
timeDiff = diff;
|
|
else
|
|
timeDiff -= diff;
|
|
date = date.substr(0,len - 5);
|
|
}
|
|
}
|
|
year = date.substr(0,2).toInteger(-1,10);
|
|
year = (year > 50) ? 1900 + year : 2000 + year;
|
|
month = date.substr(2,2).toInteger(-1,10);
|
|
day = date.substr(4,2).toInteger(-1,10);
|
|
hours = date.substr(6,2).toInteger(-1,10);
|
|
minutes = date.substr(8,2).toInteger(-1,10);
|
|
if (date.length() > 10)
|
|
seconds = date.substr(10,2).toInteger(-1,10);
|
|
if (year < 1970 || month > 12 || day > 31 || hours > 23 || minutes > 59 || seconds > 59)
|
|
return InvalidContentsError;
|
|
|
|
unsigned int epochTime = Time::toEpoch(year,month,day,hours,minutes,seconds);
|
|
if (epochTime == (unsigned int) -1)
|
|
return InvalidContentsError;
|
|
*time = epochTime + timeDiff;
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - decoded time value from data='%p', consumed %u bytes",&data,initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeAny(DataBlock data, DataBlock* val, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeAny() from data='%p'",&data);
|
|
if (!val) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeAny() - Invalid buffer for return data");
|
|
return InvalidContentsError;
|
|
}
|
|
val->append(data);
|
|
return data.length();
|
|
}
|
|
|
|
int ASNLib::decodeSequence(DataBlock& data, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeSequence() from data='%p'",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != SEQUENCE) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeSequence() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
if (length < 0)
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeSequence() - Invalid Length in data='%p'",&data);
|
|
#ifdef DEBUG
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeSequence() - decoded sequence tags from data='%p', consumed %u bytes",&data,initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
int ASNLib::decodeSet(DataBlock& data, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::decodeSet() from data='%p",&data);
|
|
if (data.length() < 2)
|
|
return InvalidLengthOrTag;
|
|
#ifdef DEBUG
|
|
unsigned int initLen = data.length();
|
|
#endif
|
|
if (tagCheck) {
|
|
if (data[0] != SET) {
|
|
DDebug(s_libName.c_str(),DebugAll,"::decodeSet() - Invalid Tag in data='%p'",&data);
|
|
return InvalidLengthOrTag;
|
|
}
|
|
data.cut(-1);
|
|
}
|
|
int length = decodeLength(data);
|
|
#ifdef DEBUG
|
|
if (length < 0)
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeSet() - Invalid Length in data='%p'",&data);
|
|
else
|
|
Debug(s_libName.c_str(),DebugAll,"::decodeSet() - decoded set tags from data='%p', consumed %u bytes",&data,initLen - data.length());
|
|
#endif
|
|
return length;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeBoolean(bool val, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 boolean ::= 0x01 asnlength=0x01 byte
|
|
*/
|
|
DataBlock data;
|
|
uint8_t b = BOOLEAN;
|
|
if (tagCheck) {
|
|
data.append(&b, 1);
|
|
b = 1;
|
|
data.append(&b, 1);
|
|
}
|
|
b = val ? 1 : 0;
|
|
data.append(&b, 1);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeBoolean('%s') - encoded boolean value into %u bytes",String::boolText(val),data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeInteger(u_int64_t intVal, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 integer ::= 0x02 asnlength byte {byte}*
|
|
*/
|
|
DataBlock data;
|
|
uint8_t tag = INTEGER;
|
|
|
|
// 9 consecutive ones or zeros are not allowed at the beginning of an integer
|
|
int size = sizeof(u_int64_t);
|
|
uint16_t msb = (uint16_t)(intVal >> ((size - 1) * 8 - 1));
|
|
|
|
while (((msb & 0x1FF) == 0 || (msb & 0x1FF) == 0x1FF) && (size - 1 >= 1)) {
|
|
size--;
|
|
msb = (uint16_t)(intVal >> ((size - 1) * 8 - 1));
|
|
}
|
|
if (size == 0)
|
|
return data;
|
|
|
|
DataBlock contents;
|
|
while(size) {
|
|
uint8_t byte = (uint8_t)(intVal >> ((size - 1) * 8));
|
|
contents.append(&byte, 1);
|
|
size--;
|
|
}
|
|
|
|
if (contents.length() == 0)
|
|
return data;
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeInteger('" FMT64 "') - encoded into %u bytes",intVal,data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeBitString(String val, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 bit string ::= 0x03 asnlength unused {byte}*
|
|
*/
|
|
DataBlock data;
|
|
uint8_t tag = BIT_STRING;
|
|
DataBlock contents;
|
|
|
|
int l = val.length();
|
|
uint8_t trail = (-l) & 0x07;
|
|
for (int i = 0; i < trail; i++)
|
|
val += "0";
|
|
contents.append(&trail, 1);
|
|
|
|
for (unsigned int i = 0; i < val.length(); i += 8) {
|
|
uint8_t hex = val.substr(i, 8).toInteger(0,2);
|
|
contents.append(&hex, 1);
|
|
}
|
|
|
|
if (tagCheck) {
|
|
data.append(&tag,1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeBitString('%s') - encoded bit string into %u bytes",val.c_str(),data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeOctetString(OctetString strVal, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 octet string ::= 0x04 asnlength byte {byte}*
|
|
*/
|
|
DataBlock data;
|
|
uint8_t tag = OCTET_STRING;
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
DataBlock len = buildLength(strVal);
|
|
data.append(len);
|
|
}
|
|
data.append(strVal);
|
|
XDebug(s_libName.c_str(),DebugAll,"ASNLib::encodeOctetString('%s') - encoded octet string into %u bytes",
|
|
strVal.toHexString().c_str(),data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeNull(bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 null ::= 0x05 00
|
|
*/
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeNull()");
|
|
DataBlock data;
|
|
uint8_t tag = NULL_ID;
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
tag = 0;
|
|
data.append(&tag, 1);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeOID(ASNObjId obj, bool tagCheck)
|
|
{
|
|
/**
|
|
* ASN.1 object id ::= 0x06 asnlength byte {byte}*
|
|
*/
|
|
DataBlock data;
|
|
uint8_t tag = OBJECT_ID;
|
|
|
|
DataBlock cont = obj.getIds();
|
|
DataBlock contents;
|
|
|
|
if (cont.length() == 0)
|
|
return data;
|
|
|
|
// first byte is built following the rule first = 40 * x + y
|
|
// x must not be greater than 2 (joint-iso-ccitt identifier)
|
|
if (cont[0] > 2) {
|
|
Debug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - first identifier is greater than the maximum allowed identifier 'joint-iso-ccitt'(2)",
|
|
obj.toString().c_str());
|
|
return data;
|
|
}
|
|
uint8_t first = 40 * cont[0];
|
|
if (cont.length() > 1) {
|
|
// y must not be greater than 39 if x < 2
|
|
if (cont[0] < 2 && cont[1] > 39) {
|
|
Debug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - cannot encode second identifier, its value is not allowed for the first identifier",
|
|
obj.toString().c_str());
|
|
return data;
|
|
}
|
|
first += cont[1];
|
|
cont.cut(-1);
|
|
}
|
|
contents.append(&first, 1);
|
|
cont.cut(-1);
|
|
|
|
contents.append(cont);
|
|
if (tagCheck) {
|
|
data.append(&tag,1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - encoded object ID into %u bytes",obj.toString().c_str(),data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeReal(float val, bool tagCheck)
|
|
{
|
|
Debug(s_libName.c_str(),DebugInfo,"::encodeReal() - STUB: encoding for real values not implemented");
|
|
DataBlock data;
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeString(String str, int type, bool tagCheck)
|
|
{
|
|
DataBlock data;
|
|
uint8_t tag = type;
|
|
|
|
DataBlock contents;
|
|
if (type == NUMERIC_STR ||
|
|
type == PRINTABLE_STR ||
|
|
type == IA5_STR ||
|
|
type == VISIBLE_STR )
|
|
contents.append(str);
|
|
|
|
if (contents.length() == 0)
|
|
return data;
|
|
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeString() - encoded string into %u bytes",data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeUtf8(String str, bool tagCheck)
|
|
{
|
|
DDebug(s_libName.c_str(),DebugAll,"::encodeUtf8()");
|
|
DataBlock data;
|
|
uint8_t tag = UTF8_STR;
|
|
DataBlock contents;
|
|
contents.append(str);
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeString() - encoded UTF8 string into %u bytes",data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeGenTime(unsigned int time, unsigned int fractions, bool tagCheck)
|
|
{
|
|
DataBlock data;
|
|
uint8_t tag = GENERALIZED_TIME;
|
|
|
|
int year;
|
|
unsigned int month, day, hours, minutes, seconds;
|
|
if (!Time::toDateTime(time, year, month, day, hours, minutes, seconds))
|
|
return data;
|
|
String dateTime = "";
|
|
dateTime += year;
|
|
(month < 10) ? dateTime += 0 : "";
|
|
dateTime += month;
|
|
(day < 10) ? dateTime += 0 : "";
|
|
dateTime += day;
|
|
(hours < 10) ? dateTime += 0 : "";
|
|
dateTime += hours;
|
|
(minutes < 10) ? dateTime += 0 : "";
|
|
dateTime += minutes;
|
|
(seconds < 10) ? dateTime += 0 : "";
|
|
dateTime += seconds;
|
|
if (fractions != 0) {
|
|
dateTime += ".";
|
|
dateTime += fractions;
|
|
}
|
|
dateTime += 'Z';
|
|
DataBlock contents;
|
|
contents.append(dateTime);
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeGenTime(time='%u', fractions='%u') - encoded time value into %u bytes",time,fractions,data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeUTCTime(unsigned int time, bool tagCheck)
|
|
{
|
|
DataBlock data;
|
|
uint8_t tag = UTC_TIME;
|
|
|
|
int year;
|
|
unsigned int month, day, hours, minutes, seconds;
|
|
if (!Time::toDateTime(time, year, month, day, hours, minutes, seconds))
|
|
return data;
|
|
String dateTime = "";
|
|
(year % 100 < 10) ? dateTime += 0 : "";
|
|
dateTime += (year % 100);
|
|
(month < 10) ? dateTime += 0 : "";
|
|
dateTime += month;
|
|
(day < 10) ? dateTime += 0 : "";
|
|
dateTime += day;
|
|
(hours < 10) ? dateTime += 0 : "";
|
|
dateTime += hours;
|
|
(minutes < 10) ? dateTime += 0 : "";
|
|
dateTime += minutes;
|
|
(seconds < 10) ? dateTime += 0 : "";
|
|
dateTime += seconds;
|
|
|
|
dateTime += 'Z';
|
|
|
|
DataBlock contents;
|
|
contents.append(dateTime);
|
|
if (tagCheck) {
|
|
data.append(&tag, 1);
|
|
DataBlock len = buildLength(contents);
|
|
data.append(len);
|
|
}
|
|
data.append(contents);
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeUTCTime(time='%u') - encoded time value into %u bytes",time,data.length());
|
|
return data;
|
|
}
|
|
|
|
DataBlock ASNLib::encodeAny(DataBlock data, bool tagCheck)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeAny()");
|
|
DataBlock db;
|
|
db.append(data);
|
|
return db;
|
|
}
|
|
|
|
int ASNLib::encodeSequence(DataBlock& data, bool tagCheck)
|
|
{
|
|
DataBlock len;
|
|
if (tagCheck) {
|
|
len = buildLength(data);
|
|
data.insert(len);
|
|
DataBlock db;
|
|
u_int8_t tag = SEQUENCE;
|
|
db.append(&tag, 1);
|
|
data.insert(db);
|
|
}
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeSequence() - added sequence tag and length for a block of %d bytes",data.length());
|
|
return len.length();
|
|
}
|
|
|
|
int ASNLib::encodeSet(DataBlock& data, bool tagCheck)
|
|
{
|
|
DDebug(s_libName.c_str(),DebugAll,"::encodeSet()");
|
|
DataBlock len;
|
|
if (tagCheck) {
|
|
len = buildLength(data);
|
|
data.insert(len);
|
|
DataBlock db;
|
|
u_int8_t tag = SET;
|
|
db.append(&tag, 1);
|
|
data.insert(db);
|
|
}
|
|
XDebug(s_libName.c_str(),DebugAll,"::encodeSet() - added set tag and length for a block of %d bytes",data.length());
|
|
return len.length();
|
|
}
|
|
|
|
/**
|
|
* AsnTag
|
|
*/
|
|
void AsnTag::decode(AsnTag& tag, DataBlock& data)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"AsnTag::decode()");
|
|
tag.classType((Class)(data[0] & 0xc0));
|
|
tag.type((Type)(data[0] & 0x20));
|
|
|
|
unsigned int code = 0;
|
|
code |= data[0] & 0x1f;
|
|
unsigned int len = 1;
|
|
if (IS_EXTENSION_ID(code) && data.length() >= 2) { // extended tag
|
|
code = 0;
|
|
while (len < data.length() && (data[len] & ASN_BIT8) == ASN_BIT8) {
|
|
code = code << 8;
|
|
code |= (data[len] & 0x7f);
|
|
len++;
|
|
}
|
|
code |= data[len] & 0x7f;
|
|
}
|
|
tag.code(code);
|
|
tag.encode();
|
|
}
|
|
|
|
void AsnTag::encode(Class clas, Type type, unsigned int code, DataBlock& data)
|
|
{
|
|
XDebug(s_libName.c_str(),DebugAll,"AsnTag::encode(clas=0x%x, type=0x%x, code=%u)",clas,type,code);
|
|
if (code < 31) {
|
|
u_int8_t tag = clas | type | code;
|
|
data.insert(DataBlock(&tag,sizeof(tag)));
|
|
}
|
|
else {
|
|
u_int8_t last = clas | type | 31;
|
|
DataBlock coding;
|
|
coding.append(&last,sizeof(last));
|
|
int size = sizeof(unsigned int);
|
|
bool start = false;
|
|
while (size > 1) {
|
|
u_int8_t msb = (code >> ((size - 1) * 8));
|
|
if (start) {
|
|
msb |= 0x80;
|
|
coding.append(&msb,sizeof(msb));
|
|
}
|
|
else {
|
|
if (msb == 0) {
|
|
size--;
|
|
continue;
|
|
}
|
|
else {
|
|
start = true;
|
|
msb |= 0x80;
|
|
coding.append(&msb,sizeof(msb));
|
|
}
|
|
}
|
|
size--;
|
|
}
|
|
last = code;
|
|
coding.append(&last,sizeof(last));
|
|
data.insert(coding);
|
|
}
|
|
#ifdef XDEBUG
|
|
String str;
|
|
str.hexify(data.data(),data.length(),' ');
|
|
Debug(s_libName.c_str(),DebugAll,"AsnTag::encode(clas=0x%x, type=0x%x, code=%u) tag=%s",clas,type,code,str.c_str());
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* ASNObjId
|
|
*/
|
|
ASNObjId::ASNObjId()
|
|
{
|
|
}
|
|
|
|
ASNObjId::ASNObjId(const String& val)
|
|
: m_value(val)
|
|
{
|
|
DDebug(s_libName.c_str(),DebugAll,"ASNObjId('%s') created",val.c_str());
|
|
}
|
|
|
|
ASNObjId::ASNObjId(const String& name, const String& val)
|
|
: m_value(val), m_name(name)
|
|
{
|
|
DDebug(s_libName.c_str(),DebugAll,"ASNObjId('%s', '%s') created",name.c_str(),val.c_str());
|
|
}
|
|
|
|
ASNObjId::ASNObjId(AsnMib* mib)
|
|
{
|
|
DDebug(s_libName.c_str(),DebugAll,"ASNObjId() created from AsnMib [%p]",mib);
|
|
if (mib) {
|
|
m_name = mib->getName();
|
|
m_value = mib->getOID();
|
|
}
|
|
}
|
|
|
|
ASNObjId::~ASNObjId()
|
|
{
|
|
m_ids.clear();
|
|
}
|
|
|
|
void ASNObjId::toDataBlock()
|
|
{
|
|
DDebug(s_libName.c_str(),DebugAll,"ASNObjId::toDataBlock() '%s'", m_value.c_str());
|
|
m_ids.clear();
|
|
ObjList* list = m_value.split('.',false);
|
|
if (list) {
|
|
for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
|
|
String* s = static_cast<String*>(o->get());
|
|
int val = s->toInteger();
|
|
if (val < 128)
|
|
m_ids.append(&val, 1);
|
|
else {
|
|
DataBlock db;
|
|
int size = sizeof(int);
|
|
uint8_t v = val;
|
|
v = v & 0x7f;
|
|
db.append(&v,1);
|
|
size--;
|
|
val = val >> 7;
|
|
while (val != 0) {
|
|
v = val;
|
|
v = v & 0x7f;
|
|
v = v | 0x80;
|
|
DataBlock tmp;
|
|
tmp.append(&v,1);
|
|
db.insert(tmp);
|
|
size--;
|
|
val = val >> 7;
|
|
}
|
|
m_ids.append(db);
|
|
}
|
|
}
|
|
TelEngine::destruct(list);
|
|
}
|
|
}
|
|
|
|
DataBlock ASNObjId::getIds()
|
|
{
|
|
toDataBlock();
|
|
return m_ids;
|
|
}
|
|
|
|
/**
|
|
* AsnMib
|
|
*/
|
|
TokenDict AsnMib::s_access[] = {
|
|
{"accessible-for-notify", AsnMib::accessibleForNotify},
|
|
{"read-only", AsnMib::readOnly},
|
|
{"read-write", AsnMib::readWrite},
|
|
{"read-create", AsnMib::readCreate},
|
|
{0,0}
|
|
};
|
|
|
|
AsnMib::AsnMib(NamedList& params)
|
|
{
|
|
if (!params)
|
|
return;
|
|
m_index = 0;
|
|
m_oid = params;
|
|
m_name = params.getValue("name","");
|
|
m_access = params.getValue("access","");
|
|
m_accessVal = lookup(m_access,s_access,0);
|
|
m_type = params.getValue("type","");
|
|
m_revision = params.getValue("revision","");
|
|
XDebug(s_libName.c_str(),DebugAll,"new AsnMib created with oid : '%s', access : '%s', type : '%s'",
|
|
m_oid.c_str(),m_access.c_str(),m_type.c_str());
|
|
}
|
|
|
|
int AsnMib::compareTo(AsnMib* mib)
|
|
{
|
|
if (!mib)
|
|
return 1;
|
|
DDebug(s_libName,DebugInfo,"AsnMib::compareTo('%s'='%s' [%p]) this=%s[%s] [%p]",
|
|
mib->getName().c_str(),mib->toString().c_str(),mib,getName().c_str(),toString().c_str(),this);
|
|
|
|
// they're equal
|
|
if (toString() == mib->toString())
|
|
return 0;
|
|
|
|
ObjList* myIDs = toString().split('.',false);
|
|
ObjList* mibIDs = mib->toString().split('.',false);
|
|
|
|
ObjList* o1 = myIDs->skipNull();
|
|
ObjList* o2 = mibIDs->skipNull();
|
|
while (o1 && o2) {
|
|
String* str1 = static_cast<String*>(o1->get());
|
|
o1 = o1->skipNext();
|
|
String* str2 = static_cast<String*>(o2->get());
|
|
o2 = o2->skipNext();
|
|
int diff = str1->toInteger() - str2->toInteger();
|
|
if (diff == 0)
|
|
continue;
|
|
if (diff > 0) {
|
|
TelEngine::destruct(myIDs);
|
|
TelEngine::destruct(mibIDs);
|
|
return 1;
|
|
}
|
|
if (diff < 0) {
|
|
TelEngine::destruct(myIDs);
|
|
TelEngine::destruct(mibIDs);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int retValue = 0;
|
|
if (!o1)
|
|
retValue = -1;
|
|
else if (!o2)
|
|
retValue = 1;
|
|
TelEngine::destruct(myIDs);
|
|
TelEngine::destruct(mibIDs);
|
|
return retValue;
|
|
}
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|