From 7961ab6175829c6a71796f34cbe0b8d247245ca9 Mon Sep 17 00:00:00 2001 From: rpm-build Date: Tue, 1 Dec 2020 15:30:19 -0300 Subject: [PATCH 2/2] Move key handling to tang itself Upstream commits: - https://github.com/latchset/tang/commit/6090505 - https://github.com/latchset/tang/commit/c71df1d - https://github.com/latchset/tang/commit/7119454 --- meson.build | 2 - src/keys.c | 455 ++++++++++++++++++++ src/keys.h | 45 ++ src/meson.build | 3 +- src/tangd-update | 83 ---- src/tangd.c | 52 +-- tests/adv | 6 +- tests/keys/-bWkGaJi0Zdvxaj4DCp28umLcRA.jwk | 1 + tests/keys/.r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk | 1 + tests/keys/.uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk | 1 + tests/keys/another-bad-file | 1 + tests/keys/empty.jwk | 0 tests/keys/invalid.jwk | 1 + tests/keys/qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk | 1 + tests/meson.build | 38 +- tests/rec | 4 +- tests/test-keys.c.in | 257 +++++++++++ tests/test-util.c | 75 ++++ tests/test-util.h | 46 ++ units/meson.build | 21 - units/tangd-keygen.service.in | 8 - units/tangd-update.path.in | 4 - units/tangd-update.service.in | 6 - units/tangd.socket | 5 - units/tangd@.service.in | 2 +- 25 files changed, 939 insertions(+), 179 deletions(-) create mode 100644 src/keys.c create mode 100644 src/keys.h delete mode 100755 src/tangd-update create mode 100644 tests/keys/-bWkGaJi0Zdvxaj4DCp28umLcRA.jwk create mode 100644 tests/keys/.r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk create mode 100644 tests/keys/.uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk create mode 100644 tests/keys/another-bad-file create mode 100644 tests/keys/empty.jwk create mode 100644 tests/keys/invalid.jwk create mode 100644 tests/keys/qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk create mode 100644 tests/test-keys.c.in create mode 100644 tests/test-util.c create mode 100644 tests/test-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/meson.build b/meson.build index d91f485..0343fa7 100644 --- a/meson.build +++ b/meson.build @@ -16,14 +16,12 @@ sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir')) bindir = join_paths(get_option('prefix'), get_option('bindir')) systemunitdir = join_paths(get_option('prefix'), 'lib/systemd/system') licensedir = join_paths(get_option('prefix'), 'share', 'licenses', meson.project_name()) -cachedir = join_paths(get_option('localstatedir'), 'cache', meson.project_name()) jwkdir = join_paths(get_option('localstatedir'), 'db', meson.project_name()) data = configuration_data() data.set('libexecdir', libexecdir) data.set('sysconfdir', sysconfdir) data.set('systemunitdir', systemunitdir) -data.set('cachedir', cachedir) data.set('jwkdir', jwkdir) add_project_arguments( diff --git a/src/keys.c b/src/keys.c new file mode 100644 index 0000000..e79be8d --- /dev/null +++ b/src/keys.c @@ -0,0 +1,455 @@ +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */ +/* + * Copyright (c) 2020 Red Hat, Inc. + * Author: Sergio Correia + * + * 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 . + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "keys.h" + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +static const char** +supported_hashes(void) +{ + /* TODO: check if jose has a way to export the hash algorithms it + * supports. */ + static const char* hashes[] = {"S1", "S224", "S256", "S384", "S512", NULL}; + return hashes; +} + +static int +is_hash(const char* alg) +{ + if (!alg) { + return 0; + } + + const char** algs = supported_hashes(); + for (size_t a = 0; algs[a]; a++) { + if (strcmp(alg, algs[a]) == 0) { + return 1; + } + } + return 0; +} + +static json_t* +jwk_generate(const char* alg) +{ + json_auto_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); + return NULL; + } + + return json_incref(jalg); +} + +static char* +jwk_thumbprint(const json_t* jwk, const char* alg) +{ + size_t elen = 0; + size_t dlen = 0; + + if (!jwk) { + fprintf(stderr, "Invalid JWK\n"); + return NULL; + } + + if (!alg || !is_hash(alg)) { + fprintf(stderr, "Invalid hash algorithm (%s)\n", alg); + return NULL; + } + + dlen = jose_jwk_thp_buf(NULL, NULL, alg, NULL, 0); + if (dlen == SIZE_MAX) { + fprintf(stderr, "Error determining hash size for %s\n", alg); + return NULL; + } + + elen = jose_b64_enc_buf(NULL, dlen, NULL, 0); + if (elen == SIZE_MAX) { + fprintf(stderr, "Error determining encoded size for %s\n", alg); + return NULL; + } + + uint8_t dec[dlen]; + char enc[elen]; + + if (!jose_jwk_thp_buf(NULL, jwk, alg, 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; + } + + return strndup(enc, elen); +} + +void +free_tang_keys_info(struct tang_keys_info* tki) +{ + if (!tki) { + return; + } + + json_t* to_free[] = {tki->m_keys, tki->m_rotated_keys, + tki->m_payload, tki->m_sign + }; + size_t len = sizeof(to_free) / sizeof(to_free[0]); + + for (size_t i = 0; i < len; i++) { + if (to_free[i] == NULL) { + continue; + } + json_decref(to_free[i]); + } + free(tki); +} + +void +cleanup_tang_keys_info(struct tang_keys_info** tki) +{ + if (!tki || !*tki) { + return; + } + free_tang_keys_info(*tki); + *tki = NULL; +} + +static struct tang_keys_info* +new_tang_keys_info(void) +{ + struct tang_keys_info* tki = calloc(1, sizeof(*tki)); + if (!tki) { + return NULL; + } + + tki->m_keys = json_array(); + tki->m_rotated_keys = json_array(); + tki->m_payload = json_array(); + tki->m_sign = json_array(); + + if (!tki->m_keys || !tki->m_rotated_keys || + !tki->m_payload || !tki->m_sign) { + free_tang_keys_info(tki); + return NULL; + } + tki->m_keys_count = 0; + return tki; +} + +static int +jwk_valid_for(const json_t* jwk, const char* use) +{ + if (!jwk || !use) { + return 0; + } + return jose_jwk_prm(NULL, jwk, false, use); +} + +static int +jwk_valid_for_signing_and_verifying(const json_t* jwk) +{ + const char* uses[] = {"sign", "verify", NULL}; + int ret = 1; + for (int i = 0; uses[i]; i++) { + if (!jwk_valid_for(jwk, uses[i])) { + ret = 0; + break; + } + } + return ret; +} + +static int +jwk_valid_for_signing(const json_t* jwk) +{ + return jwk_valid_for(jwk, "sign"); +} + +static int +jwk_valid_for_deriving_keys(const json_t* jwk) +{ + return jwk_valid_for(jwk, "deriveKey"); +} + +static void +cleanup_str(char** str) +{ + if (!str || !*str) { + return; + } + free(*str); + *str = NULL; +} + +static json_t* +jwk_sign(const json_t* to_sign, const json_t* sig_keys) +{ + if (!sig_keys || !json_is_array(sig_keys) || !json_is_array(to_sign)) { + return NULL; + } + + json_auto_t* to_sign_copy = json_deep_copy(to_sign); + if (!jose_jwk_pub(NULL, to_sign_copy)) { + fprintf(stderr, "Error removing private material from data to sign\n"); + } + + json_auto_t* payload = json_pack("{s:O}", "keys", to_sign_copy); + json_auto_t* sig_template = json_pack("{s:{s:s}}", + "protected", "cty", "jwk-set+json"); + + /* Use the template with the signing keys. */ + json_auto_t* sig_template_arr = json_array(); + size_t arr_size = json_array_size(sig_keys); + for (size_t i = 0; i < arr_size; i++) { + if (json_array_append(sig_template_arr, sig_template) == -1) { + fprintf(stderr, "Unable to append sig template to array\n"); + return NULL; + } + } + + __attribute__ ((__cleanup__(cleanup_str))) char* data_to_sign = json_dumps(payload, 0); + json_auto_t* jws = json_pack("{s:o}", "payload", + jose_b64_enc(data_to_sign, strlen(data_to_sign))); + + if (!jose_jws_sig(NULL, jws, sig_template_arr, sig_keys)) { + fprintf(stderr, "Error trying to jose_jws_sign\n"); + return NULL; + } + return json_incref(jws); +} + +static json_t* +find_by_thp(struct tang_keys_info* tki, const char* target) +{ + if (!tki) { + return NULL; + } + + json_auto_t* keys = json_deep_copy(tki->m_keys); + json_array_extend(keys, tki->m_rotated_keys); + + size_t idx; + json_t* jwk; + const char** hashes = supported_hashes(); + json_array_foreach(keys, idx, jwk) { + for (int i = 0; hashes[i]; i++) { + __attribute__ ((__cleanup__(cleanup_str))) char* thumbprint = jwk_thumbprint(jwk, hashes[i]); + if (strcmp(thumbprint, target) != 0) { + continue; + } + + if (jwk_valid_for_deriving_keys(jwk)) { + return json_incref(jwk); + } else if (jwk_valid_for_signing(jwk)) { + json_auto_t* sign = json_deep_copy(tki->m_sign); + if (json_array_append(sign, jwk) == -1) { + return NULL; + } + json_auto_t* jws = jwk_sign(tki->m_payload, sign); + if (!jws) { + return NULL; + } + return json_incref(jws); + } + } + } + return NULL; +} + +static int +prepare_payload_and_sign(struct tang_keys_info* tki) +{ + if (!tki) { + return 0; + } + + size_t idx; + json_t* jwk; + json_array_foreach(tki->m_keys, idx, jwk) { + if (jwk_valid_for_signing_and_verifying(jwk)) { + if (json_array_append(tki->m_sign, jwk) == -1) { + continue; + } + if (json_array_append(tki->m_payload, jwk) == -1) { + continue; + } + } else if (jwk_valid_for_deriving_keys(jwk)) { + if (json_array_append(tki->m_payload, jwk) == -1) { + continue; + } + } + } + if (json_array_size(tki->m_sign) == 0 || json_array_size(tki->m_payload) == 0) { + return 0; + } + return 1; +} + +static int +create_new_keys(const char* jwkdir) +{ + const char** hashes = supported_hashes(); + const char* alg[] = {"ES512", "ECMR", NULL}; + char path[PATH_MAX]; + for (int i = 0; alg[i] != NULL; i++) { + json_auto_t* jwk = jwk_generate(alg[i]); + if (!jwk) { + return 0; + } + __attribute__ ((__cleanup__(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[0]); + if (!thp) { + return 0; + } + if (snprintf(path, PATH_MAX, "%s/%s.jwk", jwkdir, thp) < 0) { + fprintf(stderr, "Unable to prepare variable with file full path (%s)\n", thp); + return 0; + } + path[sizeof(path) - 1] = '\0'; + if (json_dump_file(jwk, path, 0) == -1) { + fprintf(stderr, "Error saving JWK to file (%s)\n", path); + return 0; + } + } + return 1; +} + +static struct tang_keys_info* +load_keys(const char* jwkdir) +{ + struct tang_keys_info* tki = new_tang_keys_info(); + if (!tki) { + return NULL; + } + + struct dirent* d; + DIR* dir = opendir(jwkdir); + if (!dir) { + free_tang_keys_info(tki); + return NULL; + } + + char filepath[PATH_MAX]; + const char* pattern = ".jwk"; + while ((d = readdir(dir)) != NULL) { + if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) { + continue; + } + + char* dot = strrchr(d->d_name, '.'); + if (!dot) { + continue; + } + + if (strcmp(dot, pattern) == 0) { + /* Found a file with .jwk extension. */ + if (snprintf(filepath, PATH_MAX, "%s/%s", jwkdir, d->d_name) < 0) { + fprintf(stderr, "Unable to prepare variable with file full path (%s); skipping\n", d->d_name); + continue; + } + filepath[sizeof(filepath) - 1] = '\0'; + json_auto_t* json = json_load_file(filepath, 0, NULL); + if (!json) { + fprintf(stderr, "Invalid JSON file (%s); skipping\n", filepath); + continue; + } + + json_t* arr = tki->m_keys; + if (d->d_name[0] == '.') { + arr = tki->m_rotated_keys; + } + if (json_array_append(arr, json) == -1) { + fprintf(stderr, "Unable to append JSON (%s) to array; skipping\n", d->d_name); + continue; + } + tki->m_keys_count++; + } + } + closedir(dir); + return tki; +} + +struct tang_keys_info* +read_keys(const char* jwkdir) +{ + struct tang_keys_info* tki = load_keys(jwkdir); + if (!tki) { + return NULL; + } + + if (tki->m_keys_count == 0) { + /* Let's attempt to create a new pair of keys. */ + free_tang_keys_info(tki); + if (!create_new_keys(jwkdir)) { + return NULL; + } + tki = load_keys(jwkdir); + } + + if (!prepare_payload_and_sign(tki)) { + free_tang_keys_info(tki); + return NULL; + } + return tki; +} + +json_t* +find_jws(struct tang_keys_info* tki, const char* thp) +{ + if (!tki) { + return NULL; + } + + if (thp == NULL) { + /* Default advertisement. */ + json_auto_t* jws = jwk_sign(tki->m_payload, tki->m_sign); + if (!jws) { + return NULL; + } + return json_incref(jws); + } + return find_by_thp(tki, thp); +} + +json_t* +find_jwk(struct tang_keys_info* tki, const char* thp) +{ + if (!tki || !thp) { + return NULL; + } + return find_by_thp(tki, thp); +} diff --git a/src/keys.h b/src/keys.h new file mode 100644 index 0000000..5bae23c --- /dev/null +++ b/src/keys.h @@ -0,0 +1,45 @@ +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */ +/* + * Copyright (c) 2020 Red Hat, Inc. + * Author: Sergio Correia + * + * 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 . + */ + +#pragma once + +#include +#include + +struct tang_keys_info { + /* Arrays. */ + json_t* m_keys; /* Regular keys. */ + json_t* m_rotated_keys; /* Rotated keys. */ + + json_t* m_payload; /* Payload made of regular keys capable of + * either signing+verifying or deriving new + * keys. */ + + json_t* m_sign; /* Set of signing keys made from regular + keys. */ + + size_t m_keys_count; /* Number of keys (regular + rotated). */ + +}; + +void cleanup_tang_keys_info(struct tang_keys_info**); +void free_tang_keys_info(struct tang_keys_info*); +struct tang_keys_info* read_keys(const char* /* jwkdir */); +json_t* find_jws(struct tang_keys_info* /* tki */, const char* /* thp */); +json_t* find_jwk(struct tang_keys_info* /* tki */, const char* /* thp */); diff --git a/src/meson.build b/src/meson.build index 1eb8baf..fd14fcb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,6 @@ tangd = executable('tangd', - 'http.h', 'http.c', + 'keys.c', 'tangd.c', dependencies: [jose, http_parser], install: true, @@ -9,6 +9,5 @@ tangd = executable('tangd', bins += join_paths(meson.current_source_dir(), 'tang-show-keys') libexecbins += join_paths(meson.current_source_dir(), 'tangd-keygen') -libexecbins += join_paths(meson.current_source_dir(), 'tangd-update') # vim:set ts=2 sw=2 et: 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 -# -# 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 . -# - -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 " >&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..cd1488e 100644 --- a/src/tangd.c +++ b/src/tangd.c @@ -28,6 +28,7 @@ #include #include +#include "keys.h" static void str_cleanup(char **str) @@ -36,23 +37,20 @@ str_cleanup(char **str) free(*str); } -static void -FILE_cleanup(FILE **file) -{ - if (file && *file) - fclose(*file); -} - static int adv(enum http_method method, const char *path, const char *body, regmatch_t matches[], void *misc) { - __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; + json_auto_t *jws = NULL; + const char *jwkdir = misc; + + tki = read_keys(jwkdir); + if (!tki || tki->m_keys_count == 0) { + return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); + } if (matches[1].rm_so < matches[1].rm_eo) { size_t size = matches[1].rm_eo - matches[1].rm_so; @@ -61,24 +59,15 @@ 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) + jws = find_jws(tki, thp); + if (!jws) { return http_reply(HTTP_STATUS_NOT_FOUND, NULL); + } - if (fstat(fileno(file), &st) != 0) - return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); - - adv = calloc(st.st_size + 1, 1); + adv = json_dumps(jws, 0); if (!adv) 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); - return http_reply(HTTP_STATUS_OK, "Content-Type: application/jose+json\r\n" "Content-Length: %zu\r\n" @@ -91,9 +80,9 @@ 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; size_t size = matches[1].rm_eo - matches[1].rm_so; - char filename[PATH_MAX] = {}; - const char *cachedir = misc; + const char *jwkdir = misc; json_auto_t *jwk = NULL; json_auto_t *req = NULL; json_auto_t *rep = NULL; @@ -124,15 +113,16 @@ rec(enum http_method method, const char *path, const char *body, /* * Parse and validate the server-side JWK */ + tki = read_keys(jwkdir); + if (!tki || tki->m_keys_count == 0) { + return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); + } thp = strndup(&path[matches[1].rm_so], size); if (!thp) return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); - if (snprintf(filename, sizeof(filename), "%s/%s.jwk", cachedir, thp) < 0) - return http_reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); - - jwk = json_load_file(filename, 0, NULL); + jwk = find_jwk(tki, thp); if (!jwk) return http_reply(HTTP_STATUS_NOT_FOUND, NULL); @@ -188,7 +178,7 @@ main(int argc, char *argv[]) http_parser_init(&parser, HTTP_REQUEST); if (argc != 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s \n", argv[0]); return EXIT_FAILURE; } diff --git a/tests/adv b/tests/adv index 357d097..06d1330 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 @@ -84,4 +82,4 @@ fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` \ -g 0 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU \ -g 1 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU -test $(tang-show-keys $PORT) == $(jose jwk thp -i $TMP/db/sig.jwk) +test "$(tang-show-keys $PORT)" == "$(jose jwk thp -i $TMP/db/sig.jwk)" diff --git a/tests/keys/-bWkGaJi0Zdvxaj4DCp28umLcRA.jwk b/tests/keys/-bWkGaJi0Zdvxaj4DCp28umLcRA.jwk new file mode 100644 index 0000000..d51ccbd --- /dev/null +++ b/tests/keys/-bWkGaJi0Zdvxaj4DCp28umLcRA.jwk @@ -0,0 +1 @@ +{"alg":"ECMR","crv":"P-521","d":"AQ3u1g0L__GIGSJRX1LtjSArwJxxQz0kWXIi-X4PqwoheoeY57cw36pmWmyVsn43jDEZ6SAsiNeIw9sHDkFZe1VV","key_ops":["deriveKey"],"kty":"EC","x":"AcfowrKEKteg_jKX1CiR2RQfbUGJ73KXlcl8AgIDAgN7R6yNKWpKhZNBmV2tAxxMCQcIksqQl17UXwemvH2j2fem","y":"ACrb-y4ZhLIGX-41QYgJhniiZ85qkjILbkVUcC8gBYxOAnKWIpMGLsjrT3AYhM6jk6puwnNYbEM28s2caAEogUcA"} diff --git a/tests/keys/.r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk b/tests/keys/.r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk new file mode 100644 index 0000000..5602a0c --- /dev/null +++ b/tests/keys/.r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk @@ -0,0 +1 @@ +{"alg":"ES512","crv":"P-521","d":"Af5SfYh_4LmBDF9dCGDQRDA52yzqnzDeo-GZU05hpnLr6bsIBTFpc8rdcCm95mhZ59ngC-6WNtmAF_nLCDcHKg0A","key_ops":["sign","verify"],"kty":"EC","x":"AUxS3DXdoONUB-6-nyzdd3V42iD7obGTJ1m40t3V6jzXfABWp_gtTidwiKyDJQXxhEzMSToo-V0RGq6Qz2XTOgPe","y":"AFrkJfkLGJz_2v-k3-wdydckVcBXql2NR66HaF0U9NlcfGLezQau7XihArm4GE3-sHoQLsRa-HvYET9zyd9Syh5y"} diff --git a/tests/keys/.uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk b/tests/keys/.uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk new file mode 100644 index 0000000..5088e1c --- /dev/null +++ b/tests/keys/.uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk @@ -0,0 +1 @@ +{"alg":"ECMR","crv":"P-521","d":"Acuk66sHvSS5TN-p0XhwHhVKyifYr-ecur-7zfgQZMzSq9SeBJjuX6Ttav-7AbnVvXU_S55BgtGL5iymXGuMguCp","key_ops":["deriveKey"],"kty":"EC","x":"AEz9EwBOIrLeV4in6M1oWVnOWVR7ubkFB0R0-AwyIL7u5-7G3u2tvPIJRQY-l1Wttn7Ar4DhflcMhnb3rk5hT5yh","y":"AZt35wqOhNsnEi-GLAgyCaiW_c6h6Zyo4xwjuvXzmQMDwh9MtdaUigFuBOTlfRj1uri_YBqdpI09nYrqqgx97Ca6"} diff --git a/tests/keys/another-bad-file b/tests/keys/another-bad-file new file mode 100644 index 0000000..323fae0 --- /dev/null +++ b/tests/keys/another-bad-file @@ -0,0 +1 @@ +foobar diff --git a/tests/keys/empty.jwk b/tests/keys/empty.jwk new file mode 100644 index 0000000..e69de29 diff --git a/tests/keys/invalid.jwk b/tests/keys/invalid.jwk new file mode 100644 index 0000000..257cc56 --- /dev/null +++ b/tests/keys/invalid.jwk @@ -0,0 +1 @@ +foo diff --git a/tests/keys/qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk b/tests/keys/qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk new file mode 100644 index 0000000..107a545 --- /dev/null +++ b/tests/keys/qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk @@ -0,0 +1 @@ +{"alg":"ES512","crv":"P-521","d":"AUQpuWtoSqURl0OuWQ-I9i4X1F3sDak0Hbf9Ixj7uwjA20A0ABJdCHbai1Ai0t3yoxWKPYi6t2XjjeRzHIKyhXbf","key_ops":["sign","verify"],"kty":"EC","x":"ACbYnvh1EtLePkM5jCtuxLpMroOUNRfv-wQdXgT5AQ5bhSLv6wkrBzh1rwymo-fmCNWzrcTflzqWf-wXAd00lokM","y":"AEaDByxXfbee4TlPXgPRg5S4MVOqgObjX6_JJkySTudSfOygcx7dujsf32dOEI25d8bNKUgdjQt8lc5XtHeWXH3a"} diff --git a/tests/meson.build b/tests/meson.build index b03531d..9fe656e 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,22 +1,42 @@ +incdir = include_directories( + join_paths('..', 'src') +) + +test_data = configuration_data() +test_data.set('testjwkdir', join_paths(meson.source_root(), 'tests','keys')) + +test_keys_c = configure_file( + input: 'test-keys.c.in', + output: 'test-keys.c', + configuration: test_data +) + +test_keys = executable('test-keys', + test_keys_c, + 'test-util.c', + dependencies: [jose], + include_directories: incdir +) + sd_activate = find_program( 'systemd-socket-activate', 'systemd-activate', required: false ) +env = environment() +env.prepend('PATH', + join_paths(meson.source_root(), 'src'), + join_paths(meson.build_root(), 'src'), + separator: ':' +) + if sd_activate.found() - env = environment() - env.prepend('PATH', - join_paths(meson.source_root(), 'src'), - join_paths(meson.build_root(), 'src'), - separator: ':' - ) env.set('SD_ACTIVATE', sd_activate.path() + ' --inetd') - test('adv', find_program('adv'), env: env) + test('adv', find_program('adv'), env: env, timeout: 60) test('rec', find_program('rec'), env: env) -else - warning('Will not run the tests due to missing dependencies!') endif +test('test-keys', test_keys, env: env, timeout: 60) # vim:set ts=2 sw=2 et: 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/tests/test-keys.c.in b/tests/test-keys.c.in new file mode 100644 index 0000000..2071b9f --- /dev/null +++ b/tests/test-keys.c.in @@ -0,0 +1,257 @@ +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */ +/* + * Copyright (c) 2020 Red Hat, Inc. + * Author: Sergio Correia + * + * 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 . + */ + +#include "keys.c" +#include "test-util.h" + +const char* jwkdir = "@testjwkdir@"; + +struct thp_result { + const char* thp; + int valid; +}; + +struct test_result_int { + const char* data; + int expected; +}; + +static void +test_create_new_keys(void) +{ + __attribute__((cleanup(cleanup_str))) char* newdir = create_tempdir(); + ASSERT(newdir); + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(newdir); + ASSERT(tki); + ASSERT(tki->m_keys_count == 2); + remove_tempdir(newdir); +} + + +static void +test_is_hash(void) +{ + const struct test_result_int test_data[] = { + {NULL, 0}, + {"", 0}, + {"ES512", 0}, + {"ECMR", 0}, + {"foobar", 0}, + {"{", 0}, + {"[}", 0}, + {"[]", 0}, + {"S1", 1}, + {"S224", 1}, + {"S256", 1}, + {"S384", 1}, + {"S512", 1}, + {"S42", 0} + }; + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) { + int ret = is_hash(test_data[i].data); + ASSERT_WITH_MSG(ret == test_data[i].expected, "i = %d, alg = %s", i, test_data[i].data); + }; + +} + +static void +test_jwk_generate(void) +{ + const struct test_result_int test_data[] = { + {NULL, 0}, + {"", 0}, + {"ES512", 1}, + {"ECMR", 1}, + {"foobar", 0}, + {"{", 0}, + {"[}", 0}, + {"[]", 0} + }; + + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) { + json_auto_t* jwk = jwk_generate(test_data[i].data); + ASSERT_WITH_MSG(!!jwk == test_data[i].expected, "i = %d, alg = %s", i, test_data[i].data); + }; +} + +static void +test_find_jws(void) +{ + const struct thp_result test_data[] = { + {"00BUQM4A7NYxbOrBR9QDfkzGVGj3k57Fs4jCbJxcLYAgRFHu5B7jtbL97x1T7stQ", 1}, + {"dd5qbN1lQ6UWdZszbfx2oIcH34ShklzFL1SUQg", 1}, + {"dOZkUtZ_gLDUP53GIlyAxHMNuyrk8vdY-XXND32GccqNbT_MKpqGC-13-GNEye48", 1}, + {"DZrlBQvfvlwPQlvH_IieBdc_KpesEramLygVL_rFr7g", 1}, + {"FL_Zt5fFadUL4syeMMpUnss8aKdCrPGFy3102JGR3EE", 1}, + {"qgmqJSo6AEEuVQY7zVlklqdTMqY", 1}, + {"r4E2wG1u_YyKUo0N0rIK7jJF5Xg", 1}, + {"ugJ4Ula-YABQIiJ-0g3B_jpFpF2nl3W-DNpfLdXArhTusV0QCcd1vtgDeGHEPzpm7jEsyC7VYYSSOkZicK22mw", 1}, + {"up0Z4fRhpd4O5QwBaMCXDTlrvxCmZacU0MD8kw", 1}, + {"vllHS-M0aQFCo2yUCcAahMU4TAtXACyeuRf-zbmmTPBg7V0Pb-RRFGo5C6MnpzdirK8B3ORLOsN8RyXClvtjxA", 1}, + {NULL, 1}, + {"a", 0}, + {"foo", 0}, + {"bar", 0}, + {"XXXXXXXXXXXXXXXXXX", 0} + }; + + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir); + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) { + json_auto_t* jws = find_jws(tki, test_data[i].thp); + ASSERT_WITH_MSG(!!jws == test_data[i].valid, "i = %d, thp = %s", i, test_data[i].thp); + } + + /* Passing NULL to find_jws should return the default advertisement */ + json_auto_t* adv = find_jws(tki, NULL); + ASSERT(adv); + + + /* + * The default set of signing keys are the signing keys that are not + * rotated. The payload is made of deriving keys that are also not + * rotated. The default advertisement should be signed by this set of + * default signing keys. + */ + ASSERT(jose_jws_ver(NULL, adv, NULL, tki->m_sign, 1)); + + /* find_jws should be able to respond to thumbprints of keys using any + * of jose supported hash algorithms. */ + const char** hashes = supported_hashes(); + size_t idx; + json_t* jwk; + + /* Let's put together all the keys, including rotated ones. */ + json_auto_t* keys = json_deep_copy(tki->m_keys); + ASSERT(keys); + ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0); + ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count); + + for (int i = 0; hashes[i]; i++) { + json_array_foreach(keys, idx, jwk) { + if (!jwk_valid_for_signing(jwk)) { + continue; + } + __attribute__((cleanup(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[i]); + ASSERT_WITH_MSG(thp, "i = %d, hash = %s, key idx = %d", i, hashes[i], idx); + json_auto_t* jws = find_jws(tki, thp); + ASSERT_WITH_MSG(jws, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp); + + /* Signing keys should sign the payload, in addition to the + * default set of signing keys. */ + json_auto_t* sign = json_deep_copy(tki->m_sign); + ASSERT_WITH_MSG(sign, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp); + ASSERT_WITH_MSG(json_array_append(sign, jwk) == 0, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp); + ASSERT_WITH_MSG(jose_jws_ver(NULL, jws, NULL, sign, 1), "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp); + } + } +} + +static void +test_find_jwk(void) +{ + const struct thp_result test_data[] = { + {"1HdF3XKRSsuZdkpXNurBPoL_pvxdvCOlHuhB4DP-4xWFqbZ51zo29kR4fSiT3BGy9UrHVJ26JMBLOA1vKq3lxA", 1}, + {"9U8qgy_YjyY6Isuq6QuiKEiYZgNJShcGgJx5FJzCu6m3N6zFaIPy_HDkxkVqAZ9E", 1}, + {"-bWkGaJi0Zdvxaj4DCp28umLcRA", 1}, + {"Cy73glFjs6B6RU7wy6vWxAc-2bJy5VJOT9LyK80eKgZ8k27wXZ-3rjsuNU5tua_yHWtluyoSYtjoKXfI0E8ESw", 1}, + {"kfjbqx_b3BsgPC87HwlOWL9daGMMHBzxcFLClw", 1}, + {"L4xg2tZXTEVbsK39bzOZM1jGWn3HtOxF5gh6F9YVf5Q", 1}, + {"LsVAV2ig5LlfstM8TRSf-c7IAkLpNYbIysNuRCVlxocRCGqAh6-f9PklM4nU4N-J", 1}, + {"OkAcDxYHNlo7-tul8OubYuWXB8CPEhAkcacCmhTclMU", 1}, + {"uZ0s8YTXcGcuWduWWBSiR2OjOVg", 1}, + {"WEpfFyeoNKkE2-TosN_bP-gd9UgRvQCZpVasZQ", 1}, + {NULL, 0}, + {"a", 0}, + {"foo", 0}, + {"bar", 0}, + {"XXXXXXXXXXXXXXXXXX", 0}, + }; + + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir); + + for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) { + json_auto_t* tjwk = find_jwk(tki, test_data[i].thp); + ASSERT_WITH_MSG(!!tjwk == test_data[i].valid, "i = %d, thp = %s", i, test_data[i].thp); + } + /* Passing NULL to find_jwk should fail */ + json_auto_t* bad_jwk = find_jwk(tki, NULL); + ASSERT(bad_jwk == NULL); + + /* find_jwk should be able to respond to thumbprints of keys using any + * of jose supported hash algorithms. */ + const char** hashes = supported_hashes(); + size_t idx; + json_t* jwk; + + /* Let's put together all the keys, including rotated ones. */ + json_auto_t* keys = json_deep_copy(tki->m_keys); + ASSERT(keys); + ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0); + ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count); + + for (int i = 0; hashes[i]; i++) { + json_array_foreach(keys, idx, jwk) { + if (!jwk_valid_for_deriving_keys(jwk)) { + continue; + } + __attribute__((cleanup(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[i]); + json_auto_t* tjwk = find_jwk(tki, thp); + ASSERT_WITH_MSG(tjwk, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp); + } + } +} + +static void +test_read_keys(void) +{ + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir); + ASSERT(tki); + + /* + * Keys in tests/keys: + * - .uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk + * - .r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk + * - qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk + * - -bWkGaJi0Zdvxaj4DCp28umLcRA.jwk + */ + ASSERT(tki->m_keys_count == 4); + ASSERT(json_array_size(tki->m_keys) == 2); + ASSERT(json_array_size(tki->m_rotated_keys) == 2); + + const char* invalid_jwkdir = "foobar"; + __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki2 = read_keys(invalid_jwkdir); + ASSERT(tki2 == NULL); +} + +static void +run_tests(void) +{ + test_read_keys(); + test_find_jwk(); + test_find_jws(); + test_jwk_generate(); + test_is_hash(); + test_create_new_keys(); +} + +int main(int argc, char** argv) +{ + run_tests(); + return 0; +} diff --git a/tests/test-util.c b/tests/test-util.c new file mode 100644 index 0000000..bc1299b --- /dev/null +++ b/tests/test-util.c @@ -0,0 +1,75 @@ +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */ +/* + * Copyright (c) 2020 Red Hat, Inc. + * Author: Sergio Correia + * + * 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 . + */ + +#define _XOPEN_SOURCE 500L + +#include +#include +#include +#include +#include +#include + +#include "test-util.h" + +void +assert_func(const char* filename, + int lineno, + const char* funcname, + const char* expr, + const char* fmt, + ...) +{ + char buffer[MAX_BUF_LEN] = {}; + if (fmt) { + va_list ap; + va_start(ap, fmt); + vsnprintf(buffer, MAX_BUF_LEN, fmt, ap); + va_end(ap); + buffer[strcspn(buffer, "\r\n")] = '\0'; + } + fprintf(stderr, "%s:%d: assertion '%s' failed in %s(). %s\n", filename, + lineno, + expr, + funcname, + buffer); + abort(); +} + +static int +nftw_remove_callback(const char* path, const struct stat* stat, + int type, struct FTW* ftw) +{ + return remove(path); +} + +char* +create_tempdir(void) +{ + char template[] = "/tmp/tang.test.XXXXXX"; + char *tmpdir = mkdtemp(template); + return strdup(tmpdir); +} + +int +remove_tempdir(const char* path) +{ + return nftw(path, nftw_remove_callback, FOPEN_MAX, FTW_DEPTH|FTW_MOUNT|FTW_PHYS); +} + diff --git a/tests/test-util.h b/tests/test-util.h new file mode 100644 index 0000000..eae9a71 --- /dev/null +++ b/tests/test-util.h @@ -0,0 +1,46 @@ +/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */ +/* + * Copyright (c) 2020 Red Hat, Inc. + * Author: Sergio Correia + * + * 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 . + */ + +#pragma once + +#include + +#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof(0[arr])) +#define MAX_BUF_LEN 2048 + +void +assert_func(const char* /* filename */, + int /* line number */, + const char* /* function name */, + const char* /* expression */, + const char* /* format */, + ...); + +#define ASSERT_WITH_MSG(expr, fmt, ...) \ + if (!(expr)) \ + assert_func(__FILE__, __LINE__, __FUNCTION__, #expr, fmt, ##__VA_ARGS__) + +#define ASSERT(expr) \ + ASSERT_WITH_MSG(expr, NULL) + +char* +create_tempdir(void); + +int +remove_tempdir(const char* /* path */); diff --git a/units/meson.build b/units/meson.build index ada6dd0..6e66af9 100644 --- a/units/meson.build +++ b/units/meson.build @@ -1,31 +1,10 @@ -tangd_keygen_service = configure_file( - input: 'tangd-keygen.service.in', - output: 'tangd-keygen.service', - configuration: data -) - tangd_service = configure_file( input: 'tangd@.service.in', output: 'tangd@.service', configuration: data ) -tangd_update_path = configure_file( - input: 'tangd-update.path.in', - output: 'tangd-update.path', - configuration: data -) - -tangd_update_service = configure_file( - input: 'tangd-update.service.in', - output: 'tangd-update.service', - configuration: data -) - units += join_paths(meson.current_source_dir(), 'tangd.socket') -units += tangd_keygen_service units += tangd_service -units += tangd_update_path -units += tangd_update_service # vim:set ts=2 sw=2 et: 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 b/units/tangd.socket index 22474ea..0a3e239 100644 --- a/units/tangd.socket +++ b/units/tangd.socket @@ -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.28.0