/*- * Copyright (c) 2024 Kyle Evans * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include enum libder_ber_class { BC_UNIVERSAL = 0, BC_APPLICATION = 1, BC_CONTEXT = 2, BC_PRIVATE = 3, }; enum libder_ber_type { BT_RESERVED = 0x00, BT_BOOLEAN = 0x01, BT_INTEGER = 0x02, BT_BITSTRING = 0x03, BT_OCTETSTRING = 0x04, BT_NULL = 0x05, BT_OID = 0x06, BT_OBJDESC = 0x07, BT_EXTERNAL = 0x08, BT_REAL = 0x09, BT_ENUMERATED = 0x0a, BT_PDV = 0x0b, BT_UTF8STRING = 0x0c, BT_RELOID = 0x0d, /* 0x10, 011 not usable */ BT_NUMERICSTRING = 0x012, BT_STRING = 0x13, BT_TELEXSTRING = 0x14, BT_VIDEOTEXSTRING = 0x15, BT_IA5STRING = 0x16, BT_UTCTIME = 0x17, BT_GENTIME = 0x18, BT_GFXSTRING = 0x19, BT_VISSTRING = 0x1a, BT_GENSTRING = 0x1b, BT_UNIVSTRING = 0x1c, BT_CHARSTRING = 0x1d, BT_BMPSTRING = 0x1e, BT_SEQUENCE = 0x30, BT_SET = 0x31, }; #define BER_TYPE_CONSTRUCTED_MASK 0x20 /* Bit 6 */ #define BER_TYPE_CLASS_MASK 0xc0 /* Bits 7 and 8 */ /* * The difference between the type and the full type is just that the full type * will indicate the class of type, so it may be more useful for some operations. */ #define BER_FULL_TYPE(tval) \ ((tval) & ~(BER_TYPE_CONSTRUCTED_MASK)) #define BER_TYPE(tval) \ ((tval) & ~(BER_TYPE_CLASS_MASK | BER_TYPE_CONSTRUCTED_MASK)) #define BER_TYPE_CLASS(tval) \ (((tval) & BER_TYPE_CLASS_MASK) >> 6) #define BER_TYPE_CONSTRUCTED(tval) \ (((tval) & BER_TYPE_CONSTRUCTED_MASK) != 0) enum libder_error { LDE_NONE = 0x00, LDE_NOMEM, /* Out of memory */ LDE_INVAL, /* Invalid parameter */ LDE_SHORTHDR, /* Header too short */ LDE_BADVARLEN, /* Bad variable length encoding */ LDE_LONGLEN, /* Encoded length too large (8 byte max) */ LDE_SHORTDATA, /* Payload not available */ LDE_GARBAGE, /* Garbage after encoded data */ LDE_STREAMERR, /* Stream error */ LDE_TRUNCVARLEN, /* Variable length object truncated */ LDE_COALESCE_BADCHILD, /* Bad child encountered when coalescing */ LDE_BADOBJECT, /* Payload not valid for object type */ /* Strict violations */ LDE_STRICT_EOC, /* Strict: end-of-content violation */ LDE_STRICT_TAG, /* Strict: tag violation */ LDE_STRICT_PVARLEN, /* Strict: primitive using indefinite length */ LDE_STRICT_BOOLEAN, /* Strict: boolean encoded incorrectly */ LDE_STRICT_NULL, /* Strict: null encoded incorrectly */ LDE_STRICT_PRIMITIVE, /* Strict: type must be primitive */ LDE_STRICT_CONSTRUCTED, /* Strict: type must be constructed */ LDE_STRICT_BITSTRING, /* Strict: malformed constructed bitstring */ }; struct libder_ctx; struct libder_tag; struct libder_object; /* * By default we normalize everything, but we allow some subset of the * functionality to be disabled. Lengths are non-optional and will always be * normalized to a fixed short or long length. The upper 32-bits of * ctx->normalize are reserved for universal types so that we can quickly map * those without assigning them names. */ /* Normalize constructed types that should be coalesced (e.g., strings, time). */ #define LIBDER_NORMALIZE_CONSTRUCTED 0x0000000000000001ULL /* * Normalize tags on read. This is mostly a measure to ensure that * normalization on write doesn't get thwarted; there's no reason anybody should * be encoding low tags with the long form, but the spec doesn't appear to * forbid it. */ #define LIBDER_NORMALIZE_TAGS 0x0000000000000002ULL /* Universal types (reserved) */ #define LIBDER_NORMALIZE_TYPE_MASK 0xffffffff00000000ULL #define LIBDER_NORMALIZE_TYPE_FLAG(val) ((1ULL << val) << 32ULL) /* All valid bits. */ #define LIBDER_NORMALIZE_ALL \ (LIBDER_NORMALIZE_TYPE_MASK | LIBDER_NORMALIZE_CONSTRUCTED | \ LIBDER_NORMALIZE_TAGS) struct libder_ctx * libder_open(void); void libder_close(struct libder_ctx *); void libder_abort(struct libder_ctx *); const char *libder_get_error(struct libder_ctx *); bool libder_has_error(struct libder_ctx *); uint64_t libder_get_normalize(struct libder_ctx *); uint64_t libder_set_normalize(struct libder_ctx *, uint64_t); bool libder_get_strict(struct libder_ctx *); bool libder_set_strict(struct libder_ctx *, bool); int libder_get_verbose(struct libder_ctx *); int libder_set_verbose(struct libder_ctx *, int); struct libder_object *libder_read(struct libder_ctx *, const uint8_t *, size_t *); struct libder_object *libder_read_fd(struct libder_ctx *, int, size_t *); struct libder_object *libder_read_file(struct libder_ctx *, FILE *, size_t *); uint8_t *libder_write(struct libder_ctx *, struct libder_object *, uint8_t *, size_t *); #define DER_CHILDREN(obj) libder_obj_children(obj) #define DER_NEXT(obj) libder_obj_next(obj) #define DER_FOREACH_CHILD(var, obj) \ for ((var) = DER_CHILDREN((obj)); \ (var); \ (var) = DER_NEXT((var))) #define DER_FOREACH_CHILD_SAFE(var, obj, tvar) \ for ((var) = DER_CHILDREN((obj)); \ (var) && ((tvar) = DER_NEXT((var)), 1); \ (var) = (tvar)) struct libder_object *libder_obj_alloc(struct libder_ctx *, struct libder_tag *, const uint8_t *, size_t); struct libder_object *libder_obj_alloc_simple(struct libder_ctx *, uint8_t, const uint8_t *, size_t); void libder_obj_free(struct libder_object *); bool libder_obj_append(struct libder_object *, struct libder_object *); struct libder_object *libder_obj_child(const struct libder_object *, size_t); struct libder_object *libder_obj_children(const struct libder_object *); struct libder_object *libder_obj_next(const struct libder_object *); struct libder_tag *libder_obj_type(const struct libder_object *); uint8_t libder_obj_type_simple(const struct libder_object *); const uint8_t *libder_obj_data(const struct libder_object *, size_t *); /* Debugging aide -- probably shouldn't use. */ void libder_obj_dump(const struct libder_object *, FILE *); struct libder_tag *libder_type_alloc_simple(struct libder_ctx *, uint8_t); struct libder_tag *libder_type_dup(struct libder_ctx *, const struct libder_tag *); void libder_type_free(struct libder_tag *); #define libder_type_simple libder_type_simple_abi uint8_t libder_type_simple(const struct libder_tag *);