More work on directories. Signed directories not yet tested. No support for checking sigs yet

svn:r268
This commit is contained in:
Nick Mathewson 2003-05-07 02:13:23 +00:00
parent 3416a10627
commit d0ff485e1b
7 changed files with 218 additions and 30 deletions

View File

@ -83,8 +83,8 @@ SPEC!! - Handle socks commands other than connect, eg, bind?
o Cells
. Better comments for functions!
- Tests
NICK o Testing harness/infrastructure
. Unit tests
o Testing harness/infrastructure
NICK . Unit tests
D System tests (how?)
- Performance tests, so we know when we've improved
. webload infrastructure (Bruce)

View File

@ -545,6 +545,36 @@ int crypto_pk_private_decrypt(crypto_pk_env_t *env, unsigned char *from, int fro
}
}
int crypto_pk_public_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to)
{
assert(env && from && to);
switch(env->type) {
case CRYPTO_PK_RSA:
if (!(((RSA*)env->key)->p))
return -1;
return RSA_public_decrypt(fromlen, from, to, (RSA *)env->key,
RSA_PKCS1_OAEP_PADDING);
default:
return -1;
}
}
int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to)
{
assert(env && from && to);
switch(env->type) {
case CRYPTO_PK_RSA:
if (!(((RSA*)env->key)->p))
return -1;
return RSA_private_encrypt(fromlen, from, to, (RSA *)env->key,
RSA_PKCS1_OAEP_PADDING);
default:
return -1;
}
}
/* symmetric crypto */
int crypto_cipher_generate_key(crypto_cipher_env_t *env)
{
@ -779,3 +809,38 @@ char *crypto_perror()
return (char *)ERR_reason_error_string(ERR_get_error());
}
int
base64_encode(char *dest, int destlen, char *src, int srclen)
{
EVP_ENCODE_CTX ctx;
int len, ret;
/* 48 bytes of input -> 64 bytes of output plus newline.
Plus one more byte, in case I'm wrong.
*/
if (destlen < ((srclen/48)+1)*66)
return -1;
EVP_EncodeInit(&ctx);
EVP_EncodeUpdate(&ctx, dest, &len, src, srclen);
EVP_EncodeFinal(&ctx, dest, &ret);
ret += len;
return ret;
}
int
base64_decode(char *dest, int destlen, char *src, int srclen)
{
EVP_ENCODE_CTX ctx;
int len, ret;
/* 64 bytes of input -> *up to* 48 bytes of output.
Plus one more byte, in caes I'm wrong.
*/
if (destlen < ((srclen/64)+1)*49)
return -1;
EVP_DecodeInit(&ctx);
EVP_DecodeUpdate(&ctx, dest, &len, src, srclen);
EVP_DecodeFinal(&ctx, dest, &ret);
ret += len;
return ret;
}

View File

@ -64,6 +64,11 @@ int crypto_pk_keysize(crypto_pk_env_t *env);
int crypto_pk_public_encrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding);
int crypto_pk_private_decrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding);
int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to);
int crypto_pk_private_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to);
int base64_encode(char *dest, int destlen, char *src, int srclen);
int base64_decode(char *dest, int destlen, char *src, int srclen);
/* Key negotiation */
typedef struct crypto_dh_env_st crypto_dh_env_t;

View File

@ -555,7 +555,8 @@ void dumpstats(void) { /* dump stats to stdout */
int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) {
char *pkey;
int pkeylen;
char *signing_pkey, *signing_pkey_tag;
int pkeylen, signing_pkeylen;
int written;
int result=0;
struct exit_policy_t *tmpe;
@ -565,16 +566,30 @@ int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) {
return 0;
}
result = snprintf(s, maxlen, "router %s %d %d %d %d %d\n%s",
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";
}
result = snprintf(s, maxlen, "router %s %d %d %d %d %d\n%s%s%s",
router->address,
router->or_port,
router->op_port,
router->ap_port,
router->dir_port,
router->bandwidth,
pkey);
pkey,
signing_pkey_tag, signing_pkey);
free(pkey);
if (*signing_pkey)
free(signing_pkey);
if(result < 0 || result > maxlen) {
/* apparently different glibcs do different things on snprintf error.. so check both */
@ -607,21 +622,23 @@ int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) {
}
void dump_directory_to_string(char *s, int maxlen) {
int i;
void dump_directory_to_string(char *s, int maxlen)
{
directory_t dir;
routerinfo_t **routers = NULL;;
connection_t *conn;
routerinfo_t *router;
int written;
int i, n = 0;
/* first write my own info */
if(my_routerinfo) {
written = dump_router_to_string(s, maxlen, my_routerinfo);
maxlen -= written;
s += written;
routers = (routerinfo_t**) malloc(sizeof(routerinfo_t*) * (nfds+1));
if (!routers) {
/* freak out XXX */
return;
}
/* now write info for other routers */
for(i=0;i<nfds;i++) {
if (my_routerinfo) {
routers[n++] = my_routerinfo;
}
for(i = 0; i<nfds; ++i) {
conn = connection_array[i];
if(conn->type != CONN_TYPE_OR)
@ -633,7 +650,64 @@ void dump_directory_to_string(char *s, int maxlen) {
log(LOG_ERR,"dump_directory_to_string(): couldn't find router %d:%d!",conn->addr,conn->port);
continue;
}
routers[n++] = router;
}
dir.routers = routers;
dir.n_routers = n;
dump_directory_to_string_impl(s, maxlen, &dir);
}
int
dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir,
crypto_pk_env_t *private_key)
{
char *cp;
char digest[20];
char signature[128];
int i;
strncpy(s,
"signed-directory\n"
"client-software x y z\n" /* XXX make this real */
"server-software a b c\n\n" /* XXX make this real */
, maxlen);
/* These multiple strlen calls are inefficient, but dwarfed by the RSA
signature.
*/
i = strlen(s);
dump_directory_to_string_impl(s+i, maxlen-i, dir);
i = strlen(s);
cp = s + i;
if (crypto_SHA_digest(s, i, digest))
return -1;
if (crypto_pk_private_sign(private_key, digest, 20, signature))
return -1;
strncpy(cp,
"directory-signature\n-----BEGIN SIGNATURE-----\n", maxlen-i);
i = strlen(s);
cp = s+i;
if (base64_encode(cp, maxlen-i, signature, 128) < 0)
return -1;
i = strlen(s);
cp = s+i;
strcat(cp, "-----END SIGNATURE-----\n");
return 0;
}
void dump_directory_to_string_impl(char *s, int maxlen, directory_t *directory) {
int i;
routerinfo_t *router;
int written;
for (i = 0; i < directory->n_routers; ++i) {
router = directory->routers[i];
written = dump_router_to_string(s, maxlen, router);
if(written < 0) {
@ -645,7 +719,6 @@ void dump_directory_to_string(char *s, int maxlen) {
maxlen -= written;
s += written;
}
}
void daemonize(void) {

View File

@ -320,6 +320,7 @@ typedef struct {
uint16_t dir_port;
crypto_pk_env_t *pkey; /* public RSA key */
crypto_pk_env_t *signing_pkey; /* May be null */
/* link info */
uint32_t bandwidth;
@ -737,6 +738,7 @@ int do_main_loop(void);
void dumpstats(void);
void dump_directory_to_string(char *s, int maxlen);
void dump_directory_to_string_impl(char *s, int maxlen, directory_t *directory);
int main(int argc, char *argv[]);
@ -793,6 +795,7 @@ int router_get_list_from_string_impl(char *s, directory_t **dest);
routerinfo_t *router_get_entry_from_string(char **s);
int router_compare_to_exit_policy(connection_t *conn);
void routerlist_free(routerinfo_t *list);
#endif

View File

@ -17,7 +17,7 @@ extern routerinfo_t *my_routerinfo; /* from main.c */
/****************************************************************************/
/* static function prototypes */
static void routerlist_free(routerinfo_t *list);
void routerlist_free(routerinfo_t *list);
static routerinfo_t **make_rarray(routerinfo_t* list, int *len);
static char *eat_whitespace(char *s);
static char *find_whitespace(char *s);
@ -124,7 +124,7 @@ int router_is_me(uint32_t addr, uint16_t port)
}
/* delete a list of routers from memory */
static void routerlist_free(routerinfo_t *list)
void routerlist_free(routerinfo_t *list)
{
routerinfo_t *tmp = NULL;
struct exit_policy_t *e = NULL, *etmp = NULL;
@ -402,7 +402,6 @@ routerinfo_t *router_get_entry_from_string(char **s) {
log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\"");
return NULL;
}
puts("X");
router = malloc(sizeof(routerinfo_t));
if (!router) {
@ -477,7 +476,7 @@ routerinfo_t *router_get_entry_from_string(char **s) {
goto router_read_failed;
}
/* now advance *s so it's at the end of this router entry */
/* now advance *s so it's at the end of this public key */
next = strchr(next, '\n');
assert(next); /* can't fail, we just checked it was here */
*next = 0;
@ -494,10 +493,40 @@ routerinfo_t *router_get_entry_from_string(char **s) {
goto router_read_failed;
}
// test_write_pkey(router->pkey);
*s = next+1;
while(**s != '\n') {
*s = eat_whitespace(*s);
if (!strncasecmp(*s, "signing-key", 11)) {
/* We have a signing key */
*s = strchr(*s, '\n');
*s = eat_whitespace(*s);
next = strstr(*s,OR_PUBLICKEY_END_TAG);
router->signing_pkey = crypto_new_pk_env(CRYPTO_PK_RSA);
if (!next || !router->signing_pkey) {
log(LOG_ERR,"router_get_entry_from_string(): Couldn't find signing_pk in string");
goto router_read_failed;
}
next = strchr(next, '\n');
assert(next);
*next = 0;
if ((crypto_pk_read_public_key_from_string(router->signing_pkey, *s,
strlen(*s)))<0) {
log(LOG_ERR,"router_get_entry_from_string(): Couldn't read signing pk from string");
goto router_read_failed;
}
log(LOG_DEBUG,"router_get_entry_from_string(): Signing key size = %u.", crypto_pk_keysize(router->signing_pkey));
if (crypto_pk_keysize(router->signing_pkey) != 128) { /* keys MUST be 1024 bits in size */
log(LOG_ERR,"Signing key for router %s:%u is 1024 bits. All keys must be exactly 1024 bits long.",
router->address,router->or_port);
goto router_read_failed;
}
*s = next+1;
}
// test_write_pkey(router->pkey);
while(**s && **s != '\n') {
/* pull in a line of exit policy */
next = strchr(*s, '\n');
if(!next)
@ -509,7 +538,6 @@ routerinfo_t *router_get_entry_from_string(char **s) {
return router;
router_read_failed:
if(router->address)
free(router->address);

View File

@ -506,8 +506,8 @@ void
test_dir_format()
{
char buf[2048], buf2[512];
char *pk1_str, *pk2_str, *cp;
char buf[2048], buf2[2048];
char *pk1_str = NULL, *pk2_str = NULL, *cp;
int pk1_str_len, pk2_str_len;
routerinfo_t r1, r2;
crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
@ -528,6 +528,7 @@ test_dir_format()
r1.ap_port = 9002;
r1.dir_port = 9003;
r1.pkey = pk1;
r1.signing_pkey = NULL;
r1.bandwidth = 1000;
r1.exit_policy = NULL;
r1.next = &r2;
@ -548,6 +549,7 @@ test_dir_format()
r2.ap_port = 0;
r2.dir_port = 0;
r2.pkey = pk2;
r2.signing_pkey = pk1;
r2.bandwidth = 3000;
r2.exit_policy = &ex1;
r2.next = NULL;
@ -574,10 +576,13 @@ test_dir_format()
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(rp1->exit_policy == NULL);
strcpy(buf2, "router tor.tor.tor 9005 0 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_streq(buf, buf2);
@ -592,6 +597,7 @@ test_dir_format()
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_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT);
test_streq(rp2->exit_policy->string, "accept *:80");
test_streq(rp2->exit_policy->address, "*");
@ -601,9 +607,17 @@ 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);
/* Okay, now for the directories. */
/* XXXX free everything*/
if (pk1_str) free(pk1_str);
if (pk2_str) free(pk2_str);
if (pk1) crypto_free_pk_env(pk1);
if (pk2) crypto_free_pk_env(pk2);
if (rp1) routerlist_free(rp1);
if (rp2) routerlist_free(rp2);
}
int
@ -617,7 +631,7 @@ main(int c, char**v) {
log(LOG_ERR,NULL); /* make logging quieter */
setup_directory();
#if 1
#if 0
puts("========================== Buffers =========================");
test_buffers();
puts("========================== Crypto ==========================");