diff options
author | Nick Mathewson <nickm@torproject.org> | 2003-09-25 05:17:11 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2003-09-25 05:17:11 +0000 |
commit | 3d4ccb781ae5d74f0e16a63c89e08459d15cccf1 (patch) | |
tree | 3e9f214701c4a09bc45b453374bd6806f253a1a4 | |
parent | a3bd8b5483bfb3813ba814c8d73840ca993e0298 (diff) | |
download | tor-3d4ccb781ae5d74f0e16a63c89e08459d15cccf1.tar.gz tor-3d4ccb781ae5d74f0e16a63c89e08459d15cccf1.zip |
Refactor buffers; implement descriptors.
'buf_t' is now an opaque type defined in buffers.c .
Router descriptors now include all keys; routers generate keys as
needed on startup (in a newly defined "data directory"), and generate
their own descriptors. Descriptors are now self-signed.
Implementation is not complete: descriptors are never published; and
upon receiving a descriptor, the directory doesn't do anything with
it.
At least "routers.or" and orkeygen are now obsolete, BTW.
svn:r483
-rw-r--r-- | doc/TODO | 2 | ||||
-rw-r--r-- | doc/tor-spec.txt | 13 | ||||
-rw-r--r-- | src/common/crypto.c | 39 | ||||
-rw-r--r-- | src/common/crypto.h | 4 | ||||
-rw-r--r-- | src/common/tortls.c | 49 | ||||
-rw-r--r-- | src/common/tortls.h | 4 | ||||
-rw-r--r-- | src/or/buffers.c | 224 | ||||
-rw-r--r-- | src/or/circuit.c | 4 | ||||
-rw-r--r-- | src/or/config.c | 15 | ||||
-rw-r--r-- | src/or/connection.c | 57 | ||||
-rw-r--r-- | src/or/connection_edge.c | 7 | ||||
-rw-r--r-- | src/or/connection_or.c | 9 | ||||
-rw-r--r-- | src/or/cpuworker.c | 6 | ||||
-rw-r--r-- | src/or/directory.c | 16 | ||||
-rw-r--r-- | src/or/dns.c | 4 | ||||
-rw-r--r-- | src/or/main.c | 423 | ||||
-rw-r--r-- | src/or/onion.c | 8 | ||||
-rw-r--r-- | src/or/or.h | 68 | ||||
-rw-r--r-- | src/or/routers.c | 233 | ||||
-rw-r--r-- | src/or/test.c | 173 |
20 files changed, 880 insertions, 478 deletions
@@ -48,7 +48,7 @@ NICK - instruments ORs to report stats . integrate rep_ok functions, see what breaks ARMA - configure log files. separate log file, separate severities. ARMA - what assumptions break if we fclose(0) when we daemonize? -NICK - make buffer struct elements opaque outside buffers.c +NICK o make buffer struct elements opaque outside buffers.c ARMA - Go through log messages, reduce confusing error messages. ARMA - make the logs include more info (fd, etc) ARMA - add log convention to the HACKING file diff --git a/doc/tor-spec.txt b/doc/tor-spec.txt index 5f17e37968..5203ed7c12 100644 --- a/doc/tor-spec.txt +++ b/doc/tor-spec.txt @@ -439,12 +439,16 @@ which reveals the downstream node. (Unless otherwise noted, tokens on the same line are space-separated.) -Router ::= Router-Line Public-Key Signing-Key? Exit-Policy NL +Router ::= Router-Line Onion-Key Link-Key Signing-Key Exit-Policy Router-Signature NL Router-Line ::= "router" address ORPort APPort DirPort bandwidth NL -Public-key ::= a public key in PEM format NL -Signing-Key ::= "signing-key" NL signing key in PEM format NL +Onion-key ::= "onion-key" NL a public key in PEM format NL +Link-key ::= "link-key" NL a public key in PEM format NL +Signing-Key ::= "signing-key" NL a public key in PEM format NL Exit-Policy ::= Exit-Line* Exit-Line ::= ("accept"|"reject") string NL +Router-Signature ::= "router-signature" NL Signature +Signature ::= "-----BEGIN SIGNATURE-----" NL + Base-64-encoded-signature NL "-----END SIGNATURE-----" NL ORport ::= port where the router listens for routers/proxies (speaking cells) APPort ::= where the router listens for applications (speaking socks) @@ -475,7 +479,8 @@ Directory ::= Directory-Header Directory-Router Router* Signature Directory-Header ::= "signed-directory" NL Software-Line NL Software-Line: "recommended-software" comma-separated-version-list Directory-Router ::= Router -Signature ::= "directory-signature" NL "-----BEGIN SIGNATURE-----" NL +Directory-Signature ::= "directory-signature" NL Signature +Signature ::= "-----BEGIN SIGNATURE-----" NL Base-64-encoded-signature NL "-----END SIGNATURE-----" NL Note: The router block for the directory server must appear first. diff --git a/src/common/crypto.c b/src/common/crypto.c index 538f946ae8..b2ddbb1735 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -349,7 +349,7 @@ int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, FILE *src) return 0; } -int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, unsigned char *keyfile) +int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile) { FILE *f_pr; int retval = 0; @@ -618,6 +618,43 @@ int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromle } } +int +crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out) +{ + unsigned char *buf, *bufp; + unsigned char digest[20]; + int len; + int i; + assert(pk->type == CRYPTO_PK_RSA); + len = i2d_RSAPublicKey((RSA*)pk->key, NULL); + if (len < 0) + return -1; + if (len<FINGERPRINT_LEN+1) len = FINGERPRINT_LEN+1; + buf = bufp = tor_malloc(len+1); + len = i2d_RSAPublicKey((RSA*)pk->key, &bufp); + if (len < 0) { + free(buf); + return -1; + } + if (crypto_SHA_digest(buf, len, digest) < 0) { + free(buf); + return -1; + } + bufp = buf; + for (i = 0; i < 20; ++i) { + sprintf(bufp,"%02X",digest[i]); + bufp += 2; + if (i%2 && i != 19) { + *bufp++ = ' '; + } + } + *bufp = '\0'; + assert(strlen(buf) == FINGERPRINT_LEN); + strcpy(fp_out, buf); + free(buf); + return 0; +} + /* 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 f723e71952..ccd48fa56a 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -42,7 +42,7 @@ int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, char *src, int l int crypto_pk_write_private_key_to_file(crypto_pk_env_t *env, FILE *dest); int crypto_pk_write_public_key_to_file(crypto_pk_env_t *env, FILE *dest); int crypto_pk_check_key(crypto_pk_env_t *env); -int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, unsigned char *keyfile); +int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile); int crypto_pk_set_key(crypto_pk_env_t *env, unsigned char *key); int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b); @@ -53,6 +53,8 @@ int crypto_pk_public_encrypt(crypto_pk_env_t *env, unsigned char *from, int from 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_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 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/common/tortls.c b/src/common/tortls.c index f7d961ab83..a1d5b2c5e0 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -33,6 +33,9 @@ struct tor_tls_st { int isServer; }; +static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa, + const char *nickname); + /* global tls context, keep it here because nobody else needs to touch it */ static tor_tls_context *global_tls_context=NULL; static int tls_library_is_initialized = 0; @@ -111,8 +114,9 @@ static int always_accept_verify_cb(int preverify_ok, * commonName 'nickname', and write it, PEM-encoded, to the file named * by 'certfile'. Return 0 on success, -1 for failure. */ -int -tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname) +X509 * +tor_tls_create_certificate(crypto_pk_env_t *rsa, + const char *nickname) { time_t start_time, end_time; EVP_PKEY *pkey = NULL; @@ -120,15 +124,15 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname) X509_NAME *name = NULL; BIO *out = NULL; int nid; - int r; + int err; tor_tls_init(); start_time = time(NULL); - assert(rsa); + assert(rsa && nickname); if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa))) - return -1; + return NULL; if (!(x509 = X509_new())) goto error; if (!(X509_set_version(x509, 2))) @@ -143,7 +147,7 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname) "TOR", -1, -1, 0))) goto error; if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, - nickname, -1, -1, 0))) goto error; + (char*)nickname, -1, -1, 0))) goto error; if (!(X509_set_issuer_name(x509, name))) goto error; @@ -158,25 +162,21 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname) goto error; if (!X509_sign(x509, pkey, EVP_sha1())) goto error; - if (!(out = BIO_new_file(certfile, "w"))) - goto error; - if (!(PEM_write_bio_X509(out, x509))) - goto error; - r = 0; + err = 0; goto done; error: - r = -1; + err = 1; done: if (out) BIO_free(out); - if (x509) + if (x509 && err) X509_free(x509); if (pkey) EVP_PKEY_free(pkey); if (name) X509_NAME_free(name); - return r; + return x509; } @@ -201,16 +201,24 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname) * used for that certificate. Return -1 if failure, else 0. */ int -tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer) +tor_tls_context_new(crypto_pk_env_t *rsa, + int isServer, const char *nickname) { crypto_dh_env_t *dh = NULL; EVP_PKEY *pkey = NULL; tor_tls_context *result; - - assert((certfile && rsa) || (!certfile && !rsa)); - + X509 *cert = NULL; + tor_tls_init(); + if (rsa) { + cert = tor_tls_create_certificate(rsa, nickname); + if (!cert) { + log(LOG_ERR, "Error creating certificate"); + return NULL; + } + } + result = tor_malloc(sizeof(tor_tls_context)); result->ctx = NULL; #ifdef EVERYONE_HAS_AES @@ -225,8 +233,7 @@ tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer) #endif if (!SSL_CTX_set_cipher_list(result->ctx, CIPHER_LIST)) goto error; - if (certfile && !SSL_CTX_use_certificate_file(result->ctx,certfile, - SSL_FILETYPE_PEM)) + if (cert && !SSL_CTX_use_certificate(result->ctx,cert)) goto error; SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); if (rsa) { @@ -236,7 +243,7 @@ tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer) goto error; EVP_PKEY_free(pkey); pkey = NULL; - if (certfile) { + if (cert) { if (!SSL_CTX_check_private_key(result->ctx)) goto error; } diff --git a/src/common/tortls.h b/src/common/tortls.h index 2f45c4da33..2c8749cea3 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -16,8 +16,8 @@ typedef struct tor_tls_st tor_tls; #define TOR_TLS_WANTWRITE -1 #define TOR_TLS_DONE 0 -int tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname); -int tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer); +/* X509* tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname); */ +int tor_tls_context_new(crypto_pk_env_t *rsa, int isServer, const char *nickname); tor_tls *tor_tls_new(int sock, int isServer); void tor_tls_free(tor_tls *tls); int tor_tls_peer_has_cert(tor_tls *tls); diff --git a/src/or/buffers.c b/src/or/buffers.c index 2bddcd2ef1..3119fec5ad 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -8,50 +8,103 @@ extern or_options_t options; /* command-line and config-file options */ -/* Create a new buf of size MAX_BUF_SIZE. Write a pointer to it - * into *buf, write MAX_BUF_SIZE into *buflen, and initialize - * *buf_datalen to 0. Return 0. +struct buf_t { + char *buf; + size_t len; + size_t datalen; +}; + +#define BUF_OK(b) ((b) && (b)->buf && (b)->datalen <= (b)->len) + +/* Find the first instance of str on buf. If none exists, return -1. + * Otherwise, return index of the first character in buf _after_ the + * first instance of str. + */ +static int find_str_in_str(const char *str, int str_len, + const char *buf, int buf_len) +{ + const char *location; + const char *last_possible = buf + buf_len - str_len; + + assert(str && str_len > 0 && buf); + + if(buf_len < str_len) + return -1; + + for(location = buf; location <= last_possible; location++) + if((*location == *str) && !memcmp(location+1, str+1, str_len-1)) + return location-buf+str_len; + + return -1; +} + +/* Create and return a new buf of size 'size' */ -int buf_new(char **buf, int *buflen, int *buf_datalen) { +buf_t *buf_new_with_capacity(size_t size) { + buf_t *buf; + buf = (buf_t*)tor_malloc(sizeof(buf_t)); + buf->buf = (char *)tor_malloc(size); + buf->len = size; + buf->datalen = 0; +// memset(buf->buf,0,size); + + assert(BUF_OK(buf)); + return buf; +} - assert(buf && buflen && buf_datalen); +buf_t *buf_new() +{ + return buf_new_with_capacity(MAX_BUF_SIZE); +} - *buf = (char *)tor_malloc(MAX_BUF_SIZE); -// memset(*buf,0,MAX_BUF_SIZE); - *buflen = MAX_BUF_SIZE; - *buf_datalen = 0; - return 0; +size_t buf_datalen(const buf_t *buf) +{ + return buf->datalen; } -void buf_free(char *buf) { +size_t buf_capacity(const buf_t *buf) +{ + return buf->len; +} + +const char *_buf_peek_raw_buffer(const buf_t *buf) +{ + return buf->buf; +} + +void buf_free(buf_t *buf) { + assert(buf && buf->buf); + free(buf->buf); free(buf); } -/* read from socket s, writing onto buf+buf_datalen. + + +/* read from socket s, writing onto end of buf. * read at most 'at_most' bytes, and in any case don't read more than will fit based on buflen. * If read() returns 0, set *reached_eof to 1 and return 0. If you want to tear * down the connection return -1, else return the number of bytes read. */ -int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof) { +int read_to_buf(int s, int at_most, buf_t *buf, int *reached_eof) { int read_result; #ifdef MS_WINDOWS int e; #endif - assert(buf && *buf && buflen && buf_datalen && reached_eof && (s>=0)); + assert(BUF_OK(buf) && reached_eof && (s>=0)); /* this is the point where you would grow the buffer, if you want to */ - if(at_most > *buflen - *buf_datalen) - at_most = *buflen - *buf_datalen; /* take the min of the two */ + if(at_most > buf->len - buf->datalen) + at_most = buf->len - buf->datalen; /* take the min of the two */ if(at_most == 0) return 0; /* we shouldn't read anything */ // log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most); - read_result = read(s, *buf+*buf_datalen, at_most); + read_result = read(s, buf->buf+buf->datalen, at_most); if (read_result < 0) { if(!ERRNO_EAGAIN(errno)) { /* it's a real error */ return -1; @@ -68,31 +121,33 @@ int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, i *reached_eof = 1; return 0; } else { /* we read some bytes */ - *buf_datalen += read_result; - log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result, *buf_datalen); + buf->datalen += read_result; + log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result, + (int)buf->datalen); return read_result; } } -int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen) { +int read_to_buf_tls(tor_tls *tls, int at_most, buf_t *buf) { int r; - assert(tls && *buf && buflen && buf_datalen); + assert(tls && BUF_OK(buf)); - if (at_most > *buflen - *buf_datalen) - at_most = *buflen - *buf_datalen; + if (at_most > buf->len - buf->datalen) + at_most = buf->len - buf->datalen; if (at_most == 0) return 0; - r = tor_tls_read(tls, *buf+*buf_datalen, at_most); + r = tor_tls_read(tls, buf->buf+buf->datalen, at_most); if (r<0) return r; - *buf_datalen += r; - log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",r, *buf_datalen); + buf->datalen += r; + log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",r, (int)buf->datalen); return r; } -int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen) { +int flush_buf(int s, buf_t *buf, int *buf_flushlen) +{ /* push from buf onto s * then memmove to front of buf @@ -103,14 +158,12 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale int e; #endif - assert(buf && *buf && buflen && buf_flushlen && buf_datalen && (s>=0) && (*buf_flushlen <= *buf_datalen)); + assert(BUF_OK(buf) && buf_flushlen && (s>=0) && (*buf_flushlen <= buf->datalen)); if(*buf_flushlen == 0) /* nothing to flush */ return 0; - /* this is the point where you would grow the buffer, if you want to */ - - write_result = write(s, *buf, *buf_flushlen); + write_result = write(s, buf->buf, *buf_flushlen); if (write_result < 0) { if(!ERRNO_EAGAIN(errno)) { /* it's a real error */ return -1; @@ -124,72 +177,70 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale log_fn(LOG_DEBUG,"write() would block, returning."); return 0; } else { - *buf_datalen -= write_result; + buf->datalen -= write_result; *buf_flushlen -= write_result; - memmove(*buf, *buf+write_result, *buf_datalen); + memmove(buf->buf, buf->buf+write_result, buf->datalen); log_fn(LOG_DEBUG,"%d: flushed %d bytes, %d ready to flush, %d remain.", - s,write_result,*buf_flushlen,*buf_datalen); + s,write_result,*buf_flushlen,(int)buf->datalen); return *buf_flushlen; /* XXX USE_TLS should change to return write_result like any sane function would */ } } -int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen) +int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen) { int r; - assert(tls && *buf && buflen && buf_datalen); + assert(tls && BUF_OK(buf) && buf_flushlen); /* we want to let tls write even if flushlen is zero, because it might * have a partial record pending */ - r = tor_tls_write(tls, *buf, *buf_flushlen); + r = tor_tls_write(tls, buf->buf, *buf_flushlen); if (r < 0) { return r; } - *buf_datalen -= r; + buf->datalen -= r; *buf_flushlen -= r; - memmove(*buf, *buf+r, *buf_datalen); + memmove(buf->buf, buf->buf+r, buf->datalen); log_fn(LOG_DEBUG,"flushed %d bytes, %d ready to flush, %d remain.", - r,*buf_flushlen,*buf_datalen); + r,*buf_flushlen,(int)buf->datalen); return r; } -int write_to_buf(char *string, int string_len, - char **buf, int *buflen, int *buf_datalen) { +int write_to_buf(char *string, int string_len, buf_t *buf) { /* append string to buf (growing as needed, return -1 if "too big") * return total number of bytes on the buf */ - assert(string && buf && *buf && buflen && buf_datalen); + assert(string && BUF_OK(buf)); /* this is the point where you would grow the buffer, if you want to */ - if (string_len + *buf_datalen > *buflen) { /* we're out of luck */ + if (string_len + buf->datalen > buf->len) { /* we're out of luck */ log_fn(LOG_DEBUG, "buflen too small. Time to implement growing dynamic bufs."); return -1; } - memcpy(*buf+*buf_datalen, string, string_len); - *buf_datalen += string_len; - log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, *buf_datalen); - return *buf_datalen; + memcpy(buf->buf+buf->datalen, string, string_len); + buf->datalen += string_len; + log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, (int)buf->datalen); + return buf->datalen; } -int fetch_from_buf(char *string, int string_len, - char **buf, int *buflen, int *buf_datalen) { +int fetch_from_buf(char *string, int string_len, buf_t *buf) { /* There must be string_len bytes in buf; write them onto string, * then memmove buf back (that is, remove them from buf). * * Return the number of bytes still on the buffer. */ - assert(string && buf && *buf && buflen && buf_datalen); - assert(string_len <= *buf_datalen); /* make sure we don't ask for too much */ + assert(string && BUF_OK(buf)); + assert(string_len <= buf->datalen); /* make sure we don't ask for too much */ - memcpy(string,*buf,string_len); - *buf_datalen -= string_len; - memmove(*buf, *buf+string_len, *buf_datalen); - return *buf_datalen; + memcpy(string,buf->buf,string_len); + buf->datalen -= string_len; + memmove(buf->buf, buf->buf+string_len, buf->datalen); + return buf->datalen; } /* There is a (possibly incomplete) http statement on *buf, of the @@ -204,24 +255,24 @@ int fetch_from_buf(char *string, int string_len, * * Else, change nothing and return 0. */ -int fetch_from_buf_http(char *buf, int *buf_datalen, +int fetch_from_buf_http(buf_t *buf, char *headers_out, int max_headerlen, char *body_out, int max_bodylen) { char *headers, *body; int i; int headerlen, bodylen, contentlen; - assert(buf && buf_datalen); + assert(BUF_OK(buf)); - headers = buf; - i = find_on_inbuf("\r\n\r\n", 4, buf, *buf_datalen); + headers = buf->buf; + i = find_on_inbuf("\r\n\r\n", 4, buf); if(i < 0) { log_fn(LOG_DEBUG,"headers not all here yet."); return 0; } - body = buf+i; + body = buf->buf+i; headerlen = body-headers; /* includes the CRLFCRLF */ - bodylen = *buf_datalen - headerlen; + bodylen = buf->datalen - headerlen; log_fn(LOG_DEBUG,"headerlen %d, bodylen %d.",headerlen,bodylen); if(headers_out && max_headerlen <= headerlen) { @@ -234,9 +285,11 @@ int fetch_from_buf_http(char *buf, int *buf_datalen, } #define CONTENT_LENGTH "\r\nContent-Length: " - i = find_on_inbuf(CONTENT_LENGTH, strlen(CONTENT_LENGTH), headers, headerlen); + i = find_str_in_str(CONTENT_LENGTH, sizeof(CONTENT_LENGTH), + headers, headerlen); if(i > 0) { contentlen = atoi(headers+i); + /* XXX What if content-length is malformed? */ if(bodylen < contentlen) { log_fn(LOG_DEBUG,"body not all here yet."); return 0; /* not all there yet */ @@ -246,15 +299,15 @@ int fetch_from_buf_http(char *buf, int *buf_datalen, } /* all happy. copy into the appropriate places, and return 1 */ if(headers_out) { - memcpy(headers_out,buf,headerlen); + memcpy(headers_out,buf->buf,headerlen); headers_out[headerlen] = 0; /* null terminate it */ } if(body_out) { - memcpy(body_out,buf+headerlen,bodylen); + memcpy(body_out,buf->buf+headerlen,bodylen); body_out[bodylen] = 0; /* null terminate it */ } - *buf_datalen -= (headerlen+bodylen); - memmove(buf, buf+headerlen+bodylen, *buf_datalen); + buf->datalen -= (headerlen+bodylen); + memmove(buf, buf->buf+headerlen+bodylen, buf->datalen); return 1; } @@ -269,7 +322,7 @@ int fetch_from_buf_http(char *buf, int *buf_datalen, * If it's invalid or too big, return -1. * Else it's not all there yet, change nothing and return 0. */ -int fetch_from_buf_socks(char *buf, int *buf_datalen, +int fetch_from_buf_socks(buf_t *buf, char *addr_out, int max_addrlen, uint16_t *port_out) { socks4_t socks4_info; @@ -278,14 +331,14 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen, enum {socks4, socks4a } socks_prot = socks4a; char *next, *startaddr; - if(*buf_datalen < sizeof(socks4_t)) /* basic info available? */ + if(buf->datalen < sizeof(socks4_t)) /* basic info available? */ return 0; /* not yet */ /* an inlined socks4_unpack() */ - socks4_info.version = *buf; - socks4_info.command = *(buf+1); - socks4_info.destport = ntohs(*(uint16_t*)(buf+2)); - socks4_info.destip = ntohl(*(uint32_t*)(buf+4)); + socks4_info.version = (unsigned char) *(buf->buf); + socks4_info.command = (unsigned char) *(buf->buf+1); + socks4_info.destport = ntohs(*(uint16_t*)(buf->buf+2)); + socks4_info.destip = ntohl(*(uint32_t*)(buf->buf+4)); if(socks4_info.version != 4) { log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info.version); @@ -321,7 +374,7 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen, socks_prot = socks4; } - next = memchr(buf+SOCKS4_NETWORK_LEN, 0, *buf_datalen); + next = memchr(buf->buf+SOCKS4_NETWORK_LEN, 0, buf->datalen); if(!next) { log_fn(LOG_DEBUG,"Username not here yet."); return 0; @@ -329,7 +382,7 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen, startaddr = next+1; if(socks_prot == socks4a) { - next = memchr(startaddr, 0, buf+*buf_datalen-startaddr); + next = memchr(startaddr, 0, buf->buf+buf->datalen-startaddr); if(!next) { log_fn(LOG_DEBUG,"Destaddr not here yet."); return 0; @@ -342,32 +395,19 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen, log_fn(LOG_DEBUG,"Everything is here. Success."); *port_out = port; strcpy(addr_out, socks_prot == socks4 ? tmpbuf : startaddr); - *buf_datalen -= (next-buf+1); /* next points to the final \0 on inbuf */ - memmove(buf, next+1, *buf_datalen); + buf->datalen -= (next-buf->buf+1); /* next points to the final \0 on inbuf */ + memmove(buf->buf, next+1, buf->datalen); // log_fn(LOG_DEBUG,"buf_datalen is now %d:'%s'",*buf_datalen,buf); return 1; } -int find_on_inbuf(char *string, int string_len, - char *buf, int buf_datalen) { +int find_on_inbuf(char *string, int string_len, buf_t *buf) { /* find first instance of needle 'string' on haystack 'buf'. return how * many bytes from the beginning of buf to the end of string. * If it's not there, return -1. */ - char *location; - char *last_possible = buf + buf_datalen - string_len; - - assert(string && string_len > 0 && buf); - - if(buf_datalen < string_len) - return -1; - - for(location = buf; location <= last_possible; location++) - if((*location == *string) && !memcmp(location+1, string+1, string_len-1)) - return location-buf+string_len; - - return -1; + return find_str_in_str(string, string_len, buf->buf, buf->datalen); } /* diff --git a/src/or/circuit.c b/src/or/circuit.c index f440d7d9c7..74c0372594 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -751,7 +751,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) { cell.aci = circ->n_aci; cell.length = DH_ONIONSKIN_LEN; - if(onion_skin_create(circ->n_conn->pkey, &(circ->cpath->handshake_state), cell.payload) < 0) { + if(onion_skin_create(circ->n_conn->onion_pkey, &(circ->cpath->handshake_state), cell.payload) < 0) { log_fn(LOG_INFO,"onion_skin_create (first hop) failed."); return -1; } @@ -791,7 +791,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) { cell.length = RELAY_HEADER_SIZE + 6 + DH_ONIONSKIN_LEN; *(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr); *(uint16_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port); - if(onion_skin_create(router->pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) { + if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) { log_fn(LOG_INFO,"onion_skin_create failed."); return -1; } diff --git a/src/or/config.c b/src/or/config.c index 4d0e51149e..31b7e0235b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -189,10 +189,8 @@ static void config_assign(or_options_t *options, struct config_line *list) { /* string options */ config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) || - config_compare(list, "PrivateKeyFile", CONFIG_TYPE_STRING, &options->PrivateKeyFile) || - config_compare(list, "SigningPrivateKeyFile", CONFIG_TYPE_STRING, &options->SigningPrivateKeyFile) || + config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) || config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) || - config_compare(list, "CertFile", CONFIG_TYPE_STRING, &options->CertFile) || config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) || /* int options */ @@ -238,6 +236,7 @@ int getconfig(int argc, char **argv, or_options_t *options) { memset(options,0,sizeof(or_options_t)); options->LogLevel = "debug"; options->loglevel = LOG_DEBUG; + options->DataDirectory = NULL; options->CoinWeight = 0.8; options->MaxConn = 900; options->DirFetchPeriod = 600; @@ -246,7 +245,6 @@ int getconfig(int argc, char **argv, or_options_t *options) { options->NewCircuitPeriod = 60; /* once a minute */ options->TotalBandwidth = 800000; /* at most 800kB/s total sustained incoming */ options->NumCpus = 1; - options->CertFile = "default.cert"; /* learn config file name, get config lines, assign them */ i = 1; @@ -316,8 +314,8 @@ int getconfig(int argc, char **argv, or_options_t *options) { result = -1; } - if(options->OnionRouter && options->PrivateKeyFile == NULL) { - log(LOG_ERR,"PrivateKeyFile option required for OnionRouter, but not found."); + if(options->OnionRouter && options->DataDirectory == NULL) { + log(LOG_ERR,"DataDirectory option required for OnionRouter, but not found."); result = -1; } @@ -326,11 +324,6 @@ int getconfig(int argc, char **argv, or_options_t *options) { result = -1; } - if(options->DirPort > 0 && options->SigningPrivateKeyFile == NULL) { - log(LOG_ERR,"SigningPrivateKeyFile option required for DirServer, but not found."); - result = -1; - } - if(options->APPort < 0) { log(LOG_ERR,"APPort option can't be negative."); result = -1; diff --git a/src/or/connection.c b/src/or/connection.c index 4b2d1c6f81..05d337c10a 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -80,8 +80,8 @@ connection_t *connection_new(int type) { memset(conn,0,sizeof(connection_t)); /* zero it out to start */ conn->type = type; - if(buf_new(&conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen) < 0 || - buf_new(&conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen) < 0) + if(!(conn->inbuf = buf_new()) || + !(conn->outbuf = buf_new())) return NULL; conn->receiver_bucket = 50000; /* should be enough to do the handshake */ @@ -108,8 +108,12 @@ void connection_free(connection_t *conn) { tor_tls_free(conn->tls); } - if (conn->pkey) - crypto_free_pk_env(conn->pkey); + if (conn->onion_pkey) + crypto_free_pk_env(conn->onion_pkey); + if (conn->link_pkey) + crypto_free_pk_env(conn->link_pkey); + if (conn->identity_pkey) + crypto_free_pk_env(conn->identity_pkey); if(conn->s > 0) { log_fn(LOG_INFO,"closing fd %d.",conn->s); @@ -287,14 +291,14 @@ static int connection_tls_finish_handshake(connection_t *conn) { log_fn(LOG_INFO,"Other side has a cert but it's bad. Closing."); return -1; } - router = router_get_by_pk(pk); + router = router_get_by_link_pk(pk); if (!router) { log_fn(LOG_INFO,"Unrecognized public key from peer. Closing."); crypto_free_pk_env(pk); return -1; } - if(conn->pkey) { /* I initiated this connection. */ - if(crypto_pk_cmp_keys(conn->pkey, pk)) { + if(conn->link_pkey) { /* I initiated this connection. */ + if(crypto_pk_cmp_keys(conn->link_pkey, pk)) { log_fn(LOG_INFO,"We connected to '%s' but he gave us a different key. Closing.", router->nickname); crypto_free_pk_env(pk); return -1; @@ -306,7 +310,7 @@ static int connection_tls_finish_handshake(connection_t *conn) { log_fn(LOG_INFO,"That router is already connected. Dropping."); return -1; } - conn->pkey = pk; + conn->link_pkey = pk; conn->bandwidth = router->bandwidth; conn->addr = router->addr, conn->port = router->or_port; if(conn->address) @@ -326,13 +330,13 @@ static int connection_tls_finish_handshake(connection_t *conn) { log_fn(LOG_INFO,"Other side has a cert but it's bad. Closing."); return -1; } - router = router_get_by_pk(pk); + router = router_get_by_link_pk(pk); if (!router) { log_fn(LOG_INFO,"Unrecognized public key from peer. Closing."); crypto_free_pk_env(pk); return -1; } - if(crypto_pk_cmp_keys(conn->pkey, pk)) { + if(crypto_pk_cmp_keys(conn->link_pkey, pk)) { log_fn(LOG_INFO,"We connected to '%s' but he gave us a different key. Closing.", router->nickname); crypto_free_pk_env(pk); return -1; @@ -494,8 +498,7 @@ int connection_read_to_buf(connection_t *conn) { return connection_tls_continue_handshake(conn); /* else open, or closing */ - result = read_to_buf_tls(conn->tls, at_most, &conn->inbuf, - &conn->inbuflen, &conn->inbuf_datalen); + result = read_to_buf_tls(conn->tls, at_most, conn->inbuf); switch(result) { case TOR_TLS_ERROR: @@ -510,8 +513,9 @@ int connection_read_to_buf(connection_t *conn) { return 0; } } else { - result = read_to_buf(conn->s, at_most, &conn->inbuf, &conn->inbuflen, - &conn->inbuf_datalen, &conn->inbuf_reached_eof); + result = read_to_buf(conn->s, at_most, conn->inbuf, + &conn->inbuf_reached_eof); + // log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result); if(result < 0) @@ -534,11 +538,11 @@ int connection_read_to_buf(connection_t *conn) { } int connection_fetch_from_buf(char *string, int len, connection_t *conn) { - return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen); + return fetch_from_buf(string, len, conn->inbuf); } int connection_find_on_inbuf(char *string, int len, connection_t *conn) { - return find_on_inbuf(string, len, conn->inbuf, conn->inbuf_datalen); + return find_on_inbuf(string, len, conn->inbuf); } int connection_wants_to_flush(connection_t *conn) { @@ -550,8 +554,7 @@ int connection_outbuf_too_full(connection_t *conn) { } int connection_flush_buf(connection_t *conn) { - return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, - &conn->outbuf_flushlen, &conn->outbuf_datalen); + return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen); } /* return -1 if you want to break the conn, else return 0 */ @@ -573,8 +576,7 @@ int connection_handle_write(connection_t *conn) { } /* else open, or closing */ - switch(flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen, - &conn->outbuf_flushlen, &conn->outbuf_datalen)) { + switch(flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen)) { case TOR_TLS_ERROR: case TOR_TLS_CLOSE: log_fn(LOG_DEBUG,"tls error. breaking."); @@ -601,8 +603,7 @@ int connection_handle_write(connection_t *conn) { */ } } else { - if(flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, - &conn->outbuf_flushlen, &conn->outbuf_datalen) < 0) + if(flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen) < 0) return -1; /* conns in CONNECTING state will fall through... */ } @@ -631,7 +632,7 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) { conn->outbuf_flushlen += len; } - return write_to_buf(string, len, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen); + return write_to_buf(string, len, conn->outbuf); } int connection_receiver_bucket_should_increase(connection_t *conn) { @@ -741,29 +742,25 @@ void assert_connection_ok(connection_t *conn, time_t now) /* buffers */ assert(conn->inbuf); - assert(conn->inbuflen >= conn->inbuf_datalen); - assert(conn->inbuflen >= 0); - assert(conn->inbuf_datalen >= 0); assert(conn->outbuf); - assert(conn->outbuflen >= conn->outbuf_datalen); - assert(conn->outbuflen >= 0); - assert(conn->outbuf_datalen >= 0); assert(!now || conn->timestamp_lastread <= now); assert(!now || conn->timestamp_lastwritten <= now); assert(conn->timestamp_created <= conn->timestamp_lastread); assert(conn->timestamp_created <= conn->timestamp_lastwritten); + /* XXX Fix this; no longer so.*/ +#if 0 if(conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_DIR) assert(!conn->pkey); /* pkey is set if we're a dir client, or if we're an OR in state OPEN * connected to another OR. */ +#endif if (conn->type != CONN_TYPE_OR) { assert(conn->bandwidth == -1); assert(conn->receiver_bucket == -1); - /* Addr, port, address XXX */ assert(!conn->tls); } else { assert(conn->bandwidth); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index adec953ca8..cf658ff5b4 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -336,7 +336,7 @@ repeat_connection_package_raw_inbuf: return 0; } - amount_to_process = conn->inbuf_datalen; + amount_to_process = buf_datalen(conn->inbuf); if(!amount_to_process) return 0; @@ -352,7 +352,8 @@ repeat_connection_package_raw_inbuf: connection_fetch_from_buf(cell.payload+RELAY_HEADER_SIZE, cell.length, conn); - log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length, conn->inbuf_datalen); + log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length, + (int)buf_datalen(conn->inbuf)); cell.command = CELL_RELAY; SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_DATA); @@ -440,7 +441,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { log_fn(LOG_DEBUG,"entered."); - switch(fetch_from_buf_socks(conn->inbuf,&conn->inbuf_datalen, + switch(fetch_from_buf_socks(conn->inbuf, destaddr, sizeof(destaddr), &destport)) { case -1: log_fn(LOG_DEBUG,"Fetching socks handshake failed. Closing."); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 026de91de0..6859cff6e1 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -99,7 +99,8 @@ connection_t *connection_or_connect(routerinfo_t *router) { conn->addr = router->addr; conn->port = router->or_port; conn->bandwidth = router->bandwidth; - conn->pkey = crypto_pk_dup_key(router->pkey); + conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey); + conn->link_pkey = crypto_pk_dup_key(router->link_pkey); conn->address = strdup(router->address); if(connection_add(conn) < 0) { /* no space, forget it */ @@ -148,9 +149,9 @@ int connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn) { int connection_process_cell_from_inbuf(connection_t *conn) { char buf[CELL_NETWORK_SIZE]; cell_t cell; - - log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d.",conn->s,conn->inbuf_datalen); - if(conn->inbuf_datalen < CELL_NETWORK_SIZE) /* entire response available? */ + + log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d.",conn->s,buf_datalen(conn->inbuf)); + if(buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* entire response available? */ return 0; /* not yet */ connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn); diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 6cf21e861b..d3d945e7e6 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -73,9 +73,9 @@ int connection_cpu_process_inbuf(connection_t *conn) { } if(conn->state == CPUWORKER_STATE_BUSY_ONION) { - if(conn->inbuf_datalen < LEN_ONION_RESPONSE) /* entire answer available? */ + if(buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* entire answer available? */ return 0; /* not yet */ - assert(conn->inbuf_datalen == LEN_ONION_RESPONSE); + assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE); connection_fetch_from_buf(buf,LEN_ONION_RESPONSE,conn); @@ -147,7 +147,7 @@ int cpuworker_main(void *data) { } if(question_type == CPUWORKER_TASK_ONION) { - if(onion_skin_server_handshake(question, get_privatekey(), + if(onion_skin_server_handshake(question, get_onion_key(), reply_to_proxy, keys, 32) < 0) { /* failure */ log_fn(LOG_ERR,"onion_skin_server_handshake failed."); diff --git a/src/or/directory.c b/src/or/directory.c index b55a419409..d1e0713b5b 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -53,11 +53,11 @@ void directory_initiate_command(routerinfo_t *router, int command) { conn->address = strdup(router->address); conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */ conn->bandwidth = -1; - if (router->signing_pkey) - conn->pkey = crypto_pk_dup_key(router->signing_pkey); + if (router->identity_pkey) + conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); else { log_fn(LOG_ERR, "No signing key known for dirserver %s; signature won't be checked", conn->address); - conn->pkey = NULL; + conn->identity_pkey = NULL; } if(connection_add(conn) < 0) { /* no space, forget it */ @@ -124,7 +124,7 @@ void directory_set_dirty(void) { static void directory_rebuild(void) { if(directory_dirty) { if (dump_signed_directory_to_string(the_directory, MAX_DIR_SIZE, - get_signing_privatekey())) { + get_identity_key())) { log(LOG_ERR, "Error writing directory"); return; } @@ -144,7 +144,7 @@ int connection_dir_process_inbuf(connection_t *conn) { switch(conn->state) { case DIR_CONN_STATE_CLIENT_READING_FETCH: /* kill it, but first process the_directory and learn about new routers. */ - switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen, + switch(fetch_from_buf_http(conn->inbuf, NULL, 0, the_directory, MAX_DIR_SIZE)) { case -1: /* overflow */ log_fn(LOG_DEBUG,"'fetch' response too large. Failing."); @@ -161,11 +161,11 @@ int connection_dir_process_inbuf(connection_t *conn) { log_fn(LOG_DEBUG,"Empty directory. Ignoring."); return -1; } - if(router_get_dir_from_string(the_directory, conn->pkey) < 0) { + if(router_get_dir_from_string(the_directory, conn->identity_pkey) < 0){ log_fn(LOG_DEBUG,"...but parsing failed. Ignoring."); } else { log_fn(LOG_DEBUG,"and got an %s directory; updated routers.", - conn->pkey ? "authenticated" : "unauthenticated"); + conn->identity_pkey ? "authenticated" : "unauthenticated"); } if(options.OnionRouter) { /* connect to them all */ router_retry_connections(); @@ -196,7 +196,7 @@ static int directory_handle_command(connection_t *conn) { assert(conn && conn->type == CONN_TYPE_DIR); - switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen, + switch(fetch_from_buf_http(conn->inbuf, headers, sizeof(headers), body, sizeof(body))) { case -1: /* overflow */ log_fn(LOG_DEBUG,"input too large. Failing."); diff --git a/src/or/dns.c b/src/or/dns.c index eb1673ee2b..472094a63b 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -309,9 +309,9 @@ int connection_dns_process_inbuf(connection_t *conn) { } assert(conn->state == DNSWORKER_STATE_BUSY); - if(conn->inbuf_datalen < 4) /* entire answer available? */ + if(buf_datalen(conn->inbuf) < 4) /* entire answer available? */ return 0; /* not yet */ - assert(conn->inbuf_datalen == 4); + assert(buf_datalen(conn->inbuf) == 4); connection_fetch_from_buf((char*)&answer,sizeof(answer),conn); diff --git a/src/or/main.c b/src/or/main.c index 20a8187a6f..5676ad95a1 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -7,6 +7,7 @@ /********* START PROTOTYPES **********/ static void dumpstats(void); /* dump stats to stdout */ +static int init_descriptor(void); /********* START VARIABLES **********/ @@ -29,30 +30,42 @@ static int please_reset =0; /* whether we just got a sighup */ static int please_reap_children=0; /* whether we should waitpid for exited children*/ #endif /* signal stuff */ -/* private key */ -static crypto_pk_env_t *privatekey=NULL; -static crypto_pk_env_t *signing_privatekey=NULL; +/* private keys */ +static crypto_pk_env_t *onionkey=NULL; +static crypto_pk_env_t *linkkey=NULL; +static crypto_pk_env_t *identitykey=NULL; routerinfo_t *my_routerinfo=NULL; /********* END VARIABLES ************/ -void set_privatekey(crypto_pk_env_t *k) { - privatekey = k; +void set_onion_key(crypto_pk_env_t *k) { + onionkey = k; } -crypto_pk_env_t *get_privatekey(void) { - assert(privatekey); - return privatekey; +crypto_pk_env_t *get_onion_key(void) { + assert(onionkey); + return onionkey; } -void set_signing_privatekey(crypto_pk_env_t *k) { - signing_privatekey = k; +void set_link_key(crypto_pk_env_t *k) +{ + linkkey = k; +} + +crypto_pk_env_t *get_link_key(void) +{ + assert(linkkey); + return linkkey; } -crypto_pk_env_t *get_signing_privatekey(void) { - assert(signing_privatekey); - return signing_privatekey; +void set_identity_key(crypto_pk_env_t *k) { + identitykey = k; +} + +crypto_pk_env_t *get_identity_key(void) { + assert(identitykey); + return identitykey; } /**************************************************************************** @@ -69,7 +82,7 @@ int connection_add(connection_t *conn) { log(LOG_INFO,"connection_add(): failing because nfds is too high."); return -1; } - + conn->poll_index = nfds; connection_set_poll_socket(conn); connection_array[nfds] = conn; @@ -146,7 +159,7 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) { assert(conn); if(connection_state_is_open(conn) && !conn->marked_for_close && - !crypto_pk_cmp_keys(conn->pkey, router->pkey)) { + !crypto_pk_cmp_keys(conn->onion_pkey, router->onion_pkey)) { log(LOG_INFO,"connection_twin_get_by_addr_port(): Found twin (%s).",conn->address); return conn; } @@ -308,13 +321,11 @@ static void check_conn_marked(int i) { if(conn->s >= 0) { /* might be an incomplete edge connection */ /* FIXME there's got to be a better way to check for this -- and make other checks? */ if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING) - flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen, - &conn->outbuf_flushlen, &conn->outbuf_datalen); + flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen); else - flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, - &conn->outbuf_flushlen, &conn->outbuf_datalen); + flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen); if(connection_wants_to_flush(conn)) /* not done flushing */ - log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, conn->inbuf_datalen); + log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, (int)buf_datalen(conn->inbuf)); } connection_remove(conn); connection_free(conn); @@ -420,68 +431,218 @@ static int prepare_for_poll(void) { return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */ } -static int do_main_loop(void) { - int i; - int timeout; - int poll_result; - crypto_pk_env_t *prkey; +#define FN_ERROR -1 +#define FN_NOENT 0 +#define FN_FILE 1 +#define FN_DIR 2 +static int fn_exists(const char *fname) +{ + struct stat st; + if (stat(fname, &st)) { + if (errno == ENOENT) { + return FN_NOENT; + } + return FN_ERROR; + } + if (st.st_mode & S_IFDIR) + return FN_DIR; + else + return FN_FILE; +} - /* load the routers file */ - if(router_get_list_from_file(options.RouterFile) < 0) { - log(LOG_ERR,"Error loading router list."); - return -1; +static crypto_pk_env_t *init_key_from_file(const char *fname) +{ + crypto_pk_env_t *prkey = NULL; + int fd = -1; + FILE *file = NULL; + + if (!(prkey = crypto_new_pk_env(CRYPTO_PK_RSA))) { + log(LOG_ERR, "Error creating crypto environment."); + goto error; } - /* load the private key, if we're supposed to have one */ - if(options.OnionRouter) { - prkey = crypto_new_pk_env(CRYPTO_PK_RSA); - if (!prkey) { - log(LOG_ERR,"Error creating a crypto environment."); - return -1; + switch(fn_exists(fname)) { + case FN_DIR: + case FN_ERROR: + log(LOG_ERR, "Can't read key from %s", fname); + goto error; + case FN_NOENT: + log(LOG_INFO, "No key found in %s; generating fresh key.", fname); + if (crypto_pk_generate_key(prkey)) { + log(LOG_ERR, "Error generating key: %s", crypto_perror()); + goto error; } - if (crypto_pk_read_private_key_from_filename(prkey, options.PrivateKeyFile)) { - log(LOG_ERR,"Error loading private key."); - return -1; + if (crypto_pk_check_key(prkey) <= 0) { + log(LOG_ERR, "Generated key seems invalid"); + goto error; } - set_privatekey(prkey); - cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the private key. */ - } - - /* load the directory private key, if we're supposed to have one */ - if(options.DirPort) { - prkey = crypto_new_pk_env(CRYPTO_PK_RSA); - if (!prkey) { - log(LOG_ERR,"Error creating a crypto environment."); - return -1; + log(LOG_INFO, "Generated key seems valid"); + fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0400); + if (fd == -1) { + log(LOG_ERR, "Can't open %s for writing", fname); + goto error; } - if (crypto_pk_read_private_key_from_filename(prkey, options.SigningPrivateKeyFile)) { - log(LOG_ERR,"Error loading private key."); - return -1; + file = fdopen(fd, "w"); + if (!file) { + log(LOG_ERR, "Can't fdopen %s for writing", fname); + goto error; + } + if (crypto_pk_write_private_key_to_file(prkey, file) < 0) { + log(LOG_ERR, "Can't write private key to %s", fname); + goto error; + } + fclose(file); + /* XXX fingerprint */ + return prkey; + case FN_FILE: + if (crypto_pk_read_private_key_from_filename(prkey, fname)) { + log(LOG_ERR, "Error loading private key."); + goto error; } - set_signing_privatekey(prkey); + return prkey; + default: + assert(0); } - if(options.OnionRouter) { - struct stat statbuf; - if(stat(options.CertFile, &statbuf) < 0) { - log_fn(LOG_INFO,"CertFile %s is missing. Generating.", options.CertFile); - if(tor_tls_write_certificate(options.CertFile, - get_privatekey(), - options.Nickname) < 0) { - log_fn(LOG_ERR,"Couldn't write CertFile %s. Dying.", options.CertFile); - return -1; - } - } + error: + if (prkey) + crypto_free_pk_env(prkey); + if (fd >= 0 && !file) + close(fd); + if (file) + fclose(file); + return NULL; +} - if(tor_tls_context_new(options.CertFile, get_privatekey(), 1) < 0) { - log_fn(LOG_ERR,"Error creating tls context."); +static int init_keys(void) +{ + char keydir[512]; + char fingerprint[FINGERPRINT_LEN+1]; + char *cp; + crypto_pk_env_t *prkey; + FILE *file; + + /* OP's don't need keys. Just initialize the TLS context.*/ + if (!options.OnionRouter && !options.DirPort) { + if (tor_tls_context_new(NULL, 0, NULL)<0) { + log_fn(LOG_ERR, "Error creating TLS context for OP."); return -1; } - } else { /* just a proxy, the context is easy */ - if(tor_tls_context_new(NULL, NULL, 0) < 0) { - log_fn(LOG_ERR,"Error creating tls context."); + return 0; + } + assert(options.DataDirectory); + if (strlen(options.DataDirectory) > (512-128)) { + log_fn(LOG_ERR, "DataDirectory is too long."); + return -1; + } + strcpy(keydir, options.DataDirectory); + switch (fn_exists(keydir)) { + case FN_NOENT: + log_fn(LOG_ERR, "DataDirectory does not exist"); + return -1; + case FN_ERROR: + log_fn(LOG_ERR, "DataDirectory can't be read"); + return -1; + case FN_FILE: + log_fn(LOG_ERR, "DataDirectory is not a directory."); + return -1; + } + strcat(keydir, "/keys"); + switch (fn_exists(keydir)) { + case FN_NOENT: + if (mkdir(keydir, 0700)) { + log_fn(LOG_ERR, "Error making key directory."); return -1; } + break; + case FN_ERROR: + log_fn(LOG_ERR, "Error reading key directory."); + return -1; + case FN_FILE: + log_fn(LOG_ERR, "Key directory is not a directory."); + return -1; + case FN_DIR: + chmod(keydir, 0700); + break; + } + cp = keydir + strlen(keydir); /* End of string. */ + assert(!*cp); + + /* 1. Read identity key. Make it if none is found. */ + strcat(keydir, "/identity.key"); + prkey = init_key_from_file(keydir); + if (!prkey) return -1; + set_identity_key(prkey); + /* 2. Read onion key. Make it if none is found. */ + *cp = '\0'; + strcat(keydir, "/onion.key"); + prkey = init_key_from_file(keydir); + if (!prkey) return -1; + set_onion_key(prkey); + + /* 3. Initialize link key and TLS context. */ + *cp = '\0'; + strcat(keydir, "/link.key"); + prkey = init_key_from_file(keydir); + if (!prkey) return -1; + set_link_key(prkey); + if (tor_tls_context_new(prkey, 1, options.Nickname) < 0) { + log_fn(LOG_ERR, "Error initializing TLS context"); + return -1; + } + /* 4. Dump router descriptor to 'router.desc' */ + /* Must be called after keys are initialized. */ + if (init_descriptor()<0) { + log_fn(LOG_ERR, "Error initializing descriptor."); + return -1; + } + strcpy(keydir, options.DataDirectory); + strcat(keydir, "/router.desc"); + file = fopen(keydir, "w"); + if (!file) { + log_fn(LOG_ERR, "Error opening %s for writing", keydir); + return -1; + } + fputs(router_get_my_descriptor(), file); + fclose(file); + /* 5. Dump fingerprint to 'fingerprint' */ + strcpy(keydir, options.DataDirectory); + strcat(keydir, "/fingerprint"); + file = fopen(keydir, "w"); + if (!file) { + log_fn(LOG_ERR, "Error opening %s for writing", keydir); + return -1; + } + if (crypto_pk_get_fingerprint(get_identity_key(), fingerprint)<0) { + log_fn(LOG_ERR, "Error computing fingerprint"); + return -1; + } + fprintf(file, "%s %s\n", options.Nickname, fingerprint); + fclose(file); + + return 0; +} + +static int do_main_loop(void) { + int i; + int timeout; + int poll_result; + + /* load the routers file */ + if(router_get_list_from_file(options.RouterFile) < 0) { + log_fn(LOG_ERR,"Error loading router list."); + return -1; + } + + /* load the private keys, if we're supposed to have them, and set up the + * TLS context. */ + if (init_keys() < 0) { + log_fn(LOG_ERR,"Error initializing keys; exiting"); + return -1; + } + + if(options.OnionRouter) { + cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the private key. */ } /* start up the necessary connections based on which ports are @@ -590,9 +751,10 @@ static void dumpstats(void) { /* dump stats to stdout */ conn->state, conn_state_to_string[conn->type][conn->state], now.tv_sec - conn->timestamp_created); if(!connection_is_listener(conn)) { printf("Conn %d is to '%s:%d'.\n",i,conn->address, conn->port); - printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,conn->inbuf_datalen, - now.tv_sec - conn->timestamp_lastread); - printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,conn->outbuf_datalen, + printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i, + (int)buf_datalen(conn->inbuf), + now.tv_sec - conn->timestamp_lastread); + printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,(int)buf_datalen(conn->outbuf), now.tv_sec - conn->timestamp_lastwritten); } circuit_dump_by_conn(conn); /* dump info about all the circuits using this conn */ @@ -601,42 +763,50 @@ static void dumpstats(void) { /* dump stats to stdout */ } -int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) { - char *pkey; - char *signing_pkey, *signing_pkey_tag; - int pkeylen, signing_pkeylen; +int dump_router_to_string(char *s, int maxlen, routerinfo_t *router, + crypto_pk_env_t *ident_key) { + char *onion_pkey; + char *link_pkey; + char *identity_pkey; + char digest[20]; + char signature[128]; + int onion_pkeylen, link_pkeylen, identity_pkeylen; int written; int result=0; struct exit_policy_t *tmpe; - if(crypto_pk_write_public_key_to_string(router->pkey,&pkey,&pkeylen)<0) { - log(LOG_ERR,"dump_router_to_string(): write pkey to string failed!"); - return 0; + if(crypto_pk_write_public_key_to_string(router->onion_pkey, + &onion_pkey,&onion_pkeylen)<0) { + log_fn(LOG_ERR,"write onion_pkey to string failed!"); + return -1; } - signing_pkey = ""; - signing_pkey_tag = ""; - if (router->signing_pkey) { - if(crypto_pk_write_public_key_to_string(router->signing_pkey, - &signing_pkey,&signing_pkeylen)<0) { - log(LOG_ERR,"dump_router_to_string(): write signing_pkey to string failed!"); - return 0; - } - signing_pkey_tag = "signing-key\n"; + if(crypto_pk_write_public_key_to_string(router->identity_pkey, + &identity_pkey,&identity_pkeylen)<0) { + log_fn(LOG_ERR,"write identity_pkey to string failed!"); + return -1; + } + + if(crypto_pk_write_public_key_to_string(router->link_pkey, + &link_pkey,&link_pkeylen)<0) { + log_fn(LOG_ERR,"write link_pkey to string failed!"); + return -1; } - result = snprintf(s, maxlen, "router %s %d %d %d %d\n%s%s%s", + result = snprintf(s, maxlen, + "router %s %d %d %d %d\nonion-key\n%s" + "link-key\n%s" + "signing-key\n%s", router->address, router->or_port, router->ap_port, router->dir_port, router->bandwidth, - pkey, - signing_pkey_tag, signing_pkey); + onion_pkey, link_pkey, identity_pkey); - free(pkey); - if (*signing_pkey) - free(signing_pkey); + free(onion_pkey); + free(link_pkey); + free(identity_pkey); if(result < 0 || result > maxlen) { /* apparently different glibcs do different things on snprintf error.. so check both */ @@ -654,19 +824,34 @@ int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) { } written += result; } + if (written > maxlen-256) /* Not enough room for signature. */ + return -1; - if(written > maxlen-2) { - return -1; /* not enough space for \n\0 */ - } - /* XXX count fenceposts here. They're probably wrong. In general, - * we need a better way to handle overruns in building the directory - * string, and a better way to handle directory string size in general. */ + strcat(s+written, "router-signature\n"); + written += strlen(s+written); + s[written] = '\0'; + if (router_get_router_hash(s, digest) < 0) + return -1; + if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) { + log_fn(LOG_ERR, "Error signing digest"); + return -1; + } + strcat(s+written, "-----BEGIN SIGNATURE-----\n"); + written += strlen(s+written); + if (base64_encode(s+written, maxlen-written, signature, 128) < 0) { + log_fn(LOG_ERR, "Couldn't base64-encode signature"); + } + written += strlen(s+written); + strcat(s+written, "-----END SIGNATURE-----\n"); + written += strlen(s+written); + + if (written > maxlen-2) + return -1; /* include a last '\n' */ s[written] = '\n'; s[written+1] = 0; return written+1; - } static int @@ -738,7 +923,10 @@ dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, cp = s+i; for (i = 0; i < dir->n_routers; ++i) { router = dir->routers[i]; - written = dump_router_to_string(cp, eos-cp, router); + /* XXX This is wrong; we shouldn't sign routers, but rather propagate + * XXX the original router blocks, unaltered. + */ + written = dump_router_to_string(cp, eos-cp, router, private_key); if(written < 0) { log(LOG_ERR,"dump_signed_directory_to_string(): tried to exceed string length."); @@ -789,8 +977,35 @@ dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, return 0; } -char *router_get_my_descriptor(void) { - return "this is bob's descriptor"; +static char descriptor[8192]; +/* XXX should this replace my_routerinfo? */ +static routerinfo_t *desc_routerinfo; +const char *router_get_my_descriptor(void) { + return descriptor; +} + +static int init_descriptor(void) { + routerinfo_t *ri; + ri = tor_malloc(sizeof(routerinfo_t)); + ri->address = strdup("XXXXXXX"); /*XXX*/ + ri->nickname = strdup(options.Nickname); + /* No need to set addr. ???? */ + ri->or_port = options.ORPort; + ri->ap_port = options.APPort; + ri->dir_port = options.DirPort; + ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); + ri->link_pkey = crypto_pk_dup_key(get_link_key()); + ri->identity_pkey = crypto_pk_dup_key(get_identity_key()); + ri->bandwidth = options.TotalBandwidth; + ri->exit_policy = NULL; /* XXX implement this. */ + if (desc_routerinfo) + routerinfo_free(desc_routerinfo); + desc_routerinfo = ri; + if (dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) { + log_fn(LOG_ERR, "Couldn't dump router to string."); + return -1; + } + return 0; } void daemonize(void) { @@ -840,7 +1055,7 @@ int tor_main(int argc, char *argv[]) { crypto_seed_rng(); retval = do_main_loop(); crypto_global_cleanup(); - + return retval; } diff --git a/src/or/onion.c b/src/or/onion.c index 1c6f605a89..d884b983af 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -231,7 +231,7 @@ static unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, choice = choice % rarray_len; log(LOG_DEBUG,"new_route(): Contemplating router %u.",choice); if(choice == oldchoice || - (oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->pkey, rarray[oldchoice]->pkey)) || + (oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->onion_pkey, rarray[oldchoice]->onion_pkey)) || (options.OnionRouter && !connection_twin_get_by_addr_port(rarray[choice]->addr, rarray[choice]->or_port))) { /* Same router as last choice, or router twin, * or no routers with that key are connected to us. @@ -263,7 +263,7 @@ static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) { } } for(j=0;j<i;j++) { - if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) { + if(!crypto_pk_cmp_keys(rarray[i]->onion_pkey, rarray[j]->onion_pkey)) { /* these guys are twins. so we've already counted him. */ log(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j); goto next_i_loop; @@ -311,8 +311,8 @@ crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop) { log(LOG_DEBUG,"onion_generate_cpath(): %u : %s:%u, %u/%u",routelen-i, inet_ntoa(netaddr), (rarray[route[i]])->or_port, - (int) (rarray[route[i]])->pkey, - crypto_pk_keysize((rarray[route[i]])->pkey)); + (int) (rarray[route[i]])->onion_pkey, + crypto_pk_keysize((rarray[route[i]])->onion_pkey)); } /* create the cpath layer by layer, starting at the last hop */ diff --git a/src/or/or.h b/src/or/or.h index 48820ae422..47cc1a5c3e 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -245,6 +245,8 @@ typedef struct { #define ZERO_STREAM "\0\0\0\0\0\0\0\0" +typedef struct buf_t buf_t; + struct connection_t { uint8_t type; @@ -261,16 +263,12 @@ struct connection_t { * iteration of the main loop? */ - char *inbuf; - int inbuflen; /* how many bytes are alloc'ed for inbuf? */ - int inbuf_datalen; /* how many bytes of data are on inbuf? */ + buf_t *inbuf; int inbuf_reached_eof; /* did read() return 0 on this conn? */ long timestamp_lastread; /* when was the last time poll() said we could read? */ - char *outbuf; - int outbuflen; /* how many bytes are allocated for the outbuf? */ + buf_t *outbuf; int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */ - int outbuf_datalen; /* how much data is there total on the outbuf? */ long timestamp_lastwritten; /* when was the last time poll() said we could write? */ long timestamp_created; /* when was this connection_t created? */ @@ -287,7 +285,9 @@ struct connection_t { char *address; /* FQDN (or IP) of the guy on the other end. * strdup into this, because free_connection frees it */ - crypto_pk_env_t *pkey; /* public RSA key for the other side */ + crypto_pk_env_t *onion_pkey; /* public RSA key for the other side's onions */ + crypto_pk_env_t *link_pkey; /* public RSA key for the other side's TLS */ + crypto_pk_env_t *identity_pkey; /* public RSA key for the other side's signing */ /* Used only by OR connections: */ tor_tls *tls; @@ -331,8 +331,9 @@ typedef struct { uint16_t ap_port; uint16_t dir_port; - crypto_pk_env_t *pkey; /* public RSA key */ - crypto_pk_env_t *signing_pkey; /* May be null */ + crypto_pk_env_t *onion_pkey; /* public RSA key for onions */ + crypto_pk_env_t *link_pkey; /* public RSA key for TLS */ + crypto_pk_env_t *identity_pkey; /* public RSA key for signing */ /* link info */ uint32_t bandwidth; @@ -405,10 +406,8 @@ typedef struct circuit_t circuit_t; typedef struct { char *LogLevel; + char *DataDirectory; char *RouterFile; - char *SigningPrivateKeyFile; - char *PrivateKeyFile; - char *CertFile; char *Nickname; double CoinWeight; int Daemon; @@ -435,24 +434,29 @@ typedef struct { /********************************* buffers.c ***************************/ -int buf_new(char **buf, int *buflen, int *buf_datalen); -void buf_free(char *buf); +buf_t *buf_new(); +buf_t *buf_new_with_capacity(size_t size); +void buf_free(buf_t *buf); + +size_t buf_datalen(const buf_t *buf); +size_t buf_capacity(const buf_t *buf); +const char *_buf_peek_raw_buffer(const buf_t *buf); -int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof); -int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen); +int read_to_buf(int s, int at_most, buf_t *buf, int *reached_eof); +int read_to_buf_tls(tor_tls *tls, int at_most, buf_t *buf); -int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen); -int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen); +int flush_buf(int s, buf_t *buf, int *buf_flushlen); +int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen); -int write_to_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen); -int fetch_from_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen); -int fetch_from_buf_http(char *buf, int *buf_datalen, +int write_to_buf(char *string, int string_len, buf_t *buf); +int fetch_from_buf(char *string, int string_len, buf_t *buf); +int fetch_from_buf_http(buf_t *buf, char *headers_out, int max_headerlen, char *body_out, int max_bodylen); -int fetch_from_buf_socks(char *buf, int *buf_datalen, +int fetch_from_buf_socks(buf_t *buf, char *addr_out, int max_addrlen, uint16_t *port_out); -int find_on_inbuf(char *string, int string_len, char *buf, int buf_datalen); +int find_on_inbuf(char *string, int string_len, buf_t *buf); /********************************* circuit.c ***************************/ @@ -589,10 +593,10 @@ int dns_resolve(connection_t *exitconn); /********************************* main.c ***************************/ -void set_privatekey(crypto_pk_env_t *k); -crypto_pk_env_t *get_privatekey(void); -void set_signing_privatekey(crypto_pk_env_t *k); -crypto_pk_env_t *get_signing_privatekey(void); +void set_onion_key(crypto_pk_env_t *k); +crypto_pk_env_t *get_onion_key(void); +void set_identity_key(crypto_pk_env_t *k); +crypto_pk_env_t *get_identity_key(void); int connection_add(connection_t *conn); int connection_remove(connection_t *conn); void connection_set_poll_socket(connection_t *conn); @@ -617,7 +621,7 @@ int dump_signed_directory_to_string(char *s, int maxlen, int dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, crypto_pk_env_t *private_key); -char *router_get_my_descriptor(void); +const char *router_get_my_descriptor(void); int main(int argc, char *argv[]); @@ -655,16 +659,20 @@ int learn_my_address(struct sockaddr_in *me); void router_retry_connections(void); routerinfo_t *router_pick_directory_server(void); routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); -routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk); +routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk); +#if 0 +routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk); +#endif 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_get_router_hash(char *s, char *digest); /* Reads a list of known routers, unsigned. */ int router_get_list_from_string(char *s); /* Exported for debugging */ -int router_get_list_from_string_impl(char *s, directory_t **dest); +int router_get_list_from_string_impl(char **s, directory_t **dest); /* Reads a signed directory. */ int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey); /* Exported or debugging */ diff --git a/src/or/routers.c b/src/or/routers.c index 6341d335f1..24baa5a340 100644 --- a/src/or/routers.c +++ b/src/or/routers.c @@ -28,10 +28,6 @@ static char *eat_whitespace(char *s); static char *eat_whitespace_no_nl(char *s); static char *find_whitespace(char *s); 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); static int @@ -119,7 +115,7 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) { return NULL; } -routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk) +routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk) { int i; routerinfo_t *router; @@ -128,14 +124,32 @@ routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk) for(i=0;i<directory->n_routers;i++) { router = directory->routers[i]; - /* XXX Should this really be a separate link key? */ - if (0 == crypto_pk_cmp_keys(router->pkey, pk)) + if (0 == crypto_pk_cmp_keys(router->link_pkey, pk)) return router; } return NULL; } + +#if 0 +routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk) +{ + int i; + routerinfo_t *router; + + assert(directory); + + for(i=0;i<directory->n_routers;i++) { + router = directory->routers[i]; + /* XXX Should this really be a separate link key? */ + if (0 == crypto_pk_cmp_keys(router->identity_pkey, pk)) + return router; + } + return NULL; +} +#endif + void router_get_directory(directory_t **pdirectory) { *pdirectory = directory; @@ -174,10 +188,12 @@ void routerinfo_free(routerinfo_t *router) if (router->address) free(router->address); - if (router->pkey) - crypto_free_pk_env(router->pkey); - if (router->signing_pkey) - crypto_free_pk_env(router->signing_pkey); + if (router->onion_pkey) + crypto_free_pk_env(router->onion_pkey); + if (router->link_pkey) + crypto_free_pk_env(router->link_pkey); + if (router->identity_pkey) + crypto_free_pk_env(router->identity_pkey); e = router->exit_policy; while (e) { etmp = e->next; @@ -195,7 +211,8 @@ void directory_free(directory_t *directory) int i; for (i = 0; i < directory->n_routers; ++i) routerinfo_free(directory->routers[i]); - free(directory->routers); + if (directory->routers) + free(directory->routers); if(directory->software_versions) free(directory->software_versions); free(directory); @@ -282,6 +299,9 @@ typedef enum { K_ROUTER, K_SIGNED_DIRECTORY, K_SIGNING_KEY, + K_ONION_KEY, + K_LINK_KEY, + K_ROUTER_SIGNATURE, _SIGNATURE, _PUBLIC_KEY, _ERR, @@ -298,6 +318,9 @@ static struct token_table_ent token_table[] = { { "recommended-software", K_RECOMMENDED_SOFTWARE }, { "signed-directory", K_SIGNED_DIRECTORY }, { "signing-key", K_SIGNING_KEY }, + { "onion-key", K_ONION_KEY }, + { "link-key", K_LINK_KEY }, + { "router-signature", K_ROUTER_SIGNATURE }, { NULL, -1 } }; @@ -450,6 +473,9 @@ router_dump_token(directory_token_t *tok) { case K_ROUTER: printf("Router"); break; case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break; case K_SIGNING_KEY: printf("Signing-Key"); break; + case K_ONION_KEY: printf("Onion-key"); break; + case K_LINK_KEY: printf("Link-key"); break; + case K_ROUTER_SIGNATURE: printf("Router-signature"); break; default: printf("?????? %d\n", tok->tp); return; } @@ -459,7 +485,6 @@ router_dump_token(directory_token_t *tok) { printf("\n"); return; } - static int router_get_next_token(char **s, directory_token_t *tok) { int i; @@ -508,7 +533,7 @@ static char *find_whitespace(char *s) { int router_get_list_from_string(char *s) { - if (router_get_list_from_string_impl(s, &directory)) { + if (router_get_list_from_string_impl(&s, &directory)) { log(LOG_ERR, "Error parsing router file"); return -1; } @@ -519,43 +544,46 @@ int router_get_list_from_string(char *s) return 0; } -int router_get_list_from_string_impl(char *s, directory_t **dest) { - directory_token_t tok; - if (router_get_next_token(&s, &tok)) { - log(LOG_ERR, "Error reading routers: %s", tok.val.error); - return -1; - } - return router_get_list_from_string_tok(&s, dest, &tok); -} - -static int router_get_dir_hash(char *s, char *digest) +static int router_get_hash_impl(char *s, char *digest, const char *start_str, + const char *end_str) { char *start, *end; - start = strstr(s, "signed-directory"); + start = strstr(s, start_str); if (!start) { - log(LOG_ERR,"router_get_dir_hash(): couldn't find \"signed-directory\""); + log_fn(LOG_ERR,"couldn't find \"%s\"",start_str); return -1; } - end = strstr(start, "directory-signature"); + end = strstr(start+strlen(start_str), end_str); if (!end) { - log(LOG_ERR,"router_get_dir_hash(): couldn't find \"directory-signature\""); + log_fn(LOG_ERR,"couldn't find \"%s\"",end_str); return -1; } end = strchr(end, '\n'); if (!end) { - log(LOG_ERR,"router_get_dir_hash(): couldn't find EOL"); + log_fn(LOG_ERR,"couldn't find EOL"); return -1; } ++end; if (crypto_SHA_digest(start, end-start, digest)) { - log(LOG_ERR,"router_get_dir_hash(): couldn't compute digest"); + log_fn(LOG_ERR,"couldn't compute digest"); return -1; } return 0; } +static int router_get_dir_hash(char *s, char *digest) +{ + return router_get_hash_impl(s,digest, + "signed-directory","directory-signature"); +} +int router_get_router_hash(char *s, char *digest) +{ + return router_get_hash_impl(s,digest, + "router ","router-signature"); +} + /* return 0 if myversion is in start. Else return -1. */ int compare_recommended_versions(char *myversion, char *start) { int len_myversion = strlen(myversion); @@ -621,12 +649,11 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, log(LOG_ERR, "Error reading directory: expected %s", name); \ return -1; \ } } while(0) - + if (router_get_dir_hash(s, digest)) { log(LOG_ERR, "Unable to compute digest of directory"); - return -1; + goto err; } - NEXT_TOK(); TOK_IS(K_SIGNED_DIRECTORY, "signed-directory"); @@ -634,17 +661,17 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software"); if (tok.val.cmd.n_args != 1) { log(LOG_ERR, "Invalid recommded-software line"); - return -1; + goto err; } versions = strdup(tok.val.cmd.args[0]); - NEXT_TOK(); - if (router_get_list_from_string_tok(&s, &new_dir, &tok)) { + if (router_get_list_from_string_impl(&s, &new_dir)) { log(LOG_ERR, "Error reading routers from directory"); - return -1; + goto err; } new_dir->software_versions = versions; - + + NEXT_TOK(); TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature"); NEXT_TOK(); TOK_IS(_SIGNATURE, "signature"); @@ -653,12 +680,12 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, != 20) { log(LOG_ERR, "Error reading directory: invalid signature."); free(tok.val.signature); - return -1; + goto err; } if (memcmp(digest, signed_digest, 20)) { log(LOG_ERR, "Error reading directory: signature does not match."); free(tok.val.signature); - return -1; + goto err; } } free(tok.val.signature); @@ -671,12 +698,16 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, *dest = new_dir; return 0; + + err: + if (new_dir) + directory_free(new_dir); + return -1; #undef NEXT_TOK #undef TOK_IS } -static int router_get_list_from_string_tok(char **s, directory_t **dest, - directory_token_t *tok) +int router_get_list_from_string_impl(char **s, directory_t **dest) { routerinfo_t *router; routerinfo_t **rarray; @@ -686,8 +717,11 @@ static int router_get_list_from_string_tok(char **s, directory_t **dest, rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR); - while (tok->tp == K_ROUTER) { - router = router_get_entry_from_string_tok(s, tok); + while (1) { + *s = eat_whitespace(*s); + if (strncmp(*s, "router ", 7)!=0) + break; + router = router_get_entry_from_string(s); if (!router) { log(LOG_ERR, "Error reading router"); return -1; @@ -755,34 +789,32 @@ router_resolve_directory(directory_t *dir) 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) { - router_release_token(&tok); - 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. */ -static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t *tok) { +routerinfo_t *router_get_entry_from_string(char**s) { routerinfo_t *router = NULL; - -#define NEXT_TOKEN() \ - do { if (router_get_next_token(s, tok)) { \ - log(LOG_ERR, "Error reading directory: %s", tok->val.error); \ - goto err; \ +#if 0 + char signed_digest[128]; +#endif + char digest[128]; + directory_token_t _tok; + directory_token_t *tok = &_tok; + +#define NEXT_TOKEN() \ + do { if (router_get_next_token(s, tok)) { \ + log(LOG_ERR, "Error reading directory: %s", tok->val.error); \ + goto err; \ } } while(0) #define ARGS tok->val.cmd.args + if (router_get_router_hash(*s, digest) < 0) + return NULL; + + NEXT_TOKEN(); + if (tok->tp != K_ROUTER) { router_release_token(tok); log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\""); @@ -793,7 +825,7 @@ static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t memset(router,0,sizeof(routerinfo_t)); /* zero it out first */ /* C doesn't guarantee that NULL is represented by 0 bytes. You'll thank me for this someday. */ - router->pkey = router->signing_pkey = NULL; + router->onion_pkey = router->identity_pkey = router->link_pkey = NULL; if (tok->val.cmd.n_args != 5) { log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\""); @@ -828,38 +860,77 @@ static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t router->or_port, router->ap_port, router->dir_port, router->bandwidth); NEXT_TOKEN(); + if (tok->tp != K_ONION_KEY) { + log_fn(LOG_ERR, "Missing onion-key"); goto err; + } + 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; + log_fn(LOG_ERR, "Missing onion key"); goto err; + } /* XXX Check key length */ + router->onion_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(); - } + if (tok->tp != K_LINK_KEY) { + log_fn(LOG_ERR, "Missing link-key"); goto err; + } + NEXT_TOKEN(); + if (tok->tp != _PUBLIC_KEY) { + log_fn(LOG_ERR, "Missing link key"); goto err; + } /* XXX Check key length */ + router->link_pkey = tok->val.public_key; + + NEXT_TOKEN(); + if (tok->tp != K_SIGNING_KEY) { + log_fn(LOG_ERR, "Missing signing-key"); goto err; + } + NEXT_TOKEN(); + if (tok->tp != _PUBLIC_KEY) { + log_fn(LOG_ERR, "Missing signing key"); goto err; + } + router->identity_pkey = tok->val.public_key; + NEXT_TOKEN(); while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) { router_add_exit_policy(router, tok); NEXT_TOKEN(); } + if (tok->tp != K_ROUTER_SIGNATURE) { + log_fn(LOG_ERR,"Missing router signature"); + goto err; + } + NEXT_TOKEN(); + if (tok->tp != _SIGNATURE) { + log_fn(LOG_ERR,"Missing router signature"); + goto err; + } + assert (router->identity_pkey); +#if 0 + /* XXX This should get re-enabled, once directory servers properly + * XXX relay signed router blocks. */ + if (crypto_pk_public_checksig(router->identity_pkey, tok->val.signature, + 128, signed_digest) != 20) { + log_fn(LOG_ERR, "Invalid signature"); + goto err; + } + if (memcmp(digest, signed_digest, 20)) { + log_fn(LOG_ERR, "Mismatched signature"); + goto err; + } +#endif + return router; err: router_release_token(tok); if(router->address) free(router->address); - if(router->pkey) - crypto_free_pk_env(router->pkey); - if(router->signing_pkey) - crypto_free_pk_env(router->signing_pkey); + if(router->link_pkey) + crypto_free_pk_env(router->link_pkey); + if(router->onion_pkey) + crypto_free_pk_env(router->onion_pkey); + if(router->identity_pkey) + crypto_free_pk_env(router->identity_pkey); router_free_exit_policy(router); free(router); return NULL; diff --git a/src/or/test.c b/src/or/test.c index e8a9c18d1e..b3cc777c46 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -49,19 +49,19 @@ test_buffers() { char str[256]; char str2[256]; - char *buf; - int buflen, buf_datalen; + buf_t *buf; + buf_t *buf2; int s, i, j, eof; /**** * buf_new ****/ - if (buf_new(&buf, &buflen, &buf_datalen)) + if (!(buf = buf_new())) test_fail(); - test_eq(buflen, MAX_BUF_SIZE); - test_eq(buf_datalen, 0); + test_eq(buf_capacity(buf), MAX_BUF_SIZE); + test_eq(buf_datalen(buf), 0); /**** * read_to_buf @@ -75,52 +75,52 @@ test_buffers() { s = open("/tmp/tor_test/data", O_RDONLY, 0); eof = 0; - i = read_to_buf(s, 10, &buf, &buflen, &buf_datalen, &eof); - test_eq(buflen, MAX_BUF_SIZE); - test_eq(buf_datalen, 10); + i = read_to_buf(s, 10, buf, &eof); + test_eq(buf_capacity(buf), MAX_BUF_SIZE); + test_eq(buf_datalen(buf), 10); test_eq(eof, 0); test_eq(i, 10); - test_memeq(str, buf, 10); + test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10); /* Test reading 0 bytes. */ - i = read_to_buf(s, 0, &buf, &buflen, &buf_datalen, &eof); - test_eq(buflen, MAX_BUF_SIZE); - test_eq(buf_datalen, 10); + i = read_to_buf(s, 0, buf, &eof); + test_eq(buf_capacity(buf), MAX_BUF_SIZE); + test_eq(buf_datalen(buf), 10); test_eq(eof, 0); test_eq(i, 0); /* Now test when buffer is filled exactly. */ - buflen = 16; - i = read_to_buf(s, 6, &buf, &buflen, &buf_datalen, &eof); - test_eq(buflen, 16); - test_eq(buf_datalen, 16); + buf2 = buf_new_with_capacity(6); + i = read_to_buf(s, 6, buf2, &eof); + test_eq(buf_capacity(buf2), 6); + test_eq(buf_datalen(buf2), 6); test_eq(eof, 0); test_eq(i, 6); - test_memeq(str, buf, 16); + test_memeq(str+10, (char*)_buf_peek_raw_buffer(buf2), 6); + buf_free(buf2); /* Now test when buffer is filled with more data to read. */ - buflen = 32; - i = read_to_buf(s, 128, &buf, &buflen, &buf_datalen, &eof); - test_eq(buflen, 32); - test_eq(buf_datalen, 32); + buf2 = buf_new_with_capacity(32); + i = read_to_buf(s, 128, buf2, &eof); + test_eq(buf_capacity(buf2), 32); + test_eq(buf_datalen(buf2), 32); test_eq(eof, 0); - test_eq(i, 16); - test_memeq(str, buf, 32); + test_eq(i, 32); + buf_free(buf2); /* Now read to eof. */ - buflen = MAX_BUF_SIZE; - test_assert(buflen > 256); - i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof); - test_eq(i, (256-32)); - test_eq(buflen, MAX_BUF_SIZE); - test_eq(buf_datalen, 256); - test_memeq(str, buf, 256); + test_assert(buf_capacity(buf) > 256); + i = read_to_buf(s, 1024, buf, &eof); + test_eq(i, (256-32-10-6)); + test_eq(buf_capacity(buf), MAX_BUF_SIZE); + test_eq(buf_datalen(buf), 256-6-32); + test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10); /* XXX Check rest. */ test_eq(eof, 0); - i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof); + i = read_to_buf(s, 1024, buf, &eof); test_eq(i, 0); - test_eq(buflen, MAX_BUF_SIZE); - test_eq(buf_datalen, 256); + test_eq(buf_capacity(buf), MAX_BUF_SIZE); + test_eq(buf_datalen(buf), 256-6-32); test_eq(eof, 1); close(s); @@ -128,50 +128,59 @@ test_buffers() { /**** * find_on_inbuf ****/ + buf_free(buf); + buf = buf_new(); + s = open("/tmp/tor_test/data", O_RDONLY, 0); + eof = 0; + i = read_to_buf(s, 1024, buf, &eof); + test_eq(256, i); + close(s); - test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf, buf_datalen)); - test_eq(-1, find_on_inbuf("xyzzy", 5, buf, buf_datalen)); + test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf)); + test_eq(-1, find_on_inbuf("xyzzy", 5, buf)); /* Make sure we don't look off the end of the buffef */ - buf[256] = 'A'; - buf[257] = 'X'; - test_eq(-1, find_on_inbuf("\xff" "A", 2, buf, buf_datalen)); - test_eq(-1, find_on_inbuf("AX", 2, buf, buf_datalen)); + ((char*)_buf_peek_raw_buffer(buf))[256] = 'A'; + ((char*)_buf_peek_raw_buffer(buf))[257] = 'X'; + test_eq(-1, find_on_inbuf("\xff" "A", 2, buf)); + test_eq(-1, find_on_inbuf("AX", 2, buf)); /* Make sure we use the string length */ - test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf, buf_datalen)); + test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf)); /**** * fetch_from_buf ****/ memset(str2, 255, 256); - test_eq(246, fetch_from_buf(str2, 10, &buf, &buflen, &buf_datalen)); + test_eq(246, fetch_from_buf(str2, 10, buf)); test_memeq(str2, str, 10); - test_memeq(str+10,buf,246); - test_eq(buf_datalen,246); + test_memeq(str+10,(char*)_buf_peek_raw_buffer(buf),246); + test_eq(buf_datalen(buf),246); - test_eq(0, fetch_from_buf(str2, 246, &buf, &buflen, &buf_datalen)); + test_eq(0, fetch_from_buf(str2, 246, buf)); test_memeq(str2, str+10, 246); - test_eq(buflen,MAX_BUF_SIZE); - test_eq(buf_datalen,0); + test_eq(buf_capacity(buf),MAX_BUF_SIZE); + test_eq(buf_datalen(buf),0); /**** * write_to_buf ****/ - memset(buf, (int)'-', 256); - i = write_to_buf("Hello world", 11, &buf, &buflen, &buf_datalen); + memset((char *)_buf_peek_raw_buffer(buf), (int)'-', 256); + i = write_to_buf("Hello world", 11, buf); test_eq(i, 11); - test_eq(buf_datalen, 11); - test_memeq(buf, "Hello world", 11); - i = write_to_buf("XYZZY", 5, &buf, &buflen, &buf_datalen); + test_eq(buf_datalen(buf), 11); + test_memeq((char*)_buf_peek_raw_buffer(buf), "Hello world", 11); + i = write_to_buf("XYZZY", 5, buf); test_eq(i, 16); - test_eq(buf_datalen, 16); - test_memeq(buf, "Hello worldXYZZY", 16); + test_eq(buf_datalen(buf), 16); + test_memeq((char*)_buf_peek_raw_buffer(buf), "Hello worldXYZZY", 16); /* Test when buffer is overfull. */ +#if 0 buflen = 18; test_eq(-1, write_to_buf("This string will not fit.", 25, &buf, &buflen, &buf_datalen)); test_eq(buf_datalen, 16); test_memeq(buf, "Hello worldXYZZY--", 18); buflen = MAX_BUF_SIZE; +#endif /**** * flush_buf @@ -482,7 +491,8 @@ test_onion_handshake() { } /* from main.c */ -int dump_router_to_string(char *s, int maxlen, routerinfo_t *router); +int dump_router_to_string(char *s, int maxlen, routerinfo_t *router, + crypto_pk_env_t *ident_key); void dump_directory_to_string(char *s, int maxlen); /* from routers.c */ @@ -491,28 +501,30 @@ int compare_recommended_versions(char *myversion, char *start); void test_dir_format() { - - char buf[2048], buf2[2048]; - char *pk1_str = NULL, *pk2_str = NULL, *cp; - int pk1_str_len, pk2_str_len; + char buf[8192], buf2[8192]; + char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp; + int pk1_str_len, pk2_str_len, pk3_str_len; routerinfo_t r1, r2; - crypto_pk_env_t *pk1 = NULL, *pk2 = NULL; - routerinfo_t *rp1, *rp2; + crypto_pk_env_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL; + routerinfo_t *rp1 = NULL, *rp2 = NULL; 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)) ); + test_assert( (pk3 = crypto_new_pk_env(CRYPTO_PK_RSA)) ); test_assert(! crypto_pk_generate_key(pk1)); test_assert(! crypto_pk_generate_key(pk2)); + test_assert(! crypto_pk_generate_key(pk3)); r1.address = "testaddr1.foo.bar"; r1.addr = 0xc0a80001u; /* 192.168.0.1 */ r1.or_port = 9000; r1.ap_port = 9002; r1.dir_port = 9003; - r1.pkey = pk1; - r1.signing_pkey = NULL; + r1.onion_pkey = pk1; + r1.identity_pkey = pk2; + r1.link_pkey = pk3; r1.bandwidth = 1000; r1.exit_policy = NULL; @@ -530,8 +542,9 @@ test_dir_format() r2.or_port = 9005; r2.ap_port = 0; r2.dir_port = 0; - r2.pkey = pk2; - r2.signing_pkey = pk1; + r2.onion_pkey = pk2; + r2.identity_pkey = pk1; + r2.link_pkey = pk2; r2.bandwidth = 3000; r2.exit_policy = &ex1; @@ -539,14 +552,23 @@ test_dir_format() &pk1_str_len)); test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str, &pk2_str_len)); - strcpy(buf2, "router testaddr1.foo.bar 9000 9002 9003 1000\n"); + test_assert(!crypto_pk_write_public_key_to_string(pk3 , &pk3_str, + &pk3_str_len)); + + strcpy(buf2, "router testaddr1.foo.bar 9000 9002 9003 1000\nonion-key\n"); strcat(buf2, pk1_str); - strcat(buf2, "\n"); + strcat(buf2, "link-key\n"); + strcat(buf2, pk3_str); + strcat(buf2, "signing-key\n"); + strcat(buf2, pk2_str); + strcat(buf2, "router-signature\n"); memset(buf, 0, 2048); - test_assert(dump_router_to_string(buf, 2048, &r1)>0); + test_assert(dump_router_to_string(buf, 2048, &r1, pk1)>0); + buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same 2ce*/ test_streq(buf, buf2); - + + test_assert(dump_router_to_string(buf, 2048, &r1, pk1)>0); cp = buf; rp1 = router_get_entry_from_string(&cp); test_assert(rp1); @@ -555,16 +577,18 @@ test_dir_format() test_eq(rp1->ap_port, r1.ap_port); test_eq(rp1->dir_port, r1.dir_port); test_eq(rp1->bandwidth, r1.bandwidth); - test_assert(crypto_pk_cmp_keys(rp1->pkey, pk1) == 0); - test_assert(rp1->signing_pkey == NULL); + test_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0); + test_assert(crypto_pk_cmp_keys(rp1->link_pkey, pk3) == 0); + test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0); test_assert(rp1->exit_policy == NULL); +#if 0 strcpy(buf2, "router tor.tor.tor 9005 0 0 3000\n"); strcat(buf2, pk2_str); strcat(buf2, "signing-key\n"); strcat(buf2, pk1_str); strcat(buf2, "accept *:80\nreject 18.*:24\n\n"); - test_assert(dump_router_to_string(buf, 2048, &r2)>0); + test_assert(dump_router_to_string(buf, 2048, &r2, pk2)>0); test_streq(buf, buf2); cp = buf; @@ -575,8 +599,8 @@ test_dir_format() test_eq(rp2->ap_port, r2.ap_port); test_eq(rp2->dir_port, r2.dir_port); test_eq(rp2->bandwidth, r2.bandwidth); - test_assert(crypto_pk_cmp_keys(rp2->pkey, pk2) == 0); - test_assert(crypto_pk_cmp_keys(rp2->signing_pkey, pk1) == 0); + test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0); + test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0); test_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT); test_streq(rp2->exit_policy->string, "accept *:80"); test_streq(rp2->exit_policy->address, "*"); @@ -586,6 +610,7 @@ test_dir_format() test_streq(rp2->exit_policy->next->address, "18.*"); test_streq(rp2->exit_policy->next->port, "24"); test_assert(rp2->exit_policy->next->next == NULL); +#endif /* Okay, now for the directories. */ dir1 = (directory_t*) tor_malloc(sizeof(directory_t)); @@ -593,7 +618,7 @@ test_dir_format() dir1->routers = (routerinfo_t**) tor_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)); + test_assert(! dump_signed_directory_to_string_impl(buf, 4096, dir1, pk1)); /* puts(buf); */ test_assert(! router_get_dir_from_string_impl(buf, &dir2, pk1)); |