diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/.gitignore | 12 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 41 | ||||
| -rw-r--r-- | tests/fuzz_parallel.c | 111 | ||||
| -rw-r--r-- | tests/fuzz_stream.c | 246 | ||||
| -rw-r--r-- | tests/fuzz_write.c | 79 | ||||
| -rw-r--r-- | tests/fuzzers.h | 40 | ||||
| -rw-r--r-- | tests/make_corpus.c | 137 | ||||
| -rw-r--r-- | tests/repo.priv | bin | 0 -> 64 bytes | |||
| -rw-r--r-- | tests/repo.pub | bin | 0 -> 88 bytes | |||
| -rw-r--r-- | tests/test_common.h | 29 | ||||
| -rw-r--r-- | tests/test_privkey.c | 175 | ||||
| -rw-r--r-- | tests/test_pubkey.c | 143 |
12 files changed, 1013 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 000000000000..075588a81e75 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,12 @@ +CORPUS* +crash-* +leak-* +oom-* +*.log + +fuzz_* +test_* +!*.c +!*.h + +make_corpus diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000000..fc366ab88ed7 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,41 @@ +set(FUZZERS fuzz_parallel fuzz_stream fuzz_write) +set(UTILS ) +set(TESTS test_privkey test_pubkey) + +set(ALL_TESTS ${UTILS} ${TESTS}) + +if(BUILD_FUZZERS) + set(UTILS ${UTILS} make_corpus) + set(ALL_TESTS ${ALL_TESTS} ${FUZZERS} make_corpus) + + foreach(fuzzer IN LISTS FUZZERS) + add_executable(${fuzzer} ${fuzzer}.c) + + target_compile_options(${fuzzer} PUBLIC -fsanitize=fuzzer) + target_link_options(${fuzzer} PUBLIC -fsanitize=fuzzer) + endforeach() + + target_link_options(fuzz_parallel PUBLIC -pthread) +endif() + +foreach(prog IN LISTS UTILS TESTS) + add_executable(${prog} ${prog}.c) +endforeach() + +foreach(prog IN LISTS ALL_TESTS) + target_include_directories(${prog} PRIVATE ${CMAKE_SOURCE_DIR}/libder) + target_link_libraries(${prog} der_static) +endforeach() + +add_custom_command(TARGET test_privkey POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/repo.priv ${CMAKE_CURRENT_BINARY_DIR}/repo.priv) +add_custom_command(TARGET test_pubkey POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/repo.pub ${CMAKE_CURRENT_BINARY_DIR}/repo.pub) + +add_custom_target(check + DEPENDS test_pubkey test_privkey + COMMAND "${CMAKE_CURRENT_BINARY_DIR}/test_pubkey" + COMMAND "${CMAKE_CURRENT_BINARY_DIR}/test_privkey" +) diff --git a/tests/fuzz_parallel.c b/tests/fuzz_parallel.c new file mode 100644 index 000000000000..afd4425970a2 --- /dev/null +++ b/tests/fuzz_parallel.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <assert.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <libder.h> + +#include "fuzzers.h" + +struct fuzz_frame { + uint8_t frame_threads; +}; + +struct thread_input { + const uint8_t *data; + size_t datasz; +}; + +static void * +thread_main(void *cookie) +{ + const struct thread_input *input = cookie; + struct libder_ctx *ctx; + struct libder_object *obj; + const uint8_t *data = input->data; + size_t readsz, sz = input->datasz; + + ctx = libder_open(); + readsz = sz; + obj = libder_read(ctx, data, &readsz); + if (obj == NULL || readsz != sz) + goto out; + + if (obj != NULL) { + uint8_t *buf = NULL; + size_t bufsz = 0; + + /* + * If we successfully read it, then it shouldn't + * overflow. We're letting libder allocate the buffer, + * so we shouldn't be able to hit the 'too small' bit. + * + * I can't imagine what other errors might happen, so + * we'll just assert on it. + */ + buf = libder_write(ctx, obj, buf, &bufsz); + if (buf == NULL) + goto out; + + assert(bufsz != 0); + + free(buf); + } + +out: + libder_obj_free(obj); + libder_close(ctx); + return (NULL); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) +{ + const struct fuzz_frame *frame; + pthread_t *threads; + struct thread_input inp; + size_t nthreads; + + if (sz <= sizeof(*frame)) + return (-1); + + frame = (const void *)data; + data += sizeof(*frame); + sz -= sizeof(*frame); + + if (frame->frame_threads < 2) + return (-1); + + threads = malloc(sizeof(*threads) * frame->frame_threads); + if (threads == NULL) + return (-1); + + inp.data = data; + inp.datasz = sz; + + for (nthreads = 0; nthreads < frame->frame_threads; nthreads++) { + if (pthread_create(&threads[nthreads], NULL, thread_main, + &inp) != 0) + break; + } + + for (uint8_t i = 0; i < nthreads; i++) + pthread_join(threads[i], NULL); + + free(threads); + + return (0); +} diff --git a/tests/fuzz_stream.c b/tests/fuzz_stream.c new file mode 100644 index 000000000000..0f7cc6167e7e --- /dev/null +++ b/tests/fuzz_stream.c @@ -0,0 +1,246 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <assert.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> + +#include <libder.h> + +#include "fuzzers.h" + +struct supply_data { + const uint8_t *data; + volatile size_t datasz; + int socket; +}; + +static void * +supply_thread(void *data) +{ + struct supply_data *sdata = data; + size_t sz = sdata->datasz; + ssize_t writesz; + + do { + writesz = write(sdata->socket, sdata->data, sz); + + data += writesz; + sz -= writesz; + } while (sz != 0 && writesz > 0); + + sdata->datasz = sz; + shutdown(sdata->socket, SHUT_RDWR); + close(sdata->socket); + + return (NULL); +} + +static int +fuzz_fd(const struct fuzz_params *fparams, const uint8_t *data, size_t sz) +{ + struct supply_data sdata; + struct libder_ctx *ctx; + struct libder_object *obj; + size_t totalsz; + int sockets[2]; + pid_t pid; + int ret; + + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, + &sockets[0]); + if (ret == -1) + return (-1); + + sdata.data = data; + sdata.datasz = sz; + sdata.socket = sockets[1]; + signal(SIGCHLD, SIG_IGN); + pid = fork(); + if (pid == -1) { + close(sockets[0]); + close(sockets[1]); + return (-1); + } + + if (pid == 0) { + close(sockets[0]); + supply_thread(&sdata); + _exit(0); + } else { + close(sockets[1]); + } + + totalsz = 0; + ret = 0; + ctx = libder_open(); + libder_set_strict(ctx, !!fparams->strict); + while (totalsz < sz) { + size_t readsz = 0; + + obj = libder_read_fd(ctx, sockets[0], &readsz); + libder_obj_free(obj); + + /* + * Even invalid reads should consume at least one byte. + */ + assert(readsz != 0); + + totalsz += readsz; + if (readsz == 0) + break; + } + + assert(totalsz == sz); + libder_close(ctx); + close(sockets[0]); + + return (ret); +} + +static int +fuzz_file(const struct fuzz_params *fparams, const uint8_t *data, size_t sz) +{ + FILE *fp; + struct libder_ctx *ctx; + struct libder_object *obj; + size_t totalsz; + int ret; + + if (fparams->buftype >= BUFFER_END) + return (-1); + + fp = fmemopen(__DECONST(void *, data), sz, "rb"); + assert(fp != NULL); + + switch (fparams->buftype) { + case BUFFER_NONE: + setvbuf(fp, NULL, 0, _IONBF); + break; + case BUFFER_FULL: + setvbuf(fp, NULL, 0, _IOFBF); + break; + case BUFFER_END: + assert(0); + } + + totalsz = 0; + ret = 0; + ctx = libder_open(); + libder_set_strict(ctx, !!fparams->strict); + while (!feof(fp)) { + size_t readsz = 0; + + obj = libder_read_file(ctx, fp, &readsz); + libder_obj_free(obj); + + if (obj == NULL) + assert(readsz != 0 || feof(fp)); + else + assert(readsz != 0); + + totalsz += readsz; + } + + assert(totalsz == sz); + libder_close(ctx); + fclose(fp); + + return (ret); +} + +static int +fuzz_plain(const struct fuzz_params *fparams, const uint8_t *data, size_t sz) +{ + struct libder_ctx *ctx; + struct libder_object *obj; + int ret; + + if (sz == 0) + return (-1); + + ret = 0; + ctx = libder_open(); + libder_set_strict(ctx, !!fparams->strict); + do { + size_t readsz; + + readsz = sz; + obj = libder_read(ctx, data, &readsz); + libder_obj_free(obj); + + if (obj == NULL) + assert(readsz != 0 || readsz == sz); + else + assert(readsz != 0); + + /* + * If we hit an entirely invalid segment of the buffer, we'll + * just skip a byte and try again. + */ + data += MAX(1, readsz); + sz -= MAX(1, readsz); + } while (sz != 0); + + libder_close(ctx); + + return (ret); +}; + +static bool +validate_padding(const struct fuzz_params *fparams) +{ + const uint8_t *end = (const void *)(fparams + 1); + const uint8_t *pad = (const uint8_t *)&fparams->PARAM_PAD_START; + + while (pad < end) { + if (*pad++ != 0) + return (false); + } + + return (true); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) +{ + const struct fuzz_params *fparams; + + if (sz <= sizeof(*fparams)) + return (-1); + + fparams = (const void *)data; + if (fparams->type >= STREAM_END) + return (-1); + + if (!validate_padding(fparams)) + return (-1); + + data += sizeof(*fparams); + sz -= sizeof(*fparams); + + if (fparams->type != STREAM_FILE && fparams->buftype != BUFFER_NONE) + return (-1); + + switch (fparams->type) { + case STREAM_FD: + return (fuzz_fd(fparams, data, sz)); + case STREAM_FILE: + return (fuzz_file(fparams, data, sz)); + case STREAM_PLAIN: + return (fuzz_plain(fparams, data, sz)); + case STREAM_END: + assert(0); + } + + __builtin_trap(); +} diff --git a/tests/fuzz_write.c b/tests/fuzz_write.c new file mode 100644 index 000000000000..2ad5b5eb1764 --- /dev/null +++ b/tests/fuzz_write.c @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/socket.h> + +#include <assert.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <libder.h> + +#include "fuzzers.h" + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) +{ + struct libder_ctx *ctx; + struct libder_object *obj; + size_t readsz; + int ret; + bool strict; + + if (sz < 2) + return (-1); + + /* + * I worked this in originally by just using the high bit of the first + * byte, but then I realized that encoding it that way would make it + * impossible to get strict validation of universal and application + * tags. The former is a bit more important than the latter. + */ + strict = !!data[0]; + data++; + sz--; + + ctx = libder_open(); + libder_set_strict(ctx, strict); + ret = -1; + readsz = sz; + obj = libder_read(ctx, data, &readsz); + if (obj == NULL || readsz != sz) + goto out; + + if (obj != NULL) { + uint8_t *buf = NULL; + size_t bufsz = 0; + + /* + * If we successfully read it, then it shouldn't + * overflow. We're letting libder allocate the buffer, + * so we shouldn't be able to hit the 'too small' bit. + * + * I can't imagine what other errors might happen, so + * we'll just assert on it. + */ + buf = libder_write(ctx, obj, buf, &bufsz); + if (buf == NULL) + goto out; + + assert(bufsz != 0); + + free(buf); + } + + ret = 0; + +out: + libder_obj_free(obj); + libder_close(ctx); + + return (ret); +} diff --git a/tests/fuzzers.h b/tests/fuzzers.h new file mode 100644 index 000000000000..0f94bc7f25fb --- /dev/null +++ b/tests/fuzzers.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <stdint.h> + +enum stream_type { + STREAM_FD = 0, /* read_fd() type */ + STREAM_FILE = 1, /* read_file() type */ + STREAM_PLAIN = 2, + + STREAM_END +} __attribute__((packed)); + +enum stream_buffer { + BUFFER_NONE = 0, + BUFFER_FULL = 1, + + BUFFER_END, +} __attribute__((packed)); + +struct fuzz_params { + enum stream_type type; + enum stream_buffer buftype; + +#define PARAM_PAD_START _pad0 + uint8_t strict; + uint8_t _pad0[5]; + + /* Give me plenty of padding. */ + uint64_t padding[3]; +}; + +_Static_assert(sizeof(struct fuzz_params) == 32, + "fuzz_params ABI broken, will invalidate CORPUS"); + diff --git a/tests/make_corpus.c b/tests/make_corpus.c new file mode 100644 index 000000000000..68554d7c17de --- /dev/null +++ b/tests/make_corpus.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> + +#undef NDEBUG +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <libder.h> + +#include "fuzzers.h" + +#define LARGE_SIZE (1024 * 64) + +static const uint8_t empty_seq[] = { BT_SEQUENCE, 0x00 }; +static const uint8_t long_size[21] = { BT_OCTETSTRING, 0x83, 0x00, 0x00, 0x10 }; + +/* 64k */ +#define LARGE_SIZE_ENCODING 0x83, 0x01, 0x00, 0x00 +static const uint8_t large_octet[LARGE_SIZE + 5] = { BT_OCTETSTRING, LARGE_SIZE_ENCODING }; + +#define VARLEN_SEQ BT_OCTETSTRING, 0x04, 0x01, 0x02, 0x03, 0x04 +#define VARLEN_CHILDREN VARLEN_SEQ, VARLEN_SEQ, VARLEN_SEQ +static const uint8_t varlen[] = { BT_SEQUENCE, 0x80, + VARLEN_CHILDREN, 0x00, 0x00 }; + +#define BITSTRING1 BT_BITSTRING, 0x04, 0x03, 0xc0, 0xc0, 0xcc +#define BITSTRING2 BT_BITSTRING, 0x04, 0x05, 0xdd, 0xdd, 0xff +static const uint8_t constructed_bitstring[] = { 0x20 | BT_BITSTRING, + 2 * 6, BITSTRING1, BITSTRING2 }; + +#define FUZZER_SEED(seq) { #seq, sizeof(seq), seq } +static const struct seed { + const char *seed_name; + size_t seed_seqsz; + const uint8_t *seed_seq; +} seeds[] = { + FUZZER_SEED(empty_seq), + FUZZER_SEED(long_size), + FUZZER_SEED(large_octet), + FUZZER_SEED(varlen), + FUZZER_SEED(constructed_bitstring), +}; + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-H] <corpus-dir>\n", getprogname()); + exit(1); +} + +static void +write_one(const struct fuzz_params *params, const struct seed *seed, int dirfd, + bool striphdr) +{ + char *name; + int fd = -1; + + assert(asprintf(&name, "base_%d_%d_%d_%s", params->type, + params->buftype, params->strict, seed->seed_name) != -1); + + fd = openat(dirfd, name, O_RDWR | O_TRUNC | O_CREAT, 0644); + assert(fd != -1); + + /* + * Write our params + seed; if we're stripping the header we won't have + * the full params, but we'll still have our signal byte for strict + * mode. + */ + if (!striphdr) + assert(write(fd, ¶ms, sizeof(params)) == sizeof(params)); + else + assert(write(fd, ¶ms->strict, sizeof(params->strict)) == sizeof(params->strict)); + + assert(write(fd, seed->seed_seq, seed->seed_seqsz) == seed->seed_seqsz); + + free(name); + close(fd); +} + +int +main(int argc, char *argv[]) +{ + struct fuzz_params params; + const struct seed *seed; + const char *seed_dir; + int dirfd = -1; + bool striphdr = false; + + if (argc < 2 || argc > 3) + usage(); + + if (argc == 3 && strcmp(argv[1], "-H") != 0) + usage(); + + striphdr = argc == 3; + seed_dir = argv[argc - 1]; + + dirfd = open(seed_dir, O_SEARCH); + if (dirfd == -1) + err(1, "%s: open", seed_dir); + + memset(¶ms, 0, sizeof(params)); + + for (int type = 0; type < STREAM_END; type++) { + params.type = type; + + for (int buffered = 0; buffered < BUFFER_END; buffered++) { + params.buftype = buffered; + + for (uint8_t strict = 0; strict < 2; strict++) { + params.strict = strict; + + for (size_t i = 0; i < nitems(seeds); i++) { + seed = &seeds[i]; + + write_one(¶ms, seed, dirfd, striphdr); + } + } + + if (type != STREAM_FILE) + break; + } + } + + close(dirfd); +} diff --git a/tests/repo.priv b/tests/repo.priv Binary files differnew file mode 100644 index 000000000000..74a030b6802c --- /dev/null +++ b/tests/repo.priv diff --git a/tests/repo.pub b/tests/repo.pub Binary files differnew file mode 100644 index 000000000000..bdcb1a20a1c7 --- /dev/null +++ b/tests/repo.pub diff --git a/tests/test_common.h b/tests/test_common.h new file mode 100644 index 000000000000..76e850f19128 --- /dev/null +++ b/tests/test_common.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <assert.h> +#include <fcntl.h> +#include <libgen.h> +#include <limits.h> +#include <stdlib.h> + +static inline int +open_progdir(const char *prog) +{ + char pdir[PATH_MAX], *resolved; + int dfd; + + resolved = realpath(prog, &pdir[0]); + assert(resolved != NULL); + + resolved = dirname(&pdir[0]); + assert(resolved != NULL); + + dfd = open(resolved, O_DIRECTORY); + assert(dfd != -1); + + return (dfd); +} diff --git a/tests/test_privkey.c b/tests/test_privkey.c new file mode 100644 index 000000000000..5e7519f5a715 --- /dev/null +++ b/tests/test_privkey.c @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <libder.h> + +#include "test_common.h" + +/* + * Note that the choice of secp112r1 is completely arbitrary. I was mainly + * shooting for something pretty weak to avoid people trying to "catch me" + * checking in private key material, even though it's very incredibly clearly + * just for a test case. + */ +static const uint8_t oid_secp112r1[] = + { 0x2b, 0x81, 0x04, 0x00, 0x06 }; + +static const uint8_t privdata[] = { 0xa5, 0xf5, 0x2a, 0x56, 0x61, 0xe3, 0x58, + 0x76, 0x5c, 0x4f, 0xd6, 0x8d, 0x60, 0x54 }; + +static const uint8_t pubdata[] = { 0x00, 0x04, 0xae, 0x69, 0x41, 0x0d, 0x9c, + 0x9b, 0xf2, 0x34, 0xf6, 0x2d, 0x7c, 0x91, 0xe1, 0xc7, 0x7f, 0x23, 0xa0, + 0x84, 0x34, 0x5c, 0x38, 0x26, 0xd8, 0xcf, 0xbe, 0xf7, 0xdc, 0x8a }; + +static void +test_interface(struct libder_object *root) +{ + const uint8_t *data; + size_t datasz; + struct libder_object *keystring, *oid; + + /* Grab the oid first. */ + oid = libder_obj_child(root, 2); + assert(oid != NULL); /* Actually just the container... */ + assert(libder_obj_type_simple(oid) == 0xa0); + + oid = libder_obj_child(oid, 0); + assert(oid != NULL); /* Now *that*'s an OID. */ + assert(libder_obj_type_simple(oid) == BT_OID); + data = libder_obj_data(oid, &datasz); + assert(datasz == sizeof(oid_secp112r1)); + assert(memcmp(oid_secp112r1, data, datasz) == 0); + + keystring = libder_obj_child(root, 1); + assert(keystring != NULL); + assert(libder_obj_type_simple(keystring) == BT_OCTETSTRING); + + data = libder_obj_data(keystring, &datasz); + assert(datasz == sizeof(privdata)); + assert(memcmp(privdata, data, datasz) == 0); +} + +/* buf and bufszs are just our reference */ +static void +test_construction(struct libder_ctx *ctx, const uint8_t *buf, size_t bufsz) +{ + uint8_t *out; + struct libder_object *obj, *oidp, *pubp, *root; + struct libder_object *keystring; + size_t outsz; + uint8_t data; + + root = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0); + assert(root != NULL); + + data = 1; + obj = libder_obj_alloc_simple(ctx, BT_INTEGER, &data, 1); + assert(obj != NULL); + assert(libder_obj_append(root, obj)); + + /* Private key material */ + obj = libder_obj_alloc_simple(ctx, BT_OCTETSTRING, privdata, sizeof(privdata)); + assert(obj != NULL); + assert(libder_obj_append(root, obj)); + + /* Now throw in the OID and pubkey containers */ + oidp = libder_obj_alloc_simple(ctx, + (BC_CONTEXT << 6) | BER_TYPE_CONSTRUCTED_MASK | 0, NULL, 0); + assert(oidp != NULL); + assert(libder_obj_append(root, oidp)); + + pubp = libder_obj_alloc_simple(ctx, + (BC_CONTEXT << 6) | BER_TYPE_CONSTRUCTED_MASK | 1, NULL, 0); + assert(pubp != NULL); + assert(libder_obj_append(root, pubp)); + + /* Actually add the OID */ + obj = libder_obj_alloc_simple(ctx, BT_OID, oid_secp112r1, sizeof(oid_secp112r1)); + assert(obj != NULL); + assert(libder_obj_append(oidp, obj)); + + /* Finally, add the pubkey */ + obj = libder_obj_alloc_simple(ctx, BT_BITSTRING, pubdata, sizeof(pubdata)); + assert(obj != NULL); + assert(libder_obj_append(pubp, obj)); + + out = NULL; + outsz = 0; + out = libder_write(ctx, root, out, &outsz); + assert(out != NULL); + assert(outsz == bufsz); + + assert(memcmp(out, buf, bufsz) == 0); + + libder_obj_free(root); + free(out); +} + +int +main(int argc, char *argv[]) +{ + struct stat sb; + struct libder_ctx *ctx; + struct libder_object *root; + uint8_t *buf, *out; + size_t bufsz, outsz, rootsz; + ssize_t readsz; + int dfd, error, fd; + + dfd = open_progdir(argv[0]); + + fd = openat(dfd, "repo.priv", O_RDONLY); + assert(fd >= 0); + + close(dfd); + dfd = -1; + + error = fstat(fd, &sb); + assert(error == 0); + + bufsz = sb.st_size; + buf = malloc(bufsz); + assert(buf != NULL); + + readsz = read(fd, buf, bufsz); + close(fd); + + assert(readsz == bufsz); + + ctx = libder_open(); + rootsz = bufsz; + libder_set_verbose(ctx, 2); + root = libder_read(ctx, buf, &rootsz); + + assert(root != NULL); + assert(rootsz == bufsz); + + test_interface(root); + test_construction(ctx, buf, bufsz); + + outsz = 0; + out = NULL; + out = libder_write(ctx, root, out, &outsz); + assert(out != NULL); + assert(outsz == bufsz); + + assert(memcmp(buf, out, outsz) == 0); + + free(out); + free(buf); + libder_obj_free(root); + libder_close(ctx); +} diff --git a/tests/test_pubkey.c b/tests/test_pubkey.c new file mode 100644 index 000000000000..9fbd070f0e87 --- /dev/null +++ b/tests/test_pubkey.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <libder.h> + +#include "test_common.h" + +static const uint8_t oid_ecpubkey[] = + { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 }; +static const uint8_t oid_secp256k1[] = + { 0x2b, 0x81, 0x04, 0x00, 0x0a }; + +static const uint8_t pubdata[] = { 0x00, 0x04, 0xd1, 0x76, 0x20, 0x39, 0xe5, 0x3e, + 0x67, 0x7d, 0x8d, 0xfd, 0xc4, 0x21, 0x20, 0xcd, 0xb0, 0xbf, 0x47, 0x87, 0x6a, + 0xf8, 0x07, 0x73, 0xbe, 0xbe, 0xd5, 0xbb, 0x3c, 0xbc, 0x32, 0x93, 0xd9, 0xdf, + 0x96, 0x25, 0xb7, 0x0e, 0x3c, 0x55, 0x12, 0xee, 0x7a, 0x02, 0x39, 0x0f, 0xee, + 0x7b, 0xfe, 0x1a, 0x93, 0x76, 0xf7, 0xc2, 0xac, 0x05, 0xba, 0x9a, 0x83, 0x37, + 0xf5, 0xcd, 0x55, 0x57, 0x39, 0x6f }; + +static void +test_interface(struct libder_object *root) +{ + const uint8_t *data; + size_t datasz; + struct libder_object *keystring; + + keystring = libder_obj_child(root, 1); + assert(keystring != NULL); + assert(libder_obj_type_simple(keystring) == BT_BITSTRING); + + data = libder_obj_data(keystring, &datasz); + assert(datasz == sizeof(pubdata)); + assert(memcmp(pubdata, data, datasz) == 0); +} + +/* buf and bufszs are just our reference */ +static void +test_construction(struct libder_ctx*ctx, const uint8_t *buf, size_t bufsz) +{ + uint8_t *out; + struct libder_object *obj, *params, *root; + struct libder_object *keystring; + size_t outsz; + + root = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0); + assert(root != NULL); + + params = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0); + assert(params != NULL); + assert(libder_obj_append(root, params)); + + keystring = libder_obj_alloc_simple(ctx, BT_BITSTRING, pubdata, sizeof(pubdata)); + assert(keystring != NULL); + assert(libder_obj_append(root, keystring)); + + /* Now go back and build the two params, id and curve */ + obj = libder_obj_alloc_simple(ctx, BT_OID, oid_ecpubkey, sizeof(oid_ecpubkey)); + assert(obj != NULL); + assert(libder_obj_append(params, obj)); + + obj = libder_obj_alloc_simple(ctx, BT_OID, oid_secp256k1, sizeof(oid_secp256k1)); + assert(obj != NULL); + assert(libder_obj_append(params, obj)); + + out = NULL; + outsz = 0; + out = libder_write(ctx, root, out, &outsz); + assert(out != NULL); + assert(outsz == bufsz); + assert(memcmp(out, buf, bufsz) == 0); + + libder_obj_free(root); + free(out); +} + +int +main(int argc, char *argv[]) +{ + struct stat sb; + struct libder_ctx *ctx; + struct libder_object *root; + uint8_t *buf, *out; + size_t bufsz, outsz, rootsz; + ssize_t readsz; + int dfd, error, fd; + + dfd = open_progdir(argv[0]); + + fd = openat(dfd, "repo.pub", O_RDONLY); + assert(fd >= 0); + + close(dfd); + dfd = -1; + + error = fstat(fd, &sb); + assert(error == 0); + + bufsz = sb.st_size; + buf = malloc(bufsz); + assert(buf != NULL); + + readsz = read(fd, buf, bufsz); + close(fd); + + assert(readsz == bufsz); + + ctx = libder_open(); + rootsz = bufsz; + libder_set_verbose(ctx, 2); + root = libder_read(ctx, buf, &rootsz); + + assert(root != NULL); + assert(rootsz == bufsz); + + test_interface(root); + test_construction(ctx, buf, bufsz); + + outsz = 0; + out = NULL; + out = libder_write(ctx, root, out, &outsz); + assert(out != NULL); + assert(outsz == bufsz); + + assert(memcmp(buf, out, outsz) == 0); + + free(out); + free(buf); + libder_obj_free(root); + libder_close(ctx); +} |
