asn1c/skeletons/OBJECT_IDENTIFIER.c

357 lines
7.4 KiB
C
Raw Normal View History

/*-
* Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#include <OBJECT_IDENTIFIER.h>
#include <assert.h>
#include <errno.h>
/*
* OBJECT IDENTIFIER basic type description.
*/
static ber_tlv_tag_t asn1_DEF_OBJECT_IDENTIFIER_tags[] = {
(ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
};
asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER = {
"OBJECT IDENTIFIER",
OBJECT_IDENTIFIER_constraint,
INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
OBJECT_IDENTIFIER_encode_der,
OBJECT_IDENTIFIER_print,
INTEGER_free,
0, /* Use generic outmost tag fetcher */
asn1_DEF_OBJECT_IDENTIFIER_tags,
sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags)
/ sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags[0]),
1, /* Single UNIVERSAL tag may be implicitly overriden */
0 /* Always in primitive form */
};
/*
* Encode OBJECT IDENTIFIER type using DER.
*/
der_enc_rval_t
OBJECT_IDENTIFIER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
int tag_mode, ber_tlv_tag_t tag,
asn_app_consume_bytes_f *cb, void *app_key) {
der_enc_rval_t erval;
OBJECT_IDENTIFIER_t *st = ptr;
ASN_DEBUG("%s %s as OBJECT IDENTIFIER (tm=%d)",
cb?"Encoding":"Estimating", sd->name, tag_mode);
erval.encoded = der_write_tags(sd, st->size, tag_mode, tag,
cb, app_key);
ASN_DEBUG("OBJECT IDENTIFIER %s wrote tags %d",
sd->name, (int)erval.encoded);
if(erval.encoded == -1) {
erval.failed_type = sd;
erval.structure_ptr = ptr;
return erval;
}
if(cb && st->buf) {
ssize_t ret;
ret = cb(st->buf, st->size, app_key);
if(ret == -1) {
erval.encoded = -1;
erval.failed_type = sd;
erval.structure_ptr = ptr;
return erval;
}
} else {
assert(st->buf || st->size == 0);
}
erval.encoded += st->size;
return erval;
}
int
OBJECT_IDENTIFIER_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
asn_app_consume_bytes_f *app_errlog, void *app_key) {
const OBJECT_IDENTIFIER_t *st = sptr;
if(st && st->buf) {
if(st->size < 1) {
_ASN_ERRLOG("%s: at least one numerical value expected",
td->name);
return -1;
}
} else {
_ASN_ERRLOG("%s: value not given", td->name);
return -1;
}
return 0;
}
int
OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen, int add, unsigned long *rvalue) {
unsigned long accum;
uint8_t *arcend = arcbuf + arclen;
if(arclen * 7 > 8 * sizeof(accum)) {
if(arclen * 7 <= 8 * (sizeof(accum) + 1)) {
if((*arcbuf & ~0x8f)) {
errno = ERANGE; /* Overflow */
return -1;
}
} else {
errno = ERANGE; /* Overflow */
return -1;
}
}
/* Gather all bits into the accumulator */
for(accum = 0; arcbuf < arcend; arcbuf++)
accum = (accum << 7) | (*arcbuf & ~0x80);
accum += add; /* Actually, a negative value */
assert(accum >= 0);
*rvalue = accum;
return 0;
}
int
OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
asn_app_consume_bytes_f *cb, void *app_key) {
char scratch[64]; /* Conservative estimate */
unsigned long accum; /* Bits accumulator */
char *p; /* Position in the scratch buffer */
if(OBJECT_IDENTIFIER_get_arc_l(arcbuf, arclen, add, &accum))
return -1;
/* Fill the scratch buffer in reverse. */
p = scratch + sizeof(scratch);
for(; accum; accum /= 10)
*(--p) = (accum % 10) + 0x30;
return cb(p, sizeof(scratch) - (p - scratch), app_key);
}
int
OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
const OBJECT_IDENTIFIER_t *st = sptr;
int startn;
int add = 0;
int i;
if(!st || !st->buf)
return cb("<absent>", 8, app_key);
/* Dump preamble */
if(cb("{ ", 2, app_key))
return -1;
for(i = 0, startn = 0; i < st->size; i++) {
uint8_t b = st->buf[i];
if((b & 0x80)) /* Continuation expected */
continue;
if(startn == 0) {
/*
* First two arcs are encoded through the backdoor.
*/
if(i) {
add = -80;
if(cb("2", 1, app_key)) return -1;
} else if(b <= 39) {
add = 0;
if(cb("0", 1, app_key)) return -1;
} else if(b < 79) {
add = -40;
if(cb("1", 1, app_key)) return -1;
} else {
add = -80;
if(cb("2", 1, app_key)) return -1;
}
}
if(cb(" ", 1, app_key)) /* Separate arcs */
return -1;
if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
i - startn + 1, add,
cb, app_key))
return -1;
startn = i + 1;
add = 0;
}
return cb(" }", 2, app_key);
}
int
OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *oid,
unsigned long *arcs, int arcs_slots) {
unsigned long arc_value;
int cur_arc = 0;
int startn = 0;
int add = 0;
int i;
if(!oid || !oid->buf) {
errno = EINVAL;
return -1;
}
for(i = 0; i < oid->size; i++) {
uint8_t b = oid->buf[i];
if((b & 0x80)) /* Continuation expected */
continue;
if(startn == 0) {
/*
* First two arcs are encoded through the backdoor.
*/
if(i) {
add = -80;
if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
cur_arc++;
} else if(b <= 39) {
add = 0;
if(cur_arc < arcs_slots) arcs[cur_arc] = 0;
cur_arc++;
} else if(b < 79) {
add = -40;
if(cur_arc < arcs_slots) arcs[cur_arc] = 1;
cur_arc++;
} else {
add = -80;
if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
cur_arc++;
}
}
/* Do not fill */
if(cur_arc >= arcs_slots) {
startn = i + 1;
continue;
}
if(OBJECT_IDENTIFIER_get_arc_l(&oid->buf[startn],
i - startn + 1,
add, &arc_value))
return -1;
arcs[cur_arc++] = arc_value;
startn = i + 1;
add = 0;
}
return cur_arc;
}
int
OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int arcs_slots) {
uint8_t *buf;
uint8_t *bp;
unsigned long long first_value;
int size;
int i;
if(oid == NULL || arcs == NULL || arcs_slots < 2) {
errno = EINVAL;
return -1;
}
if(arcs[0] <= 1) {
if(arcs[1] >= 39) {
/* 8.19.4: At most 39 subsequent values (including 0) */
errno = ERANGE;
return -1;
}
} else if(arcs[0] > 2) {
/* 8.19.4: Only three values are allocated from the root node */
errno = ERANGE;
return -1;
}
first_value = arcs[0] * 40 + arcs[1];
/*
* Roughly estimate the maximum size necessary to encode these arcs.
*/
size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arcs_slots;
bp = buf = MALLOC(size + 1);
if(!buf) {
/* ENOMEM */
return -1;
}
/*
* Encode the arcs and refine the encoding size.
*/
size = 0;
{
uint8_t tbuf[sizeof(first_value) * 2];
uint8_t *tp = tbuf;
int arc_len = 0;
int add = 0;
for(; first_value; first_value >>= 7) {
unsigned int b7 = first_value & 0x7f;
*tp++ = 0x80 | b7;
add++;
if(b7) { arc_len += add; add = 0; }
}
if(arc_len) {
tp = &tbuf[arc_len - 1];
/* The last octet does not have bit 8 set. */
*tbuf &= 0x7f;
for(; tp >= tbuf; tp--)
*bp++ = *tp;
size += arc_len;
} else {
*bp++ = 0;
size++;
}
}
for(i = 2; i < arcs_slots; i++) {
unsigned long value = arcs[i];
uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
uint8_t *tp = tbuf;
int arc_len = 0;
int add = 0;
for(; value; value >>= 7) {
unsigned int b7 = value & 0x7F;
*tp++ = 0x80 | b7;
add++;
if(b7) { arc_len += add; add = 0; }
}
if(arc_len) {
tp = &tbuf[arc_len - 1];
/* The last octet does not have bit 8 set. */
*tbuf &= 0x7f;
for(; tp >= tbuf; tp--)
*bp++ = *tp;
size += arc_len;
} else {
*bp++ = 0;
size++;
}
}
/*
* Replace buffer.
*/
oid->size = size;
bp = oid->buf;
oid->buf = buf;
if(bp) FREEMEM(bp);
return 0;
}