#include "asn1_encode.h"
+struct asn1buf_st {
+ uint8_t *ptr; /* Position, moving backwards; may be NULL */
+ size_t count; /* Count of bytes written so far */
+};
+
/**** Functions for encoding primitive types ****/
-krb5_error_code
-k5_asn1_encode_bool(asn1buf *buf, intmax_t val, size_t *len_out)
+/* Insert one byte into buf going backwards. */
+static inline void
+insert_byte(asn1buf *buf, uint8_t o)
{
- uint8_t bval = val ? 0xFF : 0x00;
+ if (buf->ptr != NULL) {
+ buf->ptr--;
+ *buf->ptr = o;
+ }
+ buf->count++;
+}
- *len_out = 1;
- return asn1buf_insert_octet(buf, bval);
+/* Insert a block of bytes into buf going backwards (but without reversing
+ * bytes). */
+static inline void
+insert_bytes(asn1buf *buf, const void *bytes, size_t len)
+{
+ if (buf->ptr != NULL) {
+ memcpy(buf->ptr - len, bytes, len);
+ buf->ptr -= len;
+ }
+ buf->count += len;
}
-krb5_error_code
-k5_asn1_encode_int(asn1buf *buf, intmax_t val, size_t *len_out)
+void
+k5_asn1_encode_bool(asn1buf *buf, intmax_t val)
+{
+ insert_byte(buf, val ? 0xFF : 0x00);
+}
+
+void
+k5_asn1_encode_int(asn1buf *buf, intmax_t val)
{
- krb5_error_code ret;
- size_t len = 0;
long valcopy;
int digit;
valcopy = val;
do {
digit = valcopy & 0xFF;
- ret = asn1buf_insert_octet(buf, digit);
- if (ret)
- return ret;
- len++;
+ insert_byte(buf, digit);
valcopy = valcopy >> 8;
} while (valcopy != 0 && valcopy != ~0);
- if (val > 0 && (digit & 0x80) == 0x80) { /* make sure the high bit is */
- ret = asn1buf_insert_octet(buf, 0); /* of the proper signed-ness */
- if (ret)
- return ret;
- len++;
- } else if (val < 0 && (digit & 0x80) != 0x80) {
- ret = asn1buf_insert_octet(buf, 0xFF);
- if (ret)
- return ret;
- len++;
- }
-
-
- *len_out = len;
- return 0;
+ /* Make sure the high bit is of the proper signed-ness. */
+ if (val > 0 && (digit & 0x80) == 0x80)
+ insert_byte(buf, 0);
+ else if (val < 0 && (digit & 0x80) != 0x80)
+ insert_byte(buf, 0xFF);
}
-krb5_error_code
-k5_asn1_encode_uint(asn1buf *buf, uintmax_t val, size_t *len_out)
+void
+k5_asn1_encode_uint(asn1buf *buf, uintmax_t val)
{
- krb5_error_code ret;
- size_t len = 0;
uintmax_t valcopy;
int digit;
valcopy = val;
do {
digit = valcopy & 0xFF;
- ret = asn1buf_insert_octet(buf, digit);
- if (ret)
- return ret;
- len++;
+ insert_byte(buf, digit);
valcopy = valcopy >> 8;
} while (valcopy != 0);
- if (digit & 0x80) { /* make sure the high bit is */
- ret = asn1buf_insert_octet(buf, 0); /* of the proper signed-ness */
- if (ret)
- return ret;
- len++;
- }
-
- *len_out = len;
- return 0;
+ /* Make sure the high bit is of the proper signed-ness. */
+ if (digit & 0x80)
+ insert_byte(buf, 0);
}
krb5_error_code
-k5_asn1_encode_bytestring(asn1buf *buf, uint8_t *const *val, size_t len,
- size_t *len_out)
+k5_asn1_encode_bytestring(asn1buf *buf, uint8_t *const *val, size_t len)
{
if (len > 0 && val == NULL)
return ASN1_MISSING_FIELD;
- *len_out = len;
- return asn1buf_insert_octetstring(buf, len, *val);
+ insert_bytes(buf, *val, len);
+ return 0;
}
krb5_error_code
-k5_asn1_encode_generaltime(asn1buf *buf, time_t val, size_t *len_out)
+k5_asn1_encode_generaltime(asn1buf *buf, time_t val)
{
struct tm *gtime, gtimebuf;
- char s[16];
- uint8_t *sp;
+ char s[16], *sp;
time_t gmt_time = val;
int len;
* Time encoding: YYYYMMDDhhmmssZ
*/
if (gmt_time == 0) {
- sp = (uint8_t *)"19700101000000Z";
+ sp = "19700101000000Z";
} else {
/*
* Sanity check this just to be paranoid, as gmtime can return NULL,
if (SNPRINTF_OVERFLOW(len, sizeof(s)))
/* Shouldn't be possible given above tests. */
return ASN1_BAD_GMTIME;
- sp = (uint8_t *)s;
+ sp = s;
}
- return k5_asn1_encode_bytestring(buf, &sp, 15, len_out);
+ insert_bytes(buf, sp, 15);
+ return 0;
}
krb5_error_code
-k5_asn1_encode_bitstring(asn1buf *buf, uint8_t *const *val, size_t len,
- size_t *len_out)
+k5_asn1_encode_bitstring(asn1buf *buf, uint8_t *const *val, size_t len)
{
- krb5_error_code ret;
-
- ret = asn1buf_insert_octetstring(buf, len, *val);
- if (ret)
- return ret;
- *len_out = len + 1;
- return asn1buf_insert_octet(buf, '\0');
+ insert_bytes(buf, *val, len);
+ insert_byte(buf, 0);
+ return 0;
}
/**** Functions for decoding primitive types ****/
/* Encode a DER tag into buf with the tag parameters in t and the content
* length len. Place the length of the encoded tag in *retlen. */
static krb5_error_code
-make_tag(asn1buf *buf, const taginfo *t, size_t len, size_t *retlen)
+make_tag(asn1buf *buf, const taginfo *t, size_t len)
{
- krb5_error_code ret;
asn1_tagnum tag_copy;
- size_t sum = 0, length, len_copy;
+ size_t len_copy, oldcount;
if (t->tagnum > ASN1_TAGNUM_MAX)
return ASN1_OVERFLOW;
/* Encode the length of the content within the tag. */
if (len < 128) {
- ret = asn1buf_insert_octet(buf, len & 0x7F);
- if (ret)
- return ret;
- length = 1;
+ insert_byte(buf, len & 0x7F);
} else {
- length = 0;
- for (len_copy = len; len_copy != 0; len_copy >>= 8) {
- ret = asn1buf_insert_octet(buf, len_copy & 0xFF);
- if (ret)
- return ret;
- length++;
- }
- ret = asn1buf_insert_octet(buf, 0x80 | (length & 0x7F));
- if (ret)
- return ret;
- length++;
+ oldcount = buf->count;
+ for (len_copy = len; len_copy != 0; len_copy >>= 8)
+ insert_byte(buf, len_copy & 0xFF);
+ insert_byte(buf, 0x80 | ((buf->count - oldcount) & 0x7F));
}
- sum += length;
/* Encode the tag and construction bit. */
if (t->tagnum < 31) {
- ret = asn1buf_insert_octet(buf,
- t->asn1class | t->construction | t->tagnum);
- if (ret)
- return ret;
- length = 1;
+ insert_byte(buf, t->asn1class | t->construction | t->tagnum);
} else {
tag_copy = t->tagnum;
- length = 0;
- ret = asn1buf_insert_octet(buf, tag_copy & 0x7F);
- if (ret)
- return ret;
+ insert_byte(buf, tag_copy & 0x7F);
tag_copy >>= 7;
- length++;
- for (; tag_copy != 0; tag_copy >>= 7) {
- ret = asn1buf_insert_octet(buf, 0x80 | (tag_copy & 0x7F));
- if (ret)
- return ret;
- length++;
- }
+ for (; tag_copy != 0; tag_copy >>= 7)
+ insert_byte(buf, 0x80 | (tag_copy & 0x7F));
- ret = asn1buf_insert_octet(buf, t->asn1class | t->construction | 0x1F);
- if (ret)
- return ret;
- length++;
+ insert_byte(buf, t->asn1class | t->construction | 0x1F);
}
- sum += length;
- *retlen = sum;
return 0;
}
}
static krb5_error_code
encode_sequence_of(asn1buf *buf, size_t seqlen, const void *val,
- const struct atype_info *eltinfo, size_t *len_out);
+ const struct atype_info *eltinfo);
static krb5_error_code
encode_nullterm_sequence_of(asn1buf *buf, const void *val,
- const struct atype_info *type,
- int can_be_empty, size_t *len_out)
+ const struct atype_info *type, int can_be_empty)
{
size_t len = get_nullterm_sequence_len(val, type);
if (!can_be_empty && len == 0)
return ASN1_MISSING_FIELD;
- return encode_sequence_of(buf, len, val, type, len_out);
+ return encode_sequence_of(buf, len, val, type);
}
static intmax_t
/* Split a DER encoding into tag and contents. Insert the contents into buf,
* then return the length of the contents and the tag. */
static krb5_error_code
-split_der(asn1buf *buf, uint8_t *const *der, size_t len,
- taginfo *tag_out, size_t *len_out)
+split_der(asn1buf *buf, uint8_t *const *der, size_t len, taginfo *tag_out)
{
krb5_error_code ret;
const uint8_t *contents, *remainder;
return ret;
if (rlen != 0)
return ASN1_BAD_LENGTH;
- *len_out = clen;
- return asn1buf_insert_bytestring(buf, clen, contents);
+ insert_bytes(buf, contents, clen);
+ return 0;
}
/*
}
static krb5_error_code
-encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq,
- size_t *len_out);
+encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq);
static krb5_error_code
encode_cntype(asn1buf *buf, const void *val, size_t len,
- const struct cntype_info *c, taginfo *tag_out, size_t *len_out);
+ const struct cntype_info *c, taginfo *tag_out);
/* Encode a value (contents only, no outer tag) according to a type, and return
* its encoded tag information. */
static krb5_error_code
encode_atype(asn1buf *buf, const void *val, const struct atype_info *a,
- taginfo *tag_out, size_t *len_out)
+ taginfo *tag_out)
{
krb5_error_code ret;
case atype_fn: {
const struct fn_info *fn = a->tinfo;
assert(fn->enc != NULL);
- return fn->enc(buf, val, tag_out, len_out);
+ return fn->enc(buf, val, tag_out);
}
case atype_sequence:
assert(a->tinfo != NULL);
- ret = encode_sequence(buf, val, a->tinfo, len_out);
+ ret = encode_sequence(buf, val, a->tinfo);
if (ret)
return ret;
tag_out->asn1class = UNIVERSAL;
case atype_ptr: {
const struct ptr_info *ptr = a->tinfo;
assert(ptr->basetype != NULL);
- return encode_atype(buf, LOADPTR(val, ptr), ptr->basetype, tag_out,
- len_out);
+ return encode_atype(buf, LOADPTR(val, ptr), ptr->basetype, tag_out);
}
case atype_offset: {
const struct offset_info *off = a->tinfo;
assert(off->basetype != NULL);
return encode_atype(buf, (const char *)val + off->dataoff,
- off->basetype, tag_out, len_out);
+ off->basetype, tag_out);
}
case atype_optional: {
const struct optional_info *opt = a->tinfo;
assert(opt->is_present != NULL);
if (opt->is_present(val))
- return encode_atype(buf, val, opt->basetype, tag_out, len_out);
+ return encode_atype(buf, val, opt->basetype, tag_out);
else
return ASN1_OMITTED;
}
ret = load_count(val, counted, &count);
if (ret)
return ret;
- return encode_cntype(buf, dataptr, count, counted->basetype, tag_out,
- len_out);
+ return encode_cntype(buf, dataptr, count, counted->basetype, tag_out);
}
case atype_nullterm_sequence_of:
case atype_nonempty_nullterm_sequence_of:
assert(a->tinfo != NULL);
ret = encode_nullterm_sequence_of(buf, val, a->tinfo,
a->type ==
- atype_nullterm_sequence_of,
- len_out);
+ atype_nullterm_sequence_of);
if (ret)
return ret;
tag_out->asn1class = UNIVERSAL;
break;
case atype_tagged_thing: {
const struct tagged_info *tag = a->tinfo;
- ret = encode_atype(buf, val, tag->basetype, tag_out, len_out);
+ size_t oldcount = buf->count;
+ ret = encode_atype(buf, val, tag->basetype, tag_out);
if (ret)
return ret;
if (!tag->implicit) {
- size_t tlen;
- ret = make_tag(buf, tag_out, *len_out, &tlen);
+ ret = make_tag(buf, tag_out, buf->count - oldcount);
if (ret)
return ret;
- *len_out += tlen;
tag_out->construction = tag->construction;
}
tag_out->asn1class = tag->tagtype;
break;
}
case atype_bool:
- ret = k5_asn1_encode_bool(buf, load_int(val, a->size), len_out);
- if (ret)
- return ret;
+ k5_asn1_encode_bool(buf, load_int(val, a->size));
tag_out->asn1class = UNIVERSAL;
tag_out->construction = PRIMITIVE;
tag_out->tagnum = ASN1_BOOLEAN;
break;
case atype_int:
- ret = k5_asn1_encode_int(buf, load_int(val, a->size), len_out);
- if (ret)
- return ret;
+ k5_asn1_encode_int(buf, load_int(val, a->size));
tag_out->asn1class = UNIVERSAL;
tag_out->construction = PRIMITIVE;
tag_out->tagnum = ASN1_INTEGER;
break;
case atype_uint:
- ret = k5_asn1_encode_uint(buf, load_uint(val, a->size), len_out);
- if (ret)
- return ret;
+ k5_asn1_encode_uint(buf, load_uint(val, a->size));
tag_out->asn1class = UNIVERSAL;
tag_out->construction = PRIMITIVE;
tag_out->tagnum = ASN1_INTEGER;
break;
case atype_int_immediate: {
const struct immediate_info *imm = a->tinfo;
- ret = k5_asn1_encode_int(buf, imm->val, len_out);
- if (ret)
- return ret;
+ k5_asn1_encode_int(buf, imm->val);
tag_out->asn1class = UNIVERSAL;
tag_out->construction = PRIMITIVE;
tag_out->tagnum = ASN1_INTEGER;
}
static krb5_error_code
-encode_atype_and_tag(asn1buf *buf, const void *val, const struct atype_info *a,
- size_t *len_out)
+encode_atype_and_tag(asn1buf *buf, const void *val, const struct atype_info *a)
{
taginfo t;
krb5_error_code ret;
- size_t clen, tlen;
+ size_t oldcount = buf->count;
- ret = encode_atype(buf, val, a, &t, &clen);
+ ret = encode_atype(buf, val, a, &t);
if (ret)
return ret;
- ret = make_tag(buf, &t, clen, &tlen);
+ ret = make_tag(buf, &t, buf->count - oldcount);
if (ret)
return ret;
- *len_out = clen + tlen;
return 0;
}
*/
static krb5_error_code
encode_cntype(asn1buf *buf, const void *val, size_t count,
- const struct cntype_info *c, taginfo *tag_out, size_t *len_out)
+ const struct cntype_info *c, taginfo *tag_out)
{
krb5_error_code ret;
case cntype_string: {
const struct string_info *string = c->tinfo;
assert(string->enc != NULL);
- ret = string->enc(buf, val, count, len_out);
+ ret = string->enc(buf, val, count);
if (ret)
return ret;
tag_out->asn1class = UNIVERSAL;
break;
}
case cntype_der:
- return split_der(buf, val, count, tag_out, len_out);
+ return split_der(buf, val, count, tag_out);
case cntype_seqof: {
const struct atype_info *a = c->tinfo;
const struct ptr_info *ptr = a->tinfo;
assert(a->type == atype_ptr);
val = LOADPTR(val, ptr);
- ret = encode_sequence_of(buf, count, val, ptr->basetype, len_out);
+ ret = encode_sequence_of(buf, count, val, ptr->basetype);
if (ret)
return ret;
tag_out->asn1class = UNIVERSAL;
const struct choice_info *choice = c->tinfo;
if (count >= choice->n_options)
return ASN1_MISSING_FIELD;
- return encode_atype(buf, val, choice->options[count], tag_out,
- len_out);
+ return encode_atype(buf, val, choice->options[count], tag_out);
}
default:
}
static krb5_error_code
-encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq,
- size_t *len_out)
+encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq)
{
krb5_error_code ret;
- size_t i, len, sum = 0;
+ size_t i;
for (i = seq->n_fields; i > 0; i--) {
- ret = encode_atype_and_tag(buf, val, seq->fields[i - 1], &len);
+ ret = encode_atype_and_tag(buf, val, seq->fields[i - 1]);
if (ret == ASN1_OMITTED)
continue;
else if (ret != 0)
return ret;
- sum += len;
}
- *len_out = sum;
return 0;
}
static krb5_error_code
encode_sequence_of(asn1buf *buf, size_t seqlen, const void *val,
- const struct atype_info *eltinfo, size_t *len_out)
+ const struct atype_info *eltinfo)
{
krb5_error_code ret;
- size_t sum = 0, i, len;
+ size_t i;
const void *eltptr;
assert(eltinfo->size != 0);
for (i = seqlen; i > 0; i--) {
eltptr = (const char *)val + (i - 1) * eltinfo->size;
- ret = encode_atype_and_tag(buf, eltptr, eltinfo, &len);
+ ret = encode_atype_and_tag(buf, eltptr, eltinfo);
if (ret)
return ret;
- sum += len;
}
- *len_out = sum;
return 0;
}
krb5_error_code
k5_asn1_encode_atype(asn1buf *buf, const void *val, const struct atype_info *a,
- taginfo *tag_out, size_t *len_out)
+ taginfo *tag_out)
{
- return encode_atype(buf, val, a, tag_out, len_out);
+ return encode_atype(buf, val, a, tag_out);
}
krb5_error_code
k5_asn1_full_encode(const void *rep, const struct atype_info *a,
krb5_data **code_out)
{
- size_t len;
krb5_error_code ret;
- asn1buf *buf = NULL;
+ asn1buf buf;
krb5_data *d;
+ uint8_t *bytes;
*code_out = NULL;
if (rep == NULL)
return ASN1_MISSING_FIELD;
- ret = asn1buf_create(&buf);
+
+ /* Make a first pass over rep to count the encoding size. */
+ buf.ptr = NULL;
+ buf.count = 0;
+ ret = encode_atype_and_tag(&buf, rep, a);
if (ret)
return ret;
- ret = encode_atype_and_tag(buf, rep, a, &len);
- if (ret)
- goto cleanup;
- ret = asn12krb5_buf(buf, &d);
- if (ret)
- goto cleanup;
- *code_out = d;
-cleanup:
- asn1buf_destroy(&buf);
- return ret;
+
+ /* Allocate space for the encoding. */
+ bytes = malloc(buf.count + 1);
+ if (bytes == NULL)
+ return ENOMEM;
+ bytes[buf.count] = 0;
+
+ /* Make a second pass over rep to encode it. buf.ptr moves backwards as we
+ * encode, and will always exactly return to the base. */
+ buf.ptr = bytes + buf.count;
+ buf.count = 0;
+ ret = encode_atype_and_tag(&buf, rep, a);
+ if (ret) {
+ free(bytes);
+ return ret;
+ }
+ assert(buf.ptr == bytes);
+
+ /* Create the output data object. */
+ *code_out = malloc(sizeof(*d));
+ if (*code_out == NULL) {
+ free(bytes);
+ return ENOMEM;
+ }
+ **code_out = make_data(bytes, buf.count);
+ return 0;
}
krb5_error_code
* with old implementations.
*/
static krb5_error_code
-encode_seqno(asn1buf *buf, const void *p, taginfo *rettag, size_t *len_out)
+encode_seqno(asn1buf *buf, const void *p, taginfo *rettag)
{
uint32_t val = *(uint32_t *)p;
rettag->asn1class = UNIVERSAL;
rettag->construction = PRIMITIVE;
rettag->tagnum = ASN1_INTEGER;
- return k5_asn1_encode_uint(buf, val, len_out);
+ k5_asn1_encode_uint(buf, val);
+ return 0;
}
static krb5_error_code
decode_seqno(const taginfo *t, const uint8_t *asn1, size_t len, void *p)
/* Define the kerberos_time type, which is an ASN.1 generaltime represented in
* a krb5_timestamp. */
static krb5_error_code
-encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag,
- size_t *len_out)
+encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag)
{
time_t val = ts2tt(*(krb5_timestamp *)p);
rettag->asn1class = UNIVERSAL;
rettag->construction = PRIMITIVE;
rettag->tagnum = ASN1_GENERALTIME;
- return k5_asn1_encode_generaltime(buf, val, len_out);
+ return k5_asn1_encode_generaltime(buf, val);
}
static krb5_error_code
decode_kerberos_time(const taginfo *t, const uint8_t *asn1, size_t len,
/* Define the krb5_flags type, which is an ASN.1 bit string represented in a
* 32-bit integer. */
static krb5_error_code
-encode_krb5_flags(asn1buf *buf, const void *p, taginfo *rettag,
- size_t *len_out)
+encode_krb5_flags(asn1buf *buf, const void *p, taginfo *rettag)
{
uint8_t cbuf[4], *cptr = cbuf;
store_32_be((uint32_t)*(const krb5_flags *)p, cbuf);
rettag->asn1class = UNIVERSAL;
rettag->construction = PRIMITIVE;
rettag->tagnum = ASN1_BITSTRING;
- return k5_asn1_encode_bitstring(buf, &cptr, 4, len_out);
+ return k5_asn1_encode_bitstring(buf, &cptr, 4);
}
static krb5_error_code
decode_krb5_flags(const taginfo *t, const uint8_t *asn1, size_t len, void *val)
/* Define the last_req_type type, which is an int32_t with some massaging on
* decode for backward compatibility. */
static krb5_error_code
-encode_lr_type(asn1buf *buf, const void *p, taginfo *rettag, size_t *len_out)
+encode_lr_type(asn1buf *buf, const void *p, taginfo *rettag)
{
int32_t val = *(int32_t *)p;
rettag->asn1class = UNIVERSAL;
rettag->construction = PRIMITIVE;
rettag->tagnum = ASN1_INTEGER;
- return k5_asn1_encode_int(buf, val, len_out);
+ k5_asn1_encode_int(buf, val);
+ return 0;
}
static krb5_error_code
decode_lr_type(const taginfo *t, const uint8_t *asn1, size_t len, void *p)
};
DEFSEQTYPE(kdc_req_body_hack, kdc_req_hack, kdc_req_hack_fields);
static krb5_error_code
-encode_kdc_req_body(asn1buf *buf, const void *p, taginfo *tag_out,
- size_t *len_out)
+encode_kdc_req_body(asn1buf *buf, const void *p, taginfo *tag_out)
{
const krb5_kdc_req *val = p;
kdc_req_hack h;
h.server_realm = val->server->realm;
else
return ASN1_MISSING_FIELD;
- return k5_asn1_encode_atype(buf, &h, &k5_atype_kdc_req_body_hack, tag_out,
- len_out);
+ return k5_asn1_encode_atype(buf, &h, &k5_atype_kdc_req_body_hack, tag_out);
}
static void
free_kdc_req_body(void *val)
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* Coding Buffer Implementation */
-
-/*
- * Implementation
- *
- * Encoding mode
- *
- * The encoding buffer is filled from bottom (lowest address) to top
- * (highest address). This makes it easier to expand the buffer,
- * since realloc preserves the existing portion of the buffer.
- *
- * Note: Since ASN.1 encoding must be done in reverse, this means
- * that you can't simply memcpy out the buffer data, since it will be
- * backwards. You need to reverse-iterate through it, instead.
- *
- * ***This decision may have been a mistake. In practice, the
- * implementation will probably be tuned such that reallocation is
- * rarely necessary. Also, the realloc probably has recopy the
- * buffer itself, so we don't really gain that much by avoiding an
- * explicit copy of the buffer. --Keep this in mind for future reference.
- *
- *
- * Decoding mode
- *
- * The decoding buffer is in normal order and is created by wrapping
- * an asn1buf around a krb5_data structure.
- */
-
-/*
- * Abstraction Function
- *
- * Programs should use just pointers to asn1buf's (e.g. asn1buf *mybuf).
- * These pointers must always point to a valid, allocated asn1buf
- * structure or be NULL.
- *
- * The contents of the asn1buf represent an octet string. This string
- * begins at base and continues to the octet immediately preceding next.
- * If next == base or mybuf == NULL, then the asn1buf represents an empty
- * octet string.
- */
-
-/*
- * Representation Invariant
- *
- * Pointers to asn1buf's must always point to a valid, allocated
- * asn1buf structure or be NULL.
- *
- * base points to a valid, allocated octet array or is NULL
- * bound, if non-NULL, points to the last valid octet
- * next >= base
- * next <= bound+2 (i.e. next should be able to step just past the bound,
- * but no further. (The bound should move out in response
- * to being crossed by next.))
- */
-
-#define ASN1BUF_OMIT_INLINE_FUNCS
-#include "asn1buf.h"
-#include <stdio.h>
-
-#ifdef USE_VALGRIND
-#include <valgrind/memcheck.h>
-#else
-#define VALGRIND_CHECK_READABLE(PTR,SIZE) ((void)0)
-#endif
-
-#if !defined(__GNUC__) || defined(CONFIG_SMALL)
-/*
- * Declare private procedures as static if they're not used for inline
- * expansion of other stuff elsewhere.
- */
-static unsigned int asn1buf_free(const asn1buf *);
-static krb5_error_code asn1buf_ensure_space(asn1buf *, unsigned int);
-static krb5_error_code asn1buf_expand(asn1buf *, unsigned int);
-#endif
-
-#define asn1_is_eoc(class, num, indef) \
- ((class) == UNIVERSAL && !(num) && !(indef))
-
-krb5_error_code
-asn1buf_create(asn1buf **buf)
-{
- *buf = (asn1buf*)malloc(sizeof(asn1buf));
- if (*buf == NULL) return ENOMEM;
- (*buf)->base = NULL;
- (*buf)->bound = NULL;
- (*buf)->next = NULL;
- return 0;
-}
-
-void
-asn1buf_destroy(asn1buf **buf)
-{
- if (*buf != NULL) {
- free((*buf)->base);
- free(*buf);
- *buf = NULL;
- }
-}
-
-#ifdef asn1buf_insert_octet
-#undef asn1buf_insert_octet
-#endif
-krb5_error_code
-asn1buf_insert_octet(asn1buf *buf, const int o)
-{
- krb5_error_code retval;
-
- retval = asn1buf_ensure_space(buf,1U);
- if (retval) return retval;
- *(buf->next) = (char)o;
- (buf->next)++;
- return 0;
-}
-
-krb5_error_code
-asn1buf_insert_bytestring(asn1buf *buf, const unsigned int len, const void *sv)
-{
- krb5_error_code retval;
- unsigned int length;
- const char *s = sv;
-
- retval = asn1buf_ensure_space(buf,len);
- if (retval) return retval;
- VALGRIND_CHECK_READABLE(sv, len);
- for (length=1; length<=len; length++,(buf->next)++)
- *(buf->next) = (s[len-length]);
- return 0;
-}
-
-krb5_error_code
-asn12krb5_buf(const asn1buf *buf, krb5_data **code)
-{
- unsigned int i;
- krb5_data *d;
-
- *code = NULL;
-
- d = calloc(1, sizeof(krb5_data));
- if (d == NULL)
- return ENOMEM;
- d->length = asn1buf_len(buf);
- d->data = malloc(d->length + 1);
- if (d->data == NULL) {
- free(d);
- return ENOMEM;
- }
- for (i=0; i < d->length; i++)
- d->data[i] = buf->base[d->length - i - 1];
- d->data[d->length] = '\0';
- d->magic = KV5M_DATA;
- *code = d;
- return 0;
-}
-
-/****************************************************************/
-/* Private Procedures */
-
-static int
-asn1buf_size(const asn1buf *buf)
-{
- if (buf == NULL || buf->base == NULL) return 0;
- return buf->bound - buf->base + 1;
-}
-
-#undef asn1buf_free
-unsigned int
-asn1buf_free(const asn1buf *buf)
-{
- if (buf == NULL || buf->base == NULL) return 0;
- else return buf->bound - buf->next + 1;
-}
-
-#undef asn1buf_ensure_space
-krb5_error_code
-asn1buf_ensure_space(asn1buf *buf, const unsigned int amount)
-{
- unsigned int avail = asn1buf_free(buf);
- if (avail >= amount)
- return 0;
- return asn1buf_expand(buf, amount-avail);
-}
-
-krb5_error_code
-asn1buf_expand(asn1buf *buf, unsigned int inc)
-{
-#define STANDARD_INCREMENT 200
- int next_offset = buf->next - buf->base;
- int bound_offset;
- if (buf->base == NULL) bound_offset = -1;
- else bound_offset = buf->bound - buf->base;
-
- if (inc < STANDARD_INCREMENT)
- inc = STANDARD_INCREMENT;
-
- buf->base = realloc(buf->base, asn1buf_size(buf) + inc);
- if (buf->base == NULL) return ENOMEM; /* XXX leak */
- buf->bound = (buf->base) + bound_offset + inc;
- buf->next = (buf->base) + next_offset;
- return 0;
-}
-
-#undef asn1buf_len
-int
-asn1buf_len(const asn1buf *buf)
-{
- return buf->next - buf->base;
-}
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* Coding Buffer Specifications */
-#ifndef __ASN1BUF_H__
-#define __ASN1BUF_H__
-
-#include "k5-int.h"
-#include "krbasn1.h"
-
-typedef struct code_buffer_rep {
- char *base, *bound, *next;
-} asn1buf;
-
-
-/**************** Private Procedures ****************/
-
-#if (__GNUC__ >= 2) && !defined(CONFIG_SMALL)
-unsigned int asn1buf_free(const asn1buf *buf);
-/*
- * requires *buf is allocated
- * effects Returns the number of unused, allocated octets in *buf.
- */
-#define asn1buf_free(buf) \
- (((buf) == NULL || (buf)->base == NULL) \
- ? 0U \
- : (unsigned int)((buf)->bound - (buf)->next + 1))
-
-
-krb5_error_code asn1buf_ensure_space(asn1buf *buf, const unsigned int amount);
-/*
- * requires *buf is allocated
- * modifies *buf
- * effects If buf has less than amount octets of free space, then it is
- * expanded to have at least amount octets of free space.
- * Returns ENOMEM memory is exhausted.
- */
-#define asn1buf_ensure_space(buf,amount) \
- ((asn1buf_free(buf) < (amount)) \
- ? (asn1buf_expand((buf), (amount)-asn1buf_free(buf))) \
- : 0)
-
-krb5_error_code asn1buf_expand(asn1buf *buf, unsigned int inc);
-/*
- * requires *buf is allocated
- * modifies *buf
- * effects Expands *buf by allocating space for inc more octets.
- * Returns ENOMEM if memory is exhausted.
- */
-#endif
-
-int asn1buf_len(const asn1buf *buf);
-/*
- * requires *buf is allocated
- * effects Returns the length of the encoding in *buf.
- */
-#define asn1buf_len(buf) ((buf)->next - (buf)->base)
-
-/****** End of private procedures *****/
-
-/*
- * Overview
- *
- * The coding buffer is an array of char (to match a krb5_data structure)
- * with 3 reference pointers:
- * 1) base - The bottom of the octet array. Used for memory management
- * operations on the array (e.g. alloc, realloc, free).
- * 2) next - Points to the next available octet position in the array.
- * During encoding, this is the next free position, and it
- * advances as octets are added to the array.
- * During decoding, this is the next unread position, and it
- * advances as octets are read from the array.
- * 3) bound - Points to the top of the array. Used for bounds-checking.
- *
- * All pointers to encoding buffers should be initalized to NULL.
- *
- * Operations
- *
- * asn1buf_create
- * asn1buf_wrap_data
- * asn1buf_destroy
- * asn1buf_insert_octet
- * asn1buf_insert_charstring
- * asn1buf_remove_octet
- * asn1buf_remove_charstring
- * asn1buf_unparse
- * asn1buf_hex_unparse
- * asn12krb5_buf
- * asn1buf_remains
- *
- * (asn1buf_size)
- * (asn1buf_free)
- * (asn1buf_ensure_space)
- * (asn1buf_expand)
- * (asn1buf_len)
- */
-
-krb5_error_code asn1buf_create(asn1buf **buf);
-/*
- * effects Creates a new encoding buffer pointed to by *buf.
- * Returns ENOMEM if the buffer can't be created.
- */
-
-void asn1buf_destroy(asn1buf **buf);
-/* effects Deallocates **buf, sets *buf to NULL. */
-
-/*
- * requires *buf is allocated
- * effects Inserts o into the buffer *buf, expanding the buffer if
- * necessary. Returns ENOMEM memory is exhausted.
- */
-#if ((__GNUC__ >= 2) && !defined(ASN1BUF_OMIT_INLINE_FUNCS)) && !defined(CONFIG_SMALL)
-static inline krb5_error_code
-asn1buf_insert_octet(asn1buf *buf, const int o)
-{
- krb5_error_code retval;
-
- retval = asn1buf_ensure_space(buf,1U);
- if (retval) return retval;
- *(buf->next) = (char)o;
- (buf->next)++;
- return 0;
-}
-#else
-krb5_error_code asn1buf_insert_octet(asn1buf *buf, const int o);
-#endif
-
-krb5_error_code
-asn1buf_insert_bytestring(
- asn1buf *buf,
- const unsigned int len,
- const void *s);
-/*
- * requires *buf is allocated
- * modifies *buf
- * effects Inserts the contents of s (an array of length len)
- * into the buffer *buf, expanding the buffer if necessary.
- * Returns ENOMEM if memory is exhausted.
- */
-
-#define asn1buf_insert_octetstring asn1buf_insert_bytestring
-
-krb5_error_code asn12krb5_buf(const asn1buf *buf, krb5_data **code);
-/*
- * modifies *code
- * effects Instantiates **code with the krb5_data representation of **buf.
- */
-
-#endif