[or-cvs] r16598: {tor} Apply proposal 121 patch 3, with minor tweaks and a few comm (tor/trunk/src/or)

nickm at seul.org nickm at seul.org
Tue Aug 19 15:41:29 UTC 2008


Author: nickm
Date: 2008-08-19 11:41:28 -0400 (Tue, 19 Aug 2008)
New Revision: 16598

Modified:
   tor/trunk/src/or/or.h
   tor/trunk/src/or/rendcommon.c
   tor/trunk/src/or/rendservice.c
   tor/trunk/src/or/routerparse.c
   tor/trunk/src/or/test.c
Log:
Apply proposal 121 patch 3, with minor tweaks and a few comments.

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2008-08-19 15:33:03 UTC (rev 16597)
+++ tor/trunk/src/or/or.h	2008-08-19 15:41:28 UTC (rev 16598)
@@ -651,6 +651,23 @@
  * exchanging client authorization between hidden service and client. */
 #define REND_DESC_COOKIE_LEN_BASE64 22
 
+/** Length of client identifier in encrypted introduction points for hidden
+ * service authorization type 'basic'. */
+#define REND_BASIC_AUTH_CLIENT_ID_LEN 4
+
+/** Multiple of the number of clients to which the real number of clients
+ * is padded with fake clients for hidden service authorization type
+ * 'basic'. */
+#define REND_BASIC_AUTH_CLIENT_MULTIPLE 16
+
+/** Length of client entry consisting of client identifier and encrypted
+ * session key for hidden service authorization type 'basic'. */
+#define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \
+                                          + CIPHER_KEY_LEN)
+
+/** Maximum size of v2 hidden service descriptors. */
+#define REND_DESC_MAX_SIZE (20 * 1024)
+
 /** Legal characters for use in authorized client names for a hidden
  * service. */
 #define REND_LEGAL_CLIENTNAME_CHARACTERS \
@@ -3926,7 +3943,9 @@
 int rend_cache_size(void);
 int rend_encode_v2_descriptors(smartlist_t *descs_out,
                                rend_service_descriptor_t *desc, time_t now,
-                               const char *descriptor_cookie, uint8_t period);
+                               uint8_t period, rend_auth_type_t auth_type,
+                               crypto_pk_env_t *client_key,
+                               smartlist_t *client_cookies);
 int rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
                             const char *descriptor_cookie,
                             time_t now, uint8_t replica);
@@ -4315,10 +4334,14 @@
                                      size_t *intro_points_encrypted_size_out,
                                      size_t *encoded_size_out,
                                      const char **next_out, const char *desc);
-int rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
+int rend_decrypt_introduction_points(char **ipos_decrypted,
+                                     size_t *ipos_decrypted_size,
                                      const char *descriptor_cookie,
-                                     const char *intro_content,
-                                     size_t intro_size);
+                                     const char *ipos_encrypted,
+                                     size_t ipos_encrypted_size);
+int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
+                                   const char *intro_points_encoded,
+                                   size_t intro_points_encoded_size);
 int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
 
 #endif

Modified: tor/trunk/src/or/rendcommon.c
===================================================================
--- tor/trunk/src/or/rendcommon.c	2008-08-19 15:33:03 UTC (rev 16597)
+++ tor/trunk/src/or/rendcommon.c	2008-08-19 15:41:28 UTC (rev 16598)
@@ -150,15 +150,11 @@
   return 0;
 }
 
-/* Encode the introduction points in <b>desc</b>, optionally encrypt them with
- * an optional <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN,
- * encode it in base64, and write it to a newly allocated string, and write a
- * pointer to it to *<b>ipos_base64</b>. Return 0 for success, -1
- * otherwise. */
+/** Encode the introduction points in <b>desc</b> and write the result to a
+ * newly allocated string pointed to by <b>encoded</b>. Return 0 for
+ * success, -1 otherwise. */
 static int
-rend_encode_v2_intro_points(char **ipos_base64,
-                            rend_service_descriptor_t *desc,
-                            const char *descriptor_cookie)
+rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
 {
   size_t unenc_len;
   char *unenc = NULL;
@@ -166,7 +162,6 @@
   int i;
   int r = -1;
   /* Assemble unencrypted list of introduction points. */
-  *ipos_base64 = NULL;
   unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */
   unenc = tor_malloc_zero(unenc_len);
   for (i = 0; i < smartlist_len(desc->intro_nodes); i++) {
@@ -231,37 +226,163 @@
   }
   unenc[unenc_written++] = '\n';
   unenc[unenc_written++] = 0;
-  /* If a descriptor cookie is passed, encrypt introduction points. */
-  if (descriptor_cookie) {
-    char *enc = tor_malloc_zero(unenc_written + CIPHER_IV_LEN);
-    crypto_cipher_env_t *cipher =
-      crypto_create_init_cipher(descriptor_cookie, 1);
-    int enclen = crypto_cipher_encrypt_with_iv(cipher, enc,
-                                               unenc_written + CIPHER_IV_LEN,
-                                               unenc, unenc_written);
+  *encoded = unenc;
+  r = 0;
+ done:
+  if (r<0)
+    tor_free(unenc);
+  return r;
+}
+
+/** Encrypt the encoded introduction points in <b>encoded</b> using
+ * authorization type  'basic' with <b>client_cookies</b> and write the
+ * result to a newly allocated string pointed to by <b>encrypted_out</b> of
+ * length <b>encrypted_len</b>. Return 0 for success, -1 otherwise. */
+static int
+rend_encrypt_v2_intro_points_basic(char **encrypted_out,
+                                   size_t *encrypted_len_out,
+                                   const char *encoded,
+                                   smartlist_t *client_cookies)
+{
+  int r = -1, i, pos, enclen, client_blocks;
+  size_t len, client_entries_len;
+  char *enc = NULL, iv[CIPHER_IV_LEN], *client_part = NULL,
+       session_key[CIPHER_KEY_LEN];
+  smartlist_t *encrypted_session_keys = NULL;
+  crypto_digest_env_t *digest;
+  crypto_cipher_env_t *cipher;
+  tor_assert(encoded);
+  tor_assert(client_cookies && smartlist_len(client_cookies) > 0);
+
+  /* Generate session key. */
+  if (crypto_rand(session_key, CIPHER_KEY_LEN) < 0) {
+    log_warn(LD_REND, "Unable to generate random session key to encrypt "
+                      "introduction point string.");
+    goto done;
+  }
+
+  /* Determine length of encrypted introduction points including session
+   * keys. */
+  client_blocks = 1 + ((smartlist_len(client_cookies) - 1) /
+                       REND_BASIC_AUTH_CLIENT_MULTIPLE);
+  client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
+                       REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
+  len = 2 + client_entries_len + CIPHER_IV_LEN + strlen(encoded);
+  if (client_blocks >= 256) {
+    log_warn(LD_REND, "Too many clients in introduction point string.");
+    goto done;
+  }
+  enc = tor_malloc_zero(len);
+  enc[0] = 0x01; /* type of authorization. */
+  enc[1] = (uint8_t)client_blocks;
+
+  /* Encrypt with random session key. */
+  cipher = crypto_create_init_cipher(session_key, 1);
+  enclen = crypto_cipher_encrypt_with_iv(cipher,
+      enc + 2 + client_entries_len,
+      CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded));
+  crypto_free_cipher_env(cipher);
+  if (enclen < 0) {
+    log_warn(LD_REND, "Could not encrypt introduction point string.");
+    goto done;
+  }
+  memcpy(iv, enc + 2 + client_entries_len, CIPHER_IV_LEN);
+
+  /* Encrypt session key for cookies, determine client IDs, and put both
+   * in a smartlist. */
+  encrypted_session_keys = smartlist_create();
+  SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) {
+    client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
+    /* Encrypt session key. */
+    cipher = crypto_create_init_cipher(cookie, 1);
+    if (crypto_cipher_encrypt(cipher, client_part +
+                                  REND_BASIC_AUTH_CLIENT_ID_LEN,
+                              session_key, CIPHER_KEY_LEN) < 0) {
+      log_warn(LD_REND, "Could not encrypt session key for client.");
+      crypto_free_cipher_env(cipher);
+      tor_free(client_part);
+      goto done;
+    }
     crypto_free_cipher_env(cipher);
-    if (enclen < 0) {
-      log_warn(LD_REND, "Could not encrypt introduction point string.");
-      tor_free(enc);
+
+    /* Determine client ID. */
+    digest = crypto_new_digest_env();
+    crypto_digest_add_bytes(digest, cookie, REND_DESC_COOKIE_LEN);
+    crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
+    crypto_digest_get_digest(digest, client_part,
+                             REND_BASIC_AUTH_CLIENT_ID_LEN);
+    crypto_free_digest_env(digest);
+
+    /* Put both together. */
+    smartlist_add(encrypted_session_keys, client_part);
+  } SMARTLIST_FOREACH_END(cookie);
+
+  /* Add some fake client IDs and encrypted session keys. */
+  for (i = (smartlist_len(client_cookies) - 1) %
+           REND_BASIC_AUTH_CLIENT_MULTIPLE;
+       i < REND_BASIC_AUTH_CLIENT_MULTIPLE - 1; i++) {
+    client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
+    if (crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN) < 0) {
+      log_warn(LD_REND, "Unable to generate fake client entry.");
+      tor_free(client_part);
       goto done;
     }
-    /* Replace original string with the encrypted one. */
-    tor_free(unenc);
-    unenc = enc;
-    unenc_written = enclen;
+    smartlist_add(encrypted_session_keys, client_part);
   }
-  /* Base64-encode introduction points. */
-  *ipos_base64 = tor_malloc_zero(unenc_written * 2);
-  if (base64_encode(*ipos_base64, unenc_written * 2, unenc, unenc_written)<0) {
-    log_warn(LD_REND, "Could not encode introduction point string to "
-             "base64.");
+  /* Sort smartlist and put elements in result in order. */
+  smartlist_sort_digests(encrypted_session_keys);
+  pos = 2;
+  SMARTLIST_FOREACH(encrypted_session_keys, const char *, entry, {
+    memcpy(enc + pos, entry, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
+    pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
+  });
+  *encrypted_out = enc;
+  *encrypted_len_out = len;
+  enc = NULL; /* prevent free. */
+  r = 0;
+ done:
+  tor_free(enc);
+  if (encrypted_session_keys) {
+    SMARTLIST_FOREACH(encrypted_session_keys, char *, d, tor_free(d););
+    smartlist_free(encrypted_session_keys);
+  }
+  return r;
+}
+
+/** Encrypt the encoded introduction points in <b>encoded</b> using
+ * authorization type 'stealth' with <b>descriptor_cookie</b> of length
+ * REND_DESC_COOKIE_LEN and write the result to a newly allocated string
+ * pointed to by <b>encrypted</b> of length <b>encrypted_len</b>. Return 0
+ * for success, -1 otherwise. */
+static int
+rend_encrypt_v2_intro_points_stealth(char **encrypted_out,
+                                     size_t *encrypted_len_out,
+                                     const char *encoded,
+                                     const char *descriptor_cookie)
+{
+  int r = -1, enclen;
+  crypto_cipher_env_t *cipher;
+  char *enc;
+  tor_assert(encoded);
+  tor_assert(descriptor_cookie);
+
+  enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded));
+  enc[0] = 0x02; /* Auth type */
+  cipher = crypto_create_init_cipher(descriptor_cookie, 1);
+  enclen = crypto_cipher_encrypt_with_iv(cipher, enc + 1,
+                                         CIPHER_IV_LEN+strlen(encoded),
+                                         encoded, strlen(encoded));
+  crypto_free_cipher_env(cipher);
+  if (enclen < 0) {
+    log_warn(LD_REND, "Could not encrypt introduction point string.");
     goto done;
   }
+  *encrypted_out = enc;
+  *encrypted_len_out = enclen;
+  enc = NULL; /* prevent free */
   r = 0;
  done:
-  if (r<0)
-    tor_free(*ipos_base64);
-  tor_free(unenc);
+  tor_free(enc);
   return r;
 }
 
@@ -308,38 +429,97 @@
 }
 
 /** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b>
- * at time <b>now</b> using <b>descriptor_cookie</b> (may be <b>NULL</b> if
- * introduction points shall not be encrypted) and <b>period</b> (e.g. 0
- * for the current period, 1 for the next period, etc.) and add them to
- * the existing list <b>descs_out</b>; return the number of seconds that
- * the descriptors will be found by clients, or -1 if the encoding was not
- * successful. */
+ * at time <b>now</b> using <b>service_key</b>, depending on
+ * <b>auth_type</b> a <b>descriptor_cookie</b> and a list of
+ * <b>client_cookies</b> (which are both <b>NULL</b> if no client
+ * authorization is performed), and <b>period</b> (e.g. 0 for the current
+ * period, 1 for the next period, etc.) and add them to the existing list
+ * <b>descs_out</b>; return the number of seconds that the descriptors will
+ * be found by clients, or -1 if the encoding was not successful. */
 int
 rend_encode_v2_descriptors(smartlist_t *descs_out,
                            rend_service_descriptor_t *desc, time_t now,
-                           const char *descriptor_cookie, uint8_t period)
+                           uint8_t period, rend_auth_type_t auth_type,
+                           crypto_pk_env_t *client_key,
+                           smartlist_t *client_cookies)
 {
   char service_id[DIGEST_LEN];
   uint32_t time_period;
-  char *ipos_base64 = NULL;
+  char *ipos_base64 = NULL, *ipos = NULL, *ipos_encrypted = NULL,
+       *descriptor_cookie = NULL;
+  size_t ipos_len = 0, ipos_encrypted_len = 0;
   int k;
   uint32_t seconds_valid;
+  crypto_pk_env_t *service_key = auth_type == REND_STEALTH_AUTH ?
+                                 client_key : desc->pk;
+  tor_assert(service_key);
+  if (auth_type == REND_STEALTH_AUTH) {
+    descriptor_cookie = smartlist_get(client_cookies, 0);
+    tor_assert(descriptor_cookie);
+  }
   if (!desc) {
     log_warn(LD_REND, "Could not encode v2 descriptor: No desc given.");
     return -1;
   }
   /* Obtain service_id from public key. */
-  crypto_pk_get_digest(desc->pk, service_id);
+  crypto_pk_get_digest(service_key, service_id);
   /* Calculate current time-period. */
   time_period = get_time_period(now, period, service_id);
   /* Determine how many seconds the descriptor will be valid. */
   seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY +
                   get_seconds_valid(now, service_id);
   /* Assemble, possibly encrypt, and encode introduction points. */
-  if (smartlist_len(desc->intro_nodes) > 0 &&
-      rend_encode_v2_intro_points(&ipos_base64, desc, descriptor_cookie) < 0) {
-    log_warn(LD_REND, "Encoding of introduction points did not succeed.");
-    return -1;
+  if (smartlist_len(desc->intro_nodes) > 0) {
+    if (rend_encode_v2_intro_points(&ipos, desc) < 0) {
+      log_warn(LD_REND, "Encoding of introduction points did not succeed.");
+      return -1;
+    }
+    switch (auth_type) {
+      case REND_NO_AUTH:
+        ipos_len = strlen(ipos);
+        break;
+      case REND_BASIC_AUTH:
+        if (rend_encrypt_v2_intro_points_basic(&ipos_encrypted,
+                                               &ipos_encrypted_len, ipos,
+                                               client_cookies) < 0) {
+          log_warn(LD_REND, "Encrypting of introduction points did not "
+                            "succeed.");
+          tor_free(ipos);
+          return -1;
+        }
+        tor_free(ipos);
+        ipos = ipos_encrypted;
+        ipos_len = ipos_encrypted_len;
+        break;
+      case REND_STEALTH_AUTH:
+        if (rend_encrypt_v2_intro_points_stealth(&ipos_encrypted,
+                                                 &ipos_encrypted_len, ipos,
+                                                 descriptor_cookie) < 0) {
+          log_warn(LD_REND, "Encrypting of introduction points did not "
+                            "succeed.");
+          tor_free(ipos);
+          return -1;
+        }
+        tor_free(ipos);
+        ipos = ipos_encrypted;
+        ipos_len = ipos_encrypted_len;
+        break;
+      default:
+        log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d",
+                 (int)auth_type);
+        tor_free(ipos);
+        return -1;
+    }
+    /* Base64-encode introduction points. */
+    ipos_base64 = tor_malloc_zero(ipos_len * 2);
+    if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len)<0) {
+      log_warn(LD_REND, "Could not encode introduction point string to "
+               "base64. length=%d", ipos_len);
+      tor_free(ipos_base64);
+      tor_free(ipos);
+      return -1;
+    }
+    tor_free(ipos);
   }
   /* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */
   for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) {
@@ -369,7 +549,7 @@
     base32_encode(desc_id_base32, sizeof(desc_id_base32),
                   enc->desc_id, DIGEST_LEN);
     /* PEM-encode the public key */
-    if (crypto_pk_write_public_key_to_string(desc->pk, &permanent_key,
+    if (crypto_pk_write_public_key_to_string(service_key, &permanent_key,
                                              &permanent_key_len) < 0) {
       log_warn(LD_BUG, "Could not write public key to string.");
       rend_encoded_v2_service_descriptor_free(enc);
@@ -437,7 +617,7 @@
     }
     if (router_append_dirobj_signature(desc_str + written,
                                        desc_len - written,
-                                       desc_digest, desc->pk) < 0) {
+                                       desc_digest, service_key) < 0) {
       log_warn(LD_BUG, "Couldn't sign desc.");
       rend_encoded_v2_service_descriptor_free(enc);
       goto err;
@@ -1085,6 +1265,7 @@
   rend_cache_entry_t *e;
   tor_assert(rend_cache);
   tor_assert(desc);
+  (void) descriptor_cookie; /* We don't use it, yet. */
   /* Parse the descriptor. */
   if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
                                        &intro_size, &encoded_size,
@@ -1103,8 +1284,8 @@
   }
   /* Decode/decrypt introduction points. */
   if (intro_content) {
-    if (rend_decrypt_introduction_points(parsed, descriptor_cookie,
-                                         intro_content, intro_size) < 0) {
+    if (rend_parse_introduction_points(parsed, intro_content,
+                                       intro_size) < 0) {
       log_warn(LD_PROTOCOL,"Couldn't decode/decrypt introduction points.");
       rend_service_descriptor_free(parsed);
       tor_free(intro_content);

Modified: tor/trunk/src/or/rendservice.c
===================================================================
--- tor/trunk/src/or/rendservice.c	2008-08-19 15:33:03 UTC (rev 16597)
+++ tor/trunk/src/or/rendservice.c	2008-08-19 15:41:28 UTC (rev 16598)
@@ -487,9 +487,8 @@
   d->timestamp = time(NULL);
   d->version = service->descriptor_version;
   d->intro_nodes = smartlist_create();
-  /* Whoever understands descriptor version 2 also understands intro
-   * protocol 2. So we only support 2. */
-  d->protocols = 1 << 2;
+  /* Support intro protocols 2 and 3. */
+  d->protocols = (1 << 2) + (1 << 3);
 
   for (i = 0; i < smartlist_len(service->intro_nodes); ++i) {
     rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i);
@@ -1446,52 +1445,86 @@
       get_options()->PublishHidServDescriptors) {
     networkstatus_t *c = networkstatus_get_latest_consensus();
     if (c && smartlist_len(c->routerstatus_list) > 0) {
-      int seconds_valid;
+      int seconds_valid, i, j, num_descs;
       smartlist_t *descs = smartlist_create();
-      int i;
-      /* Encode the current descriptor. */
-      seconds_valid = rend_encode_v2_descriptors(descs, service->desc, now,
-                                                 NULL, 0);
-      if (seconds_valid < 0) {
-        log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; "
-                 "not uploading.");
-        smartlist_free(descs);
-        return;
-      }
-      /* Post the current descriptors to the hidden service directories. */
-      rend_get_service_id(service->desc->pk, serviceid);
-      log_info(LD_REND, "Sending publish request for hidden service %s",
-                   serviceid);
-      directory_post_to_hs_dir(descs, serviceid, seconds_valid);
-      /* Free memory for descriptors. */
-      for (i = 0; i < smartlist_len(descs); i++)
-        rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
-      smartlist_clear(descs);
-      /* Update next upload time. */
-      if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS
-          > rendpostperiod)
-        service->next_upload_time = now + rendpostperiod;
-      else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS)
-        service->next_upload_time = now + seconds_valid + 1;
-      else
-        service->next_upload_time = now + seconds_valid -
-            REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1;
-      /* Post also the next descriptors, if necessary. */
-      if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) {
+      smartlist_t *client_cookies = smartlist_create();
+      /* Either upload a single descriptor (including replicas) or one
+       * descriptor for each authorized client in case of authorization
+       * type 'stealth'. */
+      num_descs = service->auth_type == REND_STEALTH_AUTH ?
+                      smartlist_len(service->clients) : 1;
+      for (j = 0; j < num_descs; j++) {
+        crypto_pk_env_t *client_key = NULL;
+        rend_authorized_client_t *client = NULL;
+        smartlist_clear(client_cookies);
+        switch (service->auth_type) {
+          case REND_NO_AUTH:
+            /* Do nothing here. */
+            break;
+          case REND_BASIC_AUTH:
+            SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *,
+                cl, smartlist_add(client_cookies, cl->descriptor_cookie));
+            break;
+          case REND_STEALTH_AUTH:
+            client = smartlist_get(service->clients, j);
+            client_key = client->client_key;
+            smartlist_add(client_cookies, client->descriptor_cookie);
+            break;
+        }
+        /* Encode the current descriptor. */
         seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
-                                                   now, NULL, 1);
+                                                   now, 0,
+                                                   service->auth_type,
+                                                   client_key,
+                                                   client_cookies);
         if (seconds_valid < 0) {
           log_warn(LD_BUG, "Internal error: couldn't encode service "
                    "descriptor; not uploading.");
           smartlist_free(descs);
+          smartlist_free(client_cookies);
           return;
         }
+        /* Post the current descriptors to the hidden service directories. */
+        rend_get_service_id(service->desc->pk, serviceid);
+        log_info(LD_REND, "Sending publish request for hidden service %s",
+                     serviceid);
         directory_post_to_hs_dir(descs, serviceid, seconds_valid);
         /* Free memory for descriptors. */
         for (i = 0; i < smartlist_len(descs); i++)
           rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
+        smartlist_clear(descs);
+        /* Update next upload time. */
+        if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS
+            > rendpostperiod)
+          service->next_upload_time = now + rendpostperiod;
+        else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS)
+          service->next_upload_time = now + seconds_valid + 1;
+        else
+          service->next_upload_time = now + seconds_valid -
+              REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1;
+        /* Post also the next descriptors, if necessary. */
+        if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) {
+          seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
+                                                     now, 1,
+                                                     service->auth_type,
+                                                     client_key,
+                                                     client_cookies);
+          if (seconds_valid < 0) {
+            log_warn(LD_BUG, "Internal error: couldn't encode service "
+                     "descriptor; not uploading.");
+            smartlist_free(descs);
+            smartlist_free(client_cookies);
+            return;
+          }
+          directory_post_to_hs_dir(descs, serviceid, seconds_valid);
+          /* Free memory for descriptors. */
+          for (i = 0; i < smartlist_len(descs); i++)
+            rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
+          smartlist_clear(descs);
+        }
       }
       smartlist_free(descs);
+      smartlist_free(client_cookies);
       uploaded = 1;
       log_info(LD_REND, "Successfully uploaded v2 rend descriptors!");
     }

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2008-08-19 15:33:03 UTC (rev 16597)
+++ tor/trunk/src/or/routerparse.c	2008-08-19 15:41:28 UTC (rev 16598)
@@ -3460,6 +3460,13 @@
     eos = desc + strlen(desc);
   else
     eos = eos + 1;
+  /* Check length. */
+  if (strlen(desc) > REND_DESC_MAX_SIZE) {
+    log_warn(LD_REND, "Descriptor length is %i which exceeds "
+             "maximum rendezvous descriptor size of %i kilobytes.",
+             strlen(desc), REND_DESC_MAX_SIZE);
+    goto err;
+  }
   /* Tokenize descriptor. */
   area = memarea_new(4096);
   if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
@@ -3599,21 +3606,123 @@
   return -1;
 }
 
-/** Decrypt and decode the introduction points in
- * <b>intro_points_encrypted</b> of length
- * <b>intro_points_encrypted_size</b> using <b>descriptor_cookie</b>
- * (which may also be <b>NULL</b> if no decryption, but only parsing is
- * required), parse the introduction points, and write the result to
- * <b>parsed</b>; return the number of successfully parsed introduction
- * points or -1 in case of a failure.
- */
+/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
+ * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
+ * write the result to a newly allocated string that is pointed to by
+ * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
+ * Return 0 if decryption was successful and -1 otherwise. */
 int
-rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
+rend_decrypt_introduction_points(char **ipos_decrypted,
+                                 size_t *ipos_decrypted_size,
                                  const char *descriptor_cookie,
-                                 const char *intro_points_encrypted,
-                                 size_t intro_points_encrypted_size)
+                                 const char *ipos_encrypted,
+                                 size_t ipos_encrypted_size)
 {
-  char *ipos_decrypted = NULL;
+  tor_assert(ipos_encrypted);
+  tor_assert(descriptor_cookie);
+  if (ipos_encrypted_size < 2) {
+    log_warn(LD_REND, "Size of encrypted introduction points is too "
+                      "small.");
+    return -1;
+  }
+  if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
+    char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
+         session_key[CIPHER_KEY_LEN], *dec;
+    int declen, client_blocks;
+    size_t pos = 0, len, client_entries_len;
+    crypto_digest_env_t *digest;
+    crypto_cipher_env_t *cipher;
+    client_blocks = (int) ipos_encrypted[1];
+    client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
+                         REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
+    if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
+      log_warn(LD_REND, "Size of encrypted introduction points is too "
+                        "small.");
+      return -1;
+    }
+    memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
+    digest = crypto_new_digest_env();
+    crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
+    crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
+    crypto_digest_get_digest(digest, client_id,
+                             REND_BASIC_AUTH_CLIENT_ID_LEN);
+    crypto_free_digest_env(digest);
+    for (pos = 2; pos < 2 + client_entries_len;
+         pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
+      if (!memcmp(ipos_encrypted + pos, client_id,
+                  REND_BASIC_AUTH_CLIENT_ID_LEN)) {
+        /* Attempt to decrypt introduction points. */
+        cipher = crypto_create_init_cipher(descriptor_cookie, 0);
+        if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
+                                  + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
+                                  CIPHER_KEY_LEN) < 0) {
+          log_warn(LD_REND, "Could not decrypt session key for client.");
+          crypto_free_cipher_env(cipher);
+          return -1;
+        }
+        crypto_free_cipher_env(cipher);
+        cipher = crypto_create_init_cipher(session_key, 0);
+        len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
+        dec = tor_malloc_zero(len);
+        declen = crypto_cipher_decrypt_with_iv(cipher, dec, len,
+            ipos_encrypted + 2 + client_entries_len,
+            ipos_encrypted_size - 2 - client_entries_len);
+        crypto_free_cipher_env(cipher);
+        if (declen < 0) {
+          log_warn(LD_REND, "Could not decrypt introduction point string.");
+          tor_free(dec);
+          return -1;
+        }
+        if (strcmpstart(dec, "introduction-point ")) {
+          log_warn(LD_REND, "Decrypted introduction points don't "
+                            "look like we could parse them.");
+          tor_free(dec);
+          continue;
+        }
+        *ipos_decrypted = dec;
+        *ipos_decrypted_size = declen;
+        return 0;
+      }
+    }
+    log_warn(LD_REND, "Could not decrypt introduction points. Please "
+             "check your authorization for this service!");
+    return -1;
+  } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
+    crypto_cipher_env_t *cipher;
+    char *dec;
+    int declen;
+    dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1);
+    cipher = crypto_create_init_cipher(descriptor_cookie, 0);
+    declen = crypto_cipher_decrypt_with_iv(cipher, dec,
+                                           ipos_encrypted_size -
+                                               CIPHER_IV_LEN - 1,
+                                           ipos_encrypted + 1,
+                                           ipos_encrypted_size - 1);
+    crypto_free_cipher_env(cipher);
+    if (declen < 0) {
+      log_warn(LD_REND, "Decrypting introduction points failed!");
+      tor_free(dec);
+      return -1;
+    }
+    *ipos_decrypted = dec;
+    *ipos_decrypted_size = declen;
+    return 0;
+  } else {
+    log_warn(LD_REND, "Unknown authorization type number: %d",
+             ipos_encrypted[0]);
+    return -1;
+  }
+}
+
+/** Parse the encoded introduction points in <b>intro_points_encoded</b> of
+ * length <b>intro_points_encoded_size</b> and write the result to the
+ * descriptor in <b>parsed</b>; return the number of successfully parsed
+ * introduction points or -1 in case of a failure. */
+int
+rend_parse_introduction_points(rend_service_descriptor_t *parsed,
+                               const char *intro_points_encoded,
+                               size_t intro_points_encoded_size)
+{
   const char **current_ipo;
   smartlist_t *tokens;
   directory_token_t *tok;
@@ -3624,28 +3733,10 @@
   tor_assert(parsed);
   /** Function may only be invoked once. */
   tor_assert(!parsed->intro_nodes);
-  tor_assert(intro_points_encrypted);
-  tor_assert(intro_points_encrypted_size > 0);
-  /* Decrypt introduction points, if required. */
-  if (descriptor_cookie) {
-    crypto_cipher_env_t *cipher;
-    int unenclen;
-    ipos_decrypted = tor_malloc_zero(intro_points_encrypted_size - 16);
-    cipher = crypto_create_init_cipher(descriptor_cookie, 0);
-    unenclen = crypto_cipher_decrypt_with_iv(cipher, ipos_decrypted,
-                                             intro_points_encrypted_size - 16,
-                                             intro_points_encrypted,
-                                             intro_points_encrypted_size);
-    crypto_free_cipher_env(cipher);
-    if (unenclen < 0) {
-      tor_free(ipos_decrypted);
-      return -1;
-    }
-    intro_points_encrypted = ipos_decrypted;
-    intro_points_encrypted_size = unenclen;
-  }
+  tor_assert(intro_points_encoded);
+  tor_assert(intro_points_encoded_size > 0);
   /* Consider one intro point after the other. */
-  current_ipo = &intro_points_encrypted;
+  current_ipo = &intro_points_encoded;
   tokens = smartlist_create();
   parsed->intro_nodes = smartlist_create();
   area = memarea_new(4096);

Modified: tor/trunk/src/or/test.c
===================================================================
--- tor/trunk/src/or/test.c	2008-08-19 15:33:03 UTC (rev 16597)
+++ tor/trunk/src/or/test.c	2008-08-19 15:41:28 UTC (rev 16598)
@@ -4049,8 +4049,8 @@
     intro->intro_key = crypto_pk_dup_key(pk2);
     smartlist_add(generated->intro_nodes, intro);
   }
-  test_assert(rend_encode_v2_descriptors(descs, generated, now,
-                                         NULL, 0) > 0);
+  test_assert(rend_encode_v2_descriptors(descs, generated, now, 0,
+                                         REND_NO_AUTH, NULL, NULL) > 0);
   test_assert(rend_compute_v2_desc_id(computed_desc_id, service_id_base32,
                                       NULL, now, 0) == 0);
   test_memeq(((rend_encoded_v2_service_descriptor_t *)
@@ -4065,9 +4065,8 @@
   test_assert(parsed);
   test_memeq(((rend_encoded_v2_service_descriptor_t *)
              smartlist_get(descs, 0))->desc_id, parsed_desc_id, DIGEST_LEN);
-  test_assert(rend_decrypt_introduction_points(parsed, NULL,
-                                               intro_points_encrypted,
-                                               intro_points_size) == 3);
+  test_assert(rend_parse_introduction_points(parsed, intro_points_encrypted,
+                                             intro_points_size) == 3);
   test_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk));
   test_eq(parsed->timestamp, now);
   test_eq(parsed->version, 2);



More information about the tor-commits mailing list