static asn1_error_code encode_nullterm_sequence_of(asn1buf *buf, const void *val, const struct atype_info *type, int can_be_empty, unsigned int *retlen) { int length = get_nullterm_sequence_len(val, type); if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD; return encode_sequence_of(buf, length, val, type, retlen); }
static asn1_error_code encode_nullterm_sequence_of(asn1buf *buf, const void *val, const struct atype_info *type, int can_be_empty, size_t *len_out) { 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); }
/* * Encode an object and count according to a cntype_info structure. val is a * pointer to the object being encoded, which in most cases is itself a * pointer (but is a union in the cntype_choice case). */ static asn1_error_code encode_cntype(asn1buf *buf, const void *val, size_t count, const struct cntype_info *c, taginfo *tag_out, size_t *len_out) { asn1_error_code ret; switch (c->type) { case cntype_string: { const struct string_info *string = c->tinfo; assert(string->enc != NULL); ret = string->enc(buf, val, count, len_out); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = PRIMITIVE; tag_out->tagnum = string->tagval; break; } case cntype_der: return split_der(buf, val, count, tag_out, len_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); if (ret) return ret; tag_out->asn1class = UNIVERSAL; tag_out->construction = CONSTRUCTED; tag_out->tagnum = ASN1_SEQUENCE; break; } case cntype_choice: { 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); } default: assert(c->type > cntype_min); assert(c->type < cntype_max); abort(); } return 0; }
static asn1_error_code encode_a_field(asn1buf *buf, const void *val, const struct field_info *field, unsigned int *retlen) { asn1_error_code retval; unsigned int sum = 0; if (val == NULL) return ASN1_MISSING_FIELD; switch (field->ftype) { case field_immediate: { unsigned int length; retval = asn1_encode_integer(buf, (asn1_intmax) field->dataoff, &length); if (retval) return retval; sum += length; break; } case field_sequenceof_len: { const void *dataptr, *lenptr; int slen; unsigned int length; const struct atype_info *a; /* * The field holds a pointer to the array of objects. So the * address we compute is a pointer-to-pointer, and that's what * field->atype must help us dereference. */ dataptr = (const char *)val + field->dataoff; lenptr = (const char *)val + field->lenoff; assert(field->atype->type == atype_ptr); dataptr = LOADPTR(dataptr, field->atype); a = field->atype->basetype; assert(field->lentype != 0); assert(field->lentype->type == atype_int || field->lentype->type == atype_uint); assert(sizeof(int) <= sizeof(asn1_intmax)); assert(sizeof(unsigned int) <= sizeof(asn1_uintmax)); if (field->lentype->type == atype_int) { asn1_intmax xlen = field->lentype->loadint(lenptr); if (xlen < 0) return EINVAL; if ((unsigned int) xlen != (asn1_uintmax) xlen) return EINVAL; if ((unsigned int) xlen > INT_MAX) return EINVAL; slen = (int) xlen; } else { asn1_uintmax xlen = field->lentype->loaduint(lenptr); if ((unsigned int) xlen != xlen) return EINVAL; if (xlen > INT_MAX) return EINVAL; slen = (int) xlen; } if (slen != 0 && dataptr == NULL) return ASN1_MISSING_FIELD; retval = encode_sequence_of(buf, slen, dataptr, a, &length); if (retval) return retval; sum += length; break; } case field_normal: { const void *dataptr; const struct atype_info *a; unsigned int length; dataptr = (const char *)val + field->dataoff; a = field->atype; assert(a->type != atype_fn_len); retval = krb5int_asn1_encode_a_thing(buf, dataptr, a, &length); if (retval) { return retval; } sum += length; break; } case field_string: { const void *dataptr, *lenptr; const struct atype_info *a; size_t slen; unsigned int length; dataptr = (const char *)val + field->dataoff; lenptr = (const char *)val + field->lenoff; a = field->atype; assert(a->type == atype_fn_len); assert(field->lentype != 0); assert(field->lentype->type == atype_int || field->lentype->type == atype_uint); assert(sizeof(int) <= sizeof(asn1_intmax)); assert(sizeof(unsigned int) <= sizeof(asn1_uintmax)); if (field->lentype->type == atype_int) { asn1_intmax xlen = field->lentype->loadint(lenptr); if (xlen < 0) return EINVAL; if ((size_t) xlen != (asn1_uintmax) xlen) return EINVAL; slen = (size_t) xlen; } else { asn1_uintmax xlen = field->lentype->loaduint(lenptr); if ((size_t) xlen != xlen) return EINVAL; slen = (size_t) xlen; } dataptr = LOADPTR(dataptr, a); if (slen == SIZE_MAX) /* Error - negative or out of size_t range. */ return EINVAL; if (dataptr == NULL && slen != 0) return ASN1_MISSING_FIELD; /* * Currently our string encoders want "unsigned int" for * lengths. */ if (slen != (unsigned int) slen) return EINVAL; assert(a->enclen != NULL); retval = a->enclen(buf, (unsigned int) slen, dataptr, &length); if (retval) { return retval; } sum += length; break; } default: assert(field->ftype > field_min); assert(field->ftype < field_max); assert(__LINE__ == 0); abort(); } if (field->tag >= 0) { unsigned int length; retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, field->tag, sum, &length); if (retval) { return retval; } sum += length; } *retlen = sum; return 0; }