mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
Merge remote-tracking branch 'tor-gitlab/mr/212'
This commit is contained in:
commit
d4255253b0
4
changes/ticket40084
Normal file
4
changes/ticket40084
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
o Major features (control port, onion services):
|
||||||
|
- Add support for creating version 3 onion services with authorization
|
||||||
|
from the control port. Previously, we could only create version 2
|
||||||
|
services here. Closes ticket 40084. Patch by Neel Chauhan.
|
@ -404,6 +404,8 @@ typedef enum rend_auth_type_t {
|
|||||||
REND_NO_AUTH = 0,
|
REND_NO_AUTH = 0,
|
||||||
REND_BASIC_AUTH = 1,
|
REND_BASIC_AUTH = 1,
|
||||||
REND_STEALTH_AUTH = 2,
|
REND_STEALTH_AUTH = 2,
|
||||||
|
REND_V3_AUTH = 3, /* Dummy flag to allow adding v3 services on the
|
||||||
|
* control port */
|
||||||
} rend_auth_type_t;
|
} rend_auth_type_t;
|
||||||
|
|
||||||
/** Client-side configuration of authorization for a hidden service. */
|
/** Client-side configuration of authorization for a hidden service. */
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "feature/control/control_getinfo.h"
|
#include "feature/control/control_getinfo.h"
|
||||||
#include "feature/control/control_proto.h"
|
#include "feature/control/control_proto.h"
|
||||||
#include "feature/hs/hs_control.h"
|
#include "feature/hs/hs_control.h"
|
||||||
|
#include "feature/hs/hs_service.h"
|
||||||
#include "feature/nodelist/nodelist.h"
|
#include "feature/nodelist/nodelist.h"
|
||||||
#include "feature/nodelist/routerinfo.h"
|
#include "feature/nodelist/routerinfo.h"
|
||||||
#include "feature/nodelist/routerlist.h"
|
#include "feature/nodelist/routerlist.h"
|
||||||
@ -1648,12 +1649,13 @@ handle_control_hspost(control_connection_t *conn,
|
|||||||
* On success (RSAE_OKAY), the address_out points to a newly allocated string
|
* 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
|
* containing the onion address without the .onion part. On error, address_out
|
||||||
* is untouched. */
|
* is untouched. */
|
||||||
static hs_service_add_ephemeral_status_t
|
STATIC hs_service_add_ephemeral_status_t
|
||||||
add_onion_helper_add_service(int hs_version,
|
add_onion_helper_add_service(int hs_version,
|
||||||
add_onion_secret_key_t *pk,
|
add_onion_secret_key_t *pk,
|
||||||
smartlist_t *port_cfgs, int max_streams,
|
smartlist_t *port_cfgs, int max_streams,
|
||||||
int max_streams_close_circuit, int auth_type,
|
int max_streams_close_circuit, int auth_type,
|
||||||
smartlist_t *auth_clients, char **address_out)
|
smartlist_t *auth_clients,
|
||||||
|
smartlist_t *auth_clients_v3, char **address_out)
|
||||||
{
|
{
|
||||||
hs_service_add_ephemeral_status_t ret;
|
hs_service_add_ephemeral_status_t ret;
|
||||||
|
|
||||||
@ -1669,7 +1671,8 @@ add_onion_helper_add_service(int hs_version,
|
|||||||
break;
|
break;
|
||||||
case HS_VERSION_THREE:
|
case HS_VERSION_THREE:
|
||||||
ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams,
|
ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams,
|
||||||
max_streams_close_circuit, address_out);
|
max_streams_close_circuit,
|
||||||
|
auth_clients_v3, address_out);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tor_assert_unreached();
|
tor_assert_unreached();
|
||||||
@ -1693,7 +1696,7 @@ get_detached_onion_services(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *add_onion_keywords[] = {
|
static const char *add_onion_keywords[] = {
|
||||||
"Port", "Flags", "MaxStreams", "ClientAuth", NULL
|
"Port", "Flags", "MaxStreams", "ClientAuth", "ClientAuthV3", NULL
|
||||||
};
|
};
|
||||||
static const control_cmd_syntax_t add_onion_syntax = {
|
static const control_cmd_syntax_t add_onion_syntax = {
|
||||||
.min_args = 1, .max_args = 1,
|
.min_args = 1, .max_args = 1,
|
||||||
@ -1714,6 +1717,8 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
smartlist_t *port_cfgs = smartlist_new();
|
smartlist_t *port_cfgs = smartlist_new();
|
||||||
smartlist_t *auth_clients = NULL;
|
smartlist_t *auth_clients = NULL;
|
||||||
smartlist_t *auth_created_clients = NULL;
|
smartlist_t *auth_created_clients = NULL;
|
||||||
|
smartlist_t *auth_clients_v3 = NULL;
|
||||||
|
smartlist_t *auth_clients_v3_str = NULL;
|
||||||
int discard_pk = 0;
|
int discard_pk = 0;
|
||||||
int detach = 0;
|
int detach = 0;
|
||||||
int max_streams = 0;
|
int max_streams = 0;
|
||||||
@ -1758,6 +1763,7 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
static const char *detach_flag = "Detach";
|
static const char *detach_flag = "Detach";
|
||||||
static const char *max_s_close_flag = "MaxStreamsCloseCircuit";
|
static const char *max_s_close_flag = "MaxStreamsCloseCircuit";
|
||||||
static const char *basicauth_flag = "BasicAuth";
|
static const char *basicauth_flag = "BasicAuth";
|
||||||
|
static const char *v3auth_flag = "V3Auth";
|
||||||
static const char *non_anonymous_flag = "NonAnonymous";
|
static const char *non_anonymous_flag = "NonAnonymous";
|
||||||
|
|
||||||
smartlist_t *flags = smartlist_new();
|
smartlist_t *flags = smartlist_new();
|
||||||
@ -1778,6 +1784,8 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
max_streams_close_circuit = 1;
|
max_streams_close_circuit = 1;
|
||||||
} else if (!strcasecmp(flag, basicauth_flag)) {
|
} else if (!strcasecmp(flag, basicauth_flag)) {
|
||||||
auth_type = REND_BASIC_AUTH;
|
auth_type = REND_BASIC_AUTH;
|
||||||
|
} else if (!strcasecmp(flag, v3auth_flag)) {
|
||||||
|
auth_type = REND_V3_AUTH;
|
||||||
} else if (!strcasecmp(flag, non_anonymous_flag)) {
|
} else if (!strcasecmp(flag, non_anonymous_flag)) {
|
||||||
non_anonymous = 1;
|
non_anonymous = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -1821,6 +1829,21 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
if (created) {
|
if (created) {
|
||||||
smartlist_add(auth_created_clients, client);
|
smartlist_add(auth_created_clients, client);
|
||||||
}
|
}
|
||||||
|
} else if (!strcasecmp(arg->key, "ClientAuthV3")) {
|
||||||
|
hs_service_authorized_client_t *client_v3 =
|
||||||
|
parse_authorized_client_key(arg->value, LOG_INFO);
|
||||||
|
if (!client_v3) {
|
||||||
|
control_write_endreply(conn, 512, "Cannot decode v3 client auth key");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth_clients_v3 == NULL) {
|
||||||
|
auth_clients_v3 = smartlist_new();
|
||||||
|
auth_clients_v3_str = smartlist_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
smartlist_add(auth_clients_v3, client_v3);
|
||||||
|
smartlist_add(auth_clients_v3_str, tor_strdup(arg->value));
|
||||||
} else {
|
} else {
|
||||||
tor_assert_nonfatal_unreached();
|
tor_assert_nonfatal_unreached();
|
||||||
goto out;
|
goto out;
|
||||||
@ -1829,10 +1852,12 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
if (smartlist_len(port_cfgs) == 0) {
|
if (smartlist_len(port_cfgs) == 0) {
|
||||||
control_write_endreply(conn, 512, "Missing 'Port' argument");
|
control_write_endreply(conn, 512, "Missing 'Port' argument");
|
||||||
goto out;
|
goto out;
|
||||||
} else if (auth_type == REND_NO_AUTH && auth_clients != NULL) {
|
} else if (auth_type == REND_NO_AUTH &&
|
||||||
|
(auth_clients != NULL && auth_clients_v3 != NULL)) {
|
||||||
control_write_endreply(conn, 512, "No auth type specified");
|
control_write_endreply(conn, 512, "No auth type specified");
|
||||||
goto out;
|
goto out;
|
||||||
} else if (auth_type != REND_NO_AUTH && auth_clients == NULL) {
|
} else if (auth_type != REND_NO_AUTH &&
|
||||||
|
(auth_clients == NULL && auth_clients_v3 == NULL)) {
|
||||||
control_write_endreply(conn, 512, "No auth clients specified");
|
control_write_endreply(conn, 512, "No auth clients specified");
|
||||||
goto out;
|
goto out;
|
||||||
} else if ((auth_type == REND_BASIC_AUTH &&
|
} else if ((auth_type == REND_BASIC_AUTH &&
|
||||||
@ -1841,6 +1866,15 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
smartlist_len(auth_clients) > 16)) {
|
smartlist_len(auth_clients) > 16)) {
|
||||||
control_write_endreply(conn, 512, "Too many auth clients");
|
control_write_endreply(conn, 512, "Too many auth clients");
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if ((auth_type == REND_BASIC_AUTH ||
|
||||||
|
auth_type == REND_STEALTH_AUTH) && auth_clients_v3) {
|
||||||
|
control_write_endreply(conn, 512,
|
||||||
|
"ClientAuthV3 does not support basic or stealth auth");
|
||||||
|
goto out;
|
||||||
|
} else if (auth_type == REND_V3_AUTH && auth_clients) {
|
||||||
|
control_write_endreply(conn, 512, "ClientAuth does not support v3 auth");
|
||||||
|
goto out;
|
||||||
|
|
||||||
} else if (non_anonymous != rend_service_non_anonymous_mode_enabled(
|
} else if (non_anonymous != rend_service_non_anonymous_mode_enabled(
|
||||||
get_options())) {
|
get_options())) {
|
||||||
/* If we failed, and the non-anonymous flag is set, Tor must be in
|
/* If we failed, and the non-anonymous flag is set, Tor must be in
|
||||||
@ -1869,12 +1903,16 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hidden service version 3 don't have client authentication support so if
|
/* We can't mix ClientAuth and Version 3 Onion Services, or ClientAuthV3 and
|
||||||
* ClientAuth was given, send back an error. */
|
* Version 2. If that's the case, send back an error. */
|
||||||
if (hs_version == HS_VERSION_THREE && auth_clients) {
|
if (hs_version == HS_VERSION_THREE && auth_clients) {
|
||||||
control_write_endreply(conn, 513, "ClientAuth not supported");
|
control_write_endreply(conn, 513, "ClientAuth not supported");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (hs_version == HS_VERSION_TWO && auth_clients_v3) {
|
||||||
|
control_write_endreply(conn, 513, "ClientAuthV3 not supported");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create the HS, using private key pk, client authentication auth_type,
|
/* Create the HS, using private key pk, client authentication auth_type,
|
||||||
* the list of auth_clients, and port config port_cfg.
|
* the list of auth_clients, and port config port_cfg.
|
||||||
@ -1882,12 +1920,13 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
* regardless of success/failure.
|
* regardless of success/failure.
|
||||||
*/
|
*/
|
||||||
char *service_id = NULL;
|
char *service_id = NULL;
|
||||||
int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs,
|
int ret =
|
||||||
max_streams,
|
add_onion_helper_add_service(hs_version, &pk, port_cfgs, max_streams,
|
||||||
max_streams_close_circuit, auth_type,
|
max_streams_close_circuit, auth_type,
|
||||||
auth_clients, &service_id);
|
auth_clients, auth_clients_v3, &service_id);
|
||||||
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
|
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
|
||||||
auth_clients = NULL; /* so is auth_clients */
|
auth_clients = NULL; /* so is auth_clients */
|
||||||
|
auth_clients_v3 = NULL; /* so is auth_clients_v3 */
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case RSAE_OKAY:
|
case RSAE_OKAY:
|
||||||
{
|
{
|
||||||
@ -1919,6 +1958,11 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
tor_free(encoded);
|
tor_free(encoded);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (auth_clients_v3_str) {
|
||||||
|
SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str, {
|
||||||
|
control_printf_midreply(conn, 250, "ClientAuthV3=%s", client_str);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
send_control_done(conn);
|
send_control_done(conn);
|
||||||
break;
|
break;
|
||||||
@ -1956,6 +2000,17 @@ handle_control_add_onion(control_connection_t *conn,
|
|||||||
rend_authorized_client_free(ac));
|
rend_authorized_client_free(ac));
|
||||||
smartlist_free(auth_clients);
|
smartlist_free(auth_clients);
|
||||||
}
|
}
|
||||||
|
if (auth_clients_v3) {
|
||||||
|
SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, ac,
|
||||||
|
service_authorized_client_free(ac));
|
||||||
|
smartlist_free(auth_clients_v3);
|
||||||
|
}
|
||||||
|
if (auth_clients_v3_str) {
|
||||||
|
SMARTLIST_FOREACH(auth_clients_v3_str, char *, client_str,
|
||||||
|
tor_free(client_str));
|
||||||
|
smartlist_free(auth_clients_v3_str);
|
||||||
|
}
|
||||||
|
|
||||||
if (auth_created_clients) {
|
if (auth_created_clients) {
|
||||||
// Do not free entries; they are the same as auth_clients
|
// Do not free entries; they are the same as auth_clients
|
||||||
smartlist_free(auth_created_clients);
|
smartlist_free(auth_created_clients);
|
||||||
|
@ -75,6 +75,7 @@ typedef struct control_cmd_syntax_t {
|
|||||||
} control_cmd_syntax_t;
|
} control_cmd_syntax_t;
|
||||||
|
|
||||||
#ifdef CONTROL_CMD_PRIVATE
|
#ifdef CONTROL_CMD_PRIVATE
|
||||||
|
#include "feature/hs/hs_service.h"
|
||||||
#include "lib/crypt_ops/crypto_ed25519.h"
|
#include "lib/crypt_ops/crypto_ed25519.h"
|
||||||
|
|
||||||
/* ADD_ONION secret key to create an ephemeral service. The command supports
|
/* ADD_ONION secret key to create an ephemeral service. The command supports
|
||||||
@ -94,6 +95,14 @@ STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
|
|||||||
int *hs_version,
|
int *hs_version,
|
||||||
control_connection_t *conn);
|
control_connection_t *conn);
|
||||||
|
|
||||||
|
STATIC hs_service_add_ephemeral_status_t add_onion_helper_add_service(
|
||||||
|
int hs_version,
|
||||||
|
add_onion_secret_key_t *pk,
|
||||||
|
smartlist_t *port_cfgs, int max_streams,
|
||||||
|
int max_streams_close_circuit, int auth_type,
|
||||||
|
smartlist_t *auth_clients,
|
||||||
|
smartlist_t *auth_clients_v3, char **address_out);
|
||||||
|
|
||||||
STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg,
|
STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg,
|
||||||
int *created, control_connection_t *conn);
|
int *created, control_connection_t *conn);
|
||||||
|
|
||||||
|
@ -1927,6 +1927,9 @@ rend_auth_type_to_string(rend_auth_type_t auth_type)
|
|||||||
case REND_STEALTH_AUTH:
|
case REND_STEALTH_AUTH:
|
||||||
str = "STEALTH_AUTH";
|
str = "STEALTH_AUTH";
|
||||||
break;
|
break;
|
||||||
|
case REND_V3_AUTH:
|
||||||
|
str = "REND_V3_AUTH";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
str = "UNKNOWN";
|
str = "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
@ -1116,6 +1116,43 @@ client_filename_is_valid(const char *filename)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Parse an base32-encoded authorized client from a string.
|
||||||
|
*
|
||||||
|
* Return the key on success, return NULL, otherwise. */
|
||||||
|
hs_service_authorized_client_t *
|
||||||
|
parse_authorized_client_key(const char *key_str, int severity)
|
||||||
|
{
|
||||||
|
hs_service_authorized_client_t *client = NULL;
|
||||||
|
|
||||||
|
/* We expect a specific length of the base64 encoded key so make sure we
|
||||||
|
* have that so we don't successfully decode a value with a different length
|
||||||
|
* and end up in trouble when copying the decoded key into a fixed length
|
||||||
|
* buffer. */
|
||||||
|
if (strlen(key_str) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) {
|
||||||
|
log_fn(severity, LD_REND, "Client authorization encoded base32 public key "
|
||||||
|
"length is invalid: %s", key_str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
client = tor_malloc_zero(sizeof(hs_service_authorized_client_t));
|
||||||
|
if (base32_decode((char *) client->client_pk.public_key,
|
||||||
|
sizeof(client->client_pk.public_key),
|
||||||
|
key_str, strlen(key_str)) !=
|
||||||
|
sizeof(client->client_pk.public_key)) {
|
||||||
|
log_fn(severity, LD_REND, "Client authorization public key cannot be "
|
||||||
|
"decoded: %s", key_str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return client;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (client != NULL) {
|
||||||
|
service_authorized_client_free(client);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/** Parse an authorized client from a string. The format of a client string
|
/** Parse an authorized client from a string. The format of a client string
|
||||||
* looks like (see rend-spec-v3.txt):
|
* looks like (see rend-spec-v3.txt):
|
||||||
*
|
*
|
||||||
@ -1162,23 +1199,7 @@ parse_authorized_client(const char *client_key_str)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We expect a specific length of the base32 encoded key so make sure we
|
if ((client = parse_authorized_client_key(pubkey_b32, LOG_WARN)) == NULL) {
|
||||||
* have that so we don't successfully decode a value with a different length
|
|
||||||
* and end up in trouble when copying the decoded key into a fixed length
|
|
||||||
* buffer. */
|
|
||||||
if (strlen(pubkey_b32) != BASE32_NOPAD_LEN(CURVE25519_PUBKEY_LEN)) {
|
|
||||||
log_warn(LD_REND, "Client authorization encoded base32 public key "
|
|
||||||
"length is invalid: %s", pubkey_b32);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = tor_malloc_zero(sizeof(hs_service_authorized_client_t));
|
|
||||||
if (base32_decode((char *) client->client_pk.public_key,
|
|
||||||
sizeof(client->client_pk.public_key),
|
|
||||||
pubkey_b32, strlen(pubkey_b32)) !=
|
|
||||||
sizeof(client->client_pk.public_key)) {
|
|
||||||
log_warn(LD_REND, "Client authorization public key cannot be decoded: %s",
|
|
||||||
pubkey_b32);
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1302,7 +1323,7 @@ load_client_keys(hs_service_t *service)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Release all storage held in <b>client</b>. */
|
/** Release all storage held in <b>client</b>. */
|
||||||
STATIC void
|
void
|
||||||
service_authorized_client_free_(hs_service_authorized_client_t *client)
|
service_authorized_client_free_(hs_service_authorized_client_t *client)
|
||||||
{
|
{
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@ -3682,15 +3703,17 @@ hs_service_upload_desc_to_dir(const char *encoded_desc,
|
|||||||
/** Add the ephemeral service using the secret key sk and ports. Both max
|
/** Add the ephemeral service using the secret key sk and ports. Both max
|
||||||
* streams parameter will be set in the newly created service.
|
* streams parameter will be set in the newly created service.
|
||||||
*
|
*
|
||||||
* Ownership of sk and ports is passed to this routine. Regardless of
|
* Ownership of sk, ports, and auth_clients_v3 is passed to this routine.
|
||||||
* success/failure, callers should not touch these values after calling this
|
* Regardless of success/failure, callers should not touch these values
|
||||||
* routine, and may assume that correct cleanup has been done on failure.
|
* after calling this routine, and may assume that correct cleanup has
|
||||||
|
* been done on failure.
|
||||||
*
|
*
|
||||||
* Return an appropriate hs_service_add_ephemeral_status_t. */
|
* Return an appropriate hs_service_add_ephemeral_status_t. */
|
||||||
hs_service_add_ephemeral_status_t
|
hs_service_add_ephemeral_status_t
|
||||||
hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
|
hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
|
||||||
int max_streams_per_rdv_circuit,
|
int max_streams_per_rdv_circuit,
|
||||||
int max_streams_close_circuit, char **address_out)
|
int max_streams_close_circuit,
|
||||||
|
smartlist_t *auth_clients_v3, char **address_out)
|
||||||
{
|
{
|
||||||
hs_service_add_ephemeral_status_t ret;
|
hs_service_add_ephemeral_status_t ret;
|
||||||
hs_service_t *service = NULL;
|
hs_service_t *service = NULL;
|
||||||
@ -3734,6 +3757,16 @@ hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auth_clients_v3) {
|
||||||
|
service->config.clients = smartlist_new();
|
||||||
|
SMARTLIST_FOREACH(auth_clients_v3, hs_service_authorized_client_t *, c, {
|
||||||
|
if (c != NULL) {
|
||||||
|
smartlist_add(service->config.clients, c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
smartlist_free(auth_clients_v3);
|
||||||
|
}
|
||||||
|
|
||||||
/* Build the onion address for logging purposes but also the control port
|
/* Build the onion address for logging purposes but also the control port
|
||||||
* uses it for the HS_DESC event. */
|
* uses it for the HS_DESC event. */
|
||||||
hs_build_address(&service->keys.identity_pk,
|
hs_build_address(&service->keys.identity_pk,
|
||||||
|
@ -372,7 +372,8 @@ char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk);
|
|||||||
hs_service_add_ephemeral_status_t
|
hs_service_add_ephemeral_status_t
|
||||||
hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
|
hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
|
||||||
int max_streams_per_rdv_circuit,
|
int max_streams_per_rdv_circuit,
|
||||||
int max_streams_close_circuit, char **address_out);
|
int max_streams_close_circuit,
|
||||||
|
smartlist_t *auth_clients_v3, char **address_out);
|
||||||
int hs_service_del_ephemeral(const char *address);
|
int hs_service_del_ephemeral(const char *address);
|
||||||
|
|
||||||
/* Used outside of the HS subsystem by the control port command HSPOST. */
|
/* Used outside of the HS subsystem by the control port command HSPOST. */
|
||||||
@ -388,6 +389,15 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
|
|||||||
void hs_service_dump_stats(int severity);
|
void hs_service_dump_stats(int severity);
|
||||||
void hs_service_circuit_cleanup_on_close(const circuit_t *circ);
|
void hs_service_circuit_cleanup_on_close(const circuit_t *circ);
|
||||||
|
|
||||||
|
hs_service_authorized_client_t *
|
||||||
|
parse_authorized_client_key(const char *key_str, int severity);
|
||||||
|
|
||||||
|
void
|
||||||
|
service_authorized_client_free_(hs_service_authorized_client_t *client);
|
||||||
|
#define service_authorized_client_free(c) \
|
||||||
|
FREE_AND_NULL(hs_service_authorized_client_t, \
|
||||||
|
service_authorized_client_free_, (c))
|
||||||
|
|
||||||
#ifdef HS_SERVICE_PRIVATE
|
#ifdef HS_SERVICE_PRIVATE
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
@ -452,12 +462,6 @@ STATIC void service_descriptor_free_(hs_service_descriptor_t *desc);
|
|||||||
FREE_AND_NULL(hs_service_descriptor_t, \
|
FREE_AND_NULL(hs_service_descriptor_t, \
|
||||||
service_descriptor_free_, (d))
|
service_descriptor_free_, (d))
|
||||||
|
|
||||||
STATIC void
|
|
||||||
service_authorized_client_free_(hs_service_authorized_client_t *client);
|
|
||||||
#define service_authorized_client_free(c) \
|
|
||||||
FREE_AND_NULL(hs_service_authorized_client_t, \
|
|
||||||
service_authorized_client_free_, (c))
|
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
write_address_to_file(const hs_service_t *service, const char *fname_);
|
write_address_to_file(const hs_service_t *service, const char *fname_);
|
||||||
|
|
||||||
|
@ -548,6 +548,8 @@ rend_encode_v2_descriptors(smartlist_t *descs_out,
|
|||||||
ipos = ipos_encrypted;
|
ipos = ipos_encrypted;
|
||||||
ipos_len = ipos_encrypted_len;
|
ipos_len = ipos_encrypted_len;
|
||||||
break;
|
break;
|
||||||
|
case REND_V3_AUTH:
|
||||||
|
break; /* v3 service, break. */
|
||||||
default:
|
default:
|
||||||
log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d",
|
log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d",
|
||||||
(int)auth_type);
|
(int)auth_type);
|
||||||
|
@ -3818,6 +3818,7 @@ upload_service_descriptor(rend_service_t *service)
|
|||||||
smartlist_clear(client_cookies);
|
smartlist_clear(client_cookies);
|
||||||
switch (service->auth_type) {
|
switch (service->auth_type) {
|
||||||
case REND_NO_AUTH:
|
case REND_NO_AUTH:
|
||||||
|
case REND_V3_AUTH:
|
||||||
/* Do nothing here. */
|
/* Do nothing here. */
|
||||||
break;
|
break;
|
||||||
case REND_BASIC_AUTH:
|
case REND_BASIC_AUTH:
|
||||||
|
@ -7,15 +7,17 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
#define CONTROL_EVENTS_PRIVATE
|
#define CONTROL_EVENTS_PRIVATE
|
||||||
|
#define CONTROL_CMD_PRIVATE
|
||||||
#define HS_CLIENT_PRIVATE
|
#define HS_CLIENT_PRIVATE
|
||||||
|
#define HS_SERVICE_PRIVATE
|
||||||
|
|
||||||
#include "core/or/or.h"
|
#include "core/or/or.h"
|
||||||
#include "test/test.h"
|
#include "test/test.h"
|
||||||
#include "test/test_helpers.h"
|
#include "test/test_helpers.h"
|
||||||
#include "core/mainloop/connection.h"
|
#include "core/mainloop/connection.h"
|
||||||
#include "feature/control/control.h"
|
#include "feature/control/control.h"
|
||||||
#include "feature/control/control_events.h"
|
|
||||||
#include "feature/control/control_cmd.h"
|
#include "feature/control/control_cmd.h"
|
||||||
|
#include "feature/control/control_events.h"
|
||||||
#include "feature/control/control_fmt.h"
|
#include "feature/control/control_fmt.h"
|
||||||
#include "feature/control/control_connection_st.h"
|
#include "feature/control/control_connection_st.h"
|
||||||
#include "app/config/config.h"
|
#include "app/config/config.h"
|
||||||
@ -23,9 +25,11 @@
|
|||||||
#include "feature/hs/hs_client.h"
|
#include "feature/hs/hs_client.h"
|
||||||
#include "feature/hs/hs_control.h"
|
#include "feature/hs/hs_control.h"
|
||||||
#include "feature/nodelist/nodelist.h"
|
#include "feature/nodelist/nodelist.h"
|
||||||
|
#include "feature/rend/rendservice.h"
|
||||||
|
|
||||||
#include "feature/nodelist/node_st.h"
|
#include "feature/nodelist/node_st.h"
|
||||||
#include "feature/nodelist/routerstatus_st.h"
|
#include "feature/nodelist/routerstatus_st.h"
|
||||||
|
#include "lib/container/smartlist.h"
|
||||||
#include "lib/crypt_ops/crypto_format.h"
|
#include "lib/crypt_ops/crypto_format.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
@ -735,6 +739,122 @@ test_hs_control_add_onion_with_bad_pubkey(void *arg)
|
|||||||
tor_free(conn.current_cmd);
|
tor_free(conn.current_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test that we can add the service via the control port. */
|
||||||
|
static void
|
||||||
|
test_hs_control_add_auth_onion_service(void *arg)
|
||||||
|
{
|
||||||
|
control_connection_t conn;
|
||||||
|
char *args = NULL, *cp1 = NULL;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
hs_init();
|
||||||
|
|
||||||
|
memset(&conn, 0, sizeof(control_connection_t));
|
||||||
|
TO_CONN(&conn)->outbuf = buf_new();
|
||||||
|
conn.current_cmd = tor_strdup("ADD_ONION");
|
||||||
|
args = tor_strdup("ED25519-V3:KLMQ4CLKwlDCHuMPn8j3od33cU5LhnrLNoZh7CWChl3VkY"
|
||||||
|
"pNAkeP5dGW8xeKR9HxQBWQ/w7Kr12lA/U8Pd/oxw== "
|
||||||
|
"ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja "
|
||||||
|
"Flags=V3Auth Port=9735,127.0.0.1");
|
||||||
|
handle_control_command(&conn, (uint32_t) strlen(args), args);
|
||||||
|
cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
|
||||||
|
tt_str_op(cp1, OP_EQ,
|
||||||
|
"250-ServiceID=n35etu3yjxrqjpntmfziom5sjwspoydchmelc4xleoy4jk2u4lziz2yd\r\n"
|
||||||
|
"250-ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja\r\n"
|
||||||
|
"250 OK\r\n");
|
||||||
|
tor_free(args);
|
||||||
|
tor_free(cp1);
|
||||||
|
|
||||||
|
args = tor_strdup("ED25519-V3:iIU8EBi71qE7G6UTsROU1kWN0JMrRP/YukC0Xk5WLGyil3"
|
||||||
|
"gm4u3wEBXr+/TaCpXS+65Pcdqz+PG+4+oWHLN05A== "
|
||||||
|
"ClientAuthV3=dummy Flags=V3Auth Port=9735,127.0.0.1");
|
||||||
|
handle_control_command(&conn, (uint32_t) strlen(args), args);
|
||||||
|
cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
|
||||||
|
tt_str_op(cp1, OP_EQ, "512 Cannot decode v3 client auth key\r\n");
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(args);
|
||||||
|
tor_free(cp1);
|
||||||
|
tor_free(conn.current_cmd);
|
||||||
|
buf_free(TO_CONN(&conn)->outbuf);
|
||||||
|
SMARTLIST_FOREACH(conn.ephemeral_onion_services, char *,
|
||||||
|
service, tor_free(service));
|
||||||
|
smartlist_free(conn.ephemeral_onion_services);
|
||||||
|
hs_client_free_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test that add_onion_helper_add_service can add the service. */
|
||||||
|
static void
|
||||||
|
test_hs_control_add_onion_helper_add_service(void *arg)
|
||||||
|
{
|
||||||
|
int hs_version_good, hs_version_bad;
|
||||||
|
add_onion_secret_key_t sk_good, sk_bad;
|
||||||
|
ed25519_public_key_t pk_good, pk_bad;
|
||||||
|
char *key_new_blob_good = NULL, *key_new_blob_bad = NULL;
|
||||||
|
const char *key_new_alg_good = NULL, *key_new_alg_bad = NULL;
|
||||||
|
hs_service_authorized_client_t *client_good, *client_bad;
|
||||||
|
smartlist_t *list_v2, *list_good, *list_bad;
|
||||||
|
hs_service_ht *global_map;
|
||||||
|
rend_service_port_config_t *portcfg;
|
||||||
|
smartlist_t *portcfgs;
|
||||||
|
char *address_out_good, *address_out_bad;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
hs_init();
|
||||||
|
global_map = get_hs_service_map();
|
||||||
|
|
||||||
|
portcfg = rend_service_parse_port_config("8080", ",", NULL);
|
||||||
|
portcfgs = smartlist_new();
|
||||||
|
smartlist_add(portcfgs, portcfg);
|
||||||
|
|
||||||
|
memset(&sk_good, 0, sizeof(sk_good));
|
||||||
|
memset(&sk_bad, 0, sizeof(sk_bad));
|
||||||
|
|
||||||
|
add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_good,
|
||||||
|
&key_new_blob_good, &sk_good, &hs_version_good, NULL);
|
||||||
|
add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_bad,
|
||||||
|
&key_new_blob_bad, &sk_bad, &hs_version_bad, NULL);
|
||||||
|
|
||||||
|
ed25519_public_key_generate(&pk_good, sk_good.v3);
|
||||||
|
ed25519_public_key_generate(&pk_bad, sk_bad.v3);
|
||||||
|
|
||||||
|
client_good = parse_authorized_client_key(
|
||||||
|
"N2NU7BSRL6YODZCYPN4CREB54TYLKGIE2KYOQWLFYC23ZJVCE5DQ", LOG_INFO);
|
||||||
|
client_bad = parse_authorized_client_key("dummy", LOG_INFO);
|
||||||
|
|
||||||
|
list_v2 = smartlist_new();
|
||||||
|
list_good = smartlist_new();
|
||||||
|
smartlist_add(list_good, client_good);
|
||||||
|
list_bad = smartlist_new();
|
||||||
|
smartlist_add(list_bad, client_bad);
|
||||||
|
|
||||||
|
add_onion_helper_add_service(HS_VERSION_THREE, &sk_good, portcfgs, 1, 1,
|
||||||
|
REND_V3_AUTH, list_v2, list_good, &address_out_good);
|
||||||
|
add_onion_helper_add_service(HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1,
|
||||||
|
REND_V3_AUTH, list_v2, list_bad, &address_out_bad);
|
||||||
|
|
||||||
|
hs_service_t *srv_good = find_service(global_map, &pk_good);
|
||||||
|
hs_service_t *srv_bad = find_service(global_map, &pk_bad);
|
||||||
|
|
||||||
|
tt_int_op(smartlist_len(srv_good->config.clients), OP_EQ, 1);
|
||||||
|
tt_int_op(smartlist_len(srv_bad->config.clients), OP_EQ, 0);
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(key_new_blob_good);
|
||||||
|
tor_free(key_new_blob_bad);
|
||||||
|
tor_free(address_out_good);
|
||||||
|
tor_free(address_out_bad);
|
||||||
|
|
||||||
|
service_authorized_client_free(client_good);
|
||||||
|
|
||||||
|
smartlist_free(list_v2);
|
||||||
|
smartlist_free(list_good);
|
||||||
|
smartlist_free(list_bad);
|
||||||
|
}
|
||||||
|
|
||||||
struct testcase_t hs_control_tests[] = {
|
struct testcase_t hs_control_tests[] = {
|
||||||
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
|
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
@ -748,6 +868,10 @@ struct testcase_t hs_control_tests[] = {
|
|||||||
test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL },
|
test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL },
|
||||||
{ "hs_control_add_onion_with_bad_pubkey",
|
{ "hs_control_add_onion_with_bad_pubkey",
|
||||||
test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL },
|
test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL },
|
||||||
|
{ "hs_control_add_auth_onion_service",
|
||||||
|
test_hs_control_add_auth_onion_service, TT_FORK, NULL, NULL},
|
||||||
|
{ "hs_control_add_onion_helper_add_service",
|
||||||
|
test_hs_control_add_onion_helper_add_service, TT_FORK, NULL, NULL},
|
||||||
|
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user