From: Greg Hudson Date: Wed, 21 Mar 2018 22:17:08 +0000 (-0400) Subject: Simplify ASN.1 encoding X-Git-Tag: krb5-1.17-beta1~150 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F751%2Fhead;p=thirdparty%2Fkrb5.git Simplify ASN.1 encoding Like most ASN.1 DER implementations, we encode backwards. The existing asn1buf implementation inserts bytes forward into a resizeable buffer, then reallocates the number of bytes inserted and reverses them. Throw out this implementation and replace it with two simple inline functions in asn1_encode.c, which conditionally insert bytes in reverse order and unconditionally increment a count. Make two passes over the input representation, once to count the encoding size and once to actually encode it into a precisely allocated buffer. Remove all of the explicit length counting from encoding functions; in the places where we need intermediate lengths, compute them from the difference in buffer byte count. Make a few encoding functions return void as they no longer have error cases. --- diff --git a/src/lib/krb5/asn.1/Makefile.in b/src/lib/krb5/asn.1/Makefile.in index e2e6a354d2..fe295232ad 100644 --- a/src/lib/krb5/asn.1/Makefile.in +++ b/src/lib/krb5/asn.1/Makefile.in @@ -9,19 +9,16 @@ EHDRDIR=$(BUILDTOP)/include/krb5/asn.1 STLIBOBJS= \ asn1_encode.o\ - asn1buf.o\ asn1_k_encode.o\ ldap_key_seq.o SRCS= \ $(srcdir)/asn1_encode.c\ - $(srcdir)/asn1buf.c\ $(srcdir)/asn1_k_encode.c\ $(srcdir)/ldap_key_seq.c OBJS= \ $(OUTPRE)asn1_encode.$(OBJEXT)\ - $(OUTPRE)asn1buf.$(OBJEXT)\ $(OUTPRE)asn1_k_encode.$(OBJEXT)\ $(OUTPRE)ldap_key_seq.$(OBJEXT) diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c index a7a5a2fc34..a160cf4fe8 100644 --- a/src/lib/krb5/asn.1/asn1_encode.c +++ b/src/lib/krb5/asn.1/asn1_encode.c @@ -26,97 +26,94 @@ #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; @@ -124,7 +121,7 @@ k5_asn1_encode_generaltime(asn1buf *buf, time_t val, size_t *len_out) * 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, @@ -157,23 +154,19 @@ k5_asn1_encode_generaltime(asn1buf *buf, time_t val, size_t *len_out) 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 ****/ @@ -315,67 +308,38 @@ k5_asn1_decode_bitstring(const uint8_t *asn1, size_t len, /* 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; } @@ -506,18 +470,17 @@ get_nullterm_sequence_len(const void *valp, const struct atype_info *seq) } 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 @@ -644,8 +607,7 @@ store_count(size_t count, const struct counted_info *counted, void *val) /* 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; @@ -656,8 +618,8 @@ split_der(asn1buf *buf, uint8_t *const *der, size_t len, 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; } /* @@ -684,17 +646,16 @@ store_der(const taginfo *t, const uint8_t *asn1, size_t len, void *val, } 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; @@ -705,11 +666,11 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, 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; @@ -719,20 +680,19 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, 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; } @@ -744,16 +704,14 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, 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; @@ -762,15 +720,14 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, 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; @@ -778,34 +735,26 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, 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; @@ -821,20 +770,18 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a, } 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; } @@ -845,7 +792,7 @@ encode_atype_and_tag(asn1buf *buf, const void *val, const struct atype_info *a, */ 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; @@ -853,7 +800,7 @@ encode_cntype(asn1buf *buf, const void *val, size_t count, 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; @@ -862,13 +809,13 @@ encode_cntype(asn1buf *buf, const void *val, size_t count, 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; @@ -880,8 +827,7 @@ encode_cntype(asn1buf *buf, const void *val, size_t count, 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: @@ -894,41 +840,36 @@ encode_cntype(asn1buf *buf, const void *val, size_t count, } 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; } @@ -1572,9 +1513,9 @@ error: 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 @@ -1588,28 +1529,48 @@ 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 diff --git a/src/lib/krb5/asn.1/asn1_encode.h b/src/lib/krb5/asn.1/asn1_encode.h index 1e1707542e..fde875b573 100644 --- a/src/lib/krb5/asn.1/asn1_encode.h +++ b/src/lib/krb5/asn.1/asn1_encode.h @@ -29,9 +29,10 @@ #include "k5-int.h" #include "krbasn1.h" -#include "asn1buf.h" #include +typedef struct asn1buf_st asn1buf; + typedef struct { asn1_class asn1class; asn1_construction construction; @@ -45,18 +46,14 @@ typedef struct { /* These functions are referenced by encoder structures. They handle the * encoding of primitive ASN.1 types. */ -krb5_error_code k5_asn1_encode_bool(asn1buf *buf, intmax_t val, - size_t *len_out); -krb5_error_code k5_asn1_encode_int(asn1buf *buf, intmax_t val, - size_t *len_out); -krb5_error_code k5_asn1_encode_uint(asn1buf *buf, uintmax_t val, - size_t *len_out); +void k5_asn1_encode_bool(asn1buf *buf, intmax_t val); +void k5_asn1_encode_int(asn1buf *buf, intmax_t val); +void k5_asn1_encode_uint(asn1buf *buf, uintmax_t val); krb5_error_code k5_asn1_encode_bytestring(asn1buf *buf, uint8_t *const *val, - size_t len, size_t *len_out); + size_t len); krb5_error_code k5_asn1_encode_bitstring(asn1buf *buf, uint8_t *const *val, - size_t len, size_t *len_out); -krb5_error_code k5_asn1_encode_generaltime(asn1buf *buf, time_t val, - size_t *len_out); + size_t len); +krb5_error_code k5_asn1_encode_generaltime(asn1buf *buf, time_t val); /* These functions are referenced by encoder structures. They handle the * decoding of primitive ASN.1 types. */ @@ -148,7 +145,7 @@ struct atype_info { }; struct fn_info { - krb5_error_code (*enc)(asn1buf *, const void *, taginfo *, size_t *); + krb5_error_code (*enc)(asn1buf *, const void *, taginfo *); krb5_error_code (*dec)(const taginfo *, const uint8_t *, size_t, void *); int (*check_tag)(const taginfo *); void (*free_func)(void *); @@ -226,7 +223,7 @@ struct cntype_info { }; struct string_info { - krb5_error_code (*enc)(asn1buf *, uint8_t *const *, size_t, size_t *); + krb5_error_code (*enc)(asn1buf *, uint8_t *const *, size_t); krb5_error_code (*dec)(const uint8_t *, size_t, uint8_t **, size_t *); unsigned int tagval : 5; }; @@ -527,7 +524,7 @@ struct seq_info { * Used only by kdc_req_body. */ 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); /* Decode the tag and contents of a type, storing the result in the * caller-allocated C object val. Used only by kdc_req_body. */ diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index 0b6003b6c2..65c84be2f3 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -121,13 +121,14 @@ DEFOPTIONALZEROTYPE(opt_principal, principal); * 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) @@ -155,14 +156,13 @@ DEFOPTIONALZEROTYPE(opt_seqno, seqno); /* 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, @@ -229,15 +229,14 @@ DEFOPTIONALTYPE(opt_encrypted_data, nonempty_enc_data, NULL, encrypted_data); /* 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) @@ -316,13 +315,14 @@ DEFOPTIONALZEROTYPE(opt_checksum_ptr, checksum_ptr); /* 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) @@ -472,8 +472,7 @@ static const struct atype_info *kdc_req_hack_fields[] = { }; 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; @@ -487,8 +486,7 @@ encode_kdc_req_body(asn1buf *buf, const void *p, taginfo *tag_out, 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) diff --git a/src/lib/krb5/asn.1/asn1buf.c b/src/lib/krb5/asn.1/asn1buf.c deleted file mode 100644 index c27bfb9c17..0000000000 --- a/src/lib/krb5/asn.1/asn1buf.c +++ /dev/null @@ -1,208 +0,0 @@ -/* -*- 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 - -#ifdef USE_VALGRIND -#include -#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; -} diff --git a/src/lib/krb5/asn.1/asn1buf.h b/src/lib/krb5/asn.1/asn1buf.h deleted file mode 100644 index 494417f4cd..0000000000 --- a/src/lib/krb5/asn.1/asn1buf.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- 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 diff --git a/src/lib/krb5/asn.1/deps b/src/lib/krb5/asn.1/deps index 47050d699f..01d2d23afe 100644 --- a/src/lib/krb5/asn.1/deps +++ b/src/lib/krb5/asn.1/deps @@ -11,29 +11,19 @@ asn1_encode.so asn1_encode.po $(OUTPRE)asn1_encode.$(OBJEXT): \ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - asn1_encode.c asn1_encode.h asn1buf.h krbasn1.h -asn1buf.so asn1buf.po $(OUTPRE)asn1buf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ - $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ - $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ - $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ - $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ - $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ - $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ - $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h asn1buf.c asn1buf.h \ - krbasn1.h + asn1_encode.c asn1_encode.h krbasn1.h asn1_k_encode.so asn1_k_encode.po $(OUTPRE)asn1_k_encode.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ - $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ - $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ - $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - asn1_encode.h asn1_k_encode.c asn1buf.h krbasn1.h + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-spake.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h asn1_encode.h \ + asn1_k_encode.c krbasn1.h ldap_key_seq.so ldap_key_seq.po $(OUTPRE)ldap_key_seq.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ @@ -45,4 +35,4 @@ ldap_key_seq.so ldap_key_seq.po $(OUTPRE)ldap_key_seq.$(OBJEXT): \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h asn1_encode.h \ - asn1buf.h krbasn1.h ldap_key_seq.c + krbasn1.h ldap_key_seq.c