diff --git a/src/common/crypto.c b/src/common/crypto.c index cf209451a1..fa1bf2b734 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -677,11 +677,27 @@ crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out) } *bufp = '\0'; assert(strlen(buf) == FINGERPRINT_LEN); + assert(crypto_pk_check_fingerprint_syntax(buf)); strcpy(fp_out, buf); free(buf); return 0; } +int +crypto_pk_check_fingerprint_syntax(const char *s) +{ + int i; + for (i = 0; i < FINGERPRINT_LEN; ++i) { + if ((i%5) == 4) { + if (!isspace(s[i])) return 0; + } else { + if (!isxdigit(s[i])) return 0; + } + } + if (s[FINGERPRINT_LEN]) return 0; + return 1; +} + /* symmetric crypto */ int crypto_cipher_generate_key(crypto_cipher_env_t *env) { diff --git a/src/common/crypto.h b/src/common/crypto.h index 79e2447766..06269abab2 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -56,6 +56,7 @@ int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromle int crypto_pk_public_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to); #define FINGERPRINT_LEN 49 int crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out); +int crypto_pk_check_fingerprint_syntax(const char *s); 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/routers.c b/src/or/routers.c index 6872771538..3a9248cad8 100644 --- a/src/or/routers.c +++ b/src/or/routers.c @@ -1073,6 +1073,128 @@ int router_compare_to_exit_policy(connection_t *conn) { return 0; /* accept all by default. */ } +/*** Fingerprint handling code. ***/ +typedef struct fingerprint_entry_t { + char *nickname; + char *fingerprint; +} fingerprint_entry_t; + +static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR]; +static int n_fingerprints = 0; +/* return 0 on success, -1 on failure */ +int directory_parse_fingerprint_file(const char *fname) +{ + FILE *file; +#define BUF_LEN (FINGERPRINT_LEN+MAX_NICKNAME_LEN+20) + char buf[BUF_LEN+1]; + char *cp, *nickname, *fingerprint; + fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR]; + int n_fingerprints_tmp = 0; + int lineno=0; + int i; + if (!(file = fopen(fname, "r"))) { + log(LOG_WARNING, "Cannot open fingerprint file %s", fname); + goto err; + } + while (1) { + cp = fgets(buf, BUF_LEN, file); + ++lineno; + if (!cp) { + if (feof(file)) + break; + else { + log(LOG_WARNING, "Error reading from fingerprint file"); + goto err; + } + } + buf[BUF_LEN]='\0'; + cp = buf; + while (isspace(*cp)) + ++cp; + if (*cp == '#' || *cp == '\0') + continue; + nickname = cp; + cp = strchr(cp, ' '); + if (!cp) { + log(LOG_WARNING, "Bad line %d of fingerprint file", lineno); + goto err; + } + *cp++ = '\0'; + while (isspace(*cp)) + ++cp; + if (strlen(cp) < FINGERPRINT_LEN) { + log(LOG_WARNING, "Bad line %d of fingerprint file", lineno); + goto err; + } + fingerprint = cp; + cp[FINGERPRINT_LEN] = '\0'; + if (strlen(nickname) > MAX_NICKNAME_LEN) { + log(LOG_WARNING, "Nickname too long on line %d of fingerprint file", + lineno); + goto err; + } + if (!crypto_pk_check_fingerprint_syntax(fingerprint)) { + log(LOG_WARNING, "Invalid fingerprint on line %d of fingerprint file", + lineno); + goto err; + } + for (i = 0; i < n_fingerprints_tmp; ++i) { + if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) { + log(LOG_WARNING, "Duplicate nickname on line %d of fingerprint file", lineno); + goto err; + } + } + fingerprint_list_tmp[n_fingerprints_tmp].nickname = strdup(nickname); + fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = strdup(fingerprint); + ++n_fingerprints_tmp; + } + /* replace the global fingerprints list. */ + for (i = 0; i < n_fingerprints; ++i) { + free(fingerprint_list[i].nickname); + free(fingerprint_list[i].fingerprint); + } + memcpy(fingerprint_list, fingerprint_list_tmp, + sizeof(fingerprint_entry_t)*n_fingerprints_tmp); + n_fingerprints = n_fingerprints_tmp; + return 0; + + err: + for (i = 0; i < n_fingerprints_tmp; ++i) { + free(fingerprint_list_tmp[i].nickname); + free(fingerprint_list_tmp[i].fingerprint); + } + return -1; +#undef BUF_LEN +} + +/* return 1 if router's identity and nickname match. */ +int +directory_check_router_identity(const routerinfo_t *router) +{ + int i; + char fp[FINGERPRINT_LEN+1]; + if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) { + /* XXX Error computing fingerprint: log */ + return 0; + } + for (i=0;inickname)) { + /* Right nickname... */ + if (0==strcasecmp(fingerprint_list[i].fingerprint, fp)) { + /* Right fingerprint. */ + return 1; + } else { + /* Wrong fingerprint. */ + return 0; + } + } + } + /* No match found. XXX log. */ + return 0; +} + + + /* Local Variables: mode:c @@ -1080,4 +1202,3 @@ int router_compare_to_exit_policy(connection_t *conn) { c-basic-offset:2 End: */ -