make sure that they are owned by the user actually running the Tor
daemon on your system.
-[[opt-keygen-family]] **`--keygen-family`** __filename__::
- Generate a new family ID key in `filename`.
+[[opt-keygen-family]] **`--keygen-family`** __basename__::
+ Generate a new family ID key in __basename__`.secret_family_key`.
To use this key, install it on every relay in your family.
- (Put it in the relay's `KeyDirectory`, with a filename like
- `secret_family_key`, `secret_family_key.1`, `secret_family_key.2`.)
- Then enable the UseFamilyKeys option on your relays.
+ (Put it in the relay's `KeyDirectory`.)
+ Then enable the corresponding FamilyID option on your relays.
See (XXXX INSERT URL HERE) for more information.
**`--passphrase-fd`** __FILEDES__::
Note: do not use MyFamily when configuring your Tor instance as a
bridge.
-[[UseFamilyKeys]] **UseFamilyKeys** **0**|**1**::
- If 1, configure this relay to be part of a family identified by a shared
- secret family key. Family keys are generated with `--keygen-family`.
+[[FamilyId]] **FamilyId** __ident__::
+ Configure this relay to be part of a family
+ identified by a shared secret family key with the given key identity.
+ A corresponding family key must be stored in the relay's key directory.
+ This option can appear multiple times.
+ Family keys are generated with "--keygen-family";
+ this also generates the value you should use in the __ident__ field
+ in a file ending with ".public\_family\_id".
For information on generating and installing a family
key, see (XXXX INSERT URL HERE).
+
generated key, which the relay uses to handle any requests that were made
by clients that didn't have the new one.
-__KeyDirectory__/**`secret_family_key`**, **`secret_family_key.`**.__N__::
+__KeyDirectory__/__keyname__**`.secret_family_key`**::
A relay family's family identity key.
Used to prove membership in a relay family.
See (XXXX INSERT URL HERE) for more information.
V(UseDefaultFallbackDirs, BOOL, "1"),
OBSOLETE("FallbackNetworkstatusFile"),
+ VAR("FamilyId", LINELIST, FamilyId_lines, NULL),
V(FascistFirewall, BOOL, "0"),
V(FirewallPorts, CSV, ""),
OBSOLETE("FastFirstHopPK"),
V(MetricsPortPolicy, LINELIST, NULL),
V(TestingMinTimeToReportBandwidth, INTERVAL, "1 day"),
VAR("MyFamily", LINELIST, MyFamily_lines, NULL),
- V(UseFamilyKeys, BOOL, "0"),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
OBSOLETE("NamingAuthoritativeDirectory"),
OBSOLETE("NATDListenAddress"),
tor_free(options->command_arg);
tor_free(options->master_key_fname);
config_free_lines(options->MyFamily);
+ if (options->FamilyIds) {
+ SMARTLIST_FOREACH(options->FamilyIds,
+ ed25519_public_key_t *, k, tor_free(k));
+ smartlist_free(options->FamilyIds);
+ }
}
/** Release all memory allocated in options
struct config_line_t *MyFamily_lines; /**< Declared family for this OR. */
struct config_line_t *MyFamily; /**< Declared family for this OR,
normalized */
- int UseFamilyKeys; /**< If set, we use one or more family keys
+ struct config_line_t *FamilyId_lines; /**< If set, IDs for family keys to use
* to certify this OR's membership. */
+ struct smartlist_t *FamilyIds; /**< FamilyIds, parsed and converted
+ * to a list of ed25519_public_key_t */
struct config_line_t *NodeFamilies; /**< List of config lines for
* node families */
/** List of parsed NodeFamilies values. */
return 0;
}
+/** Implement --keygen-family; create a family ID key and write it to a file.
+ */
+static int
+do_keygen_family(const char *fname_base)
+{
+ ed25519_public_key_t pk;
+ char *fname = NULL;
+ int r = -1;
+
+ if (BUG(!fname_base))
+ goto done;
+
+ tor_asprintf(&fname, "%s.secret_family_key", fname_base);
+
+ if (create_family_id_key(fname, &pk) < 0)
+ goto done;
+
+ printf("# Generated %s\n", fname);
+ printf("FamilyId %s\n", ed25519_fmt(&pk));
+ r = 0;
+
+ done:
+ tor_free(fname);
+ return r;
+}
+
static void
init_addrinfo(void)
{
result = load_ed_keys(get_options(), time(NULL)) < 0;
break;
case CMD_KEYGEN_FAMILY:
- result = create_family_id_key(get_options()->command_arg);
+ result = do_keygen_family(get_options()->command_arg);
break;
case CMD_KEY_EXPIRATION:
init_keys();
#include "lib/meminfo/meminfo.h"
#include "lib/osinfo/uname.h"
#include "lib/process/setuid.h"
+#include "lib/crypt_ops/crypto_format.h"
/* Required for dirinfo_type_t in or_options_t */
#include "core/or/or.h"
options->MyFamily_lines, "MyFamily", msg))
return -1;
+ if (options->FamilyId_lines) {
+ options->FamilyIds = smartlist_new();
+ config_line_t *line;
+ for (line = options->FamilyId_lines; line; line = line->next) {
+ ed25519_public_key_t pk;
+ if (ed25519_public_from_base64(&pk, line->value) < 0) {
+ tor_asprintf(msg, "Invalid FamilyId %s", line->value);
+ return -1;
+ }
+ smartlist_add(options->FamilyIds, tor_memdup(&pk, sizeof(pk)));
+ }
+ }
+
if (options->ConstrainedSockets) {
if (options->DirPort_set) {
/* Providing cached directory entries while system TCP buffers are scarce
YES_IF_CHANGED_STRING(ContactInfo);
YES_IF_CHANGED_STRING(BridgeDistribution);
YES_IF_CHANGED_LINELIST(MyFamily);
- YES_IF_CHANGED_BOOL(UseFamilyKeys);
+ YES_IF_CHANGED_LINELIST(FamilyId_lines);
YES_IF_CHANGED_STRING(AccountingStart);
YES_IF_CHANGED_INT(AccountingMax);
YES_IF_CHANGED_INT(AccountingRule);
#include "feature/dirauth/dirvote.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "lib/crypt_ops/crypto_format.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
}
/**
- * Prefix for the filename in which we expect to find a family ID key.
+ * Suffix for the filenames in which we expect to find a family ID key.
*/
-#define FAMILY_KEY_FNAME "secret_family_key"
+#define FAMILY_KEY_SUFFIX ".secret_family_key"
/**
* Return true if `fname` is a possible filename of a family ID key.
STATIC bool
is_family_key_fname(const char *fname)
{
- if (0 == strcmp(fname, FAMILY_KEY_FNAME))
- return true;
+ return 0 == strcmpend(fname, FAMILY_KEY_SUFFIX);
+}
- unsigned num;
- char ch;
- if (tor_sscanf(fname, FAMILY_KEY_FNAME".%u%c", &num, &ch) == 1)
- return true;
+/** Return true if `id` is configured in `options`. */
+static bool
+family_key_id_is_expected(const or_options_t *options,
+ const ed25519_public_key_t *id)
+{
+ SMARTLIST_FOREACH(options->FamilyIds, const ed25519_public_key_t *, k, {
+ if (ed25519_pubkey_eq(k, id))
+ return true;
+ });
+ return false;
+}
+/** Return true if the key for `id` has been loaded. */
+static bool
+family_key_is_present(const ed25519_public_key_t *id)
+{
+ if (!family_id_keys)
+ return false;
+
+ SMARTLIST_FOREACH(family_id_keys, const ed25519_keypair_t *, kp, {
+ if (ed25519_pubkey_eq(&kp->pubkey, id))
+ return true;
+ });
return false;
}
* family_id_keys.
*/
STATIC int
-load_family_id_keys_impl(const char *keydir)
+load_family_id_keys_impl(const or_options_t *options,
+ const char *keydir)
{
- if (BUG(!keydir))
+ if (BUG(!options) || BUG(!keydir))
return -1;
smartlist_t *files = tor_listdir(keydir);
goto end;
}
- smartlist_add(new_keys, kp_tmp);
- kp_tmp = NULL; // prevent double-free
+ if (family_key_id_is_expected(options, &kp_tmp->pubkey)) {
+ smartlist_add(new_keys, kp_tmp);
+ kp_tmp = NULL; // prevent double-free
+ } else {
+ log_warn(LD_OR, "Found secret family key in %s "
+ "with unexpected FamilyID %s",
+ fn_tmp, ed25519_fmt(&kp_tmp->pubkey));
+ }
tor_free(fn_tmp);
tor_free(tag_tmp);
/**
* Create a new family ID key, and store it in `fname`.
+ *
+ * If pk_out is provided, set it to the generated public key.
**/
int
-create_family_id_key(const char *fname)
+create_family_id_key(const char *fname, ed25519_public_key_t *pk_out)
{
int r = -1;
ed25519_keypair_t *kp = tor_malloc_zero(sizeof(ed25519_keypair_t));
goto done;
}
+ if (pk_out) {
+ ed25519_pubkey_copy(pk_out, &kp->pubkey);
+ }
+
r = 0;
done:
load_family_id_keys(const or_options_t *options,
const networkstatus_t *ns)
{
- if (options->UseFamilyKeys) {
- if (load_family_id_keys_impl(options->KeyDirectory) < 0)
+ if (options->FamilyIds) {
+ if (load_family_id_keys_impl(options, options->KeyDirectory) < 0)
return -1;
- // This warning is _here_ because we want to give it (or not)
- // every time keys are reloaded.
- if (!smartlist_len(get_current_family_id_keys())) {
- log_warn(LD_OR,
- "UseFamilyKeys was configured, but no family keys were found. "
- "Family keys need to be in %s, with names like "
- FAMILY_KEY_FNAME", "FAMILY_KEY_FNAME".1, "
- FAMILY_KEY_FNAME".2, etc. "
- "See (XXXX INSERT URL HERE) for instructions.",
- options->KeyDirectory);
- } else {
- log_info(LD_OR, "Found %d family ID keys",
- smartlist_len(get_current_family_id_keys()));
- }
+ bool any_missing = false;
+ SMARTLIST_FOREACH_BEGIN(options->FamilyIds,
+ const ed25519_public_key_t *, id) {
+ if (!family_key_is_present(id)) {
+ log_err(LD_OR, "No key was found for listed FamilyID %s",
+ ed25519_fmt(id));
+ any_missing = true;
+ }
+ } SMARTLIST_FOREACH_END(id);
+ if (any_missing)
+ return -1;
+
+ log_info(LD_OR, "Found %d family ID keys",
+ smartlist_len(get_current_family_id_keys()));
} else {
set_family_id_keys(NULL);
}
static int have_warned_absent_myfamily = 0;
static int have_warned_absent_familykeys = 0;
- if (options->UseFamilyKeys) {
+ if (options->FamilyIds) {
if (!have_warned_absent_myfamily &&
!options->MyFamily && ns && should_publish_family_list(ns)) {
log_warn(LD_OR,
- "UseFamilyKeys was configured, but MyFamily was not. "
- "UseFamilyKeys is good, but the Tor network still requires "
+ "FamilyId was configured, but MyFamily was not. "
+ "FamilyId is good, but the Tor network still requires "
"MyFamily while clients are migrating to use family "
"keys instead.");
have_warned_absent_myfamily = 1;
options->MyFamily &&
ns && ns->consensus_method >= MIN_METHOD_FOR_FAMILY_IDS) {
log_notice(LD_OR,
- "MyFamily was configured, but UseFamilyKeys was not. "
+ "MyFamily was configured, but FamilyId was not. "
"It's a good time to start migrating your relays "
"to use family keys. "
"See (XXXX INSERT URL HERE) for instructions.");
int load_ed_keys(const or_options_t *options, time_t now);
int load_family_id_keys(const or_options_t *options,
const networkstatus_t *ns);
-int create_family_id_key(const char *fname);
+int create_family_id_key(const char *fname, ed25519_public_key_t *pk_out);
void warn_about_family_id_config(const or_options_t *options,
const networkstatus_t *ns);
int should_make_new_ed_keys(const or_options_t *options, const time_t now);
(puts("Not available: Tor has been compiled without relay support"), 0)
#define load_family_id_keys(x,y) \
(puts("Not available: Tor has been compiled without relay support"), 0)
-#define create_family_id_key(x) \
+#define create_family_id_key(x,y) \
(puts("Not available: Tor has been compiled without relay support"), -1)
#endif /* defined(HAVE_MODULE_RELAY) */
#ifdef ROUTERKEYS_PRIVATE
STATIC void set_family_id_keys(smartlist_t *keys);
STATIC bool is_family_key_fname(const char *fname);
-STATIC int load_family_id_keys_impl(const char *keydir);
+STATIC int load_family_id_keys_impl(const or_options_t *options,
+ const char *keydir);
#endif
#endif /* !defined(TOR_ROUTERKEYS_H) */
{
(void)arg;
- tt_assert(is_family_key_fname("secret_family_key"));
- tt_assert(is_family_key_fname("secret_family_key.1"));
- tt_assert(is_family_key_fname("secret_family_key.413"));
- tt_assert(! is_family_key_fname("secret_family_key.413x"));
- tt_assert(! is_family_key_fname("secret_family_key1"));
- tt_assert(! is_family_key_fname("secret_family_key.hello"));
- tt_assert(! is_family_key_fname("secret_family_key.-1"));
- tt_assert(! is_family_key_fname("fun_with_filenames.1"));
- tt_assert(! is_family_key_fname("fun_with_filenames"));
+ tt_assert(is_family_key_fname("hello.secret_family_key"));
+ tt_assert(is_family_key_fname("xyzzy.secret_family_key"));
+ tt_assert(is_family_key_fname("909.secret_family_key"));
+ tt_assert(! is_family_key_fname("zzz.secret_family_key~"));
+ tt_assert(! is_family_key_fname("secret_family_key"));
done:
;
(void) arg;
char *dname = tor_strdup(get_fname_rnd("fkeys"));
char *fname = NULL;
+ or_options_t *options = get_options_mutable();
+ ed25519_public_key_t pubkey;
#ifdef _WIN32
tt_assert(0==mkdir(dname));
tt_assert(0==mkdir(dname,0700));
#endif
+ options->FamilyIds = smartlist_new();
+
// Not a family key, will be ignored
tor_asprintf(&fname, "%s"PATH_SEPARATOR"junk.1", dname);
write_str_to_file(fname, "hello world", 0);
tor_free(fname);
- tt_int_op(0, OP_EQ, load_family_id_keys_impl(dname));
+ tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname));
tt_int_op(0, OP_EQ, smartlist_len(get_current_family_id_keys()));
// Create a family key; make sure we can load it.
- tor_asprintf(&fname, "%s"PATH_SEPARATOR"secret_family_key.12", dname);
- tt_int_op(0, OP_EQ, create_family_id_key(fname));
+ tor_asprintf(&fname, "%s"PATH_SEPARATOR"cg.secret_family_key", dname);
+ tt_int_op(0, OP_EQ, create_family_id_key(fname, &pubkey));
tor_free(fname);
+ smartlist_add(options->FamilyIds, tor_memdup(&pubkey, sizeof(pubkey)));
- tt_int_op(0, OP_EQ, load_family_id_keys_impl(dname));
+ tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname));
tt_int_op(1, OP_EQ, smartlist_len(get_current_family_id_keys()));
//Try a second key.
- tor_asprintf(&fname, "%s"PATH_SEPARATOR"secret_family_key.413", dname);
- tt_int_op(0, OP_EQ, create_family_id_key(fname));
+ tor_asprintf(&fname, "%s"PATH_SEPARATOR"eb.secret_family_key", dname);
+ tt_int_op(0, OP_EQ, create_family_id_key(fname, &pubkey));
+ smartlist_add(options->FamilyIds, tor_memdup(&pubkey, sizeof(pubkey)));
+ tor_free(fname);
+
+ tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname));
+ tt_int_op(2, OP_EQ, smartlist_len(get_current_family_id_keys()));
+
+ // Try an unlisted key, make sure it isn't loaded.
+ tor_asprintf(&fname, "%s"PATH_SEPARATOR"gt.secret_family_key", dname);
+ tt_int_op(0, OP_EQ, create_family_id_key(fname, &pubkey));
+ // Do not add to FamilyIDs here; we're leaving it unlisted.
tor_free(fname);
- tt_int_op(0, OP_EQ, load_family_id_keys_impl(dname));
+ tt_int_op(0, OP_EQ, load_family_id_keys_impl(options, dname));
tt_int_op(2, OP_EQ, smartlist_len(get_current_family_id_keys()));
// Make a junk key, make sure it causes an error.
- tor_asprintf(&fname, "%s"PATH_SEPARATOR"secret_family_key.6", dname);
+ tor_asprintf(&fname, "%s"PATH_SEPARATOR"xyz.secret_family_key", dname);
write_str_to_file(fname, "hello world", 0);
tor_free(fname);
- tt_int_op(-1, OP_EQ, load_family_id_keys_impl(dname));
+ tt_int_op(-1, OP_EQ, load_family_id_keys_impl(options, dname));
// keys unchanged
tt_int_op(2, OP_EQ, smartlist_len(get_current_family_id_keys()));