From afc0eb2c7198de0b14d18cf59484d34ac47b95a5 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 7 May 2003 18:30:46 +0000 Subject: [PATCH] Tested backends for directory signing and checking. Directory parser completely refactored. Need documentation and integration. Explanitory mail forthcoming. svn:r271 --- doc/TODO | 7 +- src/common/crypto.c | 8 +- src/common/crypto.h | 2 +- src/or/main.c | 7 +- src/or/or.h | 7 +- src/or/routers.c | 612 ++++++++++++++++++++++++++++++-------------- src/or/test.c | 37 ++- 7 files changed, 468 insertions(+), 212 deletions(-) diff --git a/doc/TODO b/doc/TODO index 73203aa312..4a934a68fb 100644 --- a/doc/TODO +++ b/doc/TODO @@ -22,7 +22,7 @@ ARMA - arma claims NICK . Handle half-open connections - Figure out what causes connections to close, standardize when we mark a connection vs when we tear it down -NICK - Look at what ssl does to keep from mutating data streams + o Look at what ssl does to keep from mutating data streams NICK . On the fly compression of each stream o Clean up the event loop (optimize and sanitize) ARMA o Remove that awful concept of 'roles' @@ -55,8 +55,13 @@ SPEC!! D Non-clique topologies . Directory servers D Automated reputation management NICK . Include key in source; sign directories + o Signed directory backend + - Document +ARMA - Integrate - Add versions to code NICK . Have directories list recommended-versions + o Include (unused) line in directories + o Check for presence of line. - Quit if running the wrong version - Command-line option to override quit . Add more information to directory server entries diff --git a/src/common/crypto.c b/src/common/crypto.c index df25563211..fe54dea83f 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -551,10 +551,8 @@ int crypto_pk_public_checksig(crypto_pk_env_t *env, unsigned char *from, int fro switch(env->type) { case CRYPTO_PK_RSA: - if (!(((RSA*)env->key)->p)) - return -1; return RSA_public_decrypt(fromlen, from, to, (RSA *)env->key, - RSA_PKCS1_OAEP_PADDING); + RSA_PKCS1_PADDING); default: return -1; } @@ -569,7 +567,7 @@ int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromle if (!(((RSA*)env->key)->p)) return -1; return RSA_private_encrypt(fromlen, from, to, (RSA *)env->key, - RSA_PKCS1_OAEP_PADDING); + RSA_PKCS1_PADDING); default: return -1; } @@ -836,7 +834,7 @@ base64_encode(char *dest, int destlen, char *src, int srclen) EVP_EncodeInit(&ctx); EVP_EncodeUpdate(&ctx, dest, &len, src, srclen); - EVP_EncodeFinal(&ctx, dest, &ret); + EVP_EncodeFinal(&ctx, dest+len, &ret); ret += len; return ret; } diff --git a/src/common/crypto.h b/src/common/crypto.h index 81a7ca16f0..38b280d7f2 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -65,7 +65,7 @@ int crypto_pk_keysize(crypto_pk_env_t *env); int crypto_pk_public_encrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding); int crypto_pk_private_decrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding); int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to); -int crypto_pk_private_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to); +int crypto_pk_public_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to); int base64_encode(char *dest, int destlen, char *src, int srclen); int base64_decode(char *dest, int destlen, char *src, int srclen); diff --git a/src/or/main.c b/src/or/main.c index dbac400e05..20c5faddc2 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -678,16 +678,17 @@ dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, dump_directory_to_string_impl(s+i, maxlen-i, dir); i = strlen(s); + strncat(s, "directory-signature\n", maxlen-i); + i = strlen(s); cp = s + i; if (crypto_SHA_digest(s, i, digest)) return -1; - if (crypto_pk_private_sign(private_key, digest, 20, signature)) + if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) return -1; - strncpy(cp, - "directory-signature\n-----BEGIN SIGNATURE-----\n", maxlen-i); + "-----BEGIN SIGNATURE-----\n", maxlen-i); i = strlen(s); cp = s+i; diff --git a/src/or/or.h b/src/or/or.h index fac26daac6..8268c381ca 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -739,6 +739,8 @@ int do_main_loop(void); void dumpstats(void); void dump_directory_to_string(char *s, int maxlen); void dump_directory_to_string_impl(char *s, int maxlen, directory_t *directory); +int dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, crypto_pk_env_t *private_key); + int main(int argc, char *argv[]); @@ -790,10 +792,13 @@ void router_get_directory(directory_t **pdirectory); int router_is_me(uint32_t addr, uint16_t port); void router_forget_router(uint32_t addr, uint16_t port); int router_get_list_from_file(char *routerfile); +int router_resolve(routerinfo_t *router); int router_get_list_from_string(char *s); int router_get_list_from_string_impl(char *s, directory_t **dest); +int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey); +int router_get_dir_from_string_impl(char *s, directory_t **dest, + crypto_pk_env_t *pkey); routerinfo_t *router_get_entry_from_string(char **s); - int router_compare_to_exit_policy(connection_t *conn); void routerlist_free(routerinfo_t *list); diff --git a/src/or/routers.c b/src/or/routers.c index f0b5205454..747d4f992e 100644 --- a/src/or/routers.c +++ b/src/or/routers.c @@ -2,7 +2,10 @@ /* See LICENSE for licensing information */ /* $Id$ */ +#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n" #define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n" +#define OR_SIGNATURE_BEGIN_TAG "-----BEGIN SIGNATURE-----\n" +#define OR_SIGNATURE_END_TAG "-----END SIGNATURE-----\n" #include "or.h" @@ -16,14 +19,22 @@ extern routerinfo_t *my_routerinfo; /* from main.c */ /****************************************************************************/ +struct directory_token; +typedef struct directory_token directory_token_t; + /* static function prototypes */ void routerlist_free(routerinfo_t *list); static routerinfo_t **make_rarray(routerinfo_t* list, int *len); static char *eat_whitespace(char *s); +static char *eat_whitespace_no_nl(char *s); static char *find_whitespace(char *s); -static int router_resolve(routerinfo_t *router); -static void router_add_exit_policy(routerinfo_t *router, char *string); static void router_free_exit_policy(routerinfo_t *router); +static routerinfo_t *router_get_entry_from_string_tok(char**s, + directory_token_t *tok); +static int router_get_list_from_string_tok(char **s, directory_t **dest, + directory_token_t *tok); +static int router_add_exit_policy(routerinfo_t *router, + directory_token_t *tok); /****************************************************************************/ @@ -288,12 +299,323 @@ int router_get_list_from_file(char *routerfile) return 0; } + +typedef enum { + K_ACCEPT, + K_CLIENT_SOFTWARE, + K_DIRECTORY_SIGNATURE, + K_REJECT, + K_ROUTER, + K_SERVER_SOFTWARE, + K_SIGNED_DIRECTORY, + K_SIGNING_KEY, + _SIGNATURE, + _PUBLIC_KEY, + _ERR, + _EOF +} directory_keyword; + +struct token_table_ent { char *t; int v; }; + +static struct token_table_ent token_table[] = { + { "accept", K_ACCEPT }, + { "client-software", K_CLIENT_SOFTWARE }, + { "directory-signature", K_DIRECTORY_SIGNATURE }, + { "reject", K_REJECT }, + { "router", K_ROUTER }, + { "server-software", K_SERVER_SOFTWARE }, + { "signed-directory", K_SIGNED_DIRECTORY }, + { "signing-key", K_SIGNING_KEY }, + { NULL, -1 } +}; + +#define MAX_ARGS 8 +struct directory_token { + directory_keyword tp; + union { + struct { + char *args[MAX_ARGS+1]; + int n_args; + } cmd; + char *signature; + char *error; + crypto_pk_env_t *public_key; + } val; +}; + +static int +_router_get_next_token(char **s, directory_token_t *tok) { + char *next; + crypto_pk_env_t *pkey = NULL; + char *signature = NULL; + int i, done; + + tok->tp = _ERR; + tok->val.error = ""; + + *s = eat_whitespace(*s); + if (!**s) { + tok->tp = _EOF; + return 0; + } else if (**s == '-') { + next = strchr(*s, '\n'); + if (! next) { tok->val.error = "No newline at EOF"; return -1; } + ++next; + if (! strncmp(*s, OR_PUBLICKEY_BEGIN_TAG, next-*s)) { + next = strstr(*s, OR_PUBLICKEY_END_TAG); + if (!next) { tok->val.error = "No public key end tag found"; return -1; } + next = strchr(next, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/ + ++next; + if (!(pkey = crypto_new_pk_env(CRYPTO_PK_RSA))) + return -1; + if (crypto_pk_read_public_key_from_string(pkey, *s, next-*s)) { + crypto_free_pk_env(pkey); + tok->val.error = "Couldn't parse public key."; + return -1; + } + tok->tp = _PUBLIC_KEY; + tok->val.public_key = pkey; + *s = next; + return 0; + } else if (! strncmp(*s, OR_SIGNATURE_BEGIN_TAG, next-*s)) { + /* Advance past newline; can't fail. */ + *s = strchr(*s, '\n'); + ++*s; + /* Find end of base64'd data */ + next = strstr(*s, OR_SIGNATURE_END_TAG); + if (!next) { tok->val.error = "No signature end tag found"; return -1; } + + signature = malloc(256); + i = base64_decode(signature, 256, *s, next-*s); + if (i<0) { + free(signature); + tok->val.error = "Error decoding signature."; return -1; + } else if (i != 128) { + free(signature); + tok->val.error = "Bad length on decoded signature."; return -1; + } + tok->tp = _SIGNATURE; + tok->val.signature = signature; + + next = strchr(next, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/ + *s = next+1; + return 0; + } else { + tok->val.error = "Unrecognized begin line"; return -1; + } + } else { + next = find_whitespace(*s); + if (!next) { + tok->val.error = "Unexpected EOF"; return -1; + } + for (i = 0 ; token_table[i].t ; ++i) { + if (!strncmp(token_table[i].t, *s, next-*s)) { + tok->tp = token_table[i].v; + i = 0; + done = (*next == '\n'); + *s = eat_whitespace_no_nl(next); + while (**s != '\n' && i <= MAX_ARGS && !done) { + next = find_whitespace(*s); + if (*next == '\n') + done = 1; + *next = 0; + tok->val.cmd.args[i++] = *s; + *s = eat_whitespace_no_nl(next+1); + }; + tok->val.cmd.n_args = i; + if (i > MAX_ARGS) { + tok->tp = _ERR; + tok->val.error = "Too many arguments"; return -1; + } + return 0; + } + } + tok->val.error = "Unrecognized command"; return -1; + } +} + +static void +router_dump_token(directory_token_t *tok) { + int i; + switch(tok->tp) + { + case _SIGNATURE: + puts("(signature)"); + return; + case _PUBLIC_KEY: + puts("(public key)"); + return; + case _ERR: + printf("(Error: %s\n)", tok->val.error); + return; + case _EOF: + puts("EOF"); + return; + case K_ACCEPT: printf("Accept"); break; + case K_CLIENT_SOFTWARE: printf("Client-Software"); break; + case K_DIRECTORY_SIGNATURE: printf("Directory-Signature"); break; + case K_REJECT: printf("Reject"); break; + case K_ROUTER: printf("Router"); break; + case K_SERVER_SOFTWARE: printf("Server-Software"); break; + case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break; + case K_SIGNING_KEY: printf("Signing-Key"); break; + default: + printf("?????? %d\n", tok->tp); return; + } + for (i = 0; i < tok->val.cmd.n_args; ++i) { + printf(" \"%s\"", tok->val.cmd.args[i]); + } + printf("\n"); + return; +} + +#ifdef DEBUG_ROUTER_TOKENS +static int +router_get_next_token(char **s, directory_token_t *tok) { + int i; + i = _router_get_next_token(s, tok); + router_dump_token(tok); + return i; +} +#else +#define router_get_next_token _router_get_next_token +#endif + + + +/* return the first char of s that is not whitespace and not a comment */ +static char *eat_whitespace(char *s) { + assert(s); + + while(isspace(*s) || *s == '#') { + while(isspace(*s)) + s++; + if(*s == '#') { /* read to a \n or \0 */ + while(*s && *s != '\n') + s++; + if(!*s) + return s; + } + } + return s; +} + +static char *eat_whitespace_no_nl(char *s) { + while(*s == ' ' || *s == '\t') + ++s; + return s; +} + +/* return the first char of s that is whitespace or '#' or '\0 */ +static char *find_whitespace(char *s) { + assert(s); + + while(*s && !isspace(*s) && *s != '#') + s++; + + return s; +} + int router_get_list_from_string(char *s) { return router_get_list_from_string_impl(s, &directory); } -int router_get_list_from_string_impl(char *s, directory_t **dest) +int router_get_list_from_string_impl(char *s, directory_t **dest) { + directory_token_t tok; + if (router_get_next_token(&s, &tok)) { + return NULL; + } + return router_get_list_from_string_tok(&s, dest, &tok); +} + +static int router_get_dir_hash(char *s, char *digest) +{ + char *start, *end; + start = strstr(s, "signed-directory"); + if (!start) return -1; + end = strstr(start, "directory-signature"); + if (!end) return -1; + end = strchr(end, '\n'); + if (!end) return -1; + ++end; + + if (crypto_SHA_digest(start, end-start, digest)) + return -1; + + return 0; +} + +int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey) +{ + return router_get_dir_from_string_impl(s, &directory, pkey); +} + +int router_get_dir_from_string_impl(char *s, directory_t **dest, + crypto_pk_env_t *pkey) +{ + directory_token_t tok; + char digest[20]; + char signed_digest[128]; + +#define NEXT_TOK() \ + do { \ + if (router_get_next_token(&s, &tok)) { \ + log(LOG_ERR, "Error reading directory: %s", tok.val.error); \ + return -1; \ + } } while (0) +#define TOK_IS(type,name) \ + do { \ + if (tok.tp != type) { \ + log(LOG_ERR, "Error reading directory: expected %s", name); \ + return -1; \ + } } while(0) + + if (router_get_dir_hash(s, digest)) + return -1; + + NEXT_TOK(); + TOK_IS(K_SIGNED_DIRECTORY, "signed-directory"); + + NEXT_TOK(); + TOK_IS(K_CLIENT_SOFTWARE, "client-software"); + + NEXT_TOK(); + TOK_IS(K_SERVER_SOFTWARE, "server-software"); + + NEXT_TOK(); + if (router_get_list_from_string_tok(&s, dest, &tok)) + return -1; + + TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature"); + NEXT_TOK(); + TOK_IS(_SIGNATURE, "signature"); + if (pkey) { + if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest) + != 20) { + log(LOG_ERR, "Error reading directory: invalid signature."); + free(tok.val.signature); + return -1; + } + if (memcmp(digest, signed_digest, 20)) { + log(LOG_ERR, "Error reading directory: signature does not match."); + free(tok.val.signature); + return -1; + } + } + free(tok.val.signature); + + NEXT_TOK(); + TOK_IS(_EOF, "end of directory"); + + return 0; +#undef NEXT_TOK +#undef TOK_IS +} + + +static int router_get_list_from_string_tok(char **s, directory_t **dest, + directory_token_t *tok) { routerinfo_t *routerlist=NULL; routerinfo_t *router; @@ -302,17 +624,8 @@ int router_get_list_from_string_impl(char *s, directory_t **dest) assert(s); - while(*s) { /* while not at the end of the string */ - router = router_get_entry_from_string(&s); - if(router == NULL) { - routerlist_free(routerlist); - return -1; - } - if (router_resolve(router)) { - routerlist_free(router); - routerlist_free(routerlist); - return -1; - } + while (tok->tp == K_ROUTER) { + router = router_get_entry_from_string_tok(s, tok); switch(router_is_me(router->addr, router->or_port)) { case 0: /* it's not me */ router->next = routerlist; @@ -329,7 +642,6 @@ int router_get_list_from_string_impl(char *s, directory_t **dest) routerlist_free(routerlist); return -1; } - s = eat_whitespace(s); } new_router_array = make_rarray(routerlist, &new_rarray_len); @@ -343,34 +655,6 @@ int router_get_list_from_string_impl(char *s, directory_t **dest) } return -1; } - -/* return the first char of s that is not whitespace and not a comment */ -static char *eat_whitespace(char *s) { - assert(s); - - while(isspace(*s) || *s == '#') { - while(isspace(*s)) - s++; - if(*s == '#') { /* read to a \n or \0 */ - while(*s && *s != '\n') - s++; - if(!*s) - return s; - } - } - return s; -} - -/* return the first char of s that is whitespace or '#' or '\0 */ -static char *find_whitespace(char *s) { - assert(s); - - while(*s && !isspace(*s) && *s != '#') - s++; - - return s; -} - static int router_resolve(routerinfo_t *router) { @@ -388,157 +672,102 @@ router_resolve(routerinfo_t *router) return 0; } + +routerinfo_t *router_get_entry_from_string(char **s) { + directory_token_t tok; + routerinfo_t *router; + if (router_get_next_token(s, &tok)) return NULL; + router = router_get_entry_from_string_tok(s, &tok); + if (tok.tp != _EOF) + return NULL; + return router; +} + /* reads a single router entry from s. * updates s so it points to after the router it just read. * mallocs a new router, returns it if all goes well, else returns NULL. */ -routerinfo_t *router_get_entry_from_string(char **s) { - routerinfo_t *router; - char *next; +static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t *tok) { + routerinfo_t *router = NULL; - /* Make sure that this string really starts with a router entry. */ - *s = eat_whitespace(*s); - if (strncasecmp(*s, "router ", 7)) { +#define NEXT_TOKEN() \ + do { if (router_get_next_token(s, tok)) goto err; \ + } while(0) + +#define ARGS tok->val.cmd.args + + if (tok->tp != K_ROUTER) { log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\""); return NULL; } - - router = malloc(sizeof(routerinfo_t)); - if (!router) { + if (!(router = malloc(sizeof(routerinfo_t)))) { log(LOG_ERR,"router_get_entry_from_string(): Could not allocate memory."); return NULL; } memset(router,0,sizeof(routerinfo_t)); /* zero it out first */ router->next = NULL; -/* Bug: if find_whitespace returns a '#', we'll squish it. */ -#define NEXT_TOKEN(s, next) \ - *s = eat_whitespace(*s); \ - next = find_whitespace(*s); \ - if(!*next) { \ - goto router_read_failed; \ - } \ - *next = 0; - - /* Skip the "router" */ - NEXT_TOKEN(s, next); - *s = next+1; - - /* read router->address */ - NEXT_TOKEN(s, next); - router->address = strdup(*s); - *s = next+1; - - /* Don't resolve address till later. */ + if (tok->val.cmd.n_args != 6) { + log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\""); + goto err; + } + + /* read router.address */ + if (!(router->address = strdup(ARGS[0]))) + goto err; router->addr = 0; - /* read router->or_port */ - NEXT_TOKEN(s, next); - router->or_port = atoi(*s); + /* Read router->or_port */ + router->or_port = atoi(ARGS[1]); if(!router->or_port) { - log(LOG_ERR,"router_get_entry_from_string(): or_port '%s' unreadable or 0. Failing.",*s); - goto router_read_failed; + log(LOG_ERR,"router_get_entry_from_string(): or_port unreadable or 0. Failing."); + goto err; } - *s = next+1; - /* read router->op_port */ - NEXT_TOKEN(s, next); - router->op_port = atoi(*s); - *s = next+1; + /* Router->op_port */ + router->op_port = atoi(ARGS[2]); - /* read router->ap_port */ - NEXT_TOKEN(s, next); - router->ap_port = atoi(*s); - *s = next+1; + /* Router->ap_port */ + router->ap_port = atoi(ARGS[3]); - /* read router->dir_port */ - NEXT_TOKEN(s, next); - router->dir_port = atoi(*s); - *s = next+1; + /* Router->dir_port */ + router->dir_port = atoi(ARGS[4]); - /* read router->bandwidth */ - NEXT_TOKEN(s, next); - router->bandwidth = atoi(*s); - if(!router->bandwidth) { - log(LOG_ERR,"router_get_entry_from_string(): bandwidth '%s' unreadable or 0. Failing.",*s); - goto router_read_failed; + /* Router->bandwidth */ + router->bandwidth = atoi(ARGS[5]); + if (!router->bandwidth) { + log(LOG_ERR,"router_get_entry_from_string(): bandwidth unreadable or 0. Failing."); } - *s = next+1; - + log(LOG_DEBUG,"or_port %d, op_port %d, ap_port %d, dir_port %d, bandwidth %d.", router->or_port, router->op_port, router->ap_port, router->dir_port, router->bandwidth); - *s = eat_whitespace(*s); - next = strstr(*s,OR_PUBLICKEY_END_TAG); - router->pkey = crypto_new_pk_env(CRYPTO_PK_RSA); - if(!next || !router->pkey) { - log(LOG_ERR,"router_get_entry_from_string(): Couldn't find pk in string"); - goto router_read_failed; - } - - /* now advance *s so it's at the end of this public key */ - next = strchr(next, '\n'); - assert(next); /* can't fail, we just checked it was here */ - *next = 0; -// log(LOG_DEBUG,"Key about to be read is: '%s'",*s); - if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) { - log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string"); - goto router_read_failed; - } - log(LOG_DEBUG,"router_get_entry_from_string(): Public key size = %u.", crypto_pk_keysize(router->pkey)); - - if (crypto_pk_keysize(router->pkey) != 128) { /* keys MUST be 1024 bits in size */ - log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.", - router->address,router->or_port); - goto router_read_failed; - } - - *s = next+1; - *s = eat_whitespace(*s); - if (!strncasecmp(*s, "signing-key", 11)) { - /* We have a signing key */ - *s = strchr(*s, '\n'); - *s = eat_whitespace(*s); - next = strstr(*s,OR_PUBLICKEY_END_TAG); - router->signing_pkey = crypto_new_pk_env(CRYPTO_PK_RSA); - if (!next || !router->signing_pkey) { - log(LOG_ERR,"router_get_entry_from_string(): Couldn't find signing_pk in string"); - goto router_read_failed; - } - next = strchr(next, '\n'); - assert(next); - *next = 0; - if ((crypto_pk_read_public_key_from_string(router->signing_pkey, *s, - strlen(*s)))<0) { - log(LOG_ERR,"router_get_entry_from_string(): Couldn't read signing pk from string"); - goto router_read_failed; + NEXT_TOKEN(); + if (tok->tp != _PUBLIC_KEY) { + log(LOG_ERR,"router_get_entry_from_string(): Missing public key"); + goto err; + } /* Check key length */ + router->pkey = tok->val.public_key; + + NEXT_TOKEN(); + if (tok->tp == K_SIGNING_KEY) { + NEXT_TOKEN(); + if (tok->tp != _PUBLIC_KEY) { + log(LOG_ERR,"router_get_entry_from_string(): Missing signing key"); + goto err; } + router->signing_pkey = tok->val.public_key; + NEXT_TOKEN(); + } - log(LOG_DEBUG,"router_get_entry_from_string(): Signing key size = %u.", crypto_pk_keysize(router->signing_pkey)); - - if (crypto_pk_keysize(router->signing_pkey) != 128) { /* keys MUST be 1024 bits in size */ - log(LOG_ERR,"Signing key for router %s:%u is 1024 bits. All keys must be exactly 1024 bits long.", - router->address,router->or_port); - goto router_read_failed; - } - *s = next+1; - } - - // test_write_pkey(router->pkey); - - while(**s && **s != '\n') { - /* pull in a line of exit policy */ - next = strchr(*s, '\n'); - if(!next) - goto router_read_failed; - *next = 0; - router_add_exit_policy(router, *s); - *s = next+1; + while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) { + router_add_exit_policy(router, tok); + NEXT_TOKEN(); } - + return router; -router_read_failed: + err: if(router->address) free(router->address); if(router->pkey) @@ -546,6 +775,8 @@ router_read_failed: router_free_exit_policy(router); free(router); return NULL; +#undef ARGS +#undef NEXT_TOKEN } static void router_free_exit_policy(routerinfo_t *router) { @@ -576,43 +807,35 @@ void test_write_pkey(crypto_pk_env_t *pkey) { } #endif -static void router_add_exit_policy(routerinfo_t *router, char *string) { +static int router_add_exit_policy(routerinfo_t *router, + directory_token_t *tok) { struct exit_policy_t *tmpe, *newe; - char *n; + char *arg, *colon; - string = eat_whitespace(string); - if(!*string) /* it was all whitespace or comment */ - return; + if (tok->val.cmd.n_args != 1) + return -1; + arg = tok->val.cmd.args[0]; newe = malloc(sizeof(struct exit_policy_t)); memset(newe,0,sizeof(struct exit_policy_t)); - - newe->string = strdup(string); - n = find_whitespace(string); - *n = 0; - - if(!strcasecmp(string,"reject")) { + + newe->string = malloc(8+strlen(arg)); + if (tok->tp == K_REJECT) { + strcpy(newe->string, "reject "); newe->policy_type = EXIT_POLICY_REJECT; - } else if(!strcasecmp(string,"accept")) { - newe->policy_type = EXIT_POLICY_ACCEPT; } else { - goto policy_read_failed; - } - - string = eat_whitespace(n+1); - if(!*string) { - goto policy_read_failed; + assert(tok->tp == K_ACCEPT); + strcpy(newe->string, "accept "); + newe->policy_type = EXIT_POLICY_ACCEPT; } - - n = strchr(string,':'); - if(!n) + strcat(newe->string, arg); + + colon = strchr(arg,':'); + if(!colon) goto policy_read_failed; - *n = 0; - newe->address = strdup(string); - string = n+1; - n = find_whitespace(string); - *n = 0; - newe->port = strdup(string); + *colon = 0; + newe->address = strdup(arg); + newe->port = strdup(colon+1); log(LOG_DEBUG,"router_add_exit_policy(): type %d, address '%s', port '%s'.", newe->policy_type, newe->address, newe->port); @@ -621,13 +844,13 @@ static void router_add_exit_policy(routerinfo_t *router, char *string) { if(!router->exit_policy) { router->exit_policy = newe; - return; + return 0; } for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ; tmpe->next = newe; - return; + return 0; policy_read_failed: assert(newe->string); @@ -639,8 +862,7 @@ policy_read_failed: if(newe->port) free(newe->port); free(newe); - return; - + return -1; } /* Return 0 if my exit policy says to allow connection to conn. diff --git a/src/or/test.c b/src/or/test.c index 45a1bcf2e8..9af2c97fcd 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -405,7 +405,7 @@ test_crypto() memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */ test_eq(-1, crypto_pk_private_decrypt(pk1, data2, 128, data3, RSA_PKCS1_OAEP_PADDING)); - + /* File operations: save and load private key */ f = fopen("/tmp/tor_test/pkey1", "wb"); test_assert(! crypto_pk_write_private_key_to_file(pk1, f)); @@ -419,11 +419,28 @@ test_crypto() "/tmp/tor_test/pkey1")); test_eq(15, crypto_pk_private_decrypt(pk2, data1, 128, data3, RSA_PKCS1_OAEP_PADDING)); - + /* Now try signing. */ + strcpy(data1, "Ossifrage"); + test_eq(128, crypto_pk_private_sign(pk1, data1, 10, data2)); + test_eq(10, crypto_pk_public_checksig(pk1, data2, 128, data3)); + test_streq(data3, "Ossifrage"); + /*XXXX test failed signing*/ + crypto_free_pk_env(pk1); crypto_free_pk_env(pk2); + /* Base64 tests */ + strcpy(data1, "Test string that contains 35 chars."); + strcat(data1, " 2nd string that contains 35 chars."); + + i = base64_encode(data2, 1024, data1, 71); + j = base64_decode(data3, 1024, data2, i); + test_streq(data3, data1); + test_eq(j, 71); + test_assert(data2[i] == '\0'); + + free(data1); free(data2); free(data3); @@ -512,9 +529,8 @@ test_dir_format() routerinfo_t r1, r2; crypto_pk_env_t *pk1 = NULL, *pk2 = NULL; routerinfo_t *rp1, *rp2; - struct exit_policy_t ex1, ex2, ex3; - - int i; + struct exit_policy_t ex1, ex2; + directory_t *dir1 = NULL, *dir2 = NULL; test_assert( (pk1 = crypto_new_pk_env(CRYPTO_PK_RSA)) ); test_assert( (pk2 = crypto_new_pk_env(CRYPTO_PK_RSA)) ); @@ -609,8 +625,15 @@ test_dir_format() test_assert(rp2->exit_policy->next->next == NULL); /* Okay, now for the directories. */ + dir1 = (directory_t*) malloc(sizeof(directory_t)); + dir1->n_routers = 2; + dir1->routers = (routerinfo_t**) malloc(sizeof(routerinfo_t*)*2); + dir1->routers[0] = &r1; + dir1->routers[1] = &r2; + test_assert(! dump_signed_directory_to_string_impl(buf, 2048, dir1, pk1)); + /* puts(buf); */ - + test_assert(! router_get_dir_from_string_impl(buf, &dir2, pk1)); if (pk1_str) free(pk1_str); if (pk2_str) free(pk2_str); @@ -618,6 +641,8 @@ test_dir_format() if (pk2) crypto_free_pk_env(pk2); if (rp1) routerlist_free(rp1); if (rp2) routerlist_free(rp2); + if (dir1) free(dir1); /* And more !*/ + if (dir1) free(dir2); /* And more !*/ } int -- 2.47.3