1744 lines
50 KiB
Diff
1744 lines
50 KiB
Diff
From a0aa280cfe7a756bc9f965129c847dc9bfd2e84d Mon Sep 17 00:00:00 2001
|
|
From: Sergio Correia <scorreia@redhat.com>
|
|
Date: Sun, 29 Sep 2019 10:05:05 -0300
|
|
Subject: [PATCH] Move key generation to tang
|
|
|
|
Until now, tang has relied the following two scripts to handle keys:
|
|
- tangd-keygen, which generates the keys in a specific JWK dir
|
|
- tangd-update, which reads the directory with the keys and updates a
|
|
cache directory with files that will be used by tang during its
|
|
operation
|
|
|
|
We also rely on systemd to watch the JWK dir and automatically run
|
|
tangd-update when it is modified, so that the cache directory would be
|
|
kept in a consistent state with regard to the available keys.
|
|
|
|
However, this has shown to be unreliable and to cause issues in some
|
|
situations. For instance, in #23 we see that sometimes the keys are not
|
|
ready when tang starts operating, and in #24 we see that we have issues
|
|
if somehow the cache directory is removed while tang is running.
|
|
|
|
To improve reliability, the handling of keys is now being moved to tang
|
|
itself. In this commit we implement routines to perform the operations
|
|
that the aforementioned scripts did; tang can now create keys and also
|
|
read them directly to perform its required operations.
|
|
|
|
Changes after this commit:
|
|
1) there is no cache directory anymore; tang will read the keys directly
|
|
from JWK dir instead of reading files from the cache directory
|
|
2) as a consequence of 1), we now pass JWK dir as the argument to tang
|
|
3) tangd-update is gone, since there is no need for a cache directory
|
|
4) when reading JWK dir, tang will create keys if there are none -- this
|
|
was already the case on startup before this commit, but now we do not
|
|
rely on systemd units to do this any longer
|
|
5) many of the previously used systemd units are not required anymore
|
|
|
|
Resolves #23
|
|
Resolves #24
|
|
---
|
|
Makefile.am | 11 +-
|
|
src/keys.c | 1043 +++++++++++++++++++++++++++++++++
|
|
src/keys.h | 84 +++
|
|
src/tangd-update | 83 ---
|
|
src/tangd.c | 60 +-
|
|
src/util.c | 141 +++++
|
|
src/util.h | 33 ++
|
|
tests/adv | 4 +-
|
|
tests/rec | 4 +-
|
|
units/tangd-keygen.service.in | 8 -
|
|
units/tangd-update.path.in | 4 -
|
|
units/tangd-update.service.in | 6 -
|
|
units/tangd.socket.in | 5 -
|
|
units/tangd@.service.in | 2 +-
|
|
14 files changed, 1342 insertions(+), 146 deletions(-)
|
|
create mode 100644 src/keys.c
|
|
create mode 100644 src/keys.h
|
|
delete mode 100755 src/tangd-update
|
|
create mode 100644 src/util.c
|
|
create mode 100644 src/util.h
|
|
delete mode 100644 units/tangd-keygen.service.in
|
|
delete mode 100644 units/tangd-update.path.in
|
|
delete mode 100644 units/tangd-update.service.in
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index af30d2f..f855dcd 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -7,17 +7,13 @@ man8_MANS=
|
|
AM_CFLAGS = @TANG_CFLAGS@ @jose_CFLAGS@
|
|
LDADD = @jose_LIBS@ @http_parser_LIBS@
|
|
|
|
-cachedir = $(localstatedir)/cache/$(PACKAGE_NAME)
|
|
jwkdir = $(localstatedir)/db/$(PACKAGE_NAME)
|
|
|
|
nodist_systemdsystemunit_DATA = \
|
|
units/tangd@.service \
|
|
- units/tangd.socket \
|
|
- units/tangd-update.path \
|
|
- units/tangd-update.service \
|
|
- units/tangd-keygen.service
|
|
+ units/tangd.socket
|
|
|
|
-dist_libexec_SCRIPTS = src/tangd-update src/tangd-keygen
|
|
+dist_libexec_SCRIPTS = src/tangd-keygen
|
|
dist_bin_SCRIPTS = src/tang-show-keys
|
|
libexec_PROGRAMS = src/tangd
|
|
|
|
@@ -39,14 +35,13 @@ man1_MANS += doc/tang-show-keys.1
|
|
man8_MANS += doc/tang.8
|
|
endif
|
|
|
|
-src_tangd_SOURCES = src/http.c src/http.h src/tangd.c
|
|
+src_tangd_SOURCES = src/util.c src/util.h src/keys.c src/keys.h src/http.c src/http.h src/tangd.c
|
|
|
|
%: %.in
|
|
$(AM_V_GEN)mkdir -p "`dirname "$@"`"
|
|
$(AM_V_GEN)$(SED) \
|
|
-e 's,@libexecdir\@,$(libexecdir),g' \
|
|
-e 's,@jwkdir\@,$(jwkdir),g' \
|
|
- -e 's,@cachedir\@,$(cachedir),g' \
|
|
$(srcdir)/$@.in > $@
|
|
|
|
AM_TESTS_ENVIRONMENT = SD_ACTIVATE="@SD_ACTIVATE@" PATH=$(srcdir)/src:$(builddir)/src:$(PATH)
|
|
diff --git a/src/keys.c b/src/keys.c
|
|
new file mode 100644
|
|
index 0000000..77f5d3c
|
|
--- /dev/null
|
|
+++ b/src/keys.c
|
|
@@ -0,0 +1,1043 @@
|
|
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
|
|
+/*
|
|
+ * Copyright (c) 2019 Red Hat, Inc.
|
|
+ * Author: Sergio Correia <scorreia@redhat.com>
|
|
+ *
|
|
+ * 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 <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#include <jose/b64.h>
|
|
+#include <jose/jwk.h>
|
|
+#include <jose/jws.h>
|
|
+#include <jose/io.h>
|
|
+#include <jansson.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "util.h"
|
|
+#include "keys.h"
|
|
+
|
|
+#ifndef PATH_MAX
|
|
+#define PATH_MAX 4096
|
|
+#endif
|
|
+
|
|
+#define TANG_MAXBUFLEN (1024 * 1024)
|
|
+
|
|
+#define DEFAULT_HASH_ALG "S1"
|
|
+
|
|
+/* TODO: check if jose has a way to export the hash algorithms it supports. */
|
|
+const char *hash_alg[] = {"S1", "S224", "S256", "S384", "S512", NULL};
|
|
+
|
|
+size_t
|
|
+hash_alg_size(void)
|
|
+{
|
|
+ size_t count = 0;
|
|
+ for (size_t i = 0; hash_alg[i]; i++) {
|
|
+ count++;
|
|
+ }
|
|
+ return count;
|
|
+}
|
|
+
|
|
+int
|
|
+is_hash(const char *alg)
|
|
+{
|
|
+ for (size_t a = 0, size = hash_alg_size(); a < size; a++) {
|
|
+ if (strcmp(alg, hash_alg[a]) == 0) {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Generates a JWK and returns a json_t*, which must be released with
|
|
+ * json_decref().
|
|
+ */
|
|
+static json_t*
|
|
+jwk_generate(const char* alg)
|
|
+{
|
|
+ json_t *jalg = json_pack("{s:s}", "alg", alg);
|
|
+ if (!jalg) {
|
|
+ fprintf(stderr, "Error packing JSON with alg %s\n", alg);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!jose_jwk_gen(NULL, jalg)) {
|
|
+ fprintf(stderr, "Error generating JWK with alg %s\n", alg);
|
|
+ json_decref(jalg);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return jalg;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Returns a thumbprint from a JWK and a given algorithm, which must be
|
|
+ * released with free().
|
|
+ */
|
|
+char*
|
|
+jwk_thumbprint(const json_t* jwk, const char* alg)
|
|
+{
|
|
+ size_t elen = 0;
|
|
+ size_t dlen = 0;
|
|
+
|
|
+ const char* hash = alg;
|
|
+ if (!is_hash(alg)) {
|
|
+ hash = DEFAULT_HASH_ALG;
|
|
+ }
|
|
+
|
|
+ dlen = jose_jwk_thp_buf(NULL, NULL, hash, NULL, 0);
|
|
+ if (dlen == SIZE_MAX) {
|
|
+ fprintf(stderr, "Error determining hash size for %s\n", hash);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ elen = jose_b64_enc_buf(NULL, dlen, NULL, 0);
|
|
+ if (elen == SIZE_MAX) {
|
|
+ fprintf(stderr, "Error determining encoded size for %s\n", hash);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ uint8_t dec[dlen];
|
|
+ char enc[elen];
|
|
+
|
|
+ if (!jose_jwk_thp_buf(NULL, jwk, hash, dec, sizeof(dec))) {
|
|
+ fprintf(stderr, "Error making thumbprint\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (jose_b64_enc_buf(dec, dlen, enc, sizeof(enc)) != elen) {
|
|
+ fprintf(stderr, "Error encoding data Base64\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ char *thp = malloc(elen + 1);
|
|
+ if (!thp) {
|
|
+ fprintf(stderr, "Error allocating string for thumbprint\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!strncpy(thp, enc, elen)) {
|
|
+ fprintf(stderr, "Error copying thumbprint to string\n");
|
|
+ free(thp);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ thp[elen] = '\0';
|
|
+ return thp;
|
|
+}
|
|
+
|
|
+char*
|
|
+jwk_thumbprint_from_file(const char *file, const char *alg)
|
|
+{
|
|
+ json_auto_t *jwk = json_load_file(file, 0, NULL);
|
|
+ if (!jwk) {
|
|
+ return 0;
|
|
+ }
|
|
+ return jwk_thumbprint(jwk, alg);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Releases the allocated memory by struct tang_jwk*.
|
|
+ */
|
|
+void
|
|
+free_tang_jwk(struct tang_jwk* tjwk)
|
|
+{
|
|
+ if (!tjwk) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (tjwk->m_json) {
|
|
+ json_decref(tjwk->m_json);
|
|
+ }
|
|
+ free(tjwk->m_from_file);
|
|
+ free(tjwk->m_thp);
|
|
+ free(tjwk->m_alg);
|
|
+ free(tjwk->m_str);
|
|
+ free(tjwk);
|
|
+}
|
|
+
|
|
+void
|
|
+cleanup_tang_jwk(struct tang_jwk **jwk)
|
|
+{
|
|
+ if (!jwk || !*jwk) {
|
|
+ return;
|
|
+ }
|
|
+ free_tang_jwk(*jwk);
|
|
+}
|
|
+
|
|
+struct tang_jwk*
|
|
+new_tang_jwk_from_args(json_t *jwk, const char* thp, const char* alg)
|
|
+{
|
|
+ if (!jwk) {
|
|
+ fprintf(stderr, "Invalid JWK (%p) \n", jwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk *tjwk = calloc(1, sizeof(*tjwk));
|
|
+ if (!tjwk) {
|
|
+ fprintf(stderr, "Error allocating new struct tang_jwk.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_json = json_incref(jwk);
|
|
+ tjwk->m_from_file = NULL;
|
|
+
|
|
+ if (alg) {
|
|
+ tjwk->m_alg = strdup(alg);
|
|
+ if (!tjwk->m_alg) {
|
|
+ fprintf(stderr, "Unable to copy algorithm (%s) to tang_jwk.\n", alg);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (thp) {
|
|
+ tjwk->m_thp = strdup(thp);
|
|
+ if (!tjwk->m_thp) {
|
|
+ fprintf(stderr, "Unable to copy thumbprint (%s).\n", thp);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ tjwk->m_str = json_dumps(tjwk->m_json, JSON_SORT_KEYS | JSON_COMPACT);
|
|
+ if (!tjwk->m_str) {
|
|
+ fprintf(stderr, "Unable to get string version from JWK.\n");
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return tjwk;
|
|
+}
|
|
+
|
|
+struct tang_jwk*
|
|
+tang_jwk_dup(const struct tang_jwk *jwk)
|
|
+{
|
|
+ if (!jwk) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk *new_jwk = new_tang_jwk_from_args(jwk->m_json, jwk->m_thp, jwk->m_alg);
|
|
+ if (!new_jwk) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (jwk->m_from_file) {
|
|
+ new_jwk->m_from_file = strdup(jwk->m_from_file);
|
|
+ if (!new_jwk->m_from_file) {
|
|
+ free_tang_jwk(new_jwk);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return new_jwk;
|
|
+}
|
|
+
|
|
+struct tang_jwk*
|
|
+new_tang_jwk(const char* file, const char* alg)
|
|
+{
|
|
+ if (!file || !alg) {
|
|
+ fprintf(stderr, "Invalid file (%s) or algorithm (%s).\n", file, alg);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ json_auto_t *jwk = json_load_file(file, 0, NULL);
|
|
+ if (!jwk) {
|
|
+ fprintf(stderr, "Unable to parse JSON from %s.\n", file);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk *tjwk = calloc(1, sizeof(*tjwk));
|
|
+ if (!tjwk) {
|
|
+ fprintf(stderr, "Error allocating new struct tang_jwk.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_json = json_incref(jwk);
|
|
+ tjwk->m_from_file = strdup(file);
|
|
+ if (!tjwk->m_from_file) {
|
|
+ fprintf(stderr, "Unable to copy file name (%s) to m_from_file.\n", file);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+ tjwk->m_alg = strdup(alg);
|
|
+ if (!tjwk->m_alg) {
|
|
+ fprintf(stderr, "Unable to copy algorithm (%s) to tang_jwk.\n", alg);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_thp = jwk_thumbprint(tjwk->m_json, tjwk->m_alg);
|
|
+ if (!tjwk->m_thp) {
|
|
+ fprintf(stderr, "Unable to get thumbprint using alg (%s).\n", alg);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_str = json_dumps(tjwk->m_json, JSON_SORT_KEYS | JSON_COMPACT);
|
|
+ if (!tjwk->m_str) {
|
|
+ fprintf(stderr, "Unable to get string version from JWK.\n");
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return tjwk;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Builds a new struct tang_jwk*, which should be destructed by calling
|
|
+ * free_tang_jwk().
|
|
+ */
|
|
+struct tang_jwk*
|
|
+generate_new_tang_jwk(const char* alg)
|
|
+{
|
|
+ if (!alg) {
|
|
+ fprintf(stderr, "Invalid algorithm.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk *tjwk = calloc(1, sizeof(*tjwk));
|
|
+ if (!tjwk) {
|
|
+ fprintf(stderr, "Error allocating new struct tang_jwk.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_alg = strdup(alg);
|
|
+ if (!tjwk->m_alg) {
|
|
+ fprintf(stderr, "Unable to copy algorithm (%s) to tang_jwk.\n", alg);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_json = jwk_generate(alg);
|
|
+ if (!tjwk->m_json) {
|
|
+ fprintf(stderr, "Unable to generate new JWK using alg (%s).\n", alg);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+ tjwk->m_thp = jwk_thumbprint(tjwk->m_json, tjwk->m_alg);
|
|
+ if (!tjwk->m_thp) {
|
|
+ fprintf(stderr, "Unable to get thumbprint using alg (%s).\n", alg);
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tjwk->m_str = json_dumps(tjwk->m_json, JSON_SORT_KEYS | JSON_COMPACT);
|
|
+ if (!tjwk->m_str) {
|
|
+ fprintf(stderr, "Unable to get string version from JWK.\n");
|
|
+ free_tang_jwk(tjwk);
|
|
+ return NULL;
|
|
+ }
|
|
+ return tjwk;
|
|
+}
|
|
+
|
|
+static int
|
|
+file_valid_for(const char *file, const char *use)
|
|
+{
|
|
+ json_auto_t *jwk = json_load_file(file, 0, NULL);
|
|
+ if (!jwk) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return jose_jwk_prm(NULL, jwk, false, use);
|
|
+}
|
|
+
|
|
+static int
|
|
+jwk_valid_for(const json_t *jwk, const char *use)
|
|
+{
|
|
+ return jose_jwk_prm(NULL, jwk, false, use);
|
|
+}
|
|
+
|
|
+
|
|
+int valid_for_signing_and_verifying(const char *file)
|
|
+{
|
|
+ json_auto_t *jwk = json_load_file(file, 0, NULL);
|
|
+ if (!jwk) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ const char *use[] = {"sign", "verify", NULL};
|
|
+ int ret = 1;
|
|
+ for (int i = 0; use[i] != NULL; i++) {
|
|
+ if (!jwk_valid_for(jwk, use[i])) {
|
|
+ ret = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int valid_for_signing(const char *file)
|
|
+{
|
|
+ return file_valid_for(file, "sign");
|
|
+}
|
|
+
|
|
+int valid_for_deriving_keys(const char *file)
|
|
+{
|
|
+ return file_valid_for(file, "deriveKey");
|
|
+}
|
|
+
|
|
+struct tang_jwk_list*
|
|
+new_tang_jwk_list(void)
|
|
+{
|
|
+ struct tang_jwk_list *tjl = malloc(sizeof(*tjl));
|
|
+ if (!tjl) {
|
|
+ return NULL;
|
|
+ }
|
|
+ tjl->m_jwk = NULL;
|
|
+ tjl->m_size = 0;
|
|
+ return tjl;
|
|
+}
|
|
+
|
|
+void
|
|
+free_tang_jwk_list(struct tang_jwk_list *tjl)
|
|
+{
|
|
+ if (!tjl) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0, size = tjl->m_size; i < size; i++) {
|
|
+ free_tang_jwk(tjl->m_jwk[i]);
|
|
+ }
|
|
+ free(tjl->m_jwk);
|
|
+ free(tjl);
|
|
+}
|
|
+
|
|
+int
|
|
+tang_jwk_list_add(struct tang_jwk_list *tjl, struct tang_jwk *jwk_to_add)
|
|
+{
|
|
+ if (!tjl || !jwk_to_add) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk *jwk = tang_jwk_dup(jwk_to_add);
|
|
+ if (!jwk) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk **new_jwk = realloc(tjl->m_jwk, sizeof(struct tang_jwk*) * (tjl->m_size + 1));
|
|
+ if (!new_jwk) {
|
|
+ fprintf(stderr, "Error reallocating memory for the new JWK.\n");
|
|
+ free_tang_jwk(jwk);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ tjl->m_jwk = new_jwk;
|
|
+ tjl->m_jwk[tjl->m_size++] = jwk;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int
|
|
+tang_jwk_thp_bsearch_cmp_func(const void *a, const void *b)
|
|
+{
|
|
+ const char *key = (const char*)a;
|
|
+ const struct tang_jwk *jwk = *(const struct tang_jwk**)b;
|
|
+ return strcmp(key, jwk->m_thp);
|
|
+}
|
|
+
|
|
+struct tang_jwk*
|
|
+tang_jwk_list_find_thp(const struct tang_jwk_list *tjl, const char *thp)
|
|
+{
|
|
+ if (!tjl || !thp) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (tjl->m_size == 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk **item = bsearch(thp, tjl->m_jwk, tjl->m_size, sizeof(struct tang_jwk*), tang_jwk_thp_bsearch_cmp_func);
|
|
+ if (!item) {
|
|
+ return NULL;
|
|
+ }
|
|
+ return *item;
|
|
+}
|
|
+
|
|
+void
|
|
+free_tang_keys_info(struct tang_keys_info *tki)
|
|
+{
|
|
+ if (!tki) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ free(tki->m_jwkdir);
|
|
+ free_file_list(tki->m_payload_keys);
|
|
+ free_file_list(tki->m_sign_keys);
|
|
+ free_tang_jwk_list(tki->m_derive);
|
|
+ free_tang_jwk_list(tki->m_adv);
|
|
+ free_tang_jwk(tki->m_default_adv);
|
|
+ free(tki);
|
|
+}
|
|
+
|
|
+struct tang_keys_info*
|
|
+new_tang_keys_info(const char* jwkdir)
|
|
+{
|
|
+ if (!jwkdir) {
|
|
+ fprintf(stderr, "Invalid JWK dir.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct tang_keys_info *tki = calloc(1, sizeof(struct tang_keys_info));
|
|
+ if (!tki) {
|
|
+ fprintf(stderr, "Error allocating tang_keys_info struct.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tki->m_jwkdir = strdup(jwkdir);
|
|
+ if (!tki->m_jwkdir) {
|
|
+ fprintf(stderr, "Error copying JWK dir to tang_keys_info struct.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tki->m_payload_keys = new_file_list();
|
|
+ if (!tki->m_payload_keys) {
|
|
+ fprintf(stderr, "Error allocating payload keys.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tki->m_sign_keys = new_file_list();
|
|
+ if (!tki->m_sign_keys) {
|
|
+ fprintf(stderr, "Error allocating signing keys.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tki->m_derive = new_tang_jwk_list();
|
|
+ if (!tki->m_derive) {
|
|
+ fprintf(stderr, "Error allocating list of deriving keys.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tki->m_adv = new_tang_jwk_list();
|
|
+ if (!tki->m_adv) {
|
|
+ fprintf(stderr, "Error allocating list adv.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tki->m_default_adv = NULL;
|
|
+
|
|
+ return tki;
|
|
+}
|
|
+
|
|
+int
|
|
+check_keys(const char* jwkdir)
|
|
+{
|
|
+ if (!jwkdir) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* We ignore hidden files in here because we only care about
|
|
+ * advertised keys. */
|
|
+ struct file_list *fl __attribute__ ((__cleanup__(cleanup_file_list))) = list_files(jwkdir, ".jwk", 1 /* ignore hidden */);
|
|
+ if (!fl) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (fl->m_size > 0) {
|
|
+ /* There are already keys in the JWKdir, so let's leave it as is. */
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* At this point, there are no keys, so let's create them. */
|
|
+ const char *alg[] = {"ES512", "ECMR", NULL};
|
|
+ char path[PATH_MAX];
|
|
+ for (int i = 0; alg[i] != NULL; i++) {
|
|
+ struct tang_jwk *jwk __attribute__((cleanup(cleanup_tang_jwk))) = generate_new_tang_jwk(alg[i]);
|
|
+ if (!jwk) {
|
|
+ fprintf(stderr, "Error generating JWK using %s\n", alg[i]);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ snprintf(path, PATH_MAX, "%s/%s.jwk", jwkdir, jwk->m_thp);
|
|
+ path[sizeof(path) - 1] = '\0';
|
|
+
|
|
+ FILE *fp = fopen(path, "w+");
|
|
+ if (!fp) {
|
|
+ fprintf(stderr, "Error creating JWK file to %s\n", path);
|
|
+ return 0;
|
|
+ }
|
|
+ fprintf(fp, "%s", jwk->m_str);
|
|
+ fclose(fp);
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int
|
|
+tang_jwk_thp_cmp_func(const void *a, const void *b)
|
|
+{
|
|
+ const struct tang_jwk *ta = *(const struct tang_jwk**)a;
|
|
+ const struct tang_jwk *tb = *(const struct tang_jwk**)b;
|
|
+ return strcmp(ta->m_thp, tb->m_thp);
|
|
+}
|
|
+
|
|
+void
|
|
+cleanup_tang_keys_info(struct tang_keys_info **tki)
|
|
+{
|
|
+ if (!tki || !*tki) {
|
|
+ return;
|
|
+ }
|
|
+ free_tang_keys_info(*tki);
|
|
+}
|
|
+
|
|
+static void
|
|
+cleanup_buffer(char **buffer)
|
|
+{
|
|
+ if (!buffer || !*buffer) {
|
|
+ return;
|
|
+ }
|
|
+ free(*buffer);
|
|
+}
|
|
+
|
|
+static void
|
|
+cleanup_jose_io_t(jose_io_t ***iosp)
|
|
+{
|
|
+ jose_io_t **ios = *iosp;
|
|
+ for (size_t i = 0; ios && ios[i]; i++) {
|
|
+ jose_io_auto(&ios[i]);
|
|
+ }
|
|
+}
|
|
+
|
|
+static json_t*
|
|
+build_json_array(const char **files, size_t total_files)
|
|
+{
|
|
+ if (!files || total_files == 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ json_t *arr = json_array();
|
|
+ if (!arr) {
|
|
+ fprintf(stderr, "Unable to create json array\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0; i < total_files; i++) {
|
|
+ json_t *jwk = json_load_file(files[i], 0, NULL);
|
|
+ if (!jwk) {
|
|
+ fprintf(stderr, "Unable to load JSON from %s; skipping\n", files[i]);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (json_array_append_new(arr, jwk) != 0) {
|
|
+ fprintf(stderr, "Unable to append JSON %s to array; skipping\n", files[i]);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ return arr;
|
|
+}
|
|
+
|
|
+static json_t*
|
|
+remove_private_keys(const struct file_list *fl)
|
|
+{
|
|
+ if (!fl) {
|
|
+ fprintf(stderr, "Invalid file list for cleaning private keys.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ json_auto_t *array = build_json_array((const char**)fl->m_files, fl->m_size);
|
|
+ if (!array || json_array_size(array) == 0) {
|
|
+ fprintf(stderr, "Empty array %p.\n", array);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0, size = json_array_size(array); i < size; i++) {
|
|
+ if (!jose_jwk_pub(NULL, json_array_get(array, i))) {
|
|
+ fprintf(stderr, "Error removing private keys.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return json_pack("{s:O}", "keys", array);
|
|
+}
|
|
+
|
|
+static json_t*
|
|
+prepare_template_sigs(size_t total)
|
|
+{
|
|
+ json_t *arr = json_array();
|
|
+ if (!arr) {
|
|
+ fprintf(stderr, "Unable to create JSON sigs array\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0; i < total; i++) {
|
|
+ json_t *cty = json_pack("{s:{s:s}}", "protected", "cty", "jwk-set+json");
|
|
+ if (!cty) {
|
|
+ fprintf(stderr, "Unable to create item %zu/%zu; skipping\n", i, total);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (json_array_append_new(arr, cty) != 0) {
|
|
+ fprintf(stderr, "Unable to append item %zu/%zu to array; skipping\n", i, total);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ return arr;
|
|
+}
|
|
+
|
|
+static jose_io_t*
|
|
+tang_prep_io(jose_io_t *io, uint8_t *buffer, size_t *buflen)
|
|
+{
|
|
+ if (!io || !buffer || !buflen) {
|
|
+ fprintf(stderr, "Either io (%p) the buffer (%p) or the buffer len (%p) are NULL\n", io, buffer, buflen);
|
|
+ }
|
|
+
|
|
+ jose_io_t **ios __attribute__((cleanup(cleanup_jose_io_t))) = NULL;
|
|
+ size_t i = 0;
|
|
+
|
|
+ ios = alloca(sizeof(*ios) * 3);
|
|
+ memset(ios, 0, sizeof(*ios) * 3);
|
|
+
|
|
+ if (io) {
|
|
+ ios[i++] = io;
|
|
+ }
|
|
+
|
|
+ ios[i] = jose_io_buffer(NULL, buffer, buflen);
|
|
+ if (!ios[i]) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (i = 0; ios[i]; i++) {
|
|
+ jose_io_auto_t *b64 = NULL;
|
|
+
|
|
+ b64 = jose_b64_enc_io(ios[i]);
|
|
+ if (!b64) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ jose_io_decref(ios[i]);
|
|
+ ios[i] = jose_io_incref(b64);
|
|
+ }
|
|
+
|
|
+ return jose_io_multiplex(NULL, ios, true);
|
|
+}
|
|
+
|
|
+static int
|
|
+prepare_deriving_jwk(struct tang_keys_info *tki, const struct file_list *fl)
|
|
+{
|
|
+ const size_t hash_alg_count = hash_alg_size();
|
|
+ for (size_t a = 0; a < hash_alg_count; a++) {
|
|
+ for (size_t i = 0; i < fl->m_size; i++) {
|
|
+ struct tang_jwk *jwk __attribute__((cleanup(cleanup_tang_jwk))) = new_tang_jwk(fl->m_files[i], hash_alg[a]);
|
|
+ if (!jwk) {
|
|
+ fprintf(stderr, "Unable to create tang_jwk from %s with alg %s; skipping.\n", fl->m_files[i], hash_alg[a]);
|
|
+ continue;
|
|
+ }
|
|
+ if (!tang_jwk_list_add(tki->m_derive, jwk)) {
|
|
+ fprintf(stderr, "Unable to add JWK from %s with alg %s to list of deriving keys; skipping.\n", fl->m_files[i], hash_alg[a]);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (tki->m_derive->m_size > 1) {
|
|
+ qsort(tki->m_derive->m_jwk, tki->m_derive->m_size, sizeof(struct tang_jwk*), tang_jwk_thp_cmp_func);
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int
|
|
+prepare_adv_jwk(struct tang_keys_info *tki, const struct file_list *fl)
|
|
+{
|
|
+ const size_t hash_alg_count = hash_alg_size();
|
|
+ json_auto_t *keys = build_json_array((const char**)tki->m_sign_keys->m_files, tki->m_sign_keys->m_size);
|
|
+ json_auto_t *pub = remove_private_keys(tki->m_payload_keys);
|
|
+
|
|
+ /*
|
|
+ * Adding dummy element in the first position. We will be be replacing
|
|
+ * it with the actual ones and then creating the JWS data.
|
|
+ */
|
|
+ json_auto_t *dummy = json_object();
|
|
+ if (json_array_insert(keys, 0, dummy) != 0) {
|
|
+ fprintf(stderr, "Error preparing adv JWKs.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ json_auto_t *sigs = prepare_template_sigs(json_array_size(keys));
|
|
+
|
|
+ for (size_t i = 0; i < fl->m_size; i++) {
|
|
+ json_auto_t *jwk = json_load_file(fl->m_files[i], 0, NULL);
|
|
+ if (!jwk) {
|
|
+ fprintf(stderr, "Unable to load JWK from %s; skipping.\n", fl->m_files[i]);
|
|
+ continue;
|
|
+ }
|
|
+ if (json_array_set(keys, 0, jwk) != 0) {
|
|
+ fprintf(stderr, "Unable to add JWK from file (%s) to array; skipping.\n", fl->m_files[i]);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ char *jws_data __attribute__((cleanup(cleanup_buffer))) = process_adv(keys, sigs, pub);
|
|
+ if (!jws_data) {
|
|
+ fprintf(stderr, "Unable to obtain JWS from %s; skipping.\n", fl->m_files[i]);
|
|
+ continue;
|
|
+ }
|
|
+ json_auto_t *jws_json = json_loads(jws_data, 0, NULL);
|
|
+ if (!jws_json) {
|
|
+ fprintf(stderr, "Unable to convert string to JSON; skipping.\n");
|
|
+ continue;
|
|
+ }
|
|
+ for (size_t a = 0; a < hash_alg_count; a++) {
|
|
+ char *thp __attribute__((cleanup(cleanup_buffer))) = jwk_thumbprint(jwk, hash_alg[a]);
|
|
+ if (!thp) {
|
|
+ fprintf(stderr, "Unable to obtain thumbprint from file (%s) and alg (%s); skipping.\n", fl->m_files[i], hash_alg[a]);
|
|
+ continue;
|
|
+ }
|
|
+ struct tang_jwk *jws __attribute__((cleanup(cleanup_tang_jwk)))= new_tang_jwk_from_args(jws_json, thp, hash_alg[a]);
|
|
+ if (!jws) {
|
|
+ fprintf(stderr, "Error creating tang_jwk with JWS data from file (%s) and alg (%s); skipping.\n", fl->m_files[i], hash_alg[a]);
|
|
+ continue;
|
|
+ }
|
|
+ if (!tang_jwk_list_add(tki->m_adv, jws)) {
|
|
+ fprintf(stderr, "Error adding JWS data from file (%s) and alg (%s) to adv list; skipping.\n", fl->m_files[i], hash_alg[a]);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (tki->m_adv->m_size > 1) {
|
|
+ qsort(tki->m_adv->m_jwk, tki->m_adv->m_size, sizeof(struct tang_jwk*), tang_jwk_thp_cmp_func);
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int
|
|
+prepare_deriving_and_adv(struct tang_keys_info *tki)
|
|
+{
|
|
+ if (!tki) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ struct file_list *fl __attribute__ ((__cleanup__(cleanup_file_list))) = list_files(tki->m_jwkdir, ".jwk", 0 /* ignore hidden */);
|
|
+ if (!fl || fl->m_size == 0) {
|
|
+ fprintf(stderr, "No JWK keys available.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ struct file_list *derive_key __attribute__((__cleanup__(cleanup_file_list))) = new_file_list();
|
|
+ struct file_list *jws __attribute__((__cleanup__(cleanup_file_list))) = new_file_list();
|
|
+
|
|
+ char filepath[PATH_MAX] = {};
|
|
+ for (size_t i = 0, size = fl->m_size; i < size; i++) {
|
|
+ snprintf(filepath, sizeof(filepath), "%s/%s", tki->m_jwkdir, fl->m_files[i]);
|
|
+ filepath[sizeof(filepath) - 1] = '\0';
|
|
+ if (valid_for_deriving_keys(filepath)) {
|
|
+ if (!file_list_add(derive_key, filepath)) {
|
|
+ fprintf(stderr, "Error adding %s to file list of keys valid for deriving keys; skipping.\n", filepath);
|
|
+ }
|
|
+ } else if (valid_for_signing(filepath)) {
|
|
+ if (!file_list_add(jws, filepath)) {
|
|
+ fprintf(stderr, "Error adding %s to file list of keys valid for signing; skipping.\n", filepath);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (derive_key->m_size == 0 || jws->m_size == 0) {
|
|
+ fprintf(stderr, "Either the number of keys able to derive keys (%zu) or to sign keys (%zu) is zero.\n", derive_key->m_size, jws->m_size);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!prepare_deriving_jwk(tki, derive_key)) {
|
|
+ fprintf(stderr, "Error preparing deriving keys JWK.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!prepare_adv_jwk(tki, jws)) {
|
|
+ fprintf(stderr, "Error preparing advertising JWK.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+struct tang_jwk*
|
|
+find_adv(const struct tang_keys_info *tki, const char* thp)
|
|
+{
|
|
+ if (!tki) {
|
|
+ fprintf(stderr, "Invalid tang_keys_info (%p).\n", tki);
|
|
+ return NULL;
|
|
+ }
|
|
+ return tang_jwk_list_find_thp(tki->m_adv, thp);
|
|
+}
|
|
+
|
|
+struct tang_jwk*
|
|
+find_deriving_key(const struct tang_keys_info *tki, const char* thp)
|
|
+{
|
|
+ if (!tki) {
|
|
+ fprintf(stderr, "Invalid tang_keys_info (%p).\n", tki);
|
|
+ return NULL;
|
|
+ }
|
|
+ return tang_jwk_list_find_thp(tki->m_derive, thp);
|
|
+}
|
|
+
|
|
+struct tang_keys_info*
|
|
+read_keys(const char *jwkdir)
|
|
+{
|
|
+ struct tang_keys_info *tki = new_tang_keys_info(jwkdir);
|
|
+ if (!tki) {
|
|
+ fprintf(stderr, "Unable to create tang_keys_info\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ struct file_list *fl __attribute__ ((__cleanup__(cleanup_file_list))) = list_files(jwkdir, ".jwk", 1 /* ignore hidden */);
|
|
+ if (!fl || fl->m_size == 0) {
|
|
+ fprintf(stderr, "No JWK keys available.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ char filepath[PATH_MAX] = {};
|
|
+ for (size_t i = 0, size = fl->m_size; i < size; i++) {
|
|
+ snprintf(filepath, sizeof(filepath), "%s/%s", jwkdir, fl->m_files[i]);
|
|
+ filepath[sizeof(filepath) - 1] = '\0';
|
|
+ if (valid_for_signing_and_verifying(filepath)) {
|
|
+ if (!file_list_add(tki->m_sign_keys, filepath)) {
|
|
+ fprintf(stderr, "Error adding %s to the list of signing keys\n", filepath);
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+ if (!file_list_add(tki->m_payload_keys, filepath)) {
|
|
+ fprintf(stderr, "Error adding %s to the list of payload keys\n", filepath);
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+ } else if (valid_for_deriving_keys(filepath)) {
|
|
+ if (!file_list_add(tki->m_payload_keys, filepath)) {
|
|
+ fprintf(stderr, "Error adding %s to the list of payload keys\n", filepath);
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!prepare_deriving_and_adv(tki)) {
|
|
+ fprintf(stderr, "Unable to prepare deriving and advcertising JWKs.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!prepare_default_adv(tki)) {
|
|
+ fprintf(stderr, "Unable to prepare the default adv.\n");
|
|
+ free_tang_keys_info(tki);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return tki;
|
|
+}
|
|
+
|
|
+int
|
|
+process_payload(const json_t *jwk, jose_io_t *io)
|
|
+{
|
|
+ char *payload __attribute__((__cleanup__(cleanup_buffer))) = json_dumps(jwk, JSON_SORT_KEYS | JSON_COMPACT);
|
|
+ if (!payload) {
|
|
+ fprintf(stderr, "Error converting JSON to char*.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0, size = strlen(payload); i < size; i++) {
|
|
+ uint8_t b = payload[i];
|
|
+ if (!io->feed(io, &b, sizeof(b))) {
|
|
+ fprintf(stderr, "Error calling io-feed with b = [%c].\n", b);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!io->done(io)) {
|
|
+ fprintf(stderr, "Error calling io-done.\n");
|
|
+ return 0;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+char*
|
|
+process_adv(const json_t *keys, json_t* sigs, const json_t *pub)
|
|
+{
|
|
+ /* For the IO data, we need to have an own buffer. */
|
|
+ uint8_t buffer[TANG_MAXBUFLEN] = {};
|
|
+ size_t buflen = sizeof(buffer);
|
|
+ json_auto_t *io_data = json_object();
|
|
+
|
|
+ jose_io_auto_t *io = jose_jws_sig_io(NULL, io_data, sigs, keys);
|
|
+ if (!io) {
|
|
+ fprintf(stderr, "jose_jws_sig_io() failed.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ io = tang_prep_io(io, buffer, &buflen);
|
|
+ if (!io) {
|
|
+ fprintf(stderr, "tang_prep_io() failed.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!process_payload(pub, io)) {
|
|
+ fprintf(stderr, "Error processing payload.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ const char *preamble = "{\"payload\":\"";
|
|
+ const char *separator = "\",";
|
|
+ const char *postamble = "}";
|
|
+ char *data __attribute__ ((__cleanup__(cleanup_buffer))) = json_dumps(io_data, JSON_EMBED | JSON_COMPACT | JSON_SORT_KEYS);
|
|
+ if (!data) {
|
|
+ fprintf(stderr, "Error obtaining signing data.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ size_t adv_len = strlen(preamble) + buflen + strlen(separator) + strlen(data) + strlen(postamble) + 1;
|
|
+ char *adv_data = malloc(adv_len);
|
|
+ snprintf(adv_data, adv_len, "%s%s%s%s%s", preamble, buffer, separator, data, postamble);
|
|
+ adv_data[adv_len - 1] = '\0';
|
|
+ return adv_data;
|
|
+}
|
|
+
|
|
+int
|
|
+prepare_default_adv(struct tang_keys_info *tki)
|
|
+{
|
|
+ if (!tki) {
|
|
+ fprintf(stderr, "Invalid tang_keys_info\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!tki->m_sign_keys || tki->m_sign_keys->m_size == 0) {
|
|
+ fprintf(stderr, "No valid signing keys.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!tki->m_payload_keys || tki->m_payload_keys->m_size <= tki->m_sign_keys->m_size) {
|
|
+ fprintf(stderr, "Invalid payload keys.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ json_auto_t *keys = build_json_array((const char**)tki->m_sign_keys->m_files, tki->m_sign_keys->m_size);
|
|
+ json_auto_t *sigs = prepare_template_sigs(tki->m_sign_keys->m_size);
|
|
+ json_auto_t *pub = remove_private_keys(tki->m_payload_keys);
|
|
+
|
|
+ char *adv_str __attribute__((cleanup(cleanup_buffer))) = process_adv(keys, sigs, pub);
|
|
+ if (!adv_str) {
|
|
+ return 0;
|
|
+ }
|
|
+ json_auto_t *json = json_loads(adv_str, 0, NULL);
|
|
+ if (!json) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ struct tang_jwk *jwk = new_tang_jwk_from_args(json, NULL, NULL);
|
|
+ if (!jwk) {
|
|
+ return 0;
|
|
+ }
|
|
+ tki->m_default_adv = jwk;
|
|
+ return 1;
|
|
+}
|
|
diff --git a/src/keys.h b/src/keys.h
|
|
new file mode 100644
|
|
index 0000000..150b881
|
|
--- /dev/null
|
|
+++ b/src/keys.h
|
|
@@ -0,0 +1,84 @@
|
|
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
|
|
+/*
|
|
+ * Copyright (c) 2019 Red Hat, Inc.
|
|
+ * Author: Sergio Correia <scorreia@redhat.com>
|
|
+ *
|
|
+ * 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 <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <jansson.h>
|
|
+#include <jose/io.h>
|
|
+
|
|
+struct tang_jwk {
|
|
+ json_t* m_json;
|
|
+ char* m_from_file;
|
|
+ char* m_str;
|
|
+ char* m_thp;
|
|
+ char* m_alg;
|
|
+};
|
|
+
|
|
+struct tang_jwk_list {
|
|
+ struct tang_jwk **m_jwk;
|
|
+ size_t m_size;
|
|
+};
|
|
+
|
|
+struct tang_keys_info {
|
|
+ char *m_jwkdir;
|
|
+ struct file_list *m_payload_keys;
|
|
+ struct file_list *m_sign_keys;
|
|
+
|
|
+ struct tang_jwk_list *m_derive;
|
|
+ struct tang_jwk_list *m_adv;
|
|
+ struct tang_jwk *m_default_adv;
|
|
+};
|
|
+
|
|
+/* struct tang_jwk. */
|
|
+struct tang_jwk *new_tang_jwk(const char* /* file */, const char* /* alg */);
|
|
+struct tang_jwk* new_tang_jwk_from_args(json_t*, const char* /* thp */, const char* /* alg */);
|
|
+struct tang_jwk* tang_jwk_dup(const struct tang_jwk*);
|
|
+struct tang_jwk *generate_new_tang_jwk(const char* /* alg */);
|
|
+void free_tang_jwk(struct tang_jwk*);
|
|
+void cleanup_tang_jwk(struct tang_jwk **jwk);
|
|
+
|
|
+/* struct tang_jwk_list. */
|
|
+struct tang_jwk_list* new_tang_jwk_list(void);
|
|
+void free_tang_jwk_list(struct tang_jwk_list*);
|
|
+int tang_jwk_list_add(struct tang_jwk_list*, struct tang_jwk*);
|
|
+struct tang_jwk* tang_jwk_list_find_thp(const struct tang_jwk_list*, const char*);
|
|
+
|
|
+char *jwk_thumbprint(const json_t* /* jwk */, const char* /* alg */);
|
|
+char *jwk_thumbprint_from_file(const char* /* file */, const char* /* alg */);
|
|
+int valid_for_signing(const char* /* file */);
|
|
+int valid_for_signing_and_verifying(const char* /* file */);
|
|
+int valid_for_deriving_keys(const char* /* file */);
|
|
+
|
|
+struct tang_keys_info* new_tang_keys_info(const char*);
|
|
+void free_tang_keys_info(struct tang_keys_info*);
|
|
+void cleanup_tang_keys_info(struct tang_keys_info**);
|
|
+
|
|
+
|
|
+struct tang_keys_info* read_keys(const char*);
|
|
+
|
|
+int process_payload(const json_t*, jose_io_t*);
|
|
+char* process_adv(const json_t*, json_t*, const json_t*);
|
|
+int prepare_default_adv(struct tang_keys_info*);
|
|
+
|
|
+size_t hash_alg_size(void);
|
|
+int check_keys(const char*);
|
|
+struct tang_jwk* find_adv(const struct tang_keys_info*, const char*);
|
|
+struct tang_jwk* find_deriving_key(const struct tang_keys_info*, const char*);
|
|
+int is_hash(const char*);
|
|
+
|
|
diff --git a/src/tangd-update b/src/tangd-update
|
|
deleted file mode 100755
|
|
index 652dbef..0000000
|
|
--- a/src/tangd-update
|
|
+++ /dev/null
|
|
@@ -1,83 +0,0 @@
|
|
-#!/bin/bash
|
|
-# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
|
|
-#
|
|
-# Copyright (c) 2016 Red Hat, Inc.
|
|
-# Author: Nathaniel McCallum <npmccallum@redhat.com>
|
|
-#
|
|
-# 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 <http://www.gnu.org/licenses/>.
|
|
-#
|
|
-
|
|
-TMP='{"protected":{"cty":"jwk-set+json"}}'
|
|
-
|
|
-trap 'exit' ERR
|
|
-
|
|
-shopt -s nullglob
|
|
-
|
|
-HASHES=`jose alg -k hash`
|
|
-
|
|
-if [ $# -ne 2 ] || [ ! -d "$1" ]; then
|
|
- echo "Usage: $0 <jwkdir> <cachedir>" >&2
|
|
- exit 1
|
|
-fi
|
|
-
|
|
-[ ! -d "$2" ] && mkdir -p -m 0700 "$2"
|
|
-
|
|
-src=`realpath "$1"`
|
|
-dst=`realpath "$2"`
|
|
-
|
|
-payl=()
|
|
-sign=()
|
|
-
|
|
-for jwk in $src/*.jwk; do
|
|
- if jose jwk use -i "$jwk" -r -u sign -u verify; then
|
|
- sign+=("-s" "$TMP" "-k" "$jwk")
|
|
- payl+=("-i" "$jwk")
|
|
- elif jose jwk use -i "$jwk" -r -u deriveKey; then
|
|
- payl+=("-i" "$jwk")
|
|
- else
|
|
- echo "Skipping invalid key: $jwk" >&2
|
|
- fi
|
|
-done
|
|
-
|
|
-if [ ${#sign[@]} -gt 0 ]; then
|
|
- jose jwk pub -s "${payl[@]}" \
|
|
- | jose jws sig -I- "${sign[@]}" -o "$dst/.default.jws"
|
|
- mv -f "$dst/.default.jws" "$dst/default.jws"
|
|
- new=default.jws
|
|
-fi
|
|
-
|
|
-shopt -s dotglob
|
|
-
|
|
-for jwk in $src/*.jwk; do
|
|
- for hsh in $HASHES; do
|
|
- thp=`jose jwk thp -i "$jwk" -a $hsh`
|
|
-
|
|
- if jose jwk use -i "$jwk" -r -u deriveKey; then
|
|
- ln -sf "$jwk" "$dst/.$thp.jwk"
|
|
- mv -f "$dst/.$thp.jwk" "$dst/$thp.jwk"
|
|
- new="$new\n$thp.jwk"
|
|
- elif jose jwk use -i "$jwk" -r -u sign; then
|
|
- keys=("${sign[@]}" -s "$TMP" -k "$jwk")
|
|
- jose jwk pub -s "${payl[@]}" \
|
|
- | jose jws sig -I- "${keys[@]}" -o "$dst/.$thp.jws"
|
|
- mv -f "$dst/.$thp.jws" "$dst/$thp.jws"
|
|
- new="$new\n$thp.jws"
|
|
- fi
|
|
- done
|
|
-done
|
|
-
|
|
-for f in "$dst"/*; do
|
|
- b=`basename "$f"`
|
|
- echo -e "$new" | grep -q "^$b\$" || rm -f "$f"
|
|
-done
|
|
diff --git a/src/tangd.c b/src/tangd.c
|
|
index dc45a90..b569f38 100644
|
|
--- a/src/tangd.c
|
|
+++ b/src/tangd.c
|
|
@@ -28,6 +28,7 @@
|
|
#include <unistd.h>
|
|
|
|
#include <jose/jose.h>
|
|
+#include "keys.h"
|
|
|
|
static void
|
|
str_cleanup(char **str)
|
|
@@ -50,9 +51,8 @@ adv(enum http_method method, const char *path, const char *body,
|
|
__attribute__((cleanup(FILE_cleanup))) FILE *file = NULL;
|
|
__attribute__((cleanup(str_cleanup))) char *adv = NULL;
|
|
__attribute__((cleanup(str_cleanup))) char *thp = NULL;
|
|
- char filename[PATH_MAX] = {};
|
|
- const char *cachedir = misc;
|
|
- struct stat st = {};
|
|
+ __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info *tki = NULL;
|
|
+ const char *jwkdir = misc;
|
|
|
|
if (matches[1].rm_so < matches[1].rm_eo) {
|
|
size_t size = matches[1].rm_eo - matches[1].rm_so;
|
|
@@ -61,23 +61,25 @@ adv(enum http_method method, const char *path, const char *body,
|
|
return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
}
|
|
|
|
- if (snprintf(filename, sizeof(filename),
|
|
- "%s/%s.jws", cachedir, thp ? thp : "default") < 0)
|
|
- return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
-
|
|
- file = fopen(filename, "r");
|
|
- if (!file)
|
|
- return http_reply(HTTP_STATUS_NOT_FOUND, NULL);
|
|
-
|
|
- if (fstat(fileno(file), &st) != 0)
|
|
+ if (!check_keys(jwkdir)) {
|
|
return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
+ }
|
|
|
|
- adv = calloc(st.st_size + 1, 1);
|
|
- if (!adv)
|
|
+ tki = read_keys(jwkdir);
|
|
+ if (!tki) {
|
|
return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
+ }
|
|
|
|
- if (fread(adv, st.st_size, 1, file) != 1)
|
|
- return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
+ if (thp) {
|
|
+ const struct tang_jwk *jwk = find_adv(tki, thp);
|
|
+ if (!jwk) {
|
|
+ return http_reply(HTTP_STATUS_NOT_FOUND, NULL);
|
|
+ }
|
|
+ adv = strdup(jwk->m_str);
|
|
+ } else {
|
|
+ /* Default adv. */
|
|
+ adv = strdup(tki->m_default_adv->m_str);
|
|
+ }
|
|
|
|
return http_reply(HTTP_STATUS_OK,
|
|
"Content-Type: application/jose+json\r\n"
|
|
@@ -91,10 +93,11 @@ rec(enum http_method method, const char *path, const char *body,
|
|
{
|
|
__attribute__((cleanup(str_cleanup))) char *enc = NULL;
|
|
__attribute__((cleanup(str_cleanup))) char *thp = NULL;
|
|
+ __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info *tki = NULL;
|
|
+ const struct tang_jwk *jwk = NULL;
|
|
+
|
|
size_t size = matches[1].rm_eo - matches[1].rm_so;
|
|
- char filename[PATH_MAX] = {};
|
|
- const char *cachedir = misc;
|
|
- json_auto_t *jwk = NULL;
|
|
+ const char *jwkdir = misc;
|
|
json_auto_t *req = NULL;
|
|
json_auto_t *rep = NULL;
|
|
const char *alg = NULL;
|
|
@@ -129,17 +132,24 @@ rec(enum http_method method, const char *path, const char *body,
|
|
if (!thp)
|
|
return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
|
|
- if (snprintf(filename, sizeof(filename), "%s/%s.jwk", cachedir, thp) < 0)
|
|
+ if (!check_keys(jwkdir)) {
|
|
+ return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
+ }
|
|
+
|
|
+ tki = read_keys(jwkdir);
|
|
+ if (!tki) {
|
|
return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
|
|
+ }
|
|
|
|
- jwk = json_load_file(filename, 0, NULL);
|
|
- if (!jwk)
|
|
+ jwk = find_deriving_key(tki, thp);
|
|
+ if (!jwk) {
|
|
return http_reply(HTTP_STATUS_NOT_FOUND, NULL);
|
|
+ }
|
|
|
|
- if (!jose_jwk_prm(NULL, jwk, true, "deriveKey"))
|
|
+ if (!jose_jwk_prm(NULL, jwk->m_json, true, "deriveKey"))
|
|
return http_reply(HTTP_STATUS_FORBIDDEN, NULL);
|
|
|
|
- if (json_unpack(jwk, "{s:s,s?s}", "d", &d, "alg", &alg) < 0)
|
|
+ if (json_unpack(jwk->m_json, "{s:s,s?s}", "d", &d, "alg", &alg) < 0)
|
|
return http_reply(HTTP_STATUS_FORBIDDEN, NULL);
|
|
|
|
if (alg && strcmp(alg, "ECMR") != 0)
|
|
@@ -148,7 +158,7 @@ rec(enum http_method method, const char *path, const char *body,
|
|
/*
|
|
* Perform the exchange and return
|
|
*/
|
|
- rep = jose_jwk_exc(NULL, jwk, req);
|
|
+ rep = jose_jwk_exc(NULL, jwk->m_json, req);
|
|
if (!rep)
|
|
return http_reply(HTTP_STATUS_BAD_REQUEST, NULL);
|
|
|
|
diff --git a/src/util.c b/src/util.c
|
|
new file mode 100644
|
|
index 0000000..b8e3756
|
|
--- /dev/null
|
|
+++ b/src/util.c
|
|
@@ -0,0 +1,141 @@
|
|
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
|
|
+/*
|
|
+ * Copyright (c) 2019 Red Hat, Inc.
|
|
+ * Author: Sergio Correia <scorreia@redhat.com>
|
|
+ *
|
|
+ * 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 <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+
|
|
+#include <dirent.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include "util.h"
|
|
+
|
|
+struct file_list*
|
|
+new_file_list(void)
|
|
+{
|
|
+ struct file_list *fl = malloc(sizeof(*fl));
|
|
+ if (!fl) {
|
|
+ return NULL;
|
|
+ }
|
|
+ fl->m_files = NULL;
|
|
+ fl->m_size = 0;
|
|
+
|
|
+ return fl;
|
|
+}
|
|
+
|
|
+void
|
|
+free_file_list(struct file_list *fl)
|
|
+{
|
|
+ if (!fl) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0, size = fl->m_size; i < size; i++) {
|
|
+ free(fl->m_files[i]);
|
|
+ }
|
|
+ free(fl->m_files);
|
|
+ fl->m_size = 0;
|
|
+ free(fl);
|
|
+}
|
|
+
|
|
+void
|
|
+cleanup_file_list(struct file_list **fl)
|
|
+{
|
|
+ if (!fl || !*fl) {
|
|
+ return;
|
|
+ }
|
|
+ free_file_list(*fl);
|
|
+}
|
|
+
|
|
+int
|
|
+file_list_add(struct file_list *fl, const char *filepath)
|
|
+{
|
|
+ if (!fl || !filepath) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ char **new_files = realloc(fl->m_files, sizeof(char *) * (fl->m_size + 1));
|
|
+ if (!new_files) {
|
|
+ fprintf(stderr, "Error reallocating memory for the new file\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ fl->m_files = new_files;
|
|
+ fl->m_files[fl->m_size++] = strdup(filepath);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+match_file(const char *file, const char *pattern)
|
|
+{
|
|
+ if (!file) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!pattern) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return strstr(file, pattern) != NULL;
|
|
+}
|
|
+
|
|
+int
|
|
+list_files_cmp_func(const void *a, const void *b)
|
|
+{
|
|
+ const char *sa = *(const char**)a;
|
|
+ const char *sb = *(const char**)b;
|
|
+ return strcmp(sa, sb);
|
|
+}
|
|
+
|
|
+struct file_list*
|
|
+list_files(const char *path, const char *pattern, int ignore_hidden)
|
|
+{
|
|
+ struct file_list *fl = new_file_list();
|
|
+ struct dirent *d;
|
|
+ DIR *dir = opendir(path);
|
|
+
|
|
+ if (dir == NULL) {
|
|
+ return fl;
|
|
+ }
|
|
+
|
|
+ while ((d = readdir(dir)) != NULL) {
|
|
+ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (ignore_hidden && d->d_name[0] == '.') {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (match_file(d->d_name, pattern)) {
|
|
+ if (!file_list_add(fl, d->d_name)) {
|
|
+ fprintf(stderr, "Unable to add file %s to file list.\n", d->d_name);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (fl->m_size > 1) {
|
|
+ qsort(fl->m_files, fl->m_size, sizeof(char*), list_files_cmp_func);
|
|
+ }
|
|
+
|
|
+ closedir(dir);
|
|
+ return fl;
|
|
+}
|
|
+
|
|
+
|
|
diff --git a/src/util.h b/src/util.h
|
|
new file mode 100644
|
|
index 0000000..c3af014
|
|
--- /dev/null
|
|
+++ b/src/util.h
|
|
@@ -0,0 +1,33 @@
|
|
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
|
|
+/*
|
|
+ * Copyright (c) 2019 Red Hat, Inc.
|
|
+ * Author: Sergio Correia <scorreia@redhat.com>
|
|
+ *
|
|
+ * 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 <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+struct file_list {
|
|
+ char **m_files;
|
|
+ size_t m_size;
|
|
+};
|
|
+
|
|
+struct file_list* new_file_list(void);
|
|
+void free_file_list(struct file_list*);
|
|
+void cleanup_file_list(struct file_list**);
|
|
+int file_list_add(struct file_list* /* fl */, const char* /* filepath */);
|
|
+int match_file(const char* /* file */, const char* /* pattern */);
|
|
+int list_files_cmp_func(const void*, const void*);
|
|
+struct file_list* list_files(const char* /* path */, const char* /* match */, int /* ignore_hidden */);
|
|
diff --git a/tests/adv b/tests/adv
|
|
index 357d097..986e632 100755
|
|
--- a/tests/adv
|
|
+++ b/tests/adv
|
|
@@ -36,15 +36,13 @@ trap 'exit' ERR
|
|
|
|
export TMP=`mktemp -d`
|
|
mkdir -p $TMP/db
|
|
-mkdir -p $TMP/cache
|
|
|
|
tangd-keygen $TMP/db sig exc
|
|
jose jwk gen -i '{"alg": "ES512"}' -o $TMP/db/.sig.jwk
|
|
jose jwk gen -i '{"alg": "ES512"}' -o $TMP/db/.oth.jwk
|
|
-tangd-update $TMP/db $TMP/cache
|
|
|
|
export PORT=`shuf -i 1024-65536 -n 1`
|
|
-$SD_ACTIVATE -l "127.0.0.1:$PORT" -a $VALGRIND tangd $TMP/cache &
|
|
+$SD_ACTIVATE -l "127.0.0.1:$PORT" -a $VALGRIND tangd $TMP/db &
|
|
export PID=$!
|
|
sleep 0.5
|
|
|
|
diff --git a/tests/rec b/tests/rec
|
|
index d1dfe97..3316565 100755
|
|
--- a/tests/rec
|
|
+++ b/tests/rec
|
|
@@ -28,11 +28,9 @@ trap 'exit' ERR
|
|
|
|
export TMP=`mktemp -d`
|
|
mkdir -p $TMP/db
|
|
-mkdir -p $TMP/cache
|
|
|
|
# Generate the server keys
|
|
tangd-keygen $TMP/db sig exc
|
|
-tangd-update $TMP/db $TMP/cache
|
|
|
|
# Generate the client keys
|
|
exc_kid=`jose jwk thp -i $TMP/db/exc.jwk`
|
|
@@ -42,7 +40,7 @@ jose jwk pub -i $TMP/exc.jwk -o $TMP/exc.pub.jwk
|
|
|
|
# Start the server
|
|
port=`shuf -i 1024-65536 -n 1`
|
|
-$SD_ACTIVATE -l 127.0.0.1:$port -a $VALGRIND tangd $TMP/cache &
|
|
+$SD_ACTIVATE -l 127.0.0.1:$port -a $VALGRIND tangd $TMP/db &
|
|
export PID=$!
|
|
sleep 0.5
|
|
|
|
diff --git a/units/tangd-keygen.service.in b/units/tangd-keygen.service.in
|
|
deleted file mode 100644
|
|
index 2f80cd8..0000000
|
|
--- a/units/tangd-keygen.service.in
|
|
+++ /dev/null
|
|
@@ -1,8 +0,0 @@
|
|
-[Unit]
|
|
-Description=Tang Server key generation script
|
|
-ConditionDirectoryNotEmpty=|!@jwkdir@
|
|
-Requires=tangd-update.path
|
|
-
|
|
-[Service]
|
|
-Type=oneshot
|
|
-ExecStart=@libexecdir@/tangd-keygen @jwkdir@
|
|
diff --git a/units/tangd-update.path.in b/units/tangd-update.path.in
|
|
deleted file mode 100644
|
|
index ee9005d..0000000
|
|
--- a/units/tangd-update.path.in
|
|
+++ /dev/null
|
|
@@ -1,4 +0,0 @@
|
|
-[Path]
|
|
-PathChanged=@jwkdir@
|
|
-MakeDirectory=true
|
|
-DirectoryMode=0700
|
|
diff --git a/units/tangd-update.service.in b/units/tangd-update.service.in
|
|
deleted file mode 100644
|
|
index 11a4cb2..0000000
|
|
--- a/units/tangd-update.service.in
|
|
+++ /dev/null
|
|
@@ -1,6 +0,0 @@
|
|
-[Unit]
|
|
-Description=Tang Server key update script
|
|
-
|
|
-[Service]
|
|
-Type=oneshot
|
|
-ExecStart=@libexecdir@/tangd-update @jwkdir@ @cachedir@
|
|
diff --git a/units/tangd.socket.in b/units/tangd.socket.in
|
|
index 22474ea..0a3e239 100644
|
|
--- a/units/tangd.socket.in
|
|
+++ b/units/tangd.socket.in
|
|
@@ -1,10 +1,5 @@
|
|
[Unit]
|
|
Description=Tang Server socket
|
|
-Requires=tangd-keygen.service
|
|
-Requires=tangd-update.service
|
|
-Requires=tangd-update.path
|
|
-After=tangd-keygen.service
|
|
-After=tangd-update.service
|
|
|
|
[Socket]
|
|
ListenStream=80
|
|
diff --git a/units/tangd@.service.in b/units/tangd@.service.in
|
|
index c4b9597..f1db261 100644
|
|
--- a/units/tangd@.service.in
|
|
+++ b/units/tangd@.service.in
|
|
@@ -5,4 +5,4 @@ Description=Tang Server
|
|
StandardInput=socket
|
|
StandardOutput=socket
|
|
StandardError=journal
|
|
-ExecStart=@libexecdir@/tangd @cachedir@
|
|
+ExecStart=@libexecdir@/tangd @jwkdir@
|
|
--
|
|
2.18.1
|
|
|