[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] Tested backends for directory signing and checking. Direct...



Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv22193/src/or

Modified Files:
	main.c or.h routers.c test.c 
Log Message:
Tested backends for directory signing and checking.  Directory parser completely refactored.  Need documentation and integration.  Explanitory mail forthcoming.

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -d -r1.55 -r1.56
--- main.c	7 May 2003 03:32:18 -0000	1.55
+++ main.c	7 May 2003 18:30:46 -0000	1.56
@@ -678,16 +678,17 @@
 
   dump_directory_to_string_impl(s+i, maxlen-i, dir);
   i = strlen(s);
+  strncat(s, "directory-signature\n", maxlen-i);
+  i = strlen(s);
   cp = s + i;
   
   if (crypto_SHA_digest(s, i, digest))
     return -1;
-  if (crypto_pk_private_sign(private_key, digest, 20, signature))
+  if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0)
     return -1;
   
-
   strncpy(cp, 
-          "directory-signature\n-----BEGIN SIGNATURE-----\n", maxlen-i);
+          "-----BEGIN SIGNATURE-----\n", maxlen-i);
           
   i = strlen(s);
   cp = s+i;

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -d -r1.77 -r1.78
--- or.h	7 May 2003 02:28:42 -0000	1.77
+++ or.h	7 May 2003 18:30:46 -0000	1.78
@@ -739,6 +739,8 @@
 void dumpstats(void);
 void dump_directory_to_string(char *s, int maxlen);
 void dump_directory_to_string_impl(char *s, int maxlen, directory_t *directory);
+int dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, crypto_pk_env_t *private_key);
+                                         
 
 int main(int argc, char *argv[]);
 
@@ -790,10 +792,13 @@
 int router_is_me(uint32_t addr, uint16_t port);
 void router_forget_router(uint32_t addr, uint16_t port);
 int router_get_list_from_file(char *routerfile);
+int router_resolve(routerinfo_t *router);
 int router_get_list_from_string(char *s);
 int router_get_list_from_string_impl(char *s, directory_t **dest);
+int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey);
+int router_get_dir_from_string_impl(char *s, directory_t **dest,
+                                    crypto_pk_env_t *pkey);
 routerinfo_t *router_get_entry_from_string(char **s);
-
 int router_compare_to_exit_policy(connection_t *conn);
 void routerlist_free(routerinfo_t *list);
 

Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- routers.c	7 May 2003 02:13:23 -0000	1.24
+++ routers.c	7 May 2003 18:30:46 -0000	1.25
@@ -2,7 +2,10 @@
 /* See LICENSE for licensing information */
 /* $Id$ */
 
+#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
 #define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n"
+#define OR_SIGNATURE_BEGIN_TAG "-----BEGIN SIGNATURE-----\n"
+#define OR_SIGNATURE_END_TAG "-----END SIGNATURE-----\n"
 
 #include "or.h"
 
@@ -16,14 +19,22 @@
 
 /****************************************************************************/
 
+struct directory_token;
+typedef struct directory_token directory_token_t;
+
 /* static function prototypes */
 void routerlist_free(routerinfo_t *list);
 static routerinfo_t **make_rarray(routerinfo_t* list, int *len);
 static char *eat_whitespace(char *s);
+static char *eat_whitespace_no_nl(char *s);
 static char *find_whitespace(char *s);
-static int router_resolve(routerinfo_t *router);
-static void router_add_exit_policy(routerinfo_t *router, char *string);
 static void router_free_exit_policy(routerinfo_t *router);
+static routerinfo_t *router_get_entry_from_string_tok(char**s, 
+                                                      directory_token_t *tok);
+static int router_get_list_from_string_tok(char **s, directory_t **dest,
+                                           directory_token_t *tok);
+static int router_add_exit_policy(routerinfo_t *router, 
+                                  directory_token_t *tok);
 
 /****************************************************************************/
 
@@ -288,12 +299,323 @@
   return 0;
 } 
 
+
+typedef enum {
+  K_ACCEPT,
+  K_CLIENT_SOFTWARE, 
+  K_DIRECTORY_SIGNATURE,
+  K_REJECT, 
+  K_ROUTER, 
+  K_SERVER_SOFTWARE,
+  K_SIGNED_DIRECTORY,
+  K_SIGNING_KEY,
+  _SIGNATURE, 
+  _PUBLIC_KEY, 
+  _ERR, 
+  _EOF 
+} directory_keyword;
+
+struct token_table_ent { char *t; int v; };
+
+static struct token_table_ent token_table[] = {
+  { "accept", K_ACCEPT },
+  { "client-software", K_CLIENT_SOFTWARE },
+  { "directory-signature", K_DIRECTORY_SIGNATURE },
+  { "reject", K_REJECT },
+  { "router", K_ROUTER },
+  { "server-software", K_SERVER_SOFTWARE },
+  { "signed-directory", K_SIGNED_DIRECTORY },
+  { "signing-key", K_SIGNING_KEY },
+  { NULL, -1 }
+};
+
+#define MAX_ARGS 8
+struct directory_token {
+  directory_keyword tp;
+  union {
+    struct {
+      char *args[MAX_ARGS+1]; 
+      int n_args;
+    } cmd;
+    char *signature;
+    char *error;
+    crypto_pk_env_t *public_key;
+  } val;
+};
+
+static int
+_router_get_next_token(char **s, directory_token_t *tok) {
+  char *next;
+  crypto_pk_env_t *pkey = NULL;
+  char *signature = NULL;
+  int i, done;
+
+  tok->tp = _ERR;
+  tok->val.error = "";
+
+  *s = eat_whitespace(*s);
+  if (!**s) {
+    tok->tp = _EOF;
+    return 0;
+  } else if (**s == '-') {
+    next = strchr(*s, '\n');
+    if (! next) { tok->val.error = "No newline at EOF"; return -1; }
+    ++next;
+    if (! strncmp(*s, OR_PUBLICKEY_BEGIN_TAG, next-*s)) {
+      next = strstr(*s, OR_PUBLICKEY_END_TAG);
+      if (!next) { tok->val.error = "No public key end tag found"; return -1; }
+      next = strchr(next, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/
+      ++next;
+      if (!(pkey = crypto_new_pk_env(CRYPTO_PK_RSA))) 
+        return -1;
+      if (crypto_pk_read_public_key_from_string(pkey, *s, next-*s)) {
+        crypto_free_pk_env(pkey);
+        tok->val.error = "Couldn't parse public key.";
+        return -1;
+      }
+      tok->tp = _PUBLIC_KEY;
+      tok->val.public_key = pkey;
+      *s = next;
+      return 0;
+    } else if (! strncmp(*s, OR_SIGNATURE_BEGIN_TAG, next-*s)) {
+      /* Advance past newline; can't fail. */
+      *s = strchr(*s, '\n'); 
+      ++*s;
+      /* Find end of base64'd data */
+      next = strstr(*s, OR_SIGNATURE_END_TAG);
+      if (!next) { tok->val.error = "No signature end tag found"; return -1; }
+      
+      signature = malloc(256);
+      i = base64_decode(signature, 256, *s, next-*s);
+      if (i<0) {
+        free(signature);
+        tok->val.error = "Error decoding signature."; return -1;
+      } else if (i != 128) {
+        free(signature);
+        tok->val.error = "Bad length on decoded signature."; return -1;
+      }
+      tok->tp = _SIGNATURE;
+      tok->val.signature = signature;
+
+      next = strchr(next, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/
+      *s = next+1;
+      return 0;
+    } else {
+      tok->val.error = "Unrecognized begin line"; return -1;
+    }
+  } else {
+    next = find_whitespace(*s);
+    if (!next) {
+      tok->val.error = "Unexpected EOF"; return -1;
+    }
+    for (i = 0 ; token_table[i].t ; ++i) {
+      if (!strncmp(token_table[i].t, *s, next-*s)) {
+        tok->tp = token_table[i].v;
+        i = 0;
+        done = (*next == '\n');
+        *s = eat_whitespace_no_nl(next);
+        while (**s != '\n' && i <= MAX_ARGS && !done) {
+          next = find_whitespace(*s);
+          if (*next == '\n')
+            done = 1;
+          *next = 0;
+          tok->val.cmd.args[i++] = *s;
+          *s = eat_whitespace_no_nl(next+1);
+        };
+        tok->val.cmd.n_args = i;
+        if (i > MAX_ARGS) {
+          tok->tp = _ERR;
+          tok->val.error = "Too many arguments"; return -1;
+        }
+        return 0;
+      }
+    }
+    tok->val.error = "Unrecognized command"; return -1;
+  }
+}
+
+static void 
+router_dump_token(directory_token_t *tok) {
+  int i;
+  switch(tok->tp) 
+    {
+    case _SIGNATURE:
+      puts("(signature)");
+      return;
+    case _PUBLIC_KEY:
+      puts("(public key)");
+      return;
+    case _ERR:
+      printf("(Error: %s\n)", tok->val.error);
+      return;
+    case _EOF:
+      puts("EOF");
+      return;
+    case K_ACCEPT: printf("Accept"); break;
+    case K_CLIENT_SOFTWARE: printf("Client-Software"); break;
+    case K_DIRECTORY_SIGNATURE: printf("Directory-Signature"); break;
+    case K_REJECT: printf("Reject"); break;
+    case K_ROUTER: printf("Router"); break;
+    case K_SERVER_SOFTWARE: printf("Server-Software"); break;
+    case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
+    case K_SIGNING_KEY: printf("Signing-Key"); break;
+    default:
+      printf("?????? %d\n", tok->tp); return;
+    }
+  for (i = 0; i < tok->val.cmd.n_args; ++i) {
+    printf(" \"%s\"", tok->val.cmd.args[i]);
+  }
+  printf("\n");
+  return;
+}
+
+#ifdef DEBUG_ROUTER_TOKENS
+static int
+router_get_next_token(char **s, directory_token_t *tok) {
+  int i;
+  i = _router_get_next_token(s, tok);
+  router_dump_token(tok);
+  return i;
+}
+#else
+#define router_get_next_token _router_get_next_token
+#endif
+
+
+
+/* return the first char of s that is not whitespace and not a comment */
+static char *eat_whitespace(char *s) {
+  assert(s);
+
+  while(isspace(*s) || *s == '#') {
+    while(isspace(*s))
+      s++;
+    if(*s == '#') { /* read to a \n or \0 */
+      while(*s && *s != '\n')
+        s++;
+      if(!*s)
+        return s;
+    }
+  }
+  return s;
+}
+
+static char *eat_whitespace_no_nl(char *s) {
+  while(*s == ' ' || *s == '\t') 
+    ++s;
+  return s;
+}
+
+/* return the first char of s that is whitespace or '#' or '\0 */
+static char *find_whitespace(char *s) {
+  assert(s);
+
+  while(*s && !isspace(*s) && *s != '#')
+    s++;
+
+  return s;
+}
+
 int router_get_list_from_string(char *s) 
 {
   return router_get_list_from_string_impl(s, &directory);
 }
 
-int router_get_list_from_string_impl(char *s, directory_t **dest)
+int router_get_list_from_string_impl(char *s, directory_t **dest) {
+  directory_token_t tok;
+  if (router_get_next_token(&s, &tok)) {
+    return NULL;
+  }
+  return router_get_list_from_string_tok(&s, dest, &tok);
+}
+
+static int router_get_dir_hash(char *s, char *digest)
+{
+  char *start, *end;
+  start = strstr(s, "signed-directory");
+  if (!start) return -1;
+  end = strstr(start, "directory-signature");
+  if (!end) return -1;
+  end = strchr(end, '\n');
+  if (!end) return -1;
+  ++end;
+  
+  if (crypto_SHA_digest(start, end-start, digest))
+    return -1;
+
+  return 0;
+}
+
+int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey)
+{
+  return router_get_dir_from_string_impl(s, &directory, pkey);
+}
+
+int router_get_dir_from_string_impl(char *s, directory_t **dest,
+                                    crypto_pk_env_t *pkey)
+{
+  directory_token_t tok;
+  char digest[20];
+  char signed_digest[128];
+  
+#define NEXT_TOK()                                                      \
+  do {                                                                  \
+    if (router_get_next_token(&s, &tok)) {                              \
+      log(LOG_ERR, "Error reading directory: %s", tok.val.error);       \
+      return -1;                                                        \
+    } } while (0)
+#define TOK_IS(type,name)                                               \
+  do {                                                                  \
+    if (tok.tp != type) {                                               \
+      log(LOG_ERR, "Error reading directory: expected %s", name);       \
+      return -1;                                                        \
+    } } while(0)
+  
+  if (router_get_dir_hash(s, digest))
+    return -1;
+
+  NEXT_TOK();
+  TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
+
+  NEXT_TOK();
+  TOK_IS(K_CLIENT_SOFTWARE, "client-software");
+
+  NEXT_TOK();
+  TOK_IS(K_SERVER_SOFTWARE, "server-software");
+  
+  NEXT_TOK();
+  if (router_get_list_from_string_tok(&s, dest, &tok))
+    return -1;
+  
+  TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
+  NEXT_TOK();
+  TOK_IS(_SIGNATURE, "signature");
+  if (pkey) {
+    if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest)
+        != 20) {
+      log(LOG_ERR, "Error reading directory: invalid signature.");
+      free(tok.val.signature);
+      return -1;
+    }
+    if (memcmp(digest, signed_digest, 20)) {
+      log(LOG_ERR, "Error reading directory: signature does not match.");
+      free(tok.val.signature);
+      return -1;
+    }
+  }
+  free(tok.val.signature);
+
+  NEXT_TOK();
+  TOK_IS(_EOF, "end of directory");
+
+  return 0;
+#undef NEXT_TOK
+#undef TOK_IS
+}
+
+
+static int router_get_list_from_string_tok(char **s, directory_t **dest,
+                                           directory_token_t *tok)
 {
   routerinfo_t *routerlist=NULL;
   routerinfo_t *router;
@@ -302,17 +624,8 @@
 
   assert(s);
 
-  while(*s) { /* while not at the end of the string */
-    router = router_get_entry_from_string(&s);
-    if(router == NULL) {
-      routerlist_free(routerlist);
-      return -1;
-    }
-    if (router_resolve(router)) {
-      routerlist_free(router);      
-      routerlist_free(routerlist);
-      return -1;
-    }
+  while (tok->tp == K_ROUTER) {
+    router = router_get_entry_from_string_tok(s, tok);
     switch(router_is_me(router->addr, router->or_port)) {
       case 0: /* it's not me */
         router->next = routerlist;
@@ -329,7 +642,6 @@
         routerlist_free(routerlist);
         return -1;
     }
-    s = eat_whitespace(s);
   }
  
   new_router_array = make_rarray(routerlist, &new_rarray_len);
@@ -343,34 +655,6 @@
   }
   return -1;
 }
-
-/* return the first char of s that is not whitespace and not a comment */
-static char *eat_whitespace(char *s) {
-  assert(s);
-
-  while(isspace(*s) || *s == '#') {
-    while(isspace(*s))
-      s++;
-    if(*s == '#') { /* read to a \n or \0 */
-      while(*s && *s != '\n')
-        s++;
-      if(!*s)
-        return s;
-    }
-  }
-  return s;
-}
-
-/* return the first char of s that is whitespace or '#' or '\0 */
-static char *find_whitespace(char *s) {
-  assert(s);
-
-  while(*s && !isspace(*s) && *s != '#')
-    s++;
-
-  return s;
-}
-
 static int 
 router_resolve(routerinfo_t *router)
 {
@@ -388,157 +672,102 @@
   return 0;
 }
 
+
+routerinfo_t *router_get_entry_from_string(char **s) {
+  directory_token_t tok;
+  routerinfo_t *router;
+  if (router_get_next_token(s, &tok)) return NULL;
+  router = router_get_entry_from_string_tok(s, &tok);
+  if (tok.tp != _EOF)
+    return NULL;
+  return router;
+}
+
 /* reads a single router entry from s.
  * updates s so it points to after the router it just read.
  * mallocs a new router, returns it if all goes well, else returns NULL.
  */
-routerinfo_t *router_get_entry_from_string(char **s) {
-  routerinfo_t *router;
-  char *next;
+static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t *tok) {
+  routerinfo_t *router = NULL;
 
-  /* Make sure that this string really starts with a router entry. */
-  *s = eat_whitespace(*s);
-  if (strncasecmp(*s, "router ", 7)) {
+#define NEXT_TOKEN()                                 \
+  do { if (router_get_next_token(s, tok)) goto err;  \
+  } while(0)
+
+#define ARGS tok->val.cmd.args
+
+  if (tok->tp != K_ROUTER) {
     log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\"");
     return NULL;
   }
-
-  router = malloc(sizeof(routerinfo_t));
-  if (!router) {
+  if (!(router = malloc(sizeof(routerinfo_t)))) {
     log(LOG_ERR,"router_get_entry_from_string(): Could not allocate memory.");
     return NULL;
   }
   memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
   router->next = NULL;
 
-/* Bug: if find_whitespace returns a '#', we'll squish it. */
-#define NEXT_TOKEN(s, next)    \
-  *s = eat_whitespace(*s);     \
-  next = find_whitespace(*s);  \
-  if(!*next) {                 \
-    goto router_read_failed;   \
-  }                            \
-  *next = 0;
-
-  /* Skip the "router" */
-  NEXT_TOKEN(s, next);
-  *s = next+1;
-
-  /* read router->address */
-  NEXT_TOKEN(s, next);
-  router->address = strdup(*s);
-  *s = next+1;
+  if (tok->val.cmd.n_args != 6) {
+    log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\"");
+    goto err;
+  }
 
-  /* Don't resolve address till later. */
+  /* read router.address */
+  if (!(router->address = strdup(ARGS[0])))
+    goto err;
   router->addr = 0;
 
-  /* read router->or_port */
-  NEXT_TOKEN(s, next);
-  router->or_port = atoi(*s);
+  /* Read router->or_port */
+  router->or_port = atoi(ARGS[1]);
   if(!router->or_port) {
-    log(LOG_ERR,"router_get_entry_from_string(): or_port '%s' unreadable or 0. Failing.",*s);
-    goto router_read_failed;
+    log(LOG_ERR,"router_get_entry_from_string(): or_port unreadable or 0. Failing.");
+    goto err;
   }
-  *s = next+1;
   
-  /* read router->op_port */
-  NEXT_TOKEN(s, next);
-  router->op_port = atoi(*s);
-  *s = next+1;
+  /* Router->op_port */
+  router->op_port = atoi(ARGS[2]);
   
-  /* read router->ap_port */
-  NEXT_TOKEN(s, next);
-  router->ap_port = atoi(*s);
-  *s = next+1;
+  /* Router->ap_port */
+  router->ap_port = atoi(ARGS[3]);
   
-  /* read router->dir_port */
-  NEXT_TOKEN(s, next);
-  router->dir_port = atoi(*s);
-  *s = next+1;
+  /* Router->dir_port */
+  router->dir_port = atoi(ARGS[4]);
 
-  /* read router->bandwidth */
-  NEXT_TOKEN(s, next);
-  router->bandwidth = atoi(*s);
-  if(!router->bandwidth) {
-    log(LOG_ERR,"router_get_entry_from_string(): bandwidth '%s' unreadable or 0. Failing.",*s);
-    goto router_read_failed;
+  /* Router->bandwidth */
+  router->bandwidth = atoi(ARGS[5]);
+  if (!router->bandwidth) {
+    log(LOG_ERR,"router_get_entry_from_string(): bandwidth unreadable or 0. Failing.");
   }
-  *s = next+1;
-
+  
   log(LOG_DEBUG,"or_port %d, op_port %d, ap_port %d, dir_port %d, bandwidth %d.",
     router->or_port, router->op_port, router->ap_port, router->dir_port, router->bandwidth);
 
-  *s = eat_whitespace(*s); 
-  next = strstr(*s,OR_PUBLICKEY_END_TAG);
-  router->pkey = crypto_new_pk_env(CRYPTO_PK_RSA);
-  if(!next || !router->pkey) {
-    log(LOG_ERR,"router_get_entry_from_string(): Couldn't find pk in string");
-    goto router_read_failed;
-  }
-  
-  /* now advance *s so it's at the end of this public key */
-  next = strchr(next, '\n');
-  assert(next); /* can't fail, we just checked it was here */
-  *next = 0;
-//  log(LOG_DEBUG,"Key about to be read is: '%s'",*s);
-  if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) {
-    log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string");
-    goto router_read_failed;
-  }
-  log(LOG_DEBUG,"router_get_entry_from_string(): Public key size = %u.", crypto_pk_keysize(router->pkey));
-
-  if (crypto_pk_keysize(router->pkey) != 128) { /* keys MUST be 1024 bits in size */
-    log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.",
-      router->address,router->or_port);
-    goto router_read_failed;
-  }
-
-  *s = next+1;
-  *s = eat_whitespace(*s);
-  if (!strncasecmp(*s, "signing-key", 11)) {
-    /* We have a signing key */
-    *s = strchr(*s, '\n');
-    *s = eat_whitespace(*s); 
-    next = strstr(*s,OR_PUBLICKEY_END_TAG);
-    router->signing_pkey = crypto_new_pk_env(CRYPTO_PK_RSA);
-    if (!next || !router->signing_pkey) {
-      log(LOG_ERR,"router_get_entry_from_string(): Couldn't find signing_pk in string");
-      goto router_read_failed;
-    }
-    next = strchr(next, '\n');
-    assert(next);
-    *next = 0;
-    if ((crypto_pk_read_public_key_from_string(router->signing_pkey, *s,
-                                               strlen(*s)))<0) {
-      log(LOG_ERR,"router_get_entry_from_string(): Couldn't read signing pk from string");
-      goto router_read_failed;
-    }
-
-    log(LOG_DEBUG,"router_get_entry_from_string(): Signing key size = %u.", crypto_pk_keysize(router->signing_pkey));
+  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;
 
-    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;
+  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;
     }
-    *s = next+1;
-  }
-      
-  //  test_write_pkey(router->pkey);  
+    router->signing_pkey = tok->val.public_key;
+    NEXT_TOKEN();
+  } 
 
-  while(**s && **s != '\n') {
-    /* pull in a line of exit policy */
-    next = strchr(*s, '\n');
-    if(!next)
-      goto router_read_failed;
-    *next = 0;
-    router_add_exit_policy(router, *s);
-    *s = next+1;
+  while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
+    router_add_exit_policy(router, tok);
+    NEXT_TOKEN();
   }
-
+  
   return router;
 
-router_read_failed:
+ err:
   if(router->address)
     free(router->address);
   if(router->pkey)
@@ -546,6 +775,8 @@
   router_free_exit_policy(router);
   free(router);
   return NULL;
+#undef ARGS
+#undef NEXT_TOKEN
 }
 
 static void router_free_exit_policy(routerinfo_t *router) {
@@ -576,43 +807,35 @@
 }
 #endif
 
-static void router_add_exit_policy(routerinfo_t *router, char *string) {
+static int router_add_exit_policy(routerinfo_t *router, 
+                                  directory_token_t *tok) {
   struct exit_policy_t *tmpe, *newe;
-  char *n;
+  char *arg, *colon;
 
-  string = eat_whitespace(string);
-  if(!*string) /* it was all whitespace or comment */
-    return;
+  if (tok->val.cmd.n_args != 1)
+    return -1;
+  arg = tok->val.cmd.args[0];
 
   newe = malloc(sizeof(struct exit_policy_t));
   memset(newe,0,sizeof(struct exit_policy_t));
-
-  newe->string = strdup(string);
-  n = find_whitespace(string);
-  *n = 0;
-
-  if(!strcasecmp(string,"reject")) {
+  
+  newe->string = malloc(8+strlen(arg));
+  if (tok->tp == K_REJECT) {
+    strcpy(newe->string, "reject ");
     newe->policy_type = EXIT_POLICY_REJECT;
-  } else if(!strcasecmp(string,"accept")) {
-    newe->policy_type = EXIT_POLICY_ACCEPT;
   } else {
-    goto policy_read_failed;
-  }
-
-  string = eat_whitespace(n+1);
-  if(!*string) {
-    goto policy_read_failed;
+    assert(tok->tp == K_ACCEPT);
+    strcpy(newe->string, "accept ");
+    newe->policy_type = EXIT_POLICY_ACCEPT;
   }
-
-  n = strchr(string,':');
-  if(!n)
+  strcat(newe->string, arg);
+  
+  colon = strchr(arg,':');
+  if(!colon)
     goto policy_read_failed;
-  *n = 0;
-  newe->address = strdup(string);
-  string = n+1;
-  n = find_whitespace(string);
-  *n = 0;
-  newe->port = strdup(string);
+  *colon = 0;
+  newe->address = strdup(arg);
+  newe->port = strdup(colon+1);
 
   log(LOG_DEBUG,"router_add_exit_policy(): type %d, address '%s', port '%s'.",
       newe->policy_type, newe->address, newe->port);
@@ -621,13 +844,13 @@
 
   if(!router->exit_policy) {
     router->exit_policy = newe;
-    return;
+    return 0;
   }
 
   for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ;
   tmpe->next = newe;
 
-  return;
+  return 0;
 
 policy_read_failed:
   assert(newe->string);
@@ -639,8 +862,7 @@
   if(newe->port)
     free(newe->port);
   free(newe);
-  return;
-
+  return -1;
 }
 
 /* Return 0 if my exit policy says to allow connection to conn.

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/src/or/test.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- test.c	7 May 2003 02:28:42 -0000	1.15
+++ test.c	7 May 2003 18:30:46 -0000	1.16
@@ -405,7 +405,7 @@
   memcpy(data2+1, "XYZZY", 5);  /* This has fails ~ once-in-2^40 */
   test_eq(-1, crypto_pk_private_decrypt(pk1, data2, 128, data3,
                                         RSA_PKCS1_OAEP_PADDING));
-
+  
   /* File operations: save and load private key */
   f = fopen("/tmp/tor_test/pkey1", "wb");
   test_assert(! crypto_pk_write_private_key_to_file(pk1, f));
@@ -419,11 +419,28 @@
                                                "/tmp/tor_test/pkey1"));
   test_eq(15, crypto_pk_private_decrypt(pk2, data1, 128, data3,
                                         RSA_PKCS1_OAEP_PADDING));
-    
 
+  /* Now try signing. */
+  strcpy(data1, "Ossifrage");
+  test_eq(128, crypto_pk_private_sign(pk1, data1, 10, data2));
+  test_eq(10, crypto_pk_public_checksig(pk1, data2, 128, data3));
+  test_streq(data3, "Ossifrage");
+  /*XXXX test failed signing*/
+    
   crypto_free_pk_env(pk1);  
   crypto_free_pk_env(pk2);  
 
+  /* Base64 tests */
+  strcpy(data1, "Test string that contains 35 chars.");
+  strcat(data1, " 2nd string that contains 35 chars.");
+
+  i = base64_encode(data2, 1024, data1, 71);
+  j = base64_decode(data3, 1024, data2, i);
+  test_streq(data3, data1);
+  test_eq(j, 71);
+  test_assert(data2[i] == '\0');
+
+
   free(data1);
   free(data2);
   free(data3);
@@ -512,9 +529,8 @@
   routerinfo_t r1, r2;
   crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
   routerinfo_t *rp1, *rp2;
-  struct exit_policy_t ex1, ex2, ex3;
-
-  int i;
+  struct exit_policy_t ex1, ex2;
+  directory_t *dir1 = NULL, *dir2 = NULL;
 
   test_assert( (pk1 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
   test_assert( (pk2 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
@@ -609,8 +625,15 @@
   test_assert(rp2->exit_policy->next->next == NULL);
 
   /* Okay, now for the directories. */
+  dir1 = (directory_t*) malloc(sizeof(directory_t));
+  dir1->n_routers = 2;
+  dir1->routers = (routerinfo_t**) malloc(sizeof(routerinfo_t*)*2);
+  dir1->routers[0] = &r1;
+  dir1->routers[1] = &r2;
+  test_assert(! dump_signed_directory_to_string_impl(buf, 2048, dir1, pk1));
+  /* puts(buf); */
   
-
+  test_assert(! router_get_dir_from_string_impl(buf, &dir2, pk1));
 
   if (pk1_str) free(pk1_str);
   if (pk2_str) free(pk2_str);
@@ -618,6 +641,8 @@
   if (pk2) crypto_free_pk_env(pk2);
   if (rp1) routerlist_free(rp1);
   if (rp2) routerlist_free(rp2);
+  if (dir1) free(dir1); /* And more !*/
+  if (dir1) free(dir2); /* And more !*/
 }
 
 int