diff options
author | George Kadianakis <desnacked@riseup.net> | 2019-05-30 15:58:20 +0300 |
---|---|---|
committer | George Kadianakis <desnacked@riseup.net> | 2019-11-18 19:16:01 +0200 |
commit | 00fdaaee1e3cdfe40230a866c497d3648c43940c (patch) | |
tree | 684128731393d2cd563098e9290d286313d0b0ed /src/feature/control | |
parent | d28b6792cb99f25d42607eb46985ac4553013dd8 (diff) | |
download | tor-00fdaaee1e3cdfe40230a866c497d3648c43940c.tar.gz tor-00fdaaee1e3cdfe40230a866c497d3648c43940c.zip |
control-port: Implement ONION_CLIENT_AUTH_ADD.
Diffstat (limited to 'src/feature/control')
-rw-r--r-- | src/feature/control/control_cmd.c | 3 | ||||
-rw-r--r-- | src/feature/control/control_hs.c | 161 | ||||
-rw-r--r-- | src/feature/control/control_hs.h | 24 |
3 files changed, 188 insertions, 0 deletions
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index e1a8292c9f..3c16722e15 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -26,6 +26,7 @@ #include "feature/control/control.h" #include "feature/control/control_auth.h" #include "feature/control/control_cmd.h" +#include "feature/control/control_hs.h" #include "feature/control/control_events.h" #include "feature/control/control_getinfo.h" #include "feature/control/control_proto.h" @@ -1970,6 +1971,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, decoded_key->v2 = pk; *hs_version = HS_VERSION_TWO; } else if (!strcasecmp(key_type_ed25519_v3, key_type)) { + /* parsing of private ed25519 key */ /* "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, @@ -2317,6 +2319,7 @@ static const control_cmd_def_t CONTROL_COMMANDS[] = MULTLINE(hspost, 0), ONE_LINE(add_onion, CMD_FL_WIPE), ONE_LINE(del_onion, CMD_FL_WIPE), + ONE_LINE(onion_client_auth_add, CMD_FL_WIPE), }; /** diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c new file mode 100644 index 0000000000..5db8a0f007 --- /dev/null +++ b/src/feature/control/control_hs.c @@ -0,0 +1,161 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_hs.c + * + * \brief Implement commands for Tor's control-socket interface that are + * related to onion services. + **/ + +#include "core/or/or.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_hs.h" +#include "feature/control/control_proto.h" +#include "feature/hs/hs_client.h" +#include "lib/encoding/confline.h" + +#include "feature/control/control_cmd_args_st.h" + +/** Parse the 'KeyType ":" PrivateKey' from <b>client_privkey_str</b> and store + * it into <b>privkey</b>. Use <b>conn</b> to output any errors if needed. + * + * Return 0 if all went well, -1 otherwise. */ +static int +parse_private_key_from_control_port(const char *client_privkey_str, + curve25519_secret_key_t *privkey, + control_connection_t *conn) +{ + int retval = -1; + smartlist_t *key_args = smartlist_new(); + + tor_assert(privkey); + + smartlist_split_string(key_args, client_privkey_str, ":", + SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(key_args) != 2) { + control_printf_endreply(conn, 512, "Invalid key type/blob"); + goto err; + } + + const char *key_type = smartlist_get(key_args, 0); + const char *key_blob = smartlist_get(key_args, 1); + + if (strcasecmp(key_type, "x25519")) { + control_printf_endreply(conn, 552, + "Unrecognized key type \"%s\"", key_type); + goto err; + } + + if (base64_decode((char*)privkey->secret_key, sizeof(privkey->secret_key), + key_blob, + strlen(key_blob)) != sizeof(privkey->secret_key)) { + control_printf_endreply(conn, 512, "Failed to decode ED25519-V3 key"); + goto err; + } + + retval = 0; + + err: + SMARTLIST_FOREACH(key_args, char *, c, tor_free(c)); + smartlist_free(key_args); + return retval; +} + +/** Syntax details for ONION_CLIENT_AUTH_ADD */ +const control_cmd_syntax_t onion_client_auth_add_syntax = { + .max_args = 2, + .accept_keywords = true, +}; + +/** Called when we get an ONION_CLIENT_AUTH_ADD command; parse the body, and + * register the new client-side client auth credentials: + * "ONION_CLIENT_AUTH_ADD" SP HSAddress + * SP KeyType ":" PrivateKeyBlob + * [SP "ClientName=" Nickname] + * [SP "Type=" TYPE] CRLF + */ +int +handle_control_onion_client_auth_add(control_connection_t *conn, + const control_cmd_args_t *args) +{ + int retval = -1; + smartlist_t *flags = smartlist_new(); + hs_client_service_authorization_t *creds = NULL; + + tor_assert(args); + + int argc = smartlist_len(args->args); + /* We need at least 'HSAddress' and 'PrivateKeyBlob' */ + if (argc < 2) { + control_printf_endreply(conn, 512, + "Incomplete ONION_CLIENT_AUTH_ADD command"); + goto err; + } + + creds = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); + + const char *hsaddress = smartlist_get(args->args, 0); + if (!hs_address_is_valid(hsaddress)) { + control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",hsaddress); + goto err; + } + strlcpy(creds->onion_address, hsaddress, sizeof(creds->onion_address)); + + /* Parse the client private key */ + const char *client_privkey = smartlist_get(args->args, 1); + if (parse_private_key_from_control_port(client_privkey, + &creds->enc_seckey, conn) < 0) { + goto err; + } + + /* Now let's parse the remaining arguments (variable size) */ + for (const config_line_t *line = args->kwargs; line; line = line->next) { + if (!strcasecmp(line->key, "ClientName")) { + /* XXX apply length restriction? */ + creds->nickname = tor_strdup(line->value); + + } else if (!strcasecmpstart(line->key, "Flags")) { + smartlist_split_string(flags, line->value, ",", SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(flags) < 1) { + control_write_endreply(conn, 512, "Invalid 'Flags' argument"); + goto err; + } + SMARTLIST_FOREACH_BEGIN(flags, const char *, flag) { + if (!strcasecmp(flag, "Permanent")) { + creds->flags |= CLIENT_AUTH_FLAG_IS_PERMANENT; + } else { + control_printf_endreply(conn, 512, "Invalid 'Flags' argument: %s", + escaped(flag)); + goto err; + } + } SMARTLIST_FOREACH_END(flag); + } + } + + hs_client_register_auth_status_t register_status; + /* Register the credential (register func takes ownership of cred.) */ + register_status = hs_client_register_auth_credentials(creds); + if (BUG(register_status == REGISTER_FAIL_BAD_ADDRESS)) { + /* It's a bug because the service addr has already been validated above */ + control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"", hsaddress); + } else if (register_status == REGISTER_FAIL_ALREADY_EXISTS) { + control_printf_endreply(conn, 551, "Client already exists"); + } else if (register_status == REGISTER_SUCCESS) { + control_printf_endreply(conn, 250, "OK"); + } else { + tor_assert_nonfatal_unreached(); + } + + retval = 0; + goto done; + + err: + client_service_authorization_free(creds); + + done: + SMARTLIST_FOREACH(flags, char *, s, tor_free(s)); + smartlist_free(flags); + return retval; +} diff --git a/src/feature/control/control_hs.h b/src/feature/control/control_hs.h new file mode 100644 index 0000000000..1fcd7de36c --- /dev/null +++ b/src/feature/control/control_hs.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_hs.c + * + * \brief Header file for control_hs.c. + **/ + +#ifndef TOR_CONTROL_HS_H +#define TOR_CONTROL_HS_H + +struct control_cmd_syntax_t; + +extern const char *onion_client_auth_add_keywords[]; +extern const struct control_cmd_syntax_t onion_client_auth_add_syntax; + +int +handle_control_onion_client_auth_add(control_connection_t *conn, + const control_cmd_args_t *args); + +#endif + |