#ifndef __ASN1_ENCODE_H__
#define __ASN1_ENCODE_H__
#include "k5-int.h"
#include "krbasn1.h"
#include <time.h>
typedef struct asn1buf_st asn1buf;
typedef struct {
asn1_class asn1class;
asn1_construction construction;
asn1_tagnum tagnum;
size_t tag_len;
} taginfo;
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);
krb5_error_code k5_asn1_encode_bitstring(asn1buf *buf, uint8_t *const *val,
size_t len);
krb5_error_code k5_asn1_encode_generaltime(asn1buf *buf, time_t val);
krb5_error_code k5_asn1_decode_bool(const uint8_t *asn1, size_t len,
intmax_t *val);
krb5_error_code k5_asn1_decode_int(const uint8_t *asn1, size_t len,
intmax_t *val);
krb5_error_code k5_asn1_decode_uint(const uint8_t *asn1, size_t len,
uintmax_t *val);
krb5_error_code k5_asn1_decode_generaltime(const uint8_t *asn1, size_t len,
time_t *time_out);
krb5_error_code k5_asn1_decode_bytestring(const uint8_t *asn1, size_t len,
uint8_t **str_out, size_t *len_out);
krb5_error_code k5_asn1_decode_bitstring(const uint8_t *asn1, size_t len,
uint8_t **bits_out, size_t *len_out);
enum atype_type {
atype_min = 1,
atype_fn,
atype_ptr,
atype_offset,
atype_optional,
atype_counted,
atype_sequence,
atype_nullterm_sequence_of,
atype_nonempty_nullterm_sequence_of,
atype_tagged_thing,
atype_bool,
atype_int,
atype_uint,
atype_int_immediate,
atype_max
};
struct atype_info {
enum atype_type type;
size_t size;
const void *tinfo;
};
struct fn_info {
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 *);
};
struct ptr_info {
void *(*loadptr)(const void *);
void (*storeptr)(void *, void *);
const struct atype_info *basetype;
};
struct offset_info {
unsigned int dataoff : 9;
const struct atype_info *basetype;
};
struct optional_info {
int (*is_present)(const void *);
void (*init)(void *);
const struct atype_info *basetype;
};
struct counted_info {
unsigned int dataoff : 9;
unsigned int lenoff : 9;
unsigned int lensigned : 1;
unsigned int lensize : 5;
const struct cntype_info *basetype;
};
struct tagged_info {
unsigned int tagval : 16, tagtype : 8, construction : 6, implicit : 1;
const struct atype_info *basetype;
};
struct immediate_info {
intmax_t val;
krb5_error_code err;
};
enum cntype_type {
cntype_min = 1,
cntype_string,
cntype_der,
cntype_seqof,
cntype_choice,
cntype_max
};
struct cntype_info {
enum cntype_type type;
const void *tinfo;
};
struct string_info {
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;
};
struct choice_info {
const struct atype_info **options;
size_t n_options;
};
struct seq_info {
const struct atype_info **fields;
size_t n_fields;
};
#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN, DECFN, CHECKFN, FREEFN) \
typedef CTYPENAME aux_type_##DESCNAME; \
static const struct fn_info aux_info_##DESCNAME = { \
ENCFN, DECFN, CHECKFN, FREEFN \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_fn, sizeof(CTYPENAME), &aux_info_##DESCNAME \
}
#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS) \
typedef CTYPENAME aux_type_##DESCNAME; \
static const struct seq_info aux_seqinfo_##DESCNAME = { \
FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_sequence, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME \
}
#define DEFBOOLTYPE(DESCNAME, CTYPENAME) \
typedef CTYPENAME aux_type_##DESCNAME; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_bool, sizeof(CTYPENAME), NULL \
}
#define DEFINTTYPE(DESCNAME, CTYPENAME) \
typedef CTYPENAME aux_type_##DESCNAME; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_int, sizeof(CTYPENAME), NULL \
}
#define DEFUINTTYPE(DESCNAME, CTYPENAME) \
typedef CTYPENAME aux_type_##DESCNAME; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_uint, sizeof(CTYPENAME), NULL \
}
#define DEFINT_IMMEDIATE(DESCNAME, VAL, ERR) \
typedef int aux_type_##DESCNAME; \
static const struct immediate_info aux_info_##DESCNAME = { \
VAL, ERR \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_int_immediate, 0, &aux_info_##DESCNAME \
}
#ifdef POINTERS_ARE_ALL_THE_SAME
#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_type_##BASEDESCNAME *aux_type_##DESCNAME; \
static const struct ptr_info aux_info_##DESCNAME = { \
NULL, NULL, &k5_atype_##BASEDESCNAME \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_ptr, sizeof(aux_type_##DESCNAME), \
&aux_info_##DESCNAME \
}
#else
#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_type_##BASEDESCNAME *aux_type_##DESCNAME; \
static void * \
aux_loadptr_##DESCNAME(const void *p) \
{ \
return *(aux_type_##DESCNAME *)p; \
} \
static void \
aux_storeptr_##DESCNAME(void *ptr, void *val) \
{ \
*(aux_type_##DESCNAME *)val = ptr; \
} \
static const struct ptr_info aux_info_##DESCNAME = { \
aux_loadptr_##DESCNAME, aux_storeptr_##DESCNAME, \
&k5_atype_##BASEDESCNAME \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_ptr, sizeof(aux_type_##DESCNAME), \
&aux_info_##DESCNAME \
}
#endif
#define DEFOFFSETTYPE(DESCNAME, STYPE, FIELDNAME, BASEDESC) \
typedef STYPE aux_type_##DESCNAME; \
static const struct offset_info aux_info_##DESCNAME = { \
OFFOF(STYPE, FIELDNAME, aux_type_##BASEDESC), \
&k5_atype_##BASEDESC \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_offset, sizeof(aux_type_##DESCNAME), \
&aux_info_##DESCNAME \
}
#define DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, SIGNED, \
CDESC) \
typedef STYPE aux_type_##DESCNAME; \
const struct counted_info aux_info_##DESCNAME = { \
OFFOF(STYPE, DATAFIELD, aux_ptrtype_##CDESC), \
OFFOF(STYPE, COUNTFIELD, aux_counttype_##CDESC), \
SIGNED, sizeof(((STYPE*)0)->COUNTFIELD), \
&k5_cntype_##CDESC \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_counted, sizeof(STYPE), \
&aux_info_##DESCNAME \
}
#define DEFCOUNTEDTYPE(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, CDESC) \
DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, 0, CDESC)
#define DEFCOUNTEDTYPE_SIGNED(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, CDESC) \
DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, 1, CDESC)
#define DEFOPTIONALTYPE(DESCNAME, PRESENT, INIT, BASEDESC) \
typedef aux_type_##BASEDESC aux_type_##DESCNAME; \
static const struct optional_info aux_info_##DESCNAME = { \
PRESENT, INIT, &k5_atype_##BASEDESC \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_optional, sizeof(aux_type_##DESCNAME), \
&aux_info_##DESCNAME \
}
#define DEFOPTIONALZEROTYPE(DESCNAME, BASEDESC) \
static int \
aux_present_##DESCNAME(const void *p) \
{ \
return *(aux_type_##BASEDESC *)p != 0; \
} \
DEFOPTIONALTYPE(DESCNAME, aux_present_##DESCNAME, NULL, BASEDESC)
#define DEFOPTIONALEMPTYTYPE(DESCNAME, BASEDESC) \
static int \
aux_present_##DESCNAME(const void *p) \
{ \
const aux_type_##BASEDESC *val = p; \
return (*val != NULL && **val != NULL); \
} \
DEFOPTIONALTYPE(DESCNAME, aux_present_##DESCNAME, NULL, BASEDESC)
#define DEFNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_type_##BASEDESCNAME aux_type_##DESCNAME; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_nullterm_sequence_of, sizeof(aux_type_##DESCNAME), \
&k5_atype_##BASEDESCNAME \
}
#define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_type_##BASEDESCNAME aux_type_##DESCNAME; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_nonempty_nullterm_sequence_of, \
sizeof(aux_type_##DESCNAME), \
&k5_atype_##BASEDESCNAME \
}
#define DEFTAGGEDTYPE(DESCNAME, CLASS, CONSTRUCTION, TAG, IMPLICIT, BASEDESC) \
typedef aux_type_##BASEDESC aux_type_##DESCNAME; \
static const struct tagged_info aux_info_##DESCNAME = { \
TAG, CLASS, CONSTRUCTION, IMPLICIT, &k5_atype_##BASEDESC \
}; \
const struct atype_info k5_atype_##DESCNAME = { \
atype_tagged_thing, sizeof(aux_type_##DESCNAME), \
&aux_info_##DESCNAME \
}
#define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \
DEFTAGGEDTYPE(DESCNAME, APPLICATION, CONSTRUCTED, TAG, 0, BASEDESC)
#define DEFCTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \
DEFTAGGEDTYPE(DESCNAME, CONTEXT_SPECIFIC, CONSTRUCTED, TAG, 0, BASEDESC)
#define DEFCTAGGEDTYPE_IMPLICIT(DESCNAME, TAG, BASEDESC) \
DEFTAGGEDTYPE(DESCNAME, CONTEXT_SPECIFIC, CONSTRUCTED, TAG, 1, BASEDESC)
#define DEFFIELD(NAME, STYPE, FIELDNAME, TAG, DESC) \
DEFOFFSETTYPE(NAME##_untagged, STYPE, FIELDNAME, DESC); \
DEFCTAGGEDTYPE(NAME, TAG, NAME##_untagged)
#define DEFCNFIELD(NAME, STYPE, DATAFIELD, LENFIELD, TAG, CDESC) \
DEFCOUNTEDTYPE(NAME##_untagged, STYPE, DATAFIELD, LENFIELD, CDESC); \
DEFCTAGGEDTYPE(NAME, TAG, NAME##_untagged)
#define DEFFIELD_IMPLICIT(NAME, STYPE, FIELDNAME, TAG, DESC) \
DEFOFFSETTYPE(NAME##_untagged, STYPE, FIELDNAME, DESC); \
DEFCTAGGEDTYPE_IMPLICIT(NAME, TAG, NAME##_untagged)
#define DEFCOUNTEDSTRINGTYPE(DESCNAME, DTYPE, LTYPE, ENCFN, DECFN, TAGVAL) \
typedef DTYPE aux_ptrtype_##DESCNAME; \
typedef LTYPE aux_counttype_##DESCNAME; \
static const struct string_info aux_info_##DESCNAME = { \
ENCFN, DECFN, TAGVAL \
}; \
const struct cntype_info k5_cntype_##DESCNAME = { \
cntype_string, &aux_info_##DESCNAME \
}
#define DEFCOUNTEDDERTYPE(DESCNAME, DTYPE, LTYPE) \
typedef DTYPE aux_ptrtype_##DESCNAME; \
typedef LTYPE aux_counttype_##DESCNAME; \
const struct cntype_info k5_cntype_##DESCNAME = { \
cntype_der, NULL \
}
#define DEFCOUNTEDSEQOFTYPE(DESCNAME, LTYPE, BASEDESC) \
typedef aux_type_##BASEDESC aux_ptrtype_##DESCNAME; \
typedef LTYPE aux_counttype_##DESCNAME; \
const struct cntype_info k5_cntype_##DESCNAME = { \
cntype_seqof, &k5_atype_##BASEDESC \
}
#define DEFCHOICETYPE(DESCNAME, UTYPE, DTYPE, FIELDS) \
typedef UTYPE aux_ptrtype_##DESCNAME; \
typedef DTYPE aux_counttype_##DESCNAME; \
static const struct choice_info aux_info_##DESCNAME = { \
FIELDS, sizeof(FIELDS) / sizeof(FIELDS[0]) \
}; \
const struct cntype_info k5_cntype_##DESCNAME = { \
cntype_choice, &aux_info_##DESCNAME \
}
#define IMPORT_TYPE(DESCNAME, CTYPENAME) \
typedef CTYPENAME aux_type_##DESCNAME; \
extern const struct atype_info k5_atype_##DESCNAME
krb5_error_code
k5_asn1_encode_atype(asn1buf *buf, const void *val, const struct atype_info *a,
taginfo *tag_out);
krb5_error_code
k5_asn1_decode_atype(const taginfo *t, const uint8_t *asn1, size_t len,
const struct atype_info *a, void *val);
extern krb5_error_code
k5_asn1_full_encode(const void *rep, const struct atype_info *a,
krb5_data **code_out);
krb5_error_code
k5_asn1_full_decode(const krb5_data *code, const struct atype_info *a,
void **rep_out);
#define MAKE_ENCODER(FNAME, DESC) \
krb5_error_code \
FNAME(const aux_type_##DESC *rep, krb5_data **code_out) \
{ \
return k5_asn1_full_encode(rep, &k5_atype_##DESC, code_out); \
} \
extern int dummy
#define MAKE_DECODER(FNAME, DESC) \
krb5_error_code \
FNAME(const krb5_data *code, aux_type_##DESC **rep_out) \
{ \
krb5_error_code ret; \
void *rep; \
*rep_out = NULL; \
ret = k5_asn1_full_decode(code, &k5_atype_##DESC, &rep); \
if (ret) \
return ret; \
*rep_out = rep; \
return 0; \
} \
extern int dummy
#include <stddef.h>
#define WARN_IF_TYPE_MISMATCH(LVALUE, TYPE) \
(sizeof(0 ? (TYPE *) 0 : &(LVALUE)))
#define OFFOF(TYPE,FIELD,FTYPE) \
(offsetof(TYPE, FIELD) \
+ 0 * WARN_IF_TYPE_MISMATCH(((TYPE*)0)->FIELD, FTYPE))
#endif