1
0
Files
2022-09-29 17:59:04 +03:00

1016 lines
17 KiB
C++

/*
* Copyright 1990 Silicon Graphics, Inc. All rights reserved.
*
* ASN.1
*
* $Revision: 1.9 $
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#include <stdio.h>
#include <libc.h>
#include <string.h>
#include <ctype.h>
#include "oid.h"
#include "asn1.h"
// The definition of MAXCOMMNAMELEN was taken from agent.c++
#define MAXCOMMNAMELEN 256
/*
* ASN object base class
*/
asnObject::asnObject(void)
{
asn = 0;
asnLength = 0;
setValue();
}
asnObject::~asnObject(void)
{
}
void
asnObject::setValue(void)
{
value = 0;
tag = TAG_NULL;
}
void
asnObject::setValue(asnObject *a)
{
tag = a->tag;
value = a->value;
}
void
asnObject::getValue(void)
{
}
unsigned int
asnObject::getTag(void)
{
if (asn != 0 && tag == TAG_NULL)
tag = *asn;
return tag;
}
int
asnObject::encode(void)
{
return 0;
}
int
asnObject::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnObject::decode(void)
{
return 0;
}
int
asnObject::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
asnObject *
asnObject::dup(void)
{
asnObject *a = new asnObject();
*a = *this;
return a;
}
char *
asnObject::getString(void)
{
char *s = new char[4];
s[0] = 0;
return s;
}
/*
* Length encoding rules:
*
* A length of 0 to 127 may be encoded as a single byte; that is,
* bit 8 is zero and bits 1 to 7 are the value.
*
* A length longer that 127 comprises of a bytes to say how many bytes make
* up the length, followed by those bytes. The first byte has bit 8 set
* and bits 1 to 7 as the byte count. The subsequent bytes contain the
* length, most significant byte first.
*/
int
asnObject::encodeLength(char **p, unsigned int len)
{
// Try to just send 1 byte
if (len < LENGTH_LONG_FORMAT) {
*(*p)++ = len;
return 1;
}
// Have to do it the long way
char *llen = *p;
unsigned int size = sizeof(int);
unsigned int shift = 8 * (size - 1);
unsigned int mask = 0xFF << shift;
while ((mask & len) == 0) {
len <<= 8;
size--;
}
if (size >= asnLength)
return 0;
for (*(*p)++ = 0; size != 0; len <<= 8, (*llen)++, size--)
*(*p)++ = len >> shift;
*llen |= LENGTH_LONG_FORMAT;
unsigned long tmp = (unsigned long)*p - (unsigned long)llen;
return (unsigned int) tmp;
}
int
asnObject::decodeLength(char **p, unsigned int& len)
{
char *start = *p;
len = *(*p)++;
if (!(len & LENGTH_LONG_FORMAT))
return 1;
len &= ~LENGTH_LONG_FORMAT;
for (unsigned int size = sizeof(int); len > size; len--) {
if (*(*p)++ != 0)
return 0; // Too big!
}
for (unsigned int result = 0; len != 0; len--)
result = (result << 8) | *(*p)++;
len = result;
unsigned long tmp = (unsigned long) *p - (unsigned long) start;
return (unsigned int) tmp;
}
/*
* ASN long class - for 64 bit
*/
asnLong::asnLong(void)
{
}
asnLong::asnLong(long i)
{
setValue(i);
}
asnLong::~asnLong(void)
{
}
void
asnLong::setValue(asnObject *a)
{
*this = *((asnLong *) a);
}
int
asnLong::encode(char *a, unsigned int len)
{
printf("Error: encode called for asnLong\n");
exit(1);
}
int
asnLong::decode(char *a, unsigned int len)
{
printf("Error: decode called for asnLong\n");
exit(1);
}
/*
* ASN integer class
*/
asnInteger::asnInteger(void)
{
}
asnInteger::asnInteger(int i)
{
setValue(i);
}
asnInteger::~asnInteger(void)
{
}
void
asnInteger::setValue(asnObject *a)
{
*this = *((asnInteger *) a);
}
int
asnInteger::encode(void)
{
if (asn == 0 || asnLength < 2)
return 0;
char *p = asn;
*p++ = tag; // Fill in the tag value
/*
* Send the least number of bytes necessary to hold a signed number
* most significant byte first. Bit 8 of the first byte must
* be zero if the number is positive.
*/
unsigned long tmp = (unsigned long)value;
unsigned int v = (unsigned int) tmp;
unsigned int len = sizeof(int);
unsigned int shift = 8 * (len - 1);
unsigned int mask = 0x1FF << (shift - 1);
while ( ((mask & v) == 0 || (mask & v) == mask) && len > 1) {
v <<= 8;
len--;
}
int llen = encodeLength(&p, len);
if (llen == 0)
return 0; // Bad length
if (len > asnLength - llen)
return 0; // End of ASN string
while (len-- != 0) {
*p++ = v >> shift;
v <<= 8;
}
tmp = (unsigned long) p - (unsigned long) asn;
return (unsigned int) tmp;
}
int
asnInteger::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnInteger::decode(void)
{
if (asn == 0 || asnLength == 0)
return 0;
char *p = asn;
tag = *p++;
if (tag != TAG_INTEGER)
return 0; // Wrong tag
if (asnLength == 1)
return 0;
unsigned int len;
int llen = decodeLength(&p, len);
if (llen == 0 )
return 0; // Bad length
if (len > asnLength - llen)
return 0; // End of ASN string
for (unsigned int size = sizeof(int); len > size; len--) {
if (*p++ != 0)
return 0; // Too big!
}
if (len > 0) {
unsigned int result = (*p & 0x80) ? -1 : 0;
for ( ; len != 0; len--)
result = (result << 8) | *p++;
unsigned long tmp = result;
value = (void *) tmp;
} else
value = 0;
unsigned long tmp = (unsigned long) p - (unsigned long) asn;
return (unsigned int) tmp;
}
int
asnInteger::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
asnObject *
asnInteger::dup(void)
{
return new asnInteger(getValue());
}
char *
asnInteger::getString(void)
{
char *s = new char[12];
sprintf(s, "%d", value);
return s;
}
/*
* ASN Octet String class
*/
asnOctetString::asnOctetString(void)
{
value = 0;
stringLength = 0;
newString = 0;
}
asnOctetString::asnOctetString(const char *s)
{
newString = 0;
setValue(s);
}
asnOctetString::asnOctetString(const char *s, unsigned int len)
{
newString = 0;
setValue(s, len);
}
asnOctetString::asnOctetString(asnOctetString &a)
{
newString = 0;
*this = a;
}
asnOctetString::~asnOctetString(void)
{
if (newString)
delete (char *) value;
}
void
asnOctetString::setValue(const char *s)
{
if (newString)
delete (char *) value;
newString = 0;
value = (void *) s;
tag = TAG_OCTET_STRING;
if (s == 0)
stringLength = 0;
else
stringLength = strlen(s);
}
void
asnOctetString::setValue(const char *s, unsigned int len)
{
if (newString)
delete (char *) value;
newString = 0;
value = (void *) s;
tag = TAG_OCTET_STRING;
stringLength = len;
}
void
asnOctetString::setValue(asnObject *a)
{
*this = *((asnOctetString *) a);
}
asnOctetString &
asnOctetString::operator=(asnOctetString &a)
{
if (newString)
delete (char *) value;
value = 0;
newString = 0;
tag = a.getTag();
stringLength = a.getLength();
if (stringLength != 0) {
newString = 1;
value = new char[stringLength];
bcopy(a.getValue(), value, stringLength);
}
return *this;
}
int
asnOctetString::encode(void)
{
if (asn == 0 || asnLength < 2)
return 0;
char *p = asn;
*p++ = tag; // Fill in the tag value
int len = stringLength;
int llen = encodeLength(&p, len);
if (llen == 0)
return 0; // Bad length
if (len > asnLength - llen)
return 0; // End of ASN string
if (len > 0)
bcopy(value, p, len);
return llen + len + 1;
}
int
asnOctetString::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnOctetString::decode(void)
{
if (asn == 0 || asnLength == 0)
return 0;
char *p = asn;
tag = *p++;
if (tag != TAG_OCTET_STRING)
return 0; // Wrong tag
if (asnLength == 1)
return 0;
int llen = decodeLength(&p, stringLength);
if (llen == 0)
return 0; // Bad length
if (stringLength > asnLength - llen)
return 0; // End of ASN string
if (stringLength != 0) {
if (value == 0) {
newString = 1;
value = new char[MAXCOMMNAMELEN];
}
bcopy(p, value, stringLength);
}
return llen + stringLength + 1;
}
int
asnOctetString::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
asnObject *
asnOctetString::dup(void)
{
return new asnOctetString(*this);
}
char *
asnOctetString::getString(void)
{
if (value == 0)
return asnObject::getString();
/*
* Check if the string is printable.
*/
char *v = (char *) value;
char *s;
for (int i = 0; i < stringLength; i++) {
if (!isprint(v[i]) && !isspace(v[i])) {
/*
* The string is not printable, so dump it.
*/
// Allow a trailing '\0' for Cabletron bug.
if (v[i] == 0 && i == stringLength - 1)
continue;
s = new char[stringLength * 3];
char *p = s;
for (*p = '\0', i = 0; i < stringLength; i++) {
if (p != s)
*p++ = ' ';
sprintf(p, "%02X", v[i]);
p += 2;
}
return s;
}
}
/*
* The string is printable, so print it.
*/
s = new char[stringLength + 1];
if (stringLength != 0)
bcopy(value, s, stringLength);
s[stringLength] = '\0';
return s;
}
/*
* ASN Null class
*/
asnNull::~asnNull(void)
{
}
void
asnNull::setValue(void)
{
value = 0;
tag = TAG_NULL;
}
void
asnNull::setValue(asnObject *)
{
}
int
asnNull::encode(void)
{
if (asn == 0 || asnLength < 2)
return 0;
char *p = asn;
*p++ = tag; // Fill in the tag value
*p = 0;
return 2;
}
int
asnNull::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnNull::decode(void)
{
if (asn == 0 || asnLength == 0)
return 0;
char *p = asn;
tag = *p++;
if (tag != TAG_NULL)
return 0; // Wrong tag
if (asnLength == 1)
return 0;
unsigned int len;
int llen = decodeLength(&p, len);
if (llen == 0 )
return 0; // Bad length
value = 0;
return llen + 1;
}
int
asnNull::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
asnObject *
asnNull::dup(void)
{
return new asnNull;
}
char *
asnNull::getString(void)
{
char *s = new char[8];
strcpy(s, "null");
return s;
}
/*
* ASN Object Identifier class
*/
asnObjectIdentifier::asnObjectIdentifier(void)
{
newOid = 0;
}
asnObjectIdentifier::asnObjectIdentifier(const char *s)
{
newOid = 0;
setValue(s);
}
asnObjectIdentifier::asnObjectIdentifier(oid *o)
{
newOid = 0;
setValue(o);
}
asnObjectIdentifier::asnObjectIdentifier(asnObjectIdentifier &a)
{
newOid = 0;
*this = a;
}
asnObjectIdentifier::~asnObjectIdentifier(void)
{
if (newOid)
delete (oid *) value;
}
void
asnObjectIdentifier::setValue(oid *o)
{
if (newOid)
delete (oid *) value;
newOid = 0;
value = o;
tag = TAG_OBJECT_IDENTIFIER;
}
void
asnObjectIdentifier::setValue(const char *s)
{
if (newOid)
delete (oid *) value;
value = new oid(s);
newOid = 1;
tag = TAG_OBJECT_IDENTIFIER;
}
void
asnObjectIdentifier::setValue(asnObject *a)
{
*this = *((asnObjectIdentifier *) a);
}
asnObjectIdentifier &
asnObjectIdentifier::operator=(asnObjectIdentifier &a)
{
if (newOid)
delete (oid *) value;
value = 0;
newOid = 0;
tag = a.getTag();
oid *oi = a.getValue();
if (oi != 0) {
newOid = 1;
value = new oid(*oi);
}
return *this;
}
int
asnObjectIdentifier::encode(void)
{
if (asn == 0 || asnLength < 2)
return 0;
char *p = asn;
*p++ = tag; // Fill in the tag value
/*
* Combine the first sub-ID with the second using
* b[0] = s[0] * 40 + s[1]. Encode the rest of the sub-IDs in
* bits 1 to 7. Bit 8 is 1 in all but the last byte of
* each sub-ID, in which it is 0. For example, 1.3.5.129 encodes
* as 2B 05 81 01.
*/
oid *objid = (oid *) value;
int objlen = objid->length;
if (objlen == 0)
return 0;
char buf[256];
unsigned int len = 1;
unsigned int sid = 2;
unsigned int size = (8 * sizeof(subID)) / 7 + 1;
unsigned int shift = 7 * (size - 1);
unsigned int mask = 0x7F << shift;
// Combine first to sub-IDs
buf[0] = (objlen == 1) ? objid->subid[0] * 40 :
objid->subid[0] * 40 + objid->subid[1];
// Encode in bits 1 to 7
for (objlen -= 2; objlen > 0; objlen--, sid++) {
unsigned int s = objid->subid[sid];
unsigned int z = size;
while ((s & mask) == 0 && z > 1) {
s <<= 7;
z--;
}
for ( ; z != 0; z--, s <<= 7, len++)
buf[len] = (s >> shift) | 0x80;
buf[len-1] &= 0x7F;
}
// Encode the length now that we know it and copy the bytes
int llen = encodeLength(&p, len);
if (llen == 0)
return 0; // Bad length
if (len > asnLength - llen)
return 0; // End of ASN string
bcopy(buf, p, len);
return llen + len + 1;
}
int
asnObjectIdentifier::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnObjectIdentifier::decode(void)
{
if (asn == 0 || asnLength == 0)
return 0;
char *p = asn;
tag = *p++;
if (tag != TAG_OBJECT_IDENTIFIER)
return 0; // Wrong tag
if (asnLength == 1)
return 0;
unsigned int len;
int llen = decodeLength(&p, len);
if (llen == 0 || len <= 0)
return 0; // Bad length
if (len > asnLength - llen)
return 0; // End of ASN string
subID tmp[OID_MAX_LENGTH];
unsigned int s = 0;
tmp[s++] = *p / 40;
tmp[s] = *p++ % 40;
unsigned int next = 1;
for (len--; len != 0; len--, next = !(*p++ & 0x80)) {
if (next)
tmp[++s] = 0;
tmp[s] = (tmp[s] << 7) | (*p & 0x7F);
}
if (value == 0) {
value = new oid;
newOid = 1;
}
oid *dst = (oid *) value;
dst->length = s + 1;
if (dst->subid == 0)
dst->subid = new subID[dst->length];
bcopy(tmp, dst->subid, dst->length * sizeof(subID));
unsigned long temp = (unsigned long) p - (unsigned long) asn;
return (unsigned int) temp;
}
int
asnObjectIdentifier::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
asnObject *
asnObjectIdentifier::dup(void)
{
return new asnObjectIdentifier(*this);
}
char *
asnObjectIdentifier::getString(void)
{
if (value == 0) {
char *s = new char[8];
strcpy(s, "null");
return s;
}
return ((oid *) value)->getString();
}
/*
* ASN Sequence class
*/
asnSequence::asnSequence(void)
{
}
asnSequence::asnSequence(unsigned int l)
{
setValue(l);
}
asnSequence::~asnSequence(void)
{
}
void
asnSequence::setValue(unsigned int l)
{
unsigned long tmp = l;
value = (void *) tmp;
tag = TAG_SEQUENCE;
}
void
asnSequence::setValue(asnObject *a)
{
asnObject::setValue(a);
}
int
asnSequence::encode(void)
{
if (asn == 0 || asnLength < 2)
return 0;
char *p = asn;
*p++ = tag; // Fill in the tag value
unsigned long tmp = (unsigned long) value;
int llen = encodeLength(&p, (unsigned int) tmp);
if (llen == 0)
return 0;
return llen + 1;
}
int
asnSequence::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnSequence::decode(void)
{
if (asn == 0 || asnLength == 0)
return 0;
char *p = asn;
tag = *p++;
if (tag != TAG_SEQUENCE)
return 0; // Wrong tag
if (asnLength == 1)
return 0;
unsigned int len;
int llen = decodeLength(&p, len);
if (llen == 0)
return 0; // Bad length
unsigned long tmp = len;
value = (void *) tmp;
return llen + 1;
}
int
asnSequence::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
char *
asnSequence::getString(void)
{
char *s = new char[12];
sprintf(s, "%u", value);
return s;
}
/*
* ASN Choice class
*/
asnChoice::asnChoice(void)
{
}
asnChoice::asnChoice(unsigned int c, unsigned int l)
{
setValue(c, l);
}
asnChoice::~asnChoice(void)
{
}
void
asnChoice::setValue(unsigned int c, unsigned int l)
{
unsigned long tmp = l;
value = (void *) tmp;
setTag(c);
}
void
asnChoice::setValue(asnObject *a)
{
asnObject::setValue(a);
}
void
asnChoice::setTag(unsigned int c)
{
tag = c;
}
int
asnChoice::encode(void)
{
if (asn == 0 || asnLength < 2)
return 0;
char *p = asn;
*p++ = tag; // Fill in the tag value
unsigned long tmp = (unsigned long) value;
int llen = encodeLength(&p, (unsigned int) tmp);
if (llen == 0)
return 0;
return llen + 1;
}
int
asnChoice::encode(char *a, unsigned int len)
{
setAsn(a, len);
return encode();
}
int
asnChoice::decode(void)
{
if (asn == 0 || asnLength == 0)
return 0;
char *p = asn;
tag = *p++;
if ((tag & 0xF0) != TAG_CHOICE)
return 0; // Wrong tag
if (asnLength == 1)
return 0;
unsigned int len;
int llen = decodeLength(&p, len);
if (llen == 0)
return 0; // Bad length
unsigned long tmp = len;
value = (void *) tmp;
return llen + 1;
}
int
asnChoice::decode(char *a, unsigned int len)
{
setAsn(a, len);
return decode();
}
char *
asnChoice::getString(void)
{
char *s = new char[12];
sprintf(s, "%u", value);
return s;
}