aboutsummaryrefslogtreecommitdiff
path: root/src/or/control.c
diff options
context:
space:
mode:
authorDavid Goulet <dgoulet@torproject.org>2017-11-09 12:20:29 -0500
committerDavid Goulet <dgoulet@torproject.org>2017-11-20 11:02:30 -0500
commit49f21b6ba30a07369ff3282615465d0f3ad40e5b (patch)
tree43dff6c77f8420086cfb2bdb81ace5329f4e8aad /src/or/control.c
parent660de600a036d0048fa6ba52bc2562f5a5ca6895 (diff)
downloadtor-49f21b6ba30a07369ff3282615465d0f3ad40e5b.tar.gz
tor-49f21b6ba30a07369ff3282615465d0f3ad40e5b.zip
control: Support HSv3 interface for ADD_ONION
At this commit, the key handling and generation is supported for a v3 service (ED25519-V3). However, the service creation is not yet implemented. This only adds the interface and code to deal with the new ED25519-V3 key type. Tests have been updated for RSA key type but nothing yet for ED25519-v3. Part of #20699 Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/or/control.c')
-rw-r--r--src/or/control.c126
1 files changed, 108 insertions, 18 deletions
diff --git a/src/or/control.c b/src/or/control.c
index 405c0c9357..ef1e0edcd8 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -4424,6 +4424,49 @@ handle_control_hspost(control_connection_t *conn,
return 0;
}
+/* Helper function for ADD_ONION that adds an ephemeral service depending on
+ * the given hs_version. The pk's type defers depending on the version so the
+ * caller should make sure those two matches. Both port_cfgs and auth_clients
+ * are now owned by the hidden service subsystem so the caller must stop
+ * accessing them.
+ *
+ * On success (RSAE_OKAY), the address_out points to a newly allocated string
+ * containing the onion address without the .onion part. On error, address_out
+ * is untouched. */
+static rend_service_add_ephemeral_status_t
+add_onion_helper_add_service(int hs_version, void *pk, smartlist_t *port_cfgs,
+ int max_streams, int max_streams_close_circuit,
+ int auth_type, smartlist_t *auth_clients,
+ char **address_out)
+{
+ rend_service_add_ephemeral_status_t ret;
+
+ tor_assert(pk);
+ tor_assert(port_cfgs);
+ tor_assert(address_out);
+
+ switch (hs_version) {
+ case HS_VERSION_TWO:
+ {
+ ret = rend_service_add_ephemeral(pk, port_cfgs, max_streams,
+ max_streams_close_circuit, auth_type,
+ auth_clients, address_out);
+ break;
+ }
+ case HS_VERSION_THREE:
+ {
+ /* XXX: Not implemented yet. */
+ *address_out = tor_strdup("this is a v3 address");
+ ret = RSAE_OKAY;
+ break;
+ }
+ default:
+ tor_assert_unreached();
+ }
+
+ return ret;
+}
+
/** Called when we get a ADD_ONION command; parse the body, and set up
* the new ephemeral Onion Service. */
static int
@@ -4605,15 +4648,15 @@ handle_control_add_onion(control_connection_t *conn,
}
/* Parse the "keytype:keyblob" argument. */
- crypto_pk_t *pk = NULL;
+ int hs_version = 0;
+ void *pk = NULL;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
- pk = add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk,
- &key_new_alg, &key_new_blob,
- &err_msg);
- if (!pk) {
+ if (add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk,
+ &key_new_alg, &key_new_blob, &pk, &hs_version,
+ &err_msg) < 0) {
if (err_msg) {
connection_write_str_to_buf(err_msg, conn);
tor_free(err_msg);
@@ -4622,16 +4665,23 @@ handle_control_add_onion(control_connection_t *conn,
}
tor_assert(!err_msg);
+ /* Hidden service version 3 don't have client authentication support so if
+ * ClientAuth was given, send back an error. */
+ if (hs_version == HS_VERSION_THREE && auth_clients) {
+ connection_printf_to_buf(conn, "513 ClientAuth not supported\r\n");
+ goto out;
+ }
+
/* Create the HS, using private key pk, client authentication auth_type,
* the list of auth_clients, and port config port_cfg.
* rend_service_add_ephemeral() will take ownership of pk and port_cfg,
* regardless of success/failure.
*/
char *service_id = NULL;
- int ret = rend_service_add_ephemeral(pk, port_cfgs, max_streams,
- max_streams_close_circuit,
- auth_type, auth_clients,
- &service_id);
+ int ret = add_onion_helper_add_service(hs_version, pk, port_cfgs,
+ max_streams,
+ max_streams_close_circuit, auth_type,
+ auth_clients, &service_id);
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
auth_clients = NULL; /* so is auth_clients */
switch (ret) {
@@ -4724,9 +4774,10 @@ handle_control_add_onion(control_connection_t *conn,
* Note: The error messages returned are deliberately vague to avoid echoing
* key material.
*/
-STATIC crypto_pk_t *
+STATIC int
add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out, char **key_new_blob_out,
+ void **decoded_key, int *hs_version,
char **err_msg_out)
{
smartlist_t *key_args = smartlist_new();
@@ -4734,7 +4785,9 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
- int ok = 0;
+ int ret = -1;
+
+ *decoded_key = NULL;
smartlist_split_string(key_args, arg, ":", SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(key_args) != 2) {
@@ -4746,6 +4799,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
static const char *key_type_new = "NEW";
static const char *key_type_best = "BEST";
static const char *key_type_rsa1024 = "RSA1024";
+ static const char *key_type_ed25519_v3 = "ED25519-V3";
const char *key_type = smartlist_get(key_args, 0);
const char *key_blob = smartlist_get(key_args, 1);
@@ -4758,9 +4812,23 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
goto err;
}
if (crypto_pk_num_bits(pk) != PK_BYTES*8) {
+ crypto_pk_free(pk);
err_msg = tor_strdup("512 Invalid RSA key size\r\n");
goto err;
}
+ *decoded_key = pk;
+ *hs_version = HS_VERSION_TWO;
+ } else if (!strcasecmp(key_type_ed25519_v3, key_type)) {
+ /* "ED25519-V3:<Base64 Blob>" - Loading a pre-existing ed25519 key. */
+ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
+ if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob,
+ strlen(key_blob)) != sizeof(sk->seckey)) {
+ tor_free(sk);
+ err_msg = tor_strdup("512 Failed to decode ED25519-V3 key\r\n");
+ goto err;
+ }
+ *decoded_key = sk;
+ *hs_version = HS_VERSION_THREE;
} else if (!strcasecmp(key_type_new, key_type)) {
/* "NEW:<Algorithm>" - Generating a new key, blob as algorithm. */
if (!strcasecmp(key_type_rsa1024, key_blob) ||
@@ -4774,12 +4842,38 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
}
if (!discard_pk) {
if (crypto_pk_base64_encode(pk, &key_new_blob)) {
+ crypto_pk_free(pk);
tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
key_type_rsa1024);
goto err;
}
key_new_alg = key_type_rsa1024;
}
+ *decoded_key = pk;
+ *hs_version = HS_VERSION_TWO;
+ } else if (!strcasecmp(key_type_ed25519_v3, key_blob)) {
+ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
+ if (ed25519_secret_key_generate(sk, 1) < 0) {
+ tor_free(sk);
+ tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n",
+ key_type_ed25519_v3);
+ goto err;
+ }
+ if (!discard_pk) {
+ ssize_t len = base64_encode_size(sizeof(sk->seckey), 0) + 1;
+ key_new_blob = tor_malloc_zero(len);
+ if (base64_encode(key_new_blob, len, (const char *) sk->seckey,
+ sizeof(sk->seckey), 0) != (len - 1)) {
+ tor_free(sk);
+ tor_free(key_new_blob);
+ tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
+ key_type_ed25519_v3);
+ goto err;
+ }
+ key_new_alg = key_type_ed25519_v3;
+ }
+ *decoded_key = sk;
+ *hs_version = HS_VERSION_THREE;
} else {
err_msg = tor_strdup("513 Invalid key type\r\n");
goto err;
@@ -4790,8 +4884,8 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
}
/* Succeded in loading or generating a private key. */
- tor_assert(pk);
- ok = 1;
+ tor_assert(*decoded_key);
+ ret = 0;
err:
SMARTLIST_FOREACH(key_args, char *, cp, {
@@ -4800,10 +4894,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
});
smartlist_free(key_args);
- if (!ok) {
- crypto_pk_free(pk);
- pk = NULL;
- }
if (err_msg_out) {
*err_msg_out = err_msg;
} else {
@@ -4812,7 +4902,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
*key_new_alg_out = key_new_alg;
*key_new_blob_out = key_new_blob;
- return pk;
+ return ret;
}
/** Helper function to handle parsing a ClientAuth argument to the