aboutsummaryrefslogtreecommitdiff
path: root/src/or/routerparse.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2008-08-08 14:36:11 +0000
committerNick Mathewson <nickm@torproject.org>2008-08-08 14:36:11 +0000
commit22259a08771275acf8ee7396b9a948385750039a (patch)
treef082809203c939a48bf6c3433225145b953b14d7 /src/or/routerparse.c
parentf6879caa0447a5fd65ff07d210146393d27cb88e (diff)
downloadtor-22259a08771275acf8ee7396b9a948385750039a.tar.gz
tor-22259a08771275acf8ee7396b9a948385750039a.zip
The first of Karsten's proposal 121 patches: configure and maintain client authorization data. Tweaked a bit: see comments on or-dev.
svn:r16475
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r--src/or/routerparse.c148
1 files changed, 147 insertions, 1 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index d86c6f05a9..365fe75d22 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -100,6 +100,10 @@ typedef enum {
R_IPO_ONION_KEY,
R_IPO_SERVICE_KEY,
+ C_CLIENT_NAME,
+ C_DESCRIPTOR_COOKIE,
+ C_CLIENT_KEY,
+
_UNRECOGNIZED,
_ERR,
_EOF,
@@ -141,6 +145,7 @@ typedef struct directory_token_t {
typedef enum {
NO_OBJ, /**< No object, ever. */
NEED_OBJ, /**< Object is required. */
+ NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */
NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
NEED_KEY, /**< Object is required, and must be a public key. */
OBJ_OK, /**< Object is optional. */
@@ -352,6 +357,15 @@ static token_rule_t ipo_token_table[] = {
END_OF_TABLE
};
+/** List of tokens allowed in the (possibly encrypted) list of introduction
+ * points of rendezvous service descriptors */
+static token_rule_t client_keys_token_table[] = {
+ T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
+ T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
+ T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
+ END_OF_TABLE
+};
+
static token_rule_t networkstatus_token_table[] = {
T1("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
@@ -2789,6 +2803,7 @@ token_check_object(memarea_t *area, const char *kwd,
}
break;
case NEED_KEY_1024:
+ case NEED_SKEY_1024:
if (tok->key && crypto_pk_keysize(tok->key) != PK_BYTES) {
tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
kwd, (int)crypto_pk_keysize(tok->key));
@@ -2799,6 +2814,19 @@ token_check_object(memarea_t *area, const char *kwd,
if (!tok->key) {
tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
}
+ if (o_syn != NEED_SKEY_1024) {
+ if (crypto_pk_key_is_private(tok->key)) {
+ tor_snprintf(ebuf, sizeof(ebuf),
+ "Private key given for %s, which wants a public key", kwd);
+ RET_ERR(ebuf);
+ }
+ } else { /* o_syn == NEED_SKEY_1024 */
+ if (!crypto_pk_key_is_private(tok->key)) {
+ tor_snprintf(ebuf, sizeof(ebuf),
+ "Public key given for %s, which wants a private key", kwd);
+ RET_ERR(ebuf);
+ }
+ }
break;
case OBJ_OK:
break;
@@ -2948,10 +2976,14 @@ get_next_token(memarea_t *area,
ebuf[sizeof(ebuf)-1] = '\0';
RET_ERR(ebuf);
}
- if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a key... */
+ if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
tok->key = crypto_new_pk_env();
if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
RET_ERR("Couldn't parse public key.");
+ } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
+ tok->key = crypto_new_pk_env();
+ if (crypto_pk_read_private_key_from_string(tok->key, obstart))
+ RET_ERR("Couldn't parse private key.");
} else { /* If it's something else, try to base64-decode it */
int r;
tok->object_body = ALLOC(next-*s); /* really, this is too much RAM. */
@@ -3668,3 +3700,117 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
return result;
}
+/** Parse the content of a client_key file in <b>ckstr</b> and add
+ * rend_authorized_client_t's for each parsed client to
+ * <b>parsed_clients</b>. Return the number of parsed clients as result
+ * or -1 for failure. */
+int
+rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
+{
+ int result = -1;
+ smartlist_t *tokens;
+ directory_token_t *tok;
+ const char *current_entry = NULL;
+ memarea_t *area = NULL;
+ if (!ckstr || strlen(ckstr) == 0)
+ return -1;
+ tokens = smartlist_create();
+ /* Begin parsing with first entry, skipping comments or whitespace at the
+ * beginning. */
+ area = memarea_new(4096);
+ /* XXXX proposal 121 This skips _everything_, not just comments or
+ * whitespace. That's no good. */
+ current_entry = strstr(ckstr, "client-name ");
+ while (!strcmpstart(current_entry, "client-name ")) {
+ rend_authorized_client_t *parsed_entry;
+ size_t len;
+ char descriptor_cookie_base64[REND_DESC_COOKIE_LEN_BASE64+2+1];
+ char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
+ /* Determine end of string. */
+ const char *eos = strstr(current_entry, "\nclient-name ");
+ if (!eos)
+ eos = current_entry + strlen(current_entry);
+ else
+ eos = eos + 1;
+ /* Free tokens and clear token list. */
+ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
+ smartlist_clear(tokens);
+ memarea_clear(area);
+ /* Tokenize string. */
+ if (tokenize_string(area, current_entry, eos, tokens,
+ client_keys_token_table, 0)) {
+ log_warn(LD_REND, "Error tokenizing client keys file.");
+ goto err;
+ }
+ /* Advance to next entry, if available. */
+ current_entry = eos;
+ /* Check minimum allowed length of token list. */
+ if (smartlist_len(tokens) < 2) {
+ log_warn(LD_REND, "Impossibly short client key entry.");
+ goto err;
+ }
+ /* Parse client name. */
+ tok = find_first_by_keyword(tokens, C_CLIENT_NAME);
+ tor_assert(tok);
+ tor_assert(tok == smartlist_get(tokens, 0));
+ tor_assert(tok->n_args == 1);
+
+ len = strlen(tok->args[0]);
+ if (len < 1 || len > 19 ||
+ strspn(tok->args[0], REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
+ log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
+ "between 1 and 19, and valid characters are "
+ "[A-Za-z0-9+-_].)", tok->args[0]);
+ goto err;
+ }
+ /* Check if client name is duplicate. */
+ if (strmap_get(parsed_clients, tok->args[0])) {
+ log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
+ "duplicate client name: '%s'. Ignoring.", tok->args[0]);
+ goto err;
+ }
+ parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
+ parsed_entry->client_name = tor_strdup(tok->args[0]);
+ strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
+ /* Parse client key. */
+ tok = find_first_by_keyword(tokens, C_CLIENT_KEY);
+ if (tok) {
+ parsed_entry->client_key = tok->key;
+ tok->key = NULL; /* Prevent free */
+ }
+
+ /* Parse descriptor cookie. */
+ tok = find_first_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
+ tor_assert(tok);
+ tor_assert(tok->n_args == 1);
+ if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
+ log_warn(LD_REND, "Descriptor cookie has illegal length: %s",
+ escaped(tok->args[0]));
+ goto err;
+ }
+ /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2,
+ * because a base64 encoding of length 24 does not fit into 16 bytes in all
+ * cases. */
+ if ((base64_decode(descriptor_cookie_tmp, REND_DESC_COOKIE_LEN+2,
+ tok->args[0], REND_DESC_COOKIE_LEN_BASE64+2+1)
+ != REND_DESC_COOKIE_LEN)) {
+ log_warn(LD_REND, "Descriptor cookie contains illegal characters: "
+ "%s", descriptor_cookie_base64);
+ goto err;
+ }
+ memcpy(parsed_entry->descriptor_cookie, descriptor_cookie_tmp,
+ REND_DESC_COOKIE_LEN);
+ }
+ result = strmap_size(parsed_clients);
+ goto done;
+ err:
+ result = -1;
+ done:
+ /* Free tokens and clear token list. */
+ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
+ smartlist_free(tokens);
+ if (area)
+ memarea_drop_all(area);
+ return result;
+}
+