📄 asn1.c
字号:
* length specified.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* in this object following the id and length.
*
* This only works on data types < 30, i.e. no extension octets.
* The maximum length is 0xFFFF;
*
* Returns a pointer to the first byte of the contents of this object.
* Returns NULL on any error.
u_char * asn_build_sequence(
u_char *data IN - pointer to start of object
int *datalength IN/OUT - number of valid bytes left in buffer
u_char type IN - asn type of object
int length IN - length of object
*/
u_char *
asn_build_sequence(u_char *data,
size_t *datalength,
u_char type,
size_t length)
{
static const char *errpre = "build seq";
char ebuf[128];
if (*datalength < 4){
sprintf(ebuf, "%s: length %d < 4: PUNT", errpre, (int)*datalength);
ERROR_MSG(ebuf);
return NULL;
}
*datalength -= 4;
*data++ = type;
*data++ = (u_char)(0x02 | ASN_LONG_LEN);
*data++ = (u_char)((length >> 8) & 0xFF);
*data++ = (u_char)(length & 0xFF);
return data;
}
/*
* asn_parse_length - interprets the length of the current object.
* On exit, length contains the value of this length field.
*
* Returns a pointer to the first byte after this length
* field (aka: the start of the data field).
* Returns NULL on any error.
u_char * asn_parse_length(
u_char *data IN - pointer to start of length field
u_long *length OUT - value of length field
*/
u_char *
asn_parse_length(u_char *data,
u_long *length)
{
static const char *errpre = "parse length";
char ebuf[128];
register u_char lengthbyte;
if (!data || !length) {
ERROR_MSG("parse length: NULL pointer");
return NULL;
}
lengthbyte = *data;
if (lengthbyte & ASN_LONG_LEN){
lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
if (lengthbyte == 0){
sprintf(ebuf, "%s: indefinite length not supported", errpre);
ERROR_MSG(ebuf);
return NULL;
}
if (lengthbyte > sizeof(long)){
sprintf(ebuf, "%s: data length %d > %d not supported", errpre,
lengthbyte, sizeof(long));
ERROR_MSG(ebuf);
return NULL;
}
data++;
*length = 0; /* protect against short lengths */
while(lengthbyte--) {
*length <<= 8;
*length |= *data++;
}
return data;
} else { /* short asnlength */
*length = (long)lengthbyte;
return data + 1;
}
}
/*
u_char * asn_build_length(
u_char *data IN - pointer to start of object
int *datalength IN/OUT - number of valid bytes left in buffer
int length IN - length of object
*/
u_char *
asn_build_length(u_char *data,
size_t *datalength,
size_t length)
{
static const char *errpre = "build length";
char ebuf[128];
u_char *start_data = data;
/* no indefinite lengths sent */
if (length < 0x80){
if (*datalength < 1){
sprintf(ebuf, "%s: bad length < 1 :%d, %d",errpre,*datalength,length);
ERROR_MSG(ebuf);
return NULL;
}
*data++ = (u_char)length;
} else if (length <= 0xFF){
if (*datalength < 2){
sprintf(ebuf, "%s: bad length < 2 :%d, %d",errpre,*datalength,length);
ERROR_MSG(ebuf);
return NULL;
}
*data++ = (u_char)(0x01 | ASN_LONG_LEN);
*data++ = (u_char)length;
} else { /* 0xFF < length <= 0xFFFF */
if (*datalength < 3){
sprintf(ebuf, "%s: bad length < 3 :%d, %d",errpre,*datalength,length);
ERROR_MSG(ebuf);
return NULL;
}
*data++ = (u_char)(0x02 | ASN_LONG_LEN);
*data++ = (u_char)((length >> 8) & 0xFF);
*data++ = (u_char)(length & 0xFF);
}
*datalength -= (data - start_data);
return data;
}
/*
* asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* following the beginning of the next object.
*
* "objid" is filled with the object identifier.
*
* Returns a pointer to the first byte past the end
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
u_char * asn_parse_objid(
u_char *data IN - pointer to start of object
int *datalength IN/OUT - number of valid bytes left in buffer
u_char *type OUT - asn type of object
oid *objid IN/OUT - pointer to start of output buffer
int *objidlength IN/OUT - number of sub-id's in objid
*/
u_char *
asn_parse_objid(u_char *data,
size_t *datalength,
u_char *type,
oid *objid,
size_t *objidlength)
{
/*
* ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
* subidentifier ::= {leadingbyte}* lastbyte
* leadingbyte ::= 1 7bitvalue
* lastbyte ::= 0 7bitvalue
*/
register u_char *bufp = data;
register oid *oidp = objid + 1;
register u_long subidentifier;
register long length;
u_long asn_length;
*type = *bufp++;
bufp = asn_parse_length(bufp, &asn_length);
if (_asn_parse_length_check("parse objid", bufp, data,
asn_length, *datalength))
return NULL;
*datalength -= (int)asn_length + (bufp - data);
DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
/* Handle invalid object identifier encodings of the form 06 00 robustly */
if (asn_length == 0)
objid[0] = objid[1] = 0;
length = asn_length;
(*objidlength)--; /* account for expansion of first byte */
while (length > 0 && (*objidlength)-- > 0){
subidentifier = 0;
do { /* shift and add in low order 7 bits */
subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8);
length--;
} while (*(u_char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
/*?? note, this test will never be true, since the largest value
of subidentifier is the value of MAX_SUBID! */
if (subidentifier > (u_long)MAX_SUBID){
ERROR_MSG("subidentifier too large");
return NULL;
}
*oidp++ = (oid)subidentifier;
}
/*
* The first two subidentifiers are encoded into the first component
* with the value (X * 40) + Y, where:
* X is the value of the first subidentifier.
* Y is the value of the second subidentifier.
*/
subidentifier = (u_long)objid[1];
if (subidentifier == 0x2B){
objid[0] = 1;
objid[1] = 3;
} else {
if (subidentifier < 40) {
objid[0] = 0;
objid[1] = subidentifier;
} else if (subidentifier < 80) {
objid[0] = 1;
objid[1] = subidentifier - 40;
} else if (subidentifier < 120) {
objid[0] = 2;
objid[1] = subidentifier - 80;
} else {
objid[1] = (subidentifier % 40);
objid[0] = ((subidentifier - objid[1]) / 40);
}
}
*objidlength = (int)(oidp - objid);
DEBUGMSG(("dump_recv", " ASN ObjID: "));
DEBUGMSGOID(("dump_recv", objid, *objidlength));
DEBUGMSG(("dump_recv", "\n"));
return bufp;
}
/*
* asn_build_objid - Builds an ASN object identifier object containing the
* input string.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* following the beginning of the next object.
*
* Returns a pointer to the first byte past the end
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
u_char * asn_build_objid(
u_char *data IN - pointer to start of object
int *datalength IN/OUT - number of valid bytes left in buffer
int type IN - asn type of object
oid *objid IN - pointer to start of input buffer
int objidlength IN - number of sub-id's in objid
*/
u_char *
asn_build_objid(u_char *data,
size_t *datalength,
u_char type,
oid *objid,
size_t objidlength)
{
/*
* ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
* subidentifier ::= {leadingbyte}* lastbyte
* leadingbyte ::= 1 7bitvalue
* lastbyte ::= 0 7bitvalue
*/
size_t asnlength;
register oid *op = objid;
u_char objid_size[MAX_OID_LEN];
register u_long objid_val;
u_long first_objid_val;
register int i;
/* check if there are at least 2 sub-identifiers */
if (objidlength == 0){
/* there are not, so make OID have two with value of zero */
objid_val = 0;
objidlength = 2;
} else if (objidlength == 1){
/* encode the first value */
objid_val = (op[0] * 40);
objidlength = 2;
op++;
} else {
/* combine the first two values */
if ( op[1] > 40 ) {
ERROR_MSG("build objid: bad second subidentifier");
return NULL;
}
objid_val = (op[0] * 40) + op[1];
op += 2;
}
first_objid_val = objid_val;
/* calculate the number of bytes needed to store the encoded value */
for (i = 1, asnlength = 0;;) {
if (objid_val < (unsigned)0x80) {
objid_size[i] = 1;
asnlength += 1;
} else if (objid_val < (unsigned)0x4000) {
objid_size[i] = 2;
asnlength += 2;
} else if (objid_val < (unsigned)0x200000) {
objid_size[i] = 3;
asnlength += 3;
} else if (objid_val < (unsigned)0x10000000) {
objid_size[i] = 4;
asnlength += 4;
} else {
objid_size[i] = 5;
asnlength += 5;
}
i++;
if (i >= (int)objidlength)
break;
objid_val = *op++;
}
/* store the ASN.1 tag and length */
data = asn_build_header(data, datalength, type, asnlength);
if (_asn_build_header_check("build objid", data, *datalength, asnlength))
return NULL;
/* store the encoded OID value */
for (i = 1, objid_val = first_objid_val, op = objid+2;
i < (int)objidlength;
i++) {
if (i != 1) objid_val = *op++;
switch (objid_size[i]) {
case 1:
*data++ = (u_char)objid_val;
break;
case 2:
*data++ = (u_char)((objid_val>>7) | 0x80);
*data++ = (u_char)(objid_val & 0x07f);
break;
case 3:
*data++ = (u_char)((objid_val>>14) | 0x80);
*data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
*data++ = (u_char)(objid_val & 0x07f);
break;
case 4:
*data++ = (u_char)((objid_val>>21) | 0x80);
*data++ = (u_char)((objid_val>>14 & 0x7f) | 0x80);
*data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
*data++ = (u_char)(objid_val & 0x07f);
break;
case 5:
*data++ = (u_char)((objid_val>>28) | 0x80);
*data++ = (u_char)((objid_val>>21 & 0x7f) | 0x80);
*data++ = (u_char)((objid_val>>14 & 0x7f) | 0x80);
*data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
*data++ = (u_char)(objid_val & 0x07f);
break;
}
}
/* return the length and data ptr */
*datalength -= asnlength;
return data;
}
/*
* asn_parse_null - Interprets an ASN null type.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* following the beginning of the next object.
*
* Returns a pointer to the first byte past the end
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
u_char * asn_parse_null(
u_char *data IN - pointer to start of object
int *datalength IN/OUT - number of valid bytes left in buffer
u_char *type OUT - asn type of object
*/
u_char *
asn_parse_null(u_char *data,
size_t *datalength,
u_char *type)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -