Merge branch '13642_offline_master_v2_squashed'

This commit is contained in:
Nick Mathewson 2015-06-17 10:12:37 -04:00
commit d68133c745
8 changed files with 199 additions and 5 deletions

View File

@ -386,6 +386,7 @@ AC_CHECK_FUNCS(
ftime \
getaddrinfo \
getifaddrs \
getpass \
getrlimit \
gettimeofday \
gmtime_r \
@ -399,6 +400,7 @@ AC_CHECK_FUNCS(
pipe \
pipe2 \
prctl \
readpassphrase \
rint \
sigaction \
socketpair \
@ -945,6 +947,7 @@ AC_CHECK_HEADERS(
netinet/in.h \
netinet/in6.h \
pwd.h \
readpassphrase.h \
stdint.h \
sys/eventfd.h \
sys/file.h \

View File

@ -67,6 +67,9 @@
#ifdef HAVE_CRT_EXTERNS_H
#include <crt_externs.h>
#endif
#ifdef HAVE_READPASSPHRASE_H
#include <readpassphrase.h>
#endif
#ifndef HAVE_GETTIMEOFDAY
#ifdef HAVE_FTIME
@ -3242,3 +3245,33 @@ tor_sleep_msec(int msec)
}
#endif
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
* characters of passphrase into <b>output</b>. */
ssize_t
tor_getpass(const char *prompt, char *output, size_t buflen)
{
tor_assert(buflen <= SSIZE_MAX);
#if defined(HAVE_READPASSPHRASE)
char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF);
if (pwd == NULL)
return -1;
return strlen(pwd);
#elif defined(HAVE_GETPASS)
/* XXX We shouldn't actually use this; it's deprecated to hell and back */
memset(output, 0, buflen);
char *pwd = getpass(prompt);
if (pwd == NULL)
return -1;
ssize_t len = (ssize_t)strlen(pwd);
strlcpy(output, pwd, buflen);
memset(pwd, 0, len);
return len;
#else
/* XXX This is even worse. */
puts(prompt);
ssize_t n = read(STDIN_FILENO, output, buflen);
if (n < 0)
return -1;
return n;
#endif
}

View File

@ -708,6 +708,8 @@ STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
#endif
#endif
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
/* This needs some of the declarations above so we include it here. */
#include "compat_threads.h"

View File

@ -1909,6 +1909,7 @@ static const struct {
{ "--hash-password", ARGUMENT_NECESSARY },
{ "--dump-config", ARGUMENT_OPTIONAL },
{ "--list-fingerprint", TAKES_NO_ARGUMENT },
{ "--keygen", TAKES_NO_ARGUMENT },
{ "--verify-config", TAKES_NO_ARGUMENT },
{ "--ignore-missing-torrc", TAKES_NO_ARGUMENT },
{ "--quiet", TAKES_NO_ARGUMENT },
@ -4434,7 +4435,9 @@ options_init_from_torrc(int argc, char **argv)
command = CMD_RUN_TOR;
for (p_index = cmdline_only_options; p_index; p_index = p_index->next) {
if (!strcmp(p_index->key,"--list-fingerprint")) {
if (!strcmp(p_index->key,"--keygen")) {
command = CMD_KEYGEN;
} else if (!strcmp(p_index->key,"--list-fingerprint")) {
command = CMD_LIST_FINGERPRINT;
} else if (!strcmp(p_index->key, "--hash-password")) {
command = CMD_HASH_PASSWORD;

View File

@ -3162,6 +3162,9 @@ tor_main(int argc, char *argv[])
#endif
result = do_main_loop();
break;
case CMD_KEYGEN:
result = load_ed_keys(get_options(), time(NULL));
break;
case CMD_LIST_FINGERPRINT:
result = do_list_fingerprint();
break;

View File

@ -3405,7 +3405,8 @@ typedef struct {
/** What should the tor process actually do? */
enum {
CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD,
CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG
CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG,
CMD_KEYGEN
} command;
char *command_arg; /**< Argument for command-line option. */

View File

@ -4,9 +4,130 @@
#include "or.h"
#include "config.h"
#include "router.h"
#include "crypto_pwbox.h"
#include "routerkeys.h"
#include "torcert.h"
#define ENC_KEY_HEADER "Boxed Ed25519 key"
#define ENC_KEY_TAG "master"
int
read_encrypted_secret_key(ed25519_secret_key_t *out,
const char *fname)
{
int r = -1;
uint8_t *secret = NULL;
size_t secret_len = 0;
char pwbuf[256];
uint8_t encrypted_key[256];
char *tag = NULL;
ssize_t encrypted_len = crypto_read_tagged_contents_from_file(fname,
ENC_KEY_HEADER,
&tag,
encrypted_key,
sizeof(encrypted_key));
if (encrypted_len < 0) {
log_info(LD_OR, "%s is missing", fname);
return 0;
}
if (strcmp(tag, ENC_KEY_TAG))
return -1;
while (1) {
ssize_t pwlen =
tor_getpass("Enter pasphrase for master key:", pwbuf, sizeof(pwbuf));
if (pwlen < 0)
goto done;
const int r = crypto_unpwbox(&secret, &secret_len,
encrypted_key, encrypted_len,
pwbuf, pwlen);
if (r == UNPWBOX_CORRUPTED) {
log_err(LD_OR, "%s is corrupted.", fname);
goto done;
} else if (r == UNPWBOX_OKAY) {
break;
}
/* Otherwise, passphrase is bad, so try again till user does ctrl-c or gets
* it right. */
}
if (secret_len != ED25519_SECKEY_LEN) {
log_err(LD_OR, "%s is corrupted.", fname);
goto done;
}
memcpy(out->seckey, secret, ED25519_SECKEY_LEN);
r = 1;
done:
memwipe(encrypted_key, 0, encrypted_len);
memwipe(pwbuf, 0, sizeof(pwbuf));
if (secret) {
memwipe(secret, 0, secret_len);
tor_free(secret);
}
return r;
}
int
write_encrypted_secret_key(const ed25519_secret_key_t *key,
const char *fname)
{
int r = -1;
char pwbuf0[256], pwbuf1[256];
uint8_t *encrypted_key = NULL;
size_t encrypted_len = 0;
while (1) {
if (tor_getpass("Enter passphrase:", pwbuf0, sizeof(pwbuf0)) < 0)
return -1;
if (tor_getpass(" One more time:", pwbuf1, sizeof(pwbuf1)) < 0)
return -1;
if (!strcmp(pwbuf0, pwbuf1))
break;
fprintf(stderr, "That didn't match.\n");
}
if (0 == strlen(pwbuf0))
return 0;
if (crypto_pwbox(&encrypted_key, &encrypted_len,
key->seckey, sizeof(key->seckey),
pwbuf0, strlen(pwbuf0), 0) < 0) {
log_warn(LD_OR, "crypto_pwbox failed!?");
goto done;
}
if (crypto_write_tagged_contents_to_file(fname,
ENC_KEY_HEADER,
ENC_KEY_TAG,
encrypted_key, encrypted_len) < 0)
goto done;
r = 1;
done:
if (encrypted_key) {
memwipe(encrypted_key, 0, encrypted_len);
tor_free(encrypted_key);
}
memwipe(pwbuf0, 0, sizeof(pwbuf0));
memwipe(pwbuf1, 0, sizeof(pwbuf1));
return r;
}
static int
write_secret_key(const ed25519_secret_key_t *key, int encrypted,
const char *fname,
const char *fname_tag,
const char *encrypted_fname)
{
if (encrypted) {
int r = write_encrypted_secret_key(key, encrypted_fname);
if (r != 0)
return r;
}
return ed25519_seckey_write_to_file(key, fname, fname_tag);
}
/**
* Read an ed25519 key and associated certificates from files beginning with
* <b>fname</b>, with certificate type <b>cert_type</b>. On failure, return
@ -38,6 +159,9 @@
*
* If INIT_ED_KEY_OMIT_SECRET is set in <b>flags</b>, do not even try to
* load or return a secret key (but create and save on if needed).
*
* If INIT_ED_KEY_TRY_ENCRYPTED is set, we look for an encrypted secret key
* and consider encrypting any new secret key.
*/
ed25519_keypair_t *
ed_key_init_from_file(const char *fname, uint32_t flags,
@ -49,10 +173,12 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
struct tor_cert_st **cert_out)
{
char *secret_fname = NULL;
char *encrypted_secret_fname = NULL;
char *public_fname = NULL;
char *cert_fname = NULL;
int created_pk = 0, created_sk = 0, created_cert = 0;
const int try_to_load = ! (flags & INIT_ED_KEY_REPLACE);
const int encrypt_key = (flags & INIT_ED_KEY_TRY_ENCRYPTED);
char tag[8];
tor_snprintf(tag, sizeof(tag), "type%d", (int)cert_type);
@ -62,15 +188,26 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t));
tor_asprintf(&secret_fname, "%s_secret_key", fname);
tor_asprintf(&encrypted_secret_fname, "%s_secret_key_encrypted", fname);
tor_asprintf(&public_fname, "%s_public_key", fname);
tor_asprintf(&cert_fname, "%s_cert", fname);
/* Try to read the secret key. */
const int have_secret = try_to_load &&
int have_secret = try_to_load &&
!(flags & INIT_ED_KEY_OMIT_SECRET) &&
ed25519_seckey_read_from_file(&keypair->seckey,
&got_tag, secret_fname) == 0;
/* Should we try for an encrypted key? */
if (!have_secret && try_to_load && encrypt_key) {
int r = read_encrypted_secret_key(&keypair->seckey,
encrypted_secret_fname);
if (r > 0) {
have_secret = 1;
got_tag = tor_strdup(tag);
}
}
if (have_secret) {
if (strcmp(got_tag, tag)) {
tor_log(severity, LD_OR, "%s has wrong tag", secret_fname);
@ -115,7 +252,9 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
}
created_pk = created_sk = created_cert = 1;
if (ed25519_seckey_write_to_file(&keypair->seckey, secret_fname, tag) < 0
if (write_secret_key(&keypair->seckey,
encrypt_key,
secret_fname, tag, encrypted_secret_fname) < 0
||
(split &&
ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag) < 0)
@ -215,6 +354,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
unlink(cert_fname);
cleanup:
tor_free(encrypted_secret_fname);
tor_free(secret_fname);
tor_free(public_fname);
tor_free(cert_fname);
@ -329,7 +469,8 @@ load_ed_keys(const or_options_t *options, time_t now)
const int need_new_signing_key =
NULL == use_signing ||
EXPIRES_SOON(check_signing_cert, 0);
EXPIRES_SOON(check_signing_cert, 0) ||
options->command == CMD_KEYGEN;
const int want_new_signing_key =
need_new_signing_key ||
EXPIRES_SOON(check_signing_cert, options->TestingSigningKeySlop);
@ -342,6 +483,8 @@ load_ed_keys(const or_options_t *options, time_t now)
flags |= INIT_ED_KEY_MISSING_SECRET_OK;
if (! want_new_signing_key)
flags |= INIT_ED_KEY_OMIT_SECRET;
if (options->command == CMD_KEYGEN)
flags |= INIT_ED_KEY_TRY_ENCRYPTED;
char *fname =
options_get_datadir_fname2(options, "keys", "ed25519_master_id");

View File

@ -14,6 +14,7 @@
#define INIT_ED_KEY_EXTRA_STRONG (1u<<5)
#define INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT (1u<<6)
#define INIT_ED_KEY_OMIT_SECRET (1u<<7)
#define INIT_ED_KEY_TRY_ENCRYPTED (1u<<8)
struct tor_cert_st;
ed25519_keypair_t *ed_key_init_from_file(const char *fname, uint32_t flags,
@ -61,6 +62,11 @@ int should_make_new_ed_keys(const or_options_t *options, const time_t now);
int generate_ed_link_cert(const or_options_t *options, time_t now);
int read_encrypted_secret_key(ed25519_secret_key_t *out,
const char *fname);
int write_encrypted_secret_key(const ed25519_secret_key_t *out,
const char *fname);
void routerkeys_free_all(void);
#endif