mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
routerkeys: Add cmdline option for learning signing key expiration.
* CLOSES #17639. * ADDS new --key-expiration commandline option which prints when the signing key expires.
This commit is contained in:
parent
fabc3deb75
commit
b2a7e8df90
4
changes/bug17639
Normal file
4
changes/bug17639
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor features:
|
||||
- Add a new commandline option, --key-expiration, which prints when
|
||||
the current signing key is going to expire. Implements ticket
|
||||
17639; patch by Isis Lovecruft.
|
@ -128,6 +128,16 @@ COMMAND-LINE OPTIONS
|
||||
the passphrase, including any trailing newlines.
|
||||
Default: read from the terminal.
|
||||
|
||||
[[opt-key-expiration]] **--key-expiration** [**purpose**]::
|
||||
The **purpose** specifies which type of key certificate to determine
|
||||
the expiration of. The only currently recognised **purpose** is
|
||||
"sign". +
|
||||
+
|
||||
Running "tor --key-expiration sign" will attempt to find your signing
|
||||
key certificate and will output, both in the logs as well as to stdout,
|
||||
the signing key certificate's expiration time in ISO-8601 format.
|
||||
For example, the output sent to stdout will be of the form:
|
||||
"signing-cert-expiry: 2017-07-25 08:30:15 UTC"
|
||||
|
||||
Other options can be specified on the command-line in the format "--option
|
||||
value", in the format "option value", or in a configuration file. For
|
||||
|
@ -2137,6 +2137,7 @@ static const struct {
|
||||
{ "--dump-config", ARGUMENT_OPTIONAL },
|
||||
{ "--list-fingerprint", TAKES_NO_ARGUMENT },
|
||||
{ "--keygen", TAKES_NO_ARGUMENT },
|
||||
{ "--key-expiration", ARGUMENT_OPTIONAL },
|
||||
{ "--newpass", TAKES_NO_ARGUMENT },
|
||||
{ "--no-passphrase", TAKES_NO_ARGUMENT },
|
||||
{ "--passphrase-fd", ARGUMENT_NECESSARY },
|
||||
@ -4932,6 +4933,9 @@ options_init_from_torrc(int argc, char **argv)
|
||||
for (p_index = cmdline_only_options; p_index; p_index = p_index->next) {
|
||||
if (!strcmp(p_index->key,"--keygen")) {
|
||||
command = CMD_KEYGEN;
|
||||
} else if (!strcmp(p_index->key, "--key-expiration")) {
|
||||
command = CMD_KEY_EXPIRATION;
|
||||
command_arg = p_index->value;
|
||||
} else if (!strcmp(p_index->key,"--list-fingerprint")) {
|
||||
command = CMD_LIST_FINGERPRINT;
|
||||
} else if (!strcmp(p_index->key, "--hash-password")) {
|
||||
|
@ -3758,6 +3758,11 @@ tor_main(int argc, char *argv[])
|
||||
case CMD_KEYGEN:
|
||||
result = load_ed_keys(get_options(), time(NULL)) < 0;
|
||||
break;
|
||||
case CMD_KEY_EXPIRATION:
|
||||
init_keys();
|
||||
result = log_cert_expiration();
|
||||
result = 0;
|
||||
break;
|
||||
case CMD_LIST_FINGERPRINT:
|
||||
result = do_list_fingerprint();
|
||||
break;
|
||||
|
@ -3588,7 +3588,8 @@ typedef struct {
|
||||
enum {
|
||||
CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD,
|
||||
CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG,
|
||||
CMD_KEYGEN
|
||||
CMD_KEYGEN,
|
||||
CMD_KEY_EXPIRATION,
|
||||
} command;
|
||||
char *command_arg; /**< Argument for command-line option. */
|
||||
|
||||
|
@ -1136,6 +1136,108 @@ init_mock_ed_keys(const crypto_pk_t *rsa_identity_key)
|
||||
#undef MAKECERT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Print the ISO8601-formated <b>expiration</b> for a certificate with
|
||||
* some <b>description</b> to stdout.
|
||||
*
|
||||
* For example, for a signing certificate, this might print out:
|
||||
* signing-cert-expiry: 2017-07-25 08:30:15 UTC
|
||||
*/
|
||||
static void
|
||||
print_cert_expiration(const char *expiration,
|
||||
const char *description)
|
||||
{
|
||||
fprintf(stderr, "%s-cert-expiry: %s\n", description, expiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log when a certificate, <b>cert</b>, with some <b>description</b> and
|
||||
* stored in a file named <b>fname</b>, is going to expire.
|
||||
*/
|
||||
static void
|
||||
log_ed_cert_expiration(const tor_cert_t *cert,
|
||||
const char *description,
|
||||
const char *fname) {
|
||||
char expiration[ISO_TIME_LEN+1];
|
||||
|
||||
if (BUG(!cert)) { /* If the specified key hasn't been loaded */
|
||||
log_warn(LD_OR, "No %s key loaded; can't get certificate expiration.",
|
||||
description);
|
||||
} else {
|
||||
format_local_iso_time(expiration, cert->valid_until);
|
||||
log_notice(LD_OR, "The %s certificate stored in %s is valid until %s.",
|
||||
description, fname, expiration);
|
||||
print_cert_expiration(expiration, description);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log when our master signing key certificate expires. Used when tor is given
|
||||
* the --key-expiration command-line option.
|
||||
*
|
||||
* Returns 0 on success and 1 on failure.
|
||||
*/
|
||||
static int
|
||||
log_master_signing_key_cert_expiration(const or_options_t *options)
|
||||
{
|
||||
const tor_cert_t *signing_key;
|
||||
char *fn = NULL;
|
||||
int failed = 0;
|
||||
time_t now = approx_time();
|
||||
|
||||
fn = options_get_datadir_fname2(options, "keys", "ed25519_signing_cert");
|
||||
|
||||
/* Try to grab our cached copy of the key. */
|
||||
signing_key = get_master_signing_key_cert();
|
||||
|
||||
tor_assert(server_identity_key_is_set());
|
||||
|
||||
/* Load our keys from disk, if necessary. */
|
||||
if (!signing_key) {
|
||||
failed = load_ed_keys(options, now) < 0;
|
||||
signing_key = get_master_signing_key_cert();
|
||||
}
|
||||
|
||||
/* If we do have a signing key, log the expiration time. */
|
||||
if (signing_key) {
|
||||
log_ed_cert_expiration(signing_key, "signing", fn);
|
||||
} else {
|
||||
log_warn(LD_OR, "Could not load signing key certificate from %s, so " \
|
||||
"we couldn't learn anything about certificate expiration.", fn);
|
||||
}
|
||||
|
||||
tor_free(fn);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log when a key certificate expires. Used when tor is given the
|
||||
* --key-expiration command-line option.
|
||||
*
|
||||
* If an command argument is given, which should specify the type of
|
||||
* key to get expiry information about (currently supported arguments
|
||||
* are "sign"), get info about that type of certificate. Otherwise,
|
||||
* print info about the supported arguments.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure.
|
||||
*/
|
||||
int
|
||||
log_cert_expiration(void)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
const char *arg = options->command_arg;
|
||||
|
||||
if (!strcmp(arg, "sign")) {
|
||||
return log_master_signing_key_cert_expiration(options);
|
||||
} else {
|
||||
fprintf(stderr, "No valid argument to --key-expiration found!\n");
|
||||
fprintf(stderr, "Currently recognised arguments are: 'sign'\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const ed25519_public_key_t *
|
||||
get_master_identity_key(void)
|
||||
{
|
||||
|
@ -63,6 +63,7 @@ MOCK_DECL(int, check_tap_onion_key_crosscert,(const uint8_t *crosscert,
|
||||
const ed25519_public_key_t *master_id_pkey,
|
||||
const uint8_t *rsa_id_digest));
|
||||
|
||||
int log_cert_expiration(void);
|
||||
int load_ed_keys(const or_options_t *options, time_t now);
|
||||
int should_make_new_ed_keys(const or_options_t *options, const time_t now);
|
||||
|
||||
|
@ -34,6 +34,7 @@ endif
|
||||
TESTS += src/test/test src/test/test-slow src/test/test-memwipe \
|
||||
src/test/test_workqueue \
|
||||
src/test/test_keygen.sh \
|
||||
src/test/test_key_expiration.sh \
|
||||
src/test/test-timers \
|
||||
$(TESTSCRIPTS)
|
||||
|
||||
@ -325,6 +326,7 @@ EXTRA_DIST += \
|
||||
src/test/slownacl_curve25519.py \
|
||||
src/test/zero_length_keys.sh \
|
||||
src/test/test_keygen.sh \
|
||||
src/test/test_key_expiration.sh \
|
||||
src/test/test_zero_length_keys.sh \
|
||||
src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh \
|
||||
src/test/test-network.sh \
|
||||
|
129
src/test/test_key_expiration.sh
Executable file
129
src/test/test_key_expiration.sh
Executable file
@ -0,0 +1,129 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Note: some of this code is lifted from zero_length_keys.sh and
|
||||
# test_keygen.sh, and could be unified.
|
||||
|
||||
umask 077
|
||||
set -e
|
||||
|
||||
if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then
|
||||
if [ "$TESTING_TOR_BINARY" = "" ] ; then
|
||||
echo "Usage: ${0} PATH_TO_TOR [case-number]"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $# -ge 1 ]; then
|
||||
TOR_BINARY="${1}"
|
||||
shift
|
||||
else
|
||||
TOR_BINARY="${TESTING_TOR_BINARY}"
|
||||
fi
|
||||
|
||||
if [ $# -ge 1 ]; then
|
||||
dflt=0
|
||||
else
|
||||
dflt=1
|
||||
fi
|
||||
|
||||
CASE1=$dflt
|
||||
CASE2=$dflt
|
||||
CASE3=$dflt
|
||||
|
||||
if [ $# -ge 1 ]; then
|
||||
eval "CASE${1}"=1
|
||||
fi
|
||||
|
||||
|
||||
dump() { xxd -p "$1" | tr -d '\n '; }
|
||||
die() { echo "$1" >&2 ; exit 5; }
|
||||
check_dir() { [ -d "$1" ] || die "$1 did not exist"; }
|
||||
check_file() { [ -e "$1" ] || die "$1 did not exist"; }
|
||||
check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; }
|
||||
check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; }
|
||||
check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; }
|
||||
|
||||
DATA_DIR=`mktemp -d -t tor_key_expiration_tests.XXXXXX`
|
||||
if [ -z "$DATA_DIR" ]; then
|
||||
echo "Failure: mktemp invocation returned empty string" >&2
|
||||
exit 3
|
||||
fi
|
||||
if [ ! -d "$DATA_DIR" ]; then
|
||||
echo "Failure: mktemp invocation result doesn't point to directory" >&2
|
||||
exit 3
|
||||
fi
|
||||
trap "rm -rf '$DATA_DIR'" 0
|
||||
|
||||
# Use an absolute path for this or Tor will complain
|
||||
DATA_DIR=`cd "${DATA_DIR}" && pwd`
|
||||
|
||||
touch "${DATA_DIR}/empty_torrc"
|
||||
|
||||
QUIETLY="--hush"
|
||||
SILENTLY="--quiet"
|
||||
TOR="${TOR_BINARY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --ExitRelay 0 -f ${DATA_DIR}/empty_torrc --DataDirectory ${DATA_DIR}"
|
||||
|
||||
##### SETUP
|
||||
#
|
||||
# Here we create a set of keys.
|
||||
|
||||
# Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there.
|
||||
echo "Setup step #1"
|
||||
${TOR} --list-fingerprint ${SILENTLY} > /dev/null
|
||||
|
||||
check_dir "${DATA_DIR}/keys"
|
||||
check_file "${DATA_DIR}/keys/ed25519_master_id_public_key"
|
||||
check_file "${DATA_DIR}/keys/ed25519_master_id_secret_key"
|
||||
check_file "${DATA_DIR}/keys/ed25519_signing_cert"
|
||||
check_file "${DATA_DIR}/keys/ed25519_signing_secret_key"
|
||||
check_file "${DATA_DIR}/keys/secret_id_key"
|
||||
check_file "${DATA_DIR}/keys/secret_onion_key"
|
||||
check_file "${DATA_DIR}/keys/secret_onion_key_ntor"
|
||||
|
||||
##### TEST CASES
|
||||
|
||||
echo "=== Starting key expiration tests."
|
||||
|
||||
FN="${DATA_DIR}/stderr"
|
||||
|
||||
if [ "$CASE1" = 1 ]; then
|
||||
echo "==== Case 1: Test --key-expiration without argument and ensure usage"
|
||||
echo " instructions are printed."
|
||||
|
||||
${TOR} ${QUIETLY} --key-expiration 2>"$FN"
|
||||
grep "No valid argument to --key-expiration found!" "$FN" >/dev/null || \
|
||||
die "Tor didn't mention supported --key-expiration argmuents"
|
||||
|
||||
echo "==== Case 1: ok"
|
||||
fi
|
||||
|
||||
if [ "$CASE2" = 1 ]; then
|
||||
echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it prints an expiration."
|
||||
|
||||
${TOR} ${QUIETLY} --key-expiration sign 2>"$FN"
|
||||
grep "signing-cert-expiry:" "$FN" >/dev/null || \
|
||||
die "Tor didn't print an expiration"
|
||||
|
||||
echo "==== Case 2: ok"
|
||||
fi
|
||||
|
||||
if [ "$CASE3" = 1 ]; then
|
||||
echo "==== Case 3: Start Tor with --key-expiration 'sign', when there is no"
|
||||
echo " signing key, and make sure that Tor generates a new key"
|
||||
echo " and prints its certificate's expiration."
|
||||
|
||||
mv "${DATA_DIR}/keys/ed25519_signing_cert" \
|
||||
"${DATA_DIR}/keys/ed25519_signing_cert.bak"
|
||||
|
||||
${TOR} --key-expiration sign > "$FN" 2>&1
|
||||
grep "It looks like I need to generate and sign a new medium-term signing key" "$FN" >/dev/null || \
|
||||
die "Tor didn't create a new signing key"
|
||||
check_file "${DATA_DIR}/keys/ed25519_signing_cert"
|
||||
grep "signing-cert-expiry:" "$FN" >/dev/null || \
|
||||
die "Tor didn't print an expiration"
|
||||
|
||||
mv "${DATA_DIR}/keys/ed25519_signing_cert.bak" \
|
||||
"${DATA_DIR}/keys/ed25519_signing_cert"
|
||||
|
||||
echo "==== Case 3: ok"
|
||||
fi
|
Loading…
Reference in New Issue
Block a user