git: ba667efb5301 - stable/14 - Add 'contrib/libder/' from commit '9c40c4de4c33b2ba1124fb752ebea0bebaa6013f'
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 11 Jan 2025 02:48:35 UTC
The branch stable/14 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=ba667efb5301da32009d5cbc5ae5df9cff895e82 commit ba667efb5301da32009d5cbc5ae5df9cff895e82 Author: Kyle Evans <kevans@FreeBSD.org> AuthorDate: 2025-01-01 21:11:02 +0000 Commit: Kyle Evans <kevans@FreeBSD.org> CommitDate: 2025-01-11 02:48:21 +0000 Add 'contrib/libder/' from commit '9c40c4de4c33b2ba1124fb752ebea0bebaa6013f' git-subtree-dir: contrib/libder git-subtree-mainline: d11904b350214943dedb64c7121d4602799d7afd git-subtree-split: 9c40c4de4c33b2ba1124fb752ebea0bebaa6013f (cherry picked from commit 35c0a8c449fd2b7f75029ebed5e10852240f0865) --- contrib/libder/.cirrus.yml | 16 + contrib/libder/.github/workflows/build.yml | 41 + contrib/libder/.gitignore | 11 + contrib/libder/CMakeLists.txt | 28 + contrib/libder/LICENSE | 22 + contrib/libder/README.md | 28 + contrib/libder/derdump/.gitignore | 1 + contrib/libder/derdump/CMakeLists.txt | 6 + contrib/libder/derdump/derdump.1 | 51 ++ contrib/libder/derdump/derdump.c | 52 ++ contrib/libder/libder/CMakeLists.txt | 12 + contrib/libder/libder/libder.3 | 179 +++++ contrib/libder/libder/libder.c | 119 +++ contrib/libder/libder/libder.h | 181 +++++ contrib/libder/libder/libder_error.c | 76 ++ contrib/libder/libder/libder_obj.3 | 138 ++++ contrib/libder/libder/libder_obj.c | 1192 ++++++++++++++++++++++++++++ contrib/libder/libder/libder_private.h | 178 +++++ contrib/libder/libder/libder_read.3 | 101 +++ contrib/libder/libder/libder_read.c | 864 ++++++++++++++++++++ contrib/libder/libder/libder_type.3 | 71 ++ contrib/libder/libder/libder_type.c | 150 ++++ contrib/libder/libder/libder_write.3 | 54 ++ contrib/libder/libder/libder_write.c | 229 ++++++ contrib/libder/tests/.gitignore | 12 + contrib/libder/tests/CMakeLists.txt | 41 + contrib/libder/tests/fuzz_parallel.c | 111 +++ contrib/libder/tests/fuzz_stream.c | 246 ++++++ contrib/libder/tests/fuzz_write.c | 79 ++ contrib/libder/tests/fuzzers.h | 40 + contrib/libder/tests/make_corpus.c | 137 ++++ contrib/libder/tests/repo.priv | Bin 0 -> 64 bytes contrib/libder/tests/repo.pub | Bin 0 -> 88 bytes contrib/libder/tests/test_common.h | 29 + contrib/libder/tests/test_privkey.c | 175 ++++ contrib/libder/tests/test_pubkey.c | 143 ++++ 36 files changed, 4813 insertions(+) diff --git a/contrib/libder/.cirrus.yml b/contrib/libder/.cirrus.yml new file mode 100644 index 000000000000..a63de71d8bf4 --- /dev/null +++ b/contrib/libder/.cirrus.yml @@ -0,0 +1,16 @@ +build_task: + matrix: + - name: FreeBSD 13 + freebsd_instance: + image: freebsd-13-2-release-amd64 + - name: FreeBSD 14 + freebsd_instance: + image: freebsd-14-0-release-amd64-ufs + setup_script: + sudo pkg install -y cmake + configure_script: + - cmake -B build -DCMAKE_BUILD_TYPE=Debug + build_script: + make -C build + test_script: + make -C build check diff --git a/contrib/libder/.github/workflows/build.yml b/contrib/libder/.github/workflows/build.yml new file mode 100644 index 000000000000..a10daa25e38f --- /dev/null +++ b/contrib/libder/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: Build libder +on: + push: + branches: ['**'] + pull_request: + types: [opened, reopened, edited, synchronize] + +permissions: + contents: read + +jobs: + build: + name: Build ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, ubuntu-22.04, macos-latest] + include: + - os: ubuntu-20.04 + - os: ubuntu-22.04 + - os: macos-latest + steps: + - name: checkout + uses: actions/checkout@v4 + - name: install system packages (Ubuntu) + if: runner.os == 'Linux' + run: | + sudo apt-get update --quiet || true + sudo apt-get -yq --no-install-suggests --no-install-recommends install cmake + - name: install system packages (macOS) + if: runner.os == 'macOS' + run: | + brew update --quiet || true + brew install cmake coreutils + - name: configure + run: | + cmake -B build -DCMAKE_BUILD_TYPE=Debug + - name: build libder + run: make -C build + - name: Run self-tests + run: make -C build check diff --git a/contrib/libder/.gitignore b/contrib/libder/.gitignore new file mode 100644 index 000000000000..34fb4e06c50b --- /dev/null +++ b/contrib/libder/.gitignore @@ -0,0 +1,11 @@ +.*.swp +.depend* +*.a +*.so +*.so.* +*.o +*.pico +*.debug +*.full + +build/ diff --git a/contrib/libder/CMakeLists.txt b/contrib/libder/CMakeLists.txt new file mode 100644 index 000000000000..cf0d39e32489 --- /dev/null +++ b/contrib/libder/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.18) + +project(libder) + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + if(NOT CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + add_compile_options(-fsanitize=address,undefined -fstrict-aliasing) + add_link_options(-fsanitize=address,undefined -fstrict-aliasing) + endif() + + add_compile_options(-Werror) +endif() + +# AppleClang is excluded for the time being; the version used in GitHub Action +# runners doesn't seem to have that part of libclang_rt installed, though the +# -fsanitize=fuzzer-no-link instrumentation seems to be fine. Maybe re-evaluate +# this for MATCHES as a possibility later. +if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + set(BUILD_FUZZERS TRUE + CACHE BOOL "Build the libFuzzer fuzzers (needs llvm)") +else() + set(BUILD_FUZZERS FALSE + CACHE BOOL "Build the libFuzzer fuzzers (needs llvm)") +endif() + +add_subdirectory(libder) +add_subdirectory(derdump) +add_subdirectory(tests) diff --git a/contrib/libder/LICENSE b/contrib/libder/LICENSE new file mode 100644 index 000000000000..477af8f22e4c --- /dev/null +++ b/contrib/libder/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/contrib/libder/README.md b/contrib/libder/README.md new file mode 100644 index 000000000000..9f700493520d --- /dev/null +++ b/contrib/libder/README.md @@ -0,0 +1,28 @@ +# libder + +## What is libder? + +libder is a small library for encoding/decoding DER-encoded objects. It is +expected to be able to decode any BER-encoded buffer, and an attempt to +re-encode the resulting tree would apply any normalization expected by a DER +decoder. The author's use is primarily to decode/encode ECC keys for +interoperability with OpenSSL. + +The authoritative source for this software is located at +https://git.kevans.dev/kevans/libder, but it's additionally mirrored to +[GitHub](https://github.com/kevans91/libder) for user-facing interactions. +Pull requests and issues are open on GitHub. + +## What is libder not? + +libder is not intended to be a general-purpose library for working with DER/BER +specified objects. It may provide some helpers for building more primitive +data types, but libder will quickly punt on anything even remotely complex and +require the library consumer to supply it as a type/payload/size triple that it +will treat as relatively opaque (modulo some encoding normalization rules that +can be applied without deeply understanding the data contained within). + +libder also doesn't do strict validation of what it reads in today, for better +or worse. e.g., a boolean may occupy more than one byte and libder will happily +present it to the application in that way. It would be normalized on +re-encoding to 0xff or 0x00 depending on whether any bits are set or not. diff --git a/contrib/libder/derdump/.gitignore b/contrib/libder/derdump/.gitignore new file mode 100644 index 000000000000..a35adcc4b71d --- /dev/null +++ b/contrib/libder/derdump/.gitignore @@ -0,0 +1 @@ +derdump diff --git a/contrib/libder/derdump/CMakeLists.txt b/contrib/libder/derdump/CMakeLists.txt new file mode 100644 index 000000000000..11657426fbc9 --- /dev/null +++ b/contrib/libder/derdump/CMakeLists.txt @@ -0,0 +1,6 @@ +file(GLOB derdump_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c) + +add_executable(derdump ${derdump_SOURCES}) + +target_include_directories(derdump PRIVATE "${CMAKE_SOURCE_DIR}/libder") +target_link_libraries(derdump der_static) diff --git a/contrib/libder/derdump/derdump.1 b/contrib/libder/derdump/derdump.1 new file mode 100644 index 000000000000..414799f3055f --- /dev/null +++ b/contrib/libder/derdump/derdump.1 @@ -0,0 +1,51 @@ +.\" +.\" SPDX-Copyright-Identifier: BSD-2-Clause +.\" +.\" Copyright (C) 2024 Kyle Evans <kevans@FreeBSD.org> +.\" +.Dd March 4, 2024 +.Dt DERDUMP 1 +.Os +.Sh NAME +.Nm derdump +.Nd dumping contents of DER encoded files +.Sh SYNOPSIS +.Nm +.Ar file1 +.Oo Ar fileN ... Oc +.Sh DESCRIPTION +The +.Nm +utility dumps the contents of one or more DER encoded +Ar file +in a more human readable format. +This is similar to the +.Xr asn1parse 1 +utility distributed with OpenSSL when used with the +.Fl inform +.Ar DER +option. +.Pp +A representation of the object will be output to +.Em stdout , +with indentation to denote objects that are encoded within other constructed +objects. +Note that +.Nm +does not make much attempt to interpret the contents of any particular object. +If an object uses one of the universal types, then a friendly name will be +displayed for that object. +If an object uses any other type, then +.Nm +will display the raw hex value of the type used. +Values of primitive objects are output as raw hex, and no effort is made to +try and print a friendly representation. +.Sh SEE ALSO +.Xr asn1parse 1 , +.Xr libder 3 +.Sh BUGS +.Nm +does not currently make any attempt to render a type that uses the long encoded +format. +Instead, it will render as +.Dq { ... } . diff --git a/contrib/libder/derdump/derdump.c b/contrib/libder/derdump/derdump.c new file mode 100644 index 000000000000..7ea3768524d8 --- /dev/null +++ b/contrib/libder/derdump/derdump.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <err.h> +#include <stdio.h> + +#include <libder.h> + +int +main(int argc, char *argv[]) +{ + FILE *fp; + struct libder_ctx *ctx; + struct libder_object *root; + size_t rootsz; + bool first = true; + + if (argc < 2) { + fprintf(stderr, "usage: %s file [file...]\n", argv[0]); + return (1); + } + + ctx = libder_open(); + libder_set_verbose(ctx, 2); + for (int i = 1; i < argc; i++) { + fp = fopen(argv[i], "rb"); + if (fp == NULL) { + warn("%s", argv[i]); + continue; + } + + if (!first) + fprintf(stderr, "\n"); + fprintf(stdout, "[%s]\n", argv[i]); + root = libder_read_file(ctx, fp, &rootsz); + if (root != NULL) { + libder_obj_dump(root, stdout); + libder_obj_free(root); + root = NULL; + } + + first = false; + fclose(fp); + } + + libder_close(ctx); + + return (0); +} diff --git a/contrib/libder/libder/CMakeLists.txt b/contrib/libder/libder/CMakeLists.txt new file mode 100644 index 000000000000..8e6f3426d649 --- /dev/null +++ b/contrib/libder/libder/CMakeLists.txt @@ -0,0 +1,12 @@ +file(GLOB libder_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c) + +add_library(der SHARED ${libder_SOURCES}) +add_library(der_static STATIC ${libder_SOURCES}) + +if(BUILD_FUZZERS AND CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_options(der PUBLIC -fsanitize=fuzzer-no-link) + target_link_options(der PUBLIC -fsanitize=fuzzer-no-link) + + target_compile_options(der_static PUBLIC -fsanitize=fuzzer-no-link) + target_link_options(der_static PUBLIC -fsanitize=fuzzer-no-link) +endif() diff --git a/contrib/libder/libder/libder.3 b/contrib/libder/libder/libder.3 new file mode 100644 index 000000000000..0e06254ef3fb --- /dev/null +++ b/contrib/libder/libder/libder.3 @@ -0,0 +1,179 @@ +.\" +.\" SPDX-Copyright-Identifier: BSD-2-Clause +.\" +.\" Copyright (C) 2024 Kyle Evans <kevans@FreeBSD.org> +.\" +.Dd March 2, 2024 +.Dt LIBDER 3 +.Os +.Sh NAME +.Nm libder , +.Nm libder_open , +.Nm libder_close , +.Nm libder_abort , +.Nm libder_get_error , +.Nm libder_has_error , +.Nm libder_get_normalize , +.Nm libder_set_normalize , +.Nm libder_get_strict , +.Nm libder_set_strict , +.Nm libder_get_verbose , +.Nm libder_set_verbose +.Nd DER encoding and decoding library +.Sh LIBRARY +.Lb libder +.Sh SYNOPSIS +.In libder.h +.Ft struct libder_ctx * +.Fn libder_open "void" +.Ft void +.Fn libder_close "struct libder_ctx *ctx" +.Ft void +.Fn libder_abort "struct libder_ctx *ctx" +.Ft const char * +.Fn libder_get_error "struct libder_ctx *ctx" +.Ft bool +.Fn libder_has_error "struct libder_ctx *ctx" +.Ft uint64_t +.Fn libder_get_normalize "struct libder_ctx *ctx" +.Ft uint64_t +.Fn libder_set_normalize "struct libder_ctx *ctx" "uint64_t normalize" +.Ft bool +.Fn libder_get_strict "struct libder_ctx *ctx" +.Ft bool +.Fn libder_set_strict "struct libder_ctx *ctx" "bool strict" +.Ft int +.Fn libder_get_verbose "struct libder_ctx *ctx" +.Ft int +.Fn libder_set_verbose "struct libder_ctx *ctx" "int verbose" +.Sh DESCRIPTION +The +.Nm +library provides functionality for decoding BER and DER encoded data, and +DER encoding data subjected to constraints outline in ITU-T +Recommendation X.690. +.Nm +will apply relevant normalization rules on write, unless they've been disabled +with +.Ft libder_set_normalize , +under the assumption that it may not be reading strictly DER encoded data. +.Pp +Note that not all of the DER rules are currently implemented. +.Nm +will coalesce constructed types that DER specifies should be primitive. +.Nm +will primarily normalize bitstrings, booleans, and integers. +This library was primarily written to be able to provide interoperability with +OpenSSL keys and signatures, so the library was written with that in mind. +Eventually it is intended that +.Nm +will support the full set of rules, but currently some responsibility is left +to the library user. +.Pp +Also note that +.Nm +does not necessarily provide +.Dq neat +ways to construct primitives. +For example, even booleans and integers currently work just by providing a +buffer that is expected to be formatted in a sane fashion. +The library user is expected to build the object tree and generally provide the +object data in a format reasonably encoded as the data for that type should be, +then +.Nm +will provide the proper framing on write and do any transformations that may +need to be done for strict conformance. +.Pp +The +.Fn libder_open +function allocates a new +.Nm +context. +The context does not hold any state about any particular structure. +All of the state held in the context is generally described in this manpage. +The +.Fn libder_close +function will free the context. +.Pp +The +.Fn libder_abort +function will abort an in-progress +.Xr libder_read_fd 3 +operation on the existing +.Fa ctx +if it is interrupted by a signal in the middle of a +.Xr read 2 +syscall. +See +.Xr libder_read_fd 3 +for further discussion. +.Pp +The +.Fn libder_get_error +function will return an error string appropriate for the current error, if any. +The +.Fn libder_has_error +function can be used to check if an error was raised in a previous operation. +.Pp +The +.Fn libder_get_normalize +and +.Fn libder_set_normalize +functions retrieve and manipulate any number of flags that detail how +functions may be used to check or set the normalization flags given +.Nm context , +which dictates how +.Nm +will normalize data on write. +The following normalization flags may be specified: +.Bl -column "LIBDER_NORMALIZE_CONSTRUCTED" +.It LIBDER_NORMALIZE_CONSTRUCTED Ta Coalesce types that may be primitive or constructed +.It LIBDER_NORMALIZE_TAGS Ta Pack tags into the lowest possible encoded value +.El +.Pp +The +.Fn LIBDER_NORMALIZE_TYPE_FLAG "enum libder_ber_type" +macaro may also be used to specify normalization of the given universal type. +By default, every valid normalization flag is enabled. +.Pp +The +.Fn libder_get_strict +and +.Fn libder_set_strict +functions may used to check or set the strict read state of the given +.Nm +context. +By default, +.Nm +operates in strict mode and rejects various methods of expressing data that are +valid looking but not strictly conformant. +The +.Va LDE_STRICT_* +constants in +.In libder.h +describe the various scenarios that strict mode may reject. +.Pp +The +.Fn libder_get_verbose +and +.Fn libder_set_verbose +functions may be used to check or set the verbosity of the given +.Nm +context. +This primarily controls how +.Nm +behaves when an error is encountered. +By default, the library will silently set the error state and return. +With a verbosity level of 1, an error will be printed when the error state is +set that contains the string that would be returned by +.Fn libder_get_error . +With a verbosity level of 2, the filename and line within +.Nm +that the error occurred in will be printed, which is primarily intended for +debugging +.Nm . +.Sh SEE ALSO +.Xr libder_obj 3 , +.Xr libder_read 3 , +.Xr libder_type 3 , +.Xr libder_write 3 diff --git a/contrib/libder/libder/libder.c b/contrib/libder/libder/libder.c new file mode 100644 index 000000000000..2d52fedd62bd --- /dev/null +++ b/contrib/libder/libder/libder.c @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "libder_private.h" + +#include <stdlib.h> +#include <unistd.h> + +/* + * Sets up the context, returns NULL on error. + */ +struct libder_ctx * +libder_open(void) +{ + struct libder_ctx *ctx; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return (NULL); + + /* Initialize */ + ctx->error = LDE_NONE; + ctx->buffer_size = 0; + ctx->verbose = 0; + ctx->normalize = LIBDER_NORMALIZE_ALL; + ctx->strict = true; + ctx->abort = 0; + + return (ctx); +} + +void +libder_abort(struct libder_ctx *ctx) +{ + + ctx->abort = 1; +} + +LIBDER_PRIVATE size_t +libder_get_buffer_size(struct libder_ctx *ctx) +{ + + if (ctx->buffer_size == 0) { + long psize; + + psize = sysconf(_SC_PAGESIZE); + if (psize <= 0) + psize = 4096; + + ctx->buffer_size = psize; + } + + return (ctx->buffer_size); +} + +uint64_t +libder_get_normalize(struct libder_ctx *ctx) +{ + + return (ctx->normalize); +} + +/* + * Set the normalization flags; returns the previous value. + */ +uint64_t +libder_set_normalize(struct libder_ctx *ctx, uint64_t nmask) +{ + uint64_t old = ctx->normalize; + + ctx->normalize = (nmask & LIBDER_NORMALIZE_ALL); + return (old); +} + +bool +libder_get_strict(struct libder_ctx *ctx) +{ + + return (ctx->strict); +} + +bool +libder_set_strict(struct libder_ctx *ctx, bool strict) +{ + bool oval = ctx->strict; + + ctx->strict = strict; + return (oval); +} + +int +libder_get_verbose(struct libder_ctx *ctx) +{ + + return (ctx->verbose); +} + +int +libder_set_verbose(struct libder_ctx *ctx, int verbose) +{ + int oval = ctx->verbose; + + ctx->verbose = verbose; + return (oval); +} + +void +libder_close(struct libder_ctx *ctx) +{ + + if (ctx == NULL) + return; + + free(ctx); +} + diff --git a/contrib/libder/libder/libder.h b/contrib/libder/libder/libder.h new file mode 100644 index 000000000000..4d28aa3052ba --- /dev/null +++ b/contrib/libder/libder/libder.h @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> + +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 *); diff --git a/contrib/libder/libder/libder_error.c b/contrib/libder/libder/libder_error.c new file mode 100644 index 000000000000..6ca0acc83e6d --- /dev/null +++ b/contrib/libder/libder/libder_error.c @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <stdio.h> + +#include "libder_private.h" + +#undef libder_set_error + +static const char libder_error_nodesc[] = "[Description not available]"; + +#define DESCRIBE(err, msg) { LDE_ ## err, msg } +static const struct libder_error_desc { + enum libder_error desc_error; + const char *desc_str; +} libder_error_descr[] = { + DESCRIBE(NONE, "No error"), + DESCRIBE(NOMEM, "Out of memory"), + DESCRIBE(INVAL, "Invalid parameter"), + DESCRIBE(SHORTHDR, "Header too short"), + DESCRIBE(BADVARLEN, "Bad variable length encoding"), + DESCRIBE(LONGLEN, "Encoded length too large (8 byte max)"), + DESCRIBE(SHORTDATA, "Payload not available (too short)"), + DESCRIBE(GARBAGE, "Garbage after encoded data"), + DESCRIBE(STREAMERR, "Stream error"), + DESCRIBE(TRUNCVARLEN, "Variable length object truncated"), + DESCRIBE(COALESCE_BADCHILD, "Bad child encountered when coalescing"), + DESCRIBE(BADOBJECT, "Payload not valid for object type"), + DESCRIBE(STRICT_EOC, "Strict: end-of-content violation"), + DESCRIBE(STRICT_TAG, "Strict: tag violation"), + DESCRIBE(STRICT_PVARLEN, "Strict: primitive using indefinite length"), + DESCRIBE(STRICT_BOOLEAN, "Strict: boolean encoded incorrectly"), + DESCRIBE(STRICT_NULL, "Strict: null encoded incorrectly"), + DESCRIBE(STRICT_PRIMITIVE, "Strict: type must be primitive"), + DESCRIBE(STRICT_CONSTRUCTED, "Strict: type must be constructed"), + DESCRIBE(STRICT_BITSTRING, "Strict: malformed constructed bitstring"), +}; + +const char * +libder_get_error(struct libder_ctx *ctx) +{ + const struct libder_error_desc *desc; + + for (size_t i = 0; i < nitems(libder_error_descr); i++) { + desc = &libder_error_descr[i]; + + if (desc->desc_error == ctx->error) + return (desc->desc_str); + } + + return (libder_error_nodesc); +} + +bool +libder_has_error(struct libder_ctx *ctx) +{ + + return (ctx->error != 0); +} + +LIBDER_PRIVATE void +libder_set_error(struct libder_ctx *ctx, int error, const char *file, int line) +{ + ctx->error = error; + + if (ctx->verbose >= 2) { + fprintf(stderr, "%s: [%s:%d]: %s (error %d)\n", + __func__, file, line, libder_get_error(ctx), error); + } else if (ctx->verbose >= 1) { + fprintf(stderr, "%s: %s (error %d)\n", __func__, + libder_get_error(ctx), error); + } +} diff --git a/contrib/libder/libder/libder_obj.3 b/contrib/libder/libder/libder_obj.3 new file mode 100644 index 000000000000..d7e51da1d2fb --- /dev/null +++ b/contrib/libder/libder/libder_obj.3 @@ -0,0 +1,138 @@ +.\" +.\" SPDX-Copyright-Identifier: BSD-2-Clause +.\" +.\" Copyright (C) 2024 Kyle Evans <kevans@FreeBSD.org> +.\" +.Dd March 2, 2024 +.Dt LIBDER_OBJ 3 +.Os +.Sh NAME +.Nm libder_obj , +.Nm libder_obj_alloc , +.Nm libder_obj_alloc_simple , *** 4094 LINES SKIPPED ***