summaryrefslogtreecommitdiffstats
path: root/src/libdnssec/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdnssec/shared')
-rw-r--r--src/libdnssec/shared/bignum.c64
-rw-r--r--src/libdnssec/shared/bignum.h41
-rw-r--r--src/libdnssec/shared/binary_wire.h53
-rw-r--r--src/libdnssec/shared/dname.c165
-rw-r--r--src/libdnssec/shared/dname.h57
-rw-r--r--src/libdnssec/shared/keyid_gnutls.c99
-rw-r--r--src/libdnssec/shared/keyid_gnutls.h30
-rw-r--r--src/libdnssec/shared/shared.h121
8 files changed, 630 insertions, 0 deletions
diff --git a/src/libdnssec/shared/bignum.c b/src/libdnssec/shared/bignum.c
new file mode 100644
index 0000000..3b347a6
--- /dev/null
+++ b/src/libdnssec/shared/bignum.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "libdnssec/shared/bignum.h"
+
+static void skip_leading_zeroes(dnssec_binary_t *value)
+{
+ while (value->size > 0 && value->data[0] == 0) {
+ value->data += 1;
+ value->size -= 1;
+ }
+}
+
+size_t bignum_size_u(const dnssec_binary_t *_value)
+{
+ dnssec_binary_t value = *_value;
+ skip_leading_zeroes(&value);
+
+ if (value.size == 0) {
+ return value.size + 1;
+ } else {
+ return value.size;
+ }
+}
+
+size_t bignum_size_s(const dnssec_binary_t *_value)
+{
+ dnssec_binary_t value = *_value;
+ skip_leading_zeroes(&value);
+
+ if (value.size == 0 || value.data[0] & 0x80) {
+ return value.size + 1;
+ } else {
+ return value.size;
+ }
+}
+
+void bignum_write(wire_ctx_t *ctx, size_t width, const dnssec_binary_t *_value)
+{
+ dnssec_binary_t value = *_value;
+ skip_leading_zeroes(&value);
+
+ size_t padding_len = width - value.size;
+ if (padding_len > 0) {
+ wire_ctx_clear(ctx, padding_len);
+ }
+ wire_ctx_write(ctx, value.data, value.size);
+}
diff --git a/src/libdnssec/shared/bignum.h b/src/libdnssec/shared/bignum.h
new file mode 100644
index 0000000..e4ddede
--- /dev/null
+++ b/src/libdnssec/shared/bignum.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+
+#include "libdnssec/binary.h"
+#include "contrib/wire_ctx.h"
+
+/*!
+ * Size needed to write unsigned number in unsigned encoding.
+ */
+size_t bignum_size_u(const dnssec_binary_t *value);
+
+/*!
+ * Size needed to write unsigned number in signed encoding.
+ *
+ * Signed encoding expects the MSB to be zero.
+ */
+size_t bignum_size_s(const dnssec_binary_t *value);
+
+/*!
+ * Write unsigned number on a fixed width in a big-endian byte order.
+ *
+ * The destination size has to be set properly to accommodate used encoding.
+ */
+void bignum_write(wire_ctx_t *ctx, size_t width, const dnssec_binary_t *value);
diff --git a/src/libdnssec/shared/binary_wire.h b/src/libdnssec/shared/binary_wire.h
new file mode 100644
index 0000000..807cfc6
--- /dev/null
+++ b/src/libdnssec/shared/binary_wire.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+
+#include "contrib/wire_ctx.h"
+#include "libdnssec/binary.h"
+
+static inline wire_ctx_t binary_init(const dnssec_binary_t *binary)
+{
+ assert(binary);
+
+ return wire_ctx_init(binary->data, binary->size);
+}
+
+static inline void binary_read(wire_ctx_t *ctx, dnssec_binary_t *data)
+{
+ assert(data);
+
+ wire_ctx_read(ctx, data->data, data->size);
+}
+
+static inline void binary_available(wire_ctx_t *ctx, dnssec_binary_t *data)
+{
+ assert(ctx);
+ assert(data);
+
+ data->data = ctx->position;
+ data->size = wire_ctx_available(ctx);
+}
+
+static inline void binary_write(wire_ctx_t *ctx, const dnssec_binary_t *data)
+{
+ assert(ctx);
+ assert(data);
+
+ wire_ctx_write(ctx, data->data, data->size);
+}
diff --git a/src/libdnssec/shared/dname.c b/src/libdnssec/shared/dname.c
new file mode 100644
index 0000000..61a5034
--- /dev/null
+++ b/src/libdnssec/shared/dname.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libdnssec/shared/dname.h"
+#include "libdnssec/shared/shared.h"
+#include "contrib/tolower.h"
+
+/*!
+ * Get length of a domain name in wire format.
+ */
+size_t dname_length(const uint8_t *dname)
+{
+ if (!dname) {
+ return 0;
+ }
+
+ const uint8_t *scan = dname;
+ uint8_t label_len;
+ do {
+ label_len = *scan;
+ scan += 1 + label_len;
+ } while (label_len > 0);
+ assert(scan > dname);
+
+ size_t length = scan - dname;
+ if (length > DNAME_MAX_LENGTH) {
+ return 0;
+ }
+
+ return length;
+}
+
+/*!
+ * Copy domain name in wire format.
+ */
+uint8_t *dname_copy(const uint8_t *dname)
+{
+ if (!dname) {
+ return NULL;
+ }
+
+ size_t length = dname_length(dname);
+ if (length == 0) {
+ return NULL;
+ }
+
+ uint8_t *copy = malloc(length);
+ if (!copy) {
+ return NULL;
+ }
+
+ memmove(copy, dname, length);
+ return copy;
+}
+
+/*!
+ * Normalize dname label in-place.
+ *
+ * \return Number of processed bytes, 0 if we encounter the last label.
+ */
+static uint8_t normalize_label(uint8_t *label)
+{
+ assert(label);
+
+ uint8_t len = *label;
+ if (len == 0 || len > DNAME_MAX_LABEL_LENGTH) {
+ return 0;
+ }
+
+ for (uint8_t *scan = label + 1, *end = scan + len; scan < end; scan++) {
+ *scan = knot_tolower(*scan);
+ }
+
+ return len + 1;
+}
+
+/*!
+ * Normalize domain name in wire format.
+ */
+void dname_normalize(uint8_t *dname)
+{
+ if (!dname) {
+ return;
+ }
+
+ uint8_t read, *scan = dname;
+ do {
+ read = normalize_label(scan);
+ scan += read;
+ } while (read > 0);
+}
+
+/*!
+ * Compare dname labels case insensitively.
+ */
+static int label_casecmp(const uint8_t *a, const uint8_t *b, uint8_t len)
+{
+ assert(a);
+ assert(b);
+
+ for (const uint8_t *a_end = a + len; a < a_end; a++, b++) {
+ if (knot_tolower(*a) != knot_tolower(*b)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * Check if two dnames are equal.
+ */
+bool dname_equal(const uint8_t *one, const uint8_t *two)
+{
+ if (!one || !two) {
+ return false;
+ }
+
+ const uint8_t *scan_one = one;
+ const uint8_t *scan_two = two;
+
+ for (;;) {
+ if (*scan_one != *scan_two) {
+ return false;
+ }
+
+ uint8_t len = *scan_one;
+ if (len == 0) {
+ return true;
+ } else if (len > DNAME_MAX_LABEL_LENGTH) {
+ return false;
+ }
+
+ scan_one += 1;
+ scan_two += 1;
+
+ if (!label_casecmp(scan_one, scan_two, len)) {
+ return false;
+ }
+
+ scan_one += len;
+ scan_two += len;
+ }
+
+ return true;
+}
diff --git a/src/libdnssec/shared/dname.h b/src/libdnssec/shared/dname.h
new file mode 100644
index 0000000..15e4e2a
--- /dev/null
+++ b/src/libdnssec/shared/dname.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*!
+ * Maximal length of domain name including labels and length bytes.
+ * \see RFC 1035
+ */
+#define DNAME_MAX_LENGTH 255
+
+/*!
+ * Maximal length of the domain name label, excluding the label size.
+ * \see RFC 1035
+ */
+#define DNAME_MAX_LABEL_LENGTH 63
+
+/*!
+ * Get length of a domain name in wire format.
+ */
+size_t dname_length(const uint8_t *dname);
+
+/*!
+ * Copy domain name in wire format.
+ */
+uint8_t *dname_copy(const uint8_t *dname);
+
+/*!
+ * Normalize domain name in wire format.
+ *
+ * Currently converts all letters to lowercase.
+ */
+void dname_normalize(uint8_t *dname);
+
+/*!
+ * Check if two dnames are equal.
+ *
+ * Case insensitive.
+ */
+bool dname_equal(const uint8_t *one, const uint8_t *two);
diff --git a/src/libdnssec/shared/keyid_gnutls.c b/src/libdnssec/shared/keyid_gnutls.c
new file mode 100644
index 0000000..eee27d3
--- /dev/null
+++ b/src/libdnssec/shared/keyid_gnutls.c
@@ -0,0 +1,99 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <string.h>
+
+#include "contrib/string.h"
+#include "libdnssec/binary.h"
+#include "libdnssec/error.h"
+#include "libdnssec/keyid.h"
+#include "libdnssec/shared/keyid_gnutls.h"
+#include "libdnssec/shared/shared.h"
+
+/*!
+ * Get binary key ID from a key (public or private).
+ */
+static int keyid_bin(gnutls_x509_privkey_t key, gnutls_pubkey_t pubkey, dnssec_binary_t *id)
+{
+ assert(key || pubkey);
+ assert(id);
+
+ // Flags can be used to enable SHA-2 since GnuTLS 3.4.7.
+
+ int flags = 0;
+ uint8_t buffer[DNSSEC_KEYID_BINARY_SIZE];
+ size_t size = DNSSEC_KEYID_SIZE;
+
+ int r = key ? gnutls_x509_privkey_get_key_id(key, flags, buffer, &size)
+ : gnutls_pubkey_get_key_id(pubkey, flags, buffer, &size);
+
+ if (r != GNUTLS_E_SUCCESS || size != DNSSEC_KEYID_BINARY_SIZE) {
+ return DNSSEC_INVALID_KEY_ID;
+ }
+
+ assert(size == DNSSEC_KEYID_BINARY_SIZE);
+ r = dnssec_binary_resize(id, size);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ memcpy(id->data, buffer, size);
+
+ return DNSSEC_EOK;
+}
+
+/*!
+ * Get hexadecimal key ID from a key (public or private).
+ */
+static int keyid_hex(gnutls_x509_privkey_t key, gnutls_pubkey_t pubkey, char **id)
+{
+ _cleanup_binary_ dnssec_binary_t bin = { 0 };
+ int r = keyid_bin(key, pubkey, &bin);
+ if (r != DNSSEC_EOK) {
+ return r;
+ }
+
+ *id = bin_to_hex(bin.data, bin.size, false);
+ if (*id == NULL) {
+ return DNSSEC_ENOMEM;
+ }
+
+ return DNSSEC_EOK;
+}
+
+int keyid_x509(gnutls_x509_privkey_t key, dnssec_binary_t *id)
+{
+ return keyid_bin(key, NULL, id);
+}
+
+int keyid_x509_hex(gnutls_x509_privkey_t key, char **id)
+{
+ return keyid_hex(key, NULL, id);
+}
+
+int keyid_pubkey(gnutls_pubkey_t pubkey, dnssec_binary_t *id)
+{
+ return keyid_bin(NULL, pubkey, id);
+}
+
+int keyid_pubkey_hex(gnutls_pubkey_t pubkey, char **id)
+{
+ return keyid_hex(NULL, pubkey, id);
+}
diff --git a/src/libdnssec/shared/keyid_gnutls.h b/src/libdnssec/shared/keyid_gnutls.h
new file mode 100644
index 0000000..356e62e
--- /dev/null
+++ b/src/libdnssec/shared/keyid_gnutls.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+
+#include "libdnssec/binary.h"
+
+int keyid_x509(gnutls_x509_privkey_t key, dnssec_binary_t *id);
+
+int keyid_x509_hex(gnutls_x509_privkey_t key, char **id);
+
+int keyid_pubkey(gnutls_pubkey_t pubkey, dnssec_binary_t *id);
+
+int keyid_pubkey_hex(gnutls_pubkey_t pubkey, char **id);
diff --git a/src/libdnssec/shared/shared.h b/src/libdnssec/shared/shared.h
new file mode 100644
index 0000000..1cde2d1
--- /dev/null
+++ b/src/libdnssec/shared/shared.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gnutls/abstract.h>
+#include <gnutls/crypto.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "libdnssec/binary.h"
+#include "libknot/attribute.h"
+
+/*!
+ * Macro to clear a structure of known size.
+ *
+ * \param pointer Pointer to the structure.
+ */
+#define clear_struct(pointer) memset((pointer), '\0', sizeof(*(pointer)))
+
+/* -- cleanup macros ------------------------------------------------------- */
+
+static inline void free_ptr(void *ptr)
+{
+ free(*(void **)ptr);
+}
+
+static inline void close_ptr(int *ptr)
+{
+ if (*ptr != -1) {
+ close(*ptr);
+ }
+}
+
+static inline void fclose_ptr(FILE **ptr)
+{
+ if (*ptr) {
+ fclose(*ptr);
+ }
+}
+
+static inline void closedir_ptr(DIR **ptr)
+{
+ if (*ptr) {
+ closedir(*ptr);
+ }
+}
+
+static inline void free_gnutls_datum_ptr(gnutls_datum_t *ptr)
+{
+ gnutls_free(ptr->data);
+}
+
+static inline void free_x509_privkey_ptr(gnutls_x509_privkey_t *ptr)
+{
+ if (*ptr) {
+ gnutls_x509_privkey_deinit(*ptr);
+ }
+}
+
+static inline void free_pubkey_ptr(gnutls_pubkey_t *ptr)
+{
+ if (*ptr) {
+ gnutls_pubkey_deinit(*ptr);
+ }
+}
+
+static inline void free_gnutls_hash_ptr(gnutls_hash_hd_t *ptr)
+{
+ if (*ptr) {
+ gnutls_hash_deinit(*ptr, NULL);
+ }
+}
+
+#define _cleanup_free_ _cleanup_(free_ptr)
+#define _cleanup_close_ _cleanup_(close_ptr)
+#define _cleanup_fclose_ _cleanup_(fclose_ptr)
+#define _cleanup_closedir_ _cleanup_(closedir_ptr)
+#define _cleanup_binary_ _cleanup_(dnssec_binary_free)
+#define _cleanup_datum_ _cleanup_(free_gnutls_datum_ptr)
+#define _cleanup_x509_privkey_ _cleanup_(free_x509_privkey_ptr)
+#define _cleanup_pubkey_ _cleanup_(free_pubkey_ptr)
+#define _cleanup_hash_ _cleanup_(free_gnutls_hash_ptr)
+
+/* -- assertions ----------------------------------------------------------- */
+
+#define assert_unreachable() assert(0)
+
+/* -- crypto helpers ------------------------------------------------------- */
+
+static inline gnutls_datum_t binary_to_datum(const dnssec_binary_t *from)
+{
+ gnutls_datum_t to = { .size = from->size, .data = from->data };
+ return to;
+}
+
+static inline dnssec_binary_t binary_from_datum(const gnutls_datum_t *from)
+{
+ dnssec_binary_t to = { .size = from->size, .data = from->data };
+ return to;
+}