commit 1474ab33956eefd9b75ef9a3e238ec7f855b8c7e Author: Daniel Pinto danielpinto52@gmail.com Date: Sat Aug 1 00:03:06 2020 +0100
Add --format argument to --key-expiration option. #30045 --- changes/feature30045 | 6 +++ doc/man/tor.1.txt | 14 +++++-- scripts/maint/practracker/exceptions.txt | 4 +- src/app/config/config.c | 35 ++++++++++++++++ src/app/config/or_options_st.h | 5 +++ src/feature/relay/routerkeys.c | 28 ++++++++++--- src/test/test_key_expiration.sh | 70 ++++++++++++++++++++++++++++++-- 7 files changed, 147 insertions(+), 15 deletions(-)
diff --git a/changes/feature30045 b/changes/feature30045 new file mode 100644 index 0000000000..9a0b8c041a --- /dev/null +++ b/changes/feature30045 @@ -0,0 +1,6 @@ + o Minor features (admin tools): + - Add new --format argument to -key-expiration option to allow + specifying the time format of expiration date. Adds Unix + timestamp format support. Patch by Daniel Pinto. Closes + ticket 30045. + diff --git a/doc/man/tor.1.txt b/doc/man/tor.1.txt index edb8593142..6e504c8a82 100644 --- a/doc/man/tor.1.txt +++ b/doc/man/tor.1.txt @@ -174,16 +174,22 @@ The following options in this section are only recognized on the If the file descriptor is not specified, the passphrase is read from the terminal by default.
-[[opt-key-expiration]] **`--key-expiration`** [__purpose__]:: +[[opt-key-expiration]] **`--key-expiration`** [__purpose__] [**`--format`** **`iso8601`**|**`timestamp`**]:: 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" + as to stdout. The optional **`--format`** argument lets you specify + the time format. Currently, **`iso8601`** and **`timestamp`** are + supported. If **`--format`** is not specified, the signing key + certificate's expiration time will be 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". If **`--format`** **`timestamp`** + is specified, the signing key certificate's expiration time will be in + Unix timestamp format. For example, the output sent to stdout will be of the form: + "signing-cert-expiry: 1500971415".
[[opt-dbg]] **--dbg-**...:: Tor may support other options beginning with the string "dbg". These diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index b2a34b808a..95c5665fb3 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -37,7 +37,7 @@ problem file-size /src/app/config/config.c 7525 problem include-count /src/app/config/config.c 81 problem function-size /src/app/config/config.c:options_act() 381 problem function-size /src/app/config/config.c:options_validate_cb() 794 -problem function-size /src/app/config/config.c:options_init_from_torrc() 198 +problem function-size /src/app/config/config.c:options_init_from_torrc() 231 problem function-size /src/app/config/config.c:options_init_from_string() 103 problem function-size /src/app/config/config.c:options_init_logs() 125 problem function-size /src/app/config/config.c:parse_bridge_line() 104 @@ -47,7 +47,7 @@ problem function-size /src/app/config/config.c:parse_dir_fallback_line() 101 problem function-size /src/app/config/config.c:port_parse_config() 435 problem function-size /src/app/config/config.c:parse_ports() 132 problem function-size /src/app/config/resolve_addr.c:resolve_my_address_v4() 197 -problem file-size /src/app/config/or_options_st.h 1050 +problem file-size /src/app/config/or_options_st.h 1069 problem include-count /src/app/main/main.c 71 problem function-size /src/app/main/main.c:dumpstats() 102 problem function-size /src/app/main/main.c:tor_init() 109 diff --git a/src/app/config/config.c b/src/app/config/config.c index a70c1d651e..1c6d4acd3e 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -2468,6 +2468,8 @@ static const struct { { .name="--key-expiration", .takes_argument=ARGUMENT_OPTIONAL, .command=CMD_KEY_EXPIRATION }, + { .name="--format", + .takes_argument=ARGUMENT_NECESSARY }, { .name="--newpass" }, { .name="--no-passphrase" }, { .name="--passphrase-fd", @@ -4425,6 +4427,39 @@ options_init_from_torrc(int argc, char **argv) } }
+ const config_line_t *format_line = config_line_find(cmdline_only_options, + "--format"); + if (format_line) { + if (command == CMD_KEY_EXPIRATION) { + const char *v = format_line->value; + // keep the same order as enum key_expiration_format + const char *formats[] = { "iso8601", "timestamp" }; + const int formats_len = sizeof(formats) / sizeof(formats[0]); + int format = -1; + for (int i = 0; i < formats_len; i++) { + if (!strcmp(v, formats[i])) { + format = i; + break; + } + } + + if (format < 0) { + log_err(LD_CONFIG, "Invalid --format value %s", escaped(v)); + retval = -1; + goto err; + } else { + get_options_mutable()->key_expiration_format = format; + } + } else { + log_err(LD_CONFIG, "--format specified without --key-expiration!"); + retval = -1; + goto err; + } + } else { + get_options_mutable()->key_expiration_format = + KEY_EXPIRATION_FORMAT_ISO8601; + } + if (config_line_find(cmdline_only_options, "--newpass")) { if (command == CMD_KEYGEN) { get_options_mutable()->change_key_passphrase = 1; diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 68be5711ce..774b476476 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -944,6 +944,11 @@ struct or_options_t { * ed25519 identity key except from tor --keygen */ int OfflineMasterKey;
+ enum { + KEY_EXPIRATION_FORMAT_ISO8601 = 0, + KEY_EXPIRATION_FORMAT_TIMESTAMP + } key_expiration_format; + enum { FORCE_PASSPHRASE_AUTO=0, FORCE_PASSPHRASE_ON, diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c index d3de83cb86..f0fd101efd 100644 --- a/src/feature/relay/routerkeys.c +++ b/src/feature/relay/routerkeys.c @@ -519,19 +519,34 @@ print_cert_expiration(const char *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. + * stored in a file named <b>fname</b>, is going to expire. Formats the expire + * time according to <b>time_format</b>. Valid time formats are in the + * key_expiration_format enum, in or_options_t. */ static void log_ed_cert_expiration(const tor_cert_t *cert, const char *description, - const char *fname) { - char expiration[ISO_TIME_LEN+1]; - + const char *fname, + int time_format) { 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); + char expiration[ISO_TIME_LEN+1]; + switch (time_format) { + case KEY_EXPIRATION_FORMAT_ISO8601: + format_local_iso_time(expiration, cert->valid_until); + break; + + case KEY_EXPIRATION_FORMAT_TIMESTAMP: + tor_snprintf(expiration, sizeof(expiration), "%"PRId64, + (int64_t) cert->valid_until); + break; + + default: + log_err(LD_BUG, "Unknown time format value: %d.", time_format); + return; + } log_notice(LD_OR, "The %s certificate stored in %s is valid until %s.", description, fname, expiration); print_cert_expiration(expiration, description); @@ -567,7 +582,8 @@ log_master_signing_key_cert_expiration(const or_options_t *options)
/* If we do have a signing key, log the expiration time. */ if (signing_key) { - log_ed_cert_expiration(signing_key, "signing", fn); + int time_format = options->key_expiration_format; + log_ed_cert_expiration(signing_key, "signing", fn, time_format); } else { log_warn(LD_OR, "Could not load signing key certificate from %s, so " \ "we couldn't learn anything about certificate expiration.", fn); diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh index 2238f7aa78..1ba8179aa1 100755 --- a/src/test/test_key_expiration.sh +++ b/src/test/test_key_expiration.sh @@ -61,6 +61,11 @@ fi CASE1=$dflt CASE2=$dflt CASE3=$dflt +CASE4=$dflt +CASE5=$dflt +CASE6=$dflt +CASE7=$dflt +CASE8=$dflt
if [ $# -ge 1 ]; then eval "CASE${1}"=1 @@ -125,16 +130,17 @@ if [ "$CASE1" = 1 ]; then
${TOR} ${QUIETLY} --key-expiration 2>"$FN" || true grep "No valid argument to --key-expiration found!" "$FN" >/dev/null || \ - die "Tor didn't mention supported --key-expiration argmuents" + die "Tor didn't mention supported --key-expiration arguments"
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." + echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it" + echo " prints an expiration using ISO8601 date format."
${TOR} ${QUIETLY} --key-expiration sign 2>"$FN" - grep "signing-cert-expiry:" "$FN" >/dev/null || \ + grep "signing-cert-expiry: [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}" "$FN" >/dev/null || \ die "Tor didn't print an expiration"
echo "==== Case 2: ok" @@ -160,3 +166,61 @@ if [ "$CASE3" = 1 ]; then
echo "==== Case 3: ok" fi + +if [ "$CASE4" = 1 ]; then + echo "==== Case 4: Start Tor with --format iso8601 and make sure it prints an" + echo " error message due to missing --key-expiration argument." + + ${TOR} --format iso8601 > "$FN" 2>&1 || true + grep -- "--format specified without --key-expiration!" "$FN" >/dev/null || \ + die "Tor didn't print a missing --key-expiration error message" + + echo "==== Case 4: ok" +fi + +if [ "$CASE5" = 1 ]; then + echo "==== Case 5: Start Tor with --key-expiration 'sign' --format '' and" + echo " make sure it prints an error message due to missing value." + + ${TOR} --key-expiration sign --format > "$FN" 2>&1 || true + grep "Command-line option '--format' with no value. Failing." "$FN" >/dev/null || \ + die "Tor didn't print a missing format value error message" + + echo "==== Case 5: ok" +fi + +if [ "$CASE6" = 1 ]; then + echo "==== Case 6: Start Tor with --key-expiration 'sign' --format 'invalid'" + echo " and make sure it prints an error message due to invalid" + echo " value." + + ${TOR} --key-expiration sign --format invalid > "$FN" 2>&1 || true + grep "Invalid --format value" "$FN" >/dev/null || \ + die "Tor didn't print an invalid format value error message" + + echo "==== Case 6: ok" +fi + +if [ "$CASE7" = 1 ]; then + echo "==== Case 7: Start Tor with --key-expiration 'sign' --format 'iso8601'" + echo " and make sure it prints an expiration using ISO8601 date" + echo " format." + + ${TOR} ${QUIETLY} --key-expiration sign --format iso8601 2>"$FN" + grep "signing-cert-expiry: [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}" "$FN" >/dev/null || \ + die "Tor didn't print an expiration" + + echo "==== Case 7: ok" +fi + +if [ "$CASE8" = 1 ]; then + echo "==== Case 8: Start Tor with --key-expiration 'sign' --format 'timestamp'" + echo " and make sure it prints an expiration using timestamp date" + echo " format." + + ${TOR} ${QUIETLY} --key-expiration sign --format timestamp 2>"$FN" + grep "signing-cert-expiry: [0-9]{5,}" "$FN" >/dev/null || \ + die "Tor didn't print an expiration" + + echo "==== Case 8: ok" +fi