diff --git a/branches/tor-0_0_6incompat/src/common/crypto.c b/branches/tor-0_0_6incompat/src/common/crypto.c index 88330892bc..831aaaa2c2 100644 --- a/branches/tor-0_0_6incompat/src/common/crypto.c +++ b/branches/tor-0_0_6incompat/src/common/crypto.c @@ -127,13 +127,18 @@ RSA *_crypto_pk_env_get_rsa(crypto_pk_env_t *env) } /* used by tortls.c */ -EVP_PKEY *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env) +EVP_PKEY *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env, int private) { RSA *key = NULL; EVP_PKEY *pkey = NULL; assert(env->key); - if (!(key = RSAPrivateKey_dup(env->key))) - goto error; + if (private) { + if (!(key = RSAPrivateKey_dup(env->key))) + goto error; + } else { + if (!(key = RSAPublicKey_dup(env->key))) + goto error; + } if (!(pkey = EVP_PKEY_new())) goto error; if (!(EVP_PKEY_assign_RSA(pkey, key))) diff --git a/branches/tor-0_0_6incompat/src/common/tortls.c b/branches/tor-0_0_6incompat/src/common/tortls.c index 4f6ee2146f..c50329167c 100644 --- a/branches/tor-0_0_6incompat/src/common/tortls.c +++ b/branches/tor-0_0_6incompat/src/common/tortls.c @@ -44,6 +44,7 @@ struct tor_tls_st { }; static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa, + crypto_pk_env_t *identity, const char *nickname); /* global tls context, keep it here because nobody else needs to touch it */ @@ -54,7 +55,7 @@ static int tls_library_is_initialized = 0; #define _TOR_TLS_ZERORETURN -5 /* These functions are declared in crypto.c but not exported. */ -EVP_PKEY *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env); +EVP_PKEY *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env, int private); crypto_pk_env_t *_crypto_new_pk_env_rsa(RSA *rsa); DH *_crypto_dh_env_get_dh(crypto_dh_env_t *dh); @@ -129,15 +130,16 @@ static int always_accept_verify_cb(int preverify_ok, } /* Generate a self-signed certificate with the private key 'rsa' and - * commonName 'nickname', and write it, PEM-encoded, to the file named - * by 'certfile'. Return 0 on success, -1 for failure. + * identity key 'identity and commonName 'nickname'. Return a certificate + * on success, NULL on failure. */ X509 * tor_tls_create_certificate(crypto_pk_env_t *rsa, + crypto_pk_env_t *identity, const char *nickname) { time_t start_time, end_time; - EVP_PKEY *pkey = NULL; + EVP_PKEY *id_pkey = NULL, *pkey=NULL; X509 *x509 = NULL; X509_NAME *name = NULL; int nid; @@ -147,8 +149,10 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa, start_time = time(NULL); assert(rsa && nickname); - if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa))) - return NULL; + if (!(id_pkey = _crypto_pk_env_get_evp_pkey(identity,1))) + goto error; + if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,0))) + goto error; if (!(x509 = X509_new())) goto error; if (!(X509_set_version(x509, 2))) @@ -176,7 +180,7 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa, goto error; if (!X509_set_pubkey(x509, pkey)) goto error; - if (!X509_sign(x509, pkey, EVP_sha1())) + if (!X509_sign(x509, id_pkey, EVP_sha1())) goto error; goto done; @@ -186,6 +190,8 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa, x509 = NULL; } done: + if (id_pkey) + EVP_PKEY_free(id_pkey); if (pkey) EVP_PKEY_free(pkey); if (name) @@ -210,26 +216,31 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa, #endif /* Create a new TLS context. If we are going to be using it as a - * server, it must have isServer set to true, certfile set to a - * filename for a certificate file, and RSA set to the private key - * used for that certificate. Return -1 if failure, else 0. + * server, it must have isServer set to true, 'identity' set to the + * identity key used to sign that certificate, and 'nickname' set to + * the server's nickname. Return -1 if failure, else 0. */ int -tor_tls_context_new(crypto_pk_env_t *rsa, +tor_tls_context_new(crypto_pk_env_t *identity, int isServer, const char *nickname) { + crypto_pk_env_t *rsa = NULL; crypto_dh_env_t *dh = NULL; EVP_PKEY *pkey = NULL; - tor_tls_context *result; + tor_tls_context *result = NULL; X509 *cert = NULL; tor_tls_init(); - if (rsa) { - cert = tor_tls_create_certificate(rsa, nickname); + if (isServer) { + if (!(rsa = crypto_new_pk_env())) + goto error; + if (crypto_pk_generate_key(rsa)<0) + goto error; + cert = tor_tls_create_certificate(rsa, identity, nickname); if (!cert) { log(LOG_WARN, "Error creating certificate"); - return -1; + goto error; } } @@ -250,8 +261,9 @@ tor_tls_context_new(crypto_pk_env_t *rsa, 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) { - if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa))) + if (isServer) { + assert(rsa); + if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1))) goto error; if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) goto error; @@ -283,6 +295,8 @@ tor_tls_context_new(crypto_pk_env_t *rsa, error: if (pkey) EVP_PKEY_free(pkey); + if (rsa) + crypto_free_pk_env(rsa); if (dh) crypto_dh_free(dh); if (result && result->ctx) @@ -509,19 +523,19 @@ tor_tls_get_peer_cert_nickname(tor_tls *tls, char *buf, int buflen) } /* If the provided tls connection is authenticated and has a - * certificate that is currently valid and is correctly self-signed, - * return its public key. Otherwise return NULL. + * certificate that is currently valid and is correctly signed by + * identity_key, return 0. Else, return -1. */ -crypto_pk_env_t * -tor_tls_verify(tor_tls *tls) +int +tor_tls_verify(tor_tls *tls, crypto_pk_env_t *identity_key) { X509 *cert = NULL; - EVP_PKEY *pkey = NULL; + EVP_PKEY *id_pkey = NULL; RSA *rsa = NULL; time_t now, t; - crypto_pk_env_t *r = NULL; + int r = -1; if (!(cert = SSL_get_peer_certificate(tls->ssl))) - return NULL; + return -1; now = time(NULL); t = now + CERT_ALLOW_SKEW; @@ -536,31 +550,19 @@ tor_tls_verify(tor_tls *tls) } /* Get the public key. */ - if (!(pkey = X509_get_pubkey(cert))) { - log_fn(LOG_WARN,"X509_get_pubkey returned null"); - goto done; - } - if (X509_verify(cert, pkey) <= 0) { + if (!(id_pkey = _crypto_pk_env_get_evp_pkey(identity_key,0)) || + X509_verify(cert, id_pkey) <= 0) { log_fn(LOG_WARN,"X509_verify on cert and pkey returned <= 0"); goto done; } - rsa = EVP_PKEY_get1_RSA(pkey); - EVP_PKEY_free(pkey); - pkey = NULL; - if (!rsa) { - log_fn(LOG_WARN,"EVP_PKEY_get1_RSA(pkey) returned null"); - goto done; - } - - r = _crypto_new_pk_env_rsa(rsa); - rsa = NULL; + r = 0; done: if (cert) X509_free(cert); - if (pkey) - EVP_PKEY_free(pkey); + if (id_pkey) + EVP_PKEY_free(id_pkey); if (rsa) RSA_free(rsa); return r; diff --git a/branches/tor-0_0_6incompat/src/common/tortls.h b/branches/tor-0_0_6incompat/src/common/tortls.h index d9e326e55c..9522de2499 100644 --- a/branches/tor-0_0_6incompat/src/common/tortls.h +++ b/branches/tor-0_0_6incompat/src/common/tortls.h @@ -22,7 +22,7 @@ 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); int tor_tls_get_peer_cert_nickname(tor_tls *tls, char *buf, int buflen); -crypto_pk_env_t *tor_tls_verify(tor_tls *tls); +int tor_tls_verify(tor_tls *tls, crypto_pk_env_t *identity); int tor_tls_read(tor_tls *tls, char *cp, int len); int tor_tls_write(tor_tls *tls, char *cp, int n); int tor_tls_handshake(tor_tls *tls); diff --git a/branches/tor-0_0_6incompat/src/or/connection.c b/branches/tor-0_0_6incompat/src/or/connection.c index f673158e5f..299d0d2d8e 100644 --- a/branches/tor-0_0_6incompat/src/or/connection.c +++ b/branches/tor-0_0_6incompat/src/or/connection.c @@ -116,8 +116,6 @@ void connection_free(connection_t *conn) { 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); tor_free(conn->nickname); diff --git a/branches/tor-0_0_6incompat/src/or/connection_or.c b/branches/tor-0_0_6incompat/src/or/connection_or.c index 5e122c8480..f8863af8a1 100644 --- a/branches/tor-0_0_6incompat/src/or/connection_or.c +++ b/branches/tor-0_0_6incompat/src/or/connection_or.c @@ -84,7 +84,6 @@ void connection_or_init_conn_from_router(connection_t *conn, routerinfo_t *route conn->port = router->or_port; conn->receiver_bucket = conn->bandwidth = router->bandwidthburst; conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey); - conn->link_pkey = crypto_pk_dup_key(router->link_pkey); conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); conn->nickname = tor_strdup(router->nickname); tor_free(conn->address); @@ -178,7 +177,6 @@ int connection_tls_continue_handshake(connection_t *conn) { } static int connection_tls_finish_handshake(connection_t *conn) { - crypto_pk_env_t *pk; routerinfo_t *router; char nickname[MAX_NICKNAME_LEN+1]; connection_t *c; @@ -203,36 +201,23 @@ static int connection_tls_finish_handshake(connection_t *conn) { return -1; } log_fn(LOG_DEBUG, "Other side claims to be '%s'", nickname); - pk = tor_tls_verify(conn->tls); - if(!pk) { + router = router_get_by_nickname(nickname); + if (!router) { + log_fn(LOG_INFO, "Unrecognized router with nickname '%s'", nickname); + return -1; + } + if(tor_tls_verify(conn->tls, router->identity_pkey)<0) { log_fn(LOG_WARN,"Other side '%s' (%s:%d) has a cert but it's invalid. Closing.", nickname, conn->address, conn->port); return -1; } - router = router_get_by_link_pk(pk); - if (!router) { - log_fn(LOG_INFO,"Unrecognized public key from peer '%s' (%s:%d). Closing.", - nickname, conn->address, conn->port); - crypto_free_pk_env(pk); + log_fn(LOG_DEBUG,"The router's cert is valid."); + + if((c=connection_exact_get_by_addr_port(router->addr,router->or_port))) { + log_fn(LOG_INFO,"Router %s is already connected on fd %d. Dropping fd %d.", router->nickname, c->s, conn->s); return -1; } - if(conn->link_pkey) { /* I initiated this connection. */ - if(crypto_pk_cmp_keys(conn->link_pkey, pk)) { - log_fn(LOG_WARN,"We connected to '%s' (%s:%d) but he gave us a different key. Closing.", - nickname, conn->address, conn->port); - crypto_free_pk_env(pk); - return -1; - } - log_fn(LOG_DEBUG,"The router's pk matches the one we meant to connect to. Good."); - } else { - if((c=connection_exact_get_by_addr_port(router->addr,router->or_port))) { - log_fn(LOG_INFO,"Router %s is already connected on fd %d. Dropping fd %d.", router->nickname, c->s, conn->s); - crypto_free_pk_env(pk); - return -1; - } - connection_or_init_conn_from_router(conn, router); - } - crypto_free_pk_env(pk); + if (strcmp(conn->nickname, nickname)) { log_fn(options.DirPort ? LOG_WARN : LOG_INFO, "Other side claims to be '%s', but we expected '%s'", diff --git a/branches/tor-0_0_6incompat/src/or/cpuworker.c b/branches/tor-0_0_6incompat/src/or/cpuworker.c index 17216cc18f..8f6d67a5c7 100644 --- a/branches/tor-0_0_6incompat/src/or/cpuworker.c +++ b/branches/tor-0_0_6incompat/src/or/cpuworker.c @@ -12,8 +12,9 @@ extern or_options_t options; /* command-line and config-file options */ #define LEN_ONION_QUESTION (1+TAG_LEN+ONIONSKIN_CHALLENGE_LEN) #define LEN_ONION_RESPONSE (1+TAG_LEN+ONIONSKIN_REPLY_LEN+40+32) -int num_cpuworkers=0; -int num_cpuworkers_busy=0; +static int num_cpuworkers=0; +static int num_cpuworkers_busy=0; +static time_t last_rotation_time=0; int cpuworker_main(void *data); static int spawn_cpuworker(void); @@ -21,6 +22,7 @@ static void spawn_enough_cpuworkers(void); static void process_pending_task(connection_t *cpuworker); void cpu_init(void) { + last_rotation_time=time(NULL); spawn_enough_cpuworkers(); } @@ -47,6 +49,18 @@ static void tag_unpack(char *tag, uint32_t *addr, uint16_t *port, uint16_t *circ log_fn(LOG_DEBUG,"onion was from %s:%d, circ_id %d.", inet_ntoa(in), *port, *circ_id); } +void cpuworkers_rotate(void) +{ + connection_t *cpuworker; + while ((cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, + CPUWORKER_STATE_IDLE))) { + connection_mark_for_close(cpuworker,0); + --num_cpuworkers; + } + last_rotation_time = time(NULL); + spawn_enough_cpuworkers(); +} + int connection_cpu_process_inbuf(connection_t *conn) { char success; unsigned char buf[LEN_ONION_RESPONSE]; @@ -111,7 +125,13 @@ int connection_cpu_process_inbuf(connection_t *conn) { done_processing: conn->state = CPUWORKER_STATE_IDLE; num_cpuworkers_busy--; - process_pending_task(conn); + if (conn->timestamp_created < last_rotation_time) { + connection_mark_for_close(conn,0); + num_cpuworkers--; + spawn_enough_cpuworkers(); + } else { + process_pending_task(conn); + } return 0; } @@ -126,6 +146,7 @@ int cpuworker_main(void *data) { unsigned char reply_to_proxy[ONIONSKIN_REPLY_LEN]; unsigned char buf[LEN_ONION_RESPONSE]; char tag[TAG_LEN]; + crypto_pk_env_t *onion_key = NULL, *last_onion_key = NULL; close(fdarray[0]); /* this is the side of the socketpair the parent uses */ fd = fdarray[1]; /* this side is ours */ @@ -133,27 +154,32 @@ int cpuworker_main(void *data) { connection_free_all(); /* so the child doesn't hold the parent's fd's open */ #endif + /* XXXX WINDOWS lock here. */ + onion_key = crypto_pk_dup_key(get_onion_key()); + if (get_previous_onion_key()) + last_onion_key = crypto_pk_dup_key(get_previous_onion_key()); + for(;;) { if(recv(fd, &question_type, 1, 0) != 1) { // log_fn(LOG_ERR,"read type failed. Exiting."); log_fn(LOG_INFO,"cpuworker exiting because tor process died."); - spawn_exit(); + goto end; } assert(question_type == CPUWORKER_TASK_ONION); if(read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) { log_fn(LOG_ERR,"read tag failed. Exiting."); - spawn_exit(); + goto end; } if(read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) != ONIONSKIN_CHALLENGE_LEN) { log_fn(LOG_ERR,"read question failed. Exiting."); - spawn_exit(); + goto end; } if(question_type == CPUWORKER_TASK_ONION) { - if(onion_skin_server_handshake(question, get_onion_key(), + if(onion_skin_server_handshake(question, onion_key, last_onion_key, reply_to_proxy, keys, 40+32) < 0) { /* failure */ log_fn(LOG_WARN,"onion_skin_server_handshake failed."); @@ -173,6 +199,12 @@ int cpuworker_main(void *data) { log_fn(LOG_DEBUG,"finished writing response."); } } + end: + if (onion_key) + crypto_free_pk_env(onion_key); + if (last_onion_key) + crypto_free_pk_env(last_onion_key); + spawn_exit(); return 0; /* windows wants this function to return an int */ } @@ -263,7 +295,7 @@ int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type, return 0; } - if(!cpuworker) + if (!cpuworker) cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE); assert(cpuworker); diff --git a/branches/tor-0_0_6incompat/src/or/onion.c b/branches/tor-0_0_6incompat/src/or/onion.c index aa93d81b79..1cb249da87 100644 --- a/branches/tor-0_0_6incompat/src/or/onion.c +++ b/branches/tor-0_0_6incompat/src/or/onion.c @@ -575,9 +575,6 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout [16 bytes] Symmetric key for encrypting blob past RSA [112 bytes] g^x part 1 (inside the RSA) [16 bytes] g^x part 2 (symmetrically encrypted) -[ 6 bytes] Meeting point (IP/port) -[ 8 bytes] Meeting cookie -[16 bytes] End-to-end authentication [optional] * Stores the DH private key into handshake_state_out for later completion * of the handshake. @@ -603,7 +600,7 @@ onion_skin_create(crypto_pk_env_t *dest_router_key, pkbytes = crypto_pk_keysize(dest_router_key); assert(dhbytes == 128); assert(pkbytes == 128); - challenge = tor_malloc_zero(ONIONSKIN_CHALLENGE_LEN-CIPHER_KEY_LEN); + challenge = tor_malloc_zero(DH_KEY_LEN); if (crypto_dh_get_public(dh, challenge, dhbytes)) goto err; @@ -625,8 +622,8 @@ onion_skin_create(crypto_pk_env_t *dest_router_key, /* set meeting point, meeting cookie, etc here. Leave zero for now. */ if (crypto_pk_public_hybrid_encrypt(dest_router_key, challenge, - ONIONSKIN_CHALLENGE_LEN-CIPHER_KEY_LEN, - onion_skin_out, PK_NO_PADDING, 1)<0) + ONIONSKIN_CHALLENGE_LEN-CIPHER_KEY_LEN, + onion_skin_out, PK_PKCS1_OAEP_PADDING, 1)<0) goto err; tor_free(challenge); @@ -647,6 +644,7 @@ onion_skin_create(crypto_pk_env_t *dest_router_key, int onion_skin_server_handshake(char *onion_skin, /* ONIONSKIN_CHALLENGE_LEN bytes */ crypto_pk_env_t *private_key, + crypto_pk_env_t *prev_private_key, char *handshake_reply_out, /* ONIONSKIN_REPLY_LEN bytes */ char *key_out, int key_out_len) @@ -655,11 +653,28 @@ onion_skin_server_handshake(char *onion_skin, /* ONIONSKIN_CHALLENGE_LEN bytes * crypto_dh_env_t *dh = NULL; int len; char *key_material=NULL; + int i; + crypto_pk_env_t *k; - if (crypto_pk_private_hybrid_decrypt(private_key, - onion_skin, ONIONSKIN_CHALLENGE_LEN, - challenge, PK_NO_PADDING)<0) + len = -1; + for (i=0;i<2;++i) { + k = i==0?private_key:prev_private_key; + if (!k) + break; + len = crypto_pk_private_hybrid_decrypt(k, + onion_skin, ONIONSKIN_CHALLENGE_LEN, + challenge, PK_PKCS1_OAEP_PADDING); + if (len>0) + break; + } + if (len<0) { + log_fn(LOG_WARN, "Couldn't decrypt onionskin"); goto err; + } else if (len != DH_KEY_LEN) { + log_fn(LOG_WARN, "Unexpected onionskin length after decryption: %d", + len); + goto err; + } dh = crypto_dh_new(); if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) diff --git a/branches/tor-0_0_6incompat/src/or/or.h b/branches/tor-0_0_6incompat/src/or/or.h index 8bb41f6d9f..b9cd482361 100644 --- a/branches/tor-0_0_6incompat/src/or/or.h +++ b/branches/tor-0_0_6incompat/src/or/or.h @@ -377,7 +377,6 @@ struct connection_t { * strdup into this, because free_connection frees it */ 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 */ char *nickname; @@ -441,7 +440,6 @@ typedef struct { time_t published_on; 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 */ int is_running; @@ -488,8 +486,10 @@ struct crypt_path_t { }; #define DH_KEY_LEN DH_BYTES -#define ONIONSKIN_CHALLENGE_LEN (16+DH_KEY_LEN) -#define ONIONSKIN_REPLY_LEN (DH_KEY_LEN+20) +#define ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\ + CIPHER_KEY_LEN+\ + DH_KEY_LEN) +#define ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN) #define REND_COOKIE_LEN DIGEST_LEN typedef struct crypt_path_t crypt_path_t; @@ -878,6 +878,7 @@ void connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn); /********************************* cpuworker.c *****************************/ void cpu_init(void); +void cpuworkers_rotate(void); int connection_cpu_finished_flushing(connection_t *conn); int connection_cpu_process_inbuf(connection_t *conn); int cpuworker_main(void *data); @@ -944,6 +945,7 @@ int onion_skin_create(crypto_pk_env_t *router_key, int onion_skin_server_handshake(char *onion_skin, crypto_pk_env_t *private_key, + crypto_pk_env_t *prev_private_key, char *handshake_reply_out, char *key_out, int key_out_len); @@ -960,11 +962,12 @@ cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, void set_onion_key(crypto_pk_env_t *k); crypto_pk_env_t *get_onion_key(void); +crypto_pk_env_t *get_previous_onion_key(void); void set_identity_key(crypto_pk_env_t *k); crypto_pk_env_t *get_identity_key(void); -crypto_pk_env_t *get_link_key(void); int init_keys(void); crypto_pk_env_t *init_key_from_file(const char *fname); +void rotate_onion_key(void); void router_retry_connections(void); void router_upload_dir_desc_to_dirservers(void); @@ -985,7 +988,6 @@ routerinfo_t *router_choose_random_node(routerlist_t *dir, char *preferred, char *excluded, struct smartlist_t *excludedsmartlist); routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); -routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk); routerinfo_t *router_get_by_nickname(char *nickname); void router_get_routerlist(routerlist_t **prouterlist); void routerinfo_free(routerinfo_t *router); diff --git a/branches/tor-0_0_6incompat/src/or/router.c b/branches/tor-0_0_6incompat/src/or/router.c index fa841c0896..c0a30a95ef 100644 --- a/branches/tor-0_0_6incompat/src/or/router.c +++ b/branches/tor-0_0_6incompat/src/or/router.c @@ -12,7 +12,7 @@ extern or_options_t options; /* command-line and config-file options */ /* private keys */ static crypto_pk_env_t *onionkey=NULL; -static crypto_pk_env_t *linkkey=NULL; +static crypto_pk_env_t *lastonionkey=NULL; static crypto_pk_env_t *identitykey=NULL; void set_onion_key(crypto_pk_env_t *k) { @@ -24,15 +24,8 @@ crypto_pk_env_t *get_onion_key(void) { return onionkey; } -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_previous_onion_key(void) { + return lastonionkey; } void set_identity_key(crypto_pk_env_t *k) { @@ -46,6 +39,46 @@ crypto_pk_env_t *get_identity_key(void) { /************************************************************/ +/* Replace the previous onion key with the current onion key, and generate + * a new previous onion key. Immediately after calling this function, + * the OR should: + * a) shedule all previous cpuworker to shut down _after_ processing + * pending work. (This will cause fresh cpuworkers to be generated.) + * b) generate and upload a fresh routerinfo. + */ +void rotate_onion_key(void) +{ + char fname[512]; + crypto_pk_env_t *prkey; + sprintf(fname,"%s/keys/onion.key",options.DataDirectory); + if (!(prkey = crypto_new_pk_env())) { + log(LOG_ERR, "Error creating crypto environment."); + goto error; + } + if (crypto_pk_generate_key(onionkey)) { + log(LOG_ERR, "Error generating key: %s", crypto_perror()); + goto error; + } + if (crypto_pk_write_private_key_to_filename(prkey, fname)) { + log(LOG_ERR, "Couldn't write generated key to %s.", fname); + goto error; + } + if (lastonionkey) + crypto_free_pk_env(lastonionkey); + /* XXXX WINDOWS on windows, we need to protect this next bit with a lock. + */ + lastonionkey = onionkey; + onionkey = prkey; + if (router_rebuild_descriptor() <0) { + goto error; + } + router_upload_dir_desc_to_dirservers(); + /* Mark all CPU workers to close. */ + return; + error: + log_fn(LOG_WARN, "Couldn't rotate onion key."); +} + /* Try to read an RSA key from 'fname'. If 'fname' doesn't exist, create a new * RSA key and save it in 'fname'. Return the read/created key, or NULL on * error. @@ -146,12 +179,7 @@ int init_keys(void) { set_onion_key(prkey); /* 3. Initialize link key and TLS context. */ - strcpy(cp, "/link.key"); - log_fn(LOG_INFO,"Reading/making link key %s...",keydir); - prkey = init_key_from_file(keydir); - if (!prkey) return -1; - set_link_key(prkey); - if (tor_tls_context_new(prkey, 1, options.Nickname) < 0) { + if (tor_tls_context_new(get_identity_key(), 1, options.Nickname) < 0) { log_fn(LOG_ERR, "Error initializing TLS context"); return -1; } @@ -370,7 +398,6 @@ int router_rebuild_descriptor(void) { ri->dir_port = options.DirPort; ri->published_on = time(NULL); 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()); get_platform_str(platform, sizeof(platform)); ri->platform = tor_strdup(platform); @@ -403,13 +430,12 @@ void get_platform_str(char *platform, int len) int router_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; struct in_addr in; char digest[20]; char signature[128]; char published[32]; - int onion_pkeylen, link_pkeylen, identity_pkeylen; + int onion_pkeylen, identity_pkeylen; int written; int result=0; struct exit_policy_t *tmpe; @@ -436,19 +462,14 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, return -1; } - if(crypto_pk_write_public_key_to_string(router->link_pkey, - &link_pkey,&link_pkeylen)<0) { - log_fn(LOG_WARN,"write link_pkey to string failed!"); - return -1; - } strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&router->published_on)); + /* XXXX eventually, don't include link key */ result = snprintf(s, maxlen, "router %s %s %d %d %d %d\n" "platform %s\n" "published %s\n" "onion-key\n%s" - "link-key\n%s" "signing-key\n%s", router->nickname, router->address, @@ -459,10 +480,9 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, /* XXXBC also write bandwidthburst */ router->platform, published, - onion_pkey, link_pkey, identity_pkey); + onion_pkey, identity_pkey); free(onion_pkey); - free(link_pkey); free(identity_pkey); if(result < 0 || result >= maxlen) { diff --git a/branches/tor-0_0_6incompat/src/or/routerlist.c b/branches/tor-0_0_6incompat/src/or/routerlist.c index df0d6b7d04..758ef0a121 100644 --- a/branches/tor-0_0_6incompat/src/or/routerlist.c +++ b/branches/tor-0_0_6incompat/src/or/routerlist.c @@ -30,7 +30,7 @@ typedef enum { K_SIGNED_DIRECTORY, K_SIGNING_KEY, K_ONION_KEY, - K_LINK_KEY, + K_LINK_KEY, /* XXXX obsolete */ K_ROUTER_SIGNATURE, K_PUBLISHED, K_RUNNING_ROUTERS, @@ -305,21 +305,6 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) { return NULL; } -routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk) -{ - int i; - routerinfo_t *router; - - assert(routerlist); - - for(i=0;irouters);i++) { - router = smartlist_get(routerlist->routers, i); - if (0 == crypto_pk_cmp_keys(router->link_pkey, pk)) - return router; - } - return NULL; -} - routerinfo_t *router_get_by_nickname(char *nickname) { int i; @@ -354,8 +339,6 @@ void routerinfo_free(routerinfo_t *router) tor_free(router->platform); 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); while (router->exit_policy) { @@ -380,8 +363,6 @@ routerinfo_t *routerinfo_copy(const routerinfo_t *router) r->platform = tor_strdup(r->platform); if (r->onion_pkey) r->onion_pkey = crypto_pk_dup_key(r->onion_pkey); - if (r->link_pkey) - r->link_pkey = crypto_pk_dup_key(r->link_pkey); if (r->identity_pkey) r->identity_pkey = crypto_pk_dup_key(r->identity_pkey); e = &r->exit_policy; @@ -949,7 +930,7 @@ routerinfo_t *router_get_entry_from_string(const char *s, } router = tor_malloc_zero(sizeof(routerinfo_t)); - router->onion_pkey = router->identity_pkey = router->link_pkey = NULL; + router->onion_pkey = router->identity_pkey = NULL; ports_set = bw_set = 0; if (tok->n_args == 2 || tok->n_args == 6) { @@ -1020,12 +1001,9 @@ routerinfo_t *router_get_entry_from_string(const char *s, router->onion_pkey = tok->key; tok->key = NULL; /* Prevent free */ - if (!(tok = find_first_by_keyword(tokens, K_LINK_KEY))) { - log_fn(LOG_WARN, "Missing onion key"); goto err; + if ((tok = find_first_by_keyword(tokens, K_LINK_KEY))) { + log_fn(LOG_INFO, "Skipping obsolete link-key"); goto err; } - /* XXX Check key length */ - router->link_pkey = tok->key; - tok->key = NULL; /* Prevent free */ if (!(tok = find_first_by_keyword(tokens, K_SIGNING_KEY))) { log_fn(LOG_WARN, "Missing onion key"); goto err; diff --git a/branches/tor-0_0_6incompat/src/or/test.c b/branches/tor-0_0_6incompat/src/or/test.c index 61daaf589b..bb20165e52 100644 --- a/branches/tor-0_0_6incompat/src/or/test.c +++ b/branches/tor-0_0_6incompat/src/or/test.c @@ -650,7 +650,7 @@ test_onion_handshake() { /* server handshake */ memset(s_buf, 0, ONIONSKIN_REPLY_LEN); memset(s_keys, 0, 40); - test_assert(! onion_skin_server_handshake(c_buf, pk, s_buf, s_keys, 40)); + test_assert(! onion_skin_server_handshake(c_buf, pk, NULL, s_buf, s_keys, 40)); /* client handshake 2 */ memset(c_keys, 0, 40); @@ -701,7 +701,6 @@ test_dir_format() r1.dir_port = 9003; r1.onion_pkey = pk1; r1.identity_pkey = pk2; - r1.link_pkey = pk3; r1.bandwidthrate = r1.bandwidthburst = 1000; r1.exit_policy = NULL; r1.nickname = "Magri"; @@ -727,7 +726,6 @@ test_dir_format() r2.dir_port = 0; r2.onion_pkey = pk2; r2.identity_pkey = pk1; - r2.link_pkey = pk2; r2.bandwidthrate = r2.bandwidthburst = 3000; r2.exit_policy = &ex1; r2.nickname = "Fred"; @@ -749,8 +747,6 @@ test_dir_format() "published 1970-01-01 00:00:00\n" "onion-key\n"); strcat(buf2, pk1_str); - strcat(buf2, "link-key\n"); - strcat(buf2, pk3_str); strcat(buf2, "signing-key\n"); strcat(buf2, pk2_str); strcat(buf2, "router-signature\n"); @@ -769,7 +765,6 @@ test_dir_format() test_eq(rp1->bandwidthrate, r1.bandwidthrate); // test_eq(rp1->bandwidthburst, r1.bandwidthburst); 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);