- test and log for bug #0003423
[oweals/gnunet.git] / src / gnsrecord / gnsrecord_crypto.c
index 823ffcae335e11ecb454dd2b5f06e7103fc7a21b..8cf8e532fb2b019f3f0dca16960da9bc83e5bf01 100644 (file)
@@ -78,39 +78,59 @@ derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
  * @param rd_count number of records
  * @return NULL on error (block too large)
  */
-struct GNUNET_NAMESTORE_Block *
-GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+struct GNUNET_GNSRECORD_Block *
+GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
                               struct GNUNET_TIME_Absolute expire,
                               const char *label,
-                              const struct GNUNET_NAMESTORE_RecordData *rd,
+                              const struct GNUNET_GNSRECORD_Data *rd,
                               unsigned int rd_count)
 {
-  size_t payload_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
+  size_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
   char payload[sizeof (uint32_t) + payload_len];
-  struct GNUNET_NAMESTORE_Block *block;
+  struct GNUNET_GNSRECORD_Block *block;
   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
   struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+  struct GNUNET_GNSRECORD_Data rdc[rd_count];
   uint32_t rd_count_nbo;
+  unsigned int i;
+  struct GNUNET_TIME_Absolute now;
 
-  if (payload_len > GNUNET_NAMESTORE_MAX_VALUE_SIZE)
+  if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
     return NULL;
+  /* convert relative to absolute times */
+  now = GNUNET_TIME_absolute_get ();
+  for (i=0;i<rd_count;i++)
+  {
+    rdc[i] = rd[i];
+    if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
+    {
+      struct GNUNET_TIME_Relative t;
+
+      /* encrypted blocks must never have relative expiration times, convert! */
+      rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
+      t.rel_value_us = rdc[i].expiration_time;
+      rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
+    }
+  }
+  /* serialize */
   rd_count_nbo = htonl (rd_count);
   memcpy (payload, &rd_count_nbo, sizeof (uint32_t));
   GNUNET_assert (payload_len ==
-                GNUNET_NAMESTORE_records_serialize (rd_count, rd,
+                GNUNET_GNSRECORD_records_serialize (rd_count, rdc,
                                                     payload_len, &payload[sizeof (uint32_t)]));
-  block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) +
+  block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) +
                         sizeof (uint32_t) + payload_len);
   block->purpose.size = htonl (sizeof (uint32_t) + payload_len +
                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
                               sizeof (struct GNUNET_TIME_AbsoluteNBO));
   block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
   block->expiration_time = GNUNET_TIME_absolute_hton (expire);
+  /* encrypt and sign */
   dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
-                                      label,
-                                      "gns");
+                                                 label,
+                                                 "gns");
   GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
                                    &block->derived_key);
   GNUNET_CRYPTO_ecdsa_key_get_public (key,
@@ -118,8 +138,8 @@ GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
   derive_block_aes_key (&iv, &skey, label, &pkey);
   GNUNET_break (payload_len + sizeof (uint32_t) ==
                GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t),
-                                          &skey, &iv,
-                                          &block[1]));
+                                                 &skey, &iv,
+                                                 &block[1]));
   if (GNUNET_OK !=
       GNUNET_CRYPTO_ecdsa_sign (dkey,
                              &block->purpose,
@@ -143,7 +163,7 @@ GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  * @return #GNUNET_OK if the signature is valid
  */
 int
-GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block)
+GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
 {
   return GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
                                   &block->purpose,
@@ -164,10 +184,10 @@ GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block)
  *        not well-formed
  */
 int
-GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
+GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
                                const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
                                const char *label,
-                               GNUNET_NAMESTORE_RecordCallback proc,
+                               GNUNET_GNSRECORD_RecordCallback proc,
                                void *proc_cls)
 {
   size_t payload_len = ntohl (block->purpose.size) -
@@ -203,10 +223,14 @@ GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
       return GNUNET_SYSERR;
     }
     {
-      struct GNUNET_NAMESTORE_RecordData rd[rd_count];
+      struct GNUNET_GNSRECORD_Data rd[rd_count];
+      unsigned int i;
+      unsigned int j;
+      unsigned int k;
+      struct GNUNET_TIME_Absolute now;
 
       if (GNUNET_OK !=
-         GNUNET_NAMESTORE_records_deserialize (payload_len - sizeof (uint32_t),
+         GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof (uint32_t),
                                                &payload[sizeof (uint32_t)],
                                                rd_count,
                                                rd))
@@ -214,6 +238,52 @@ GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
        GNUNET_break_op (0);
        return GNUNET_SYSERR;
       }
+      /* hide expired records */
+      now = GNUNET_TIME_absolute_get ();
+      j = 0;
+      for (i=0;i<rd_count;i++)
+      {
+        if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PENDING))
+          continue; /* PENDING should never be used */
+        if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
+        {
+          /* encrypted blocks must never have relative expiration times, skip! */
+          GNUNET_break_op (0);
+          continue;
+        }
+
+        if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))
+        {
+          int include_record = GNUNET_YES;
+          /* Shadow record, figure out if we have a not expired active record */
+          for (k=0;k<rd_count;k++)
+          {
+            if (k == i)
+              continue;
+            if (rd[i].expiration_time < now.abs_value_us)
+              include_record = GNUNET_NO; /* Shadow record is expired */
+            if ((rd[k].record_type == rd[i].record_type)
+                && (rd[k].expiration_time >= now.abs_value_us)
+                && (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)))
+              include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */
+          }
+          if (GNUNET_YES == include_record)
+          {
+            rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */
+            if (j != i)
+              rd[j] = rd[i];
+            j++;
+          }
+        }
+        else if (rd[i].expiration_time >= now.abs_value_us)
+        {
+          /* Include this record */
+          if (j != i)
+            rd[j] = rd[i];
+          j++;
+        }
+      }
+      rd_count = j;
       if (NULL != proc)
        proc (proc_cls, rd_count, (0 != rd_count) ? rd : NULL);
     }
@@ -230,14 +300,14 @@ GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
  * @param query hash to use for the query
  */
 void
-GNUNET_NAMESTORE_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+GNUNET_GNSRECORD_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
                                         const char *label,
                                         struct GNUNET_HashCode *query)
 {
   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
 
   GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
-  GNUNET_NAMESTORE_query_from_public_key (&pub, label, query);
+  GNUNET_GNSRECORD_query_from_public_key (&pub, label, query);
 }
 
 
@@ -249,7 +319,7 @@ GNUNET_NAMESTORE_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivate
  * @param query hash to use for the query
  */
 void
-GNUNET_NAMESTORE_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
+GNUNET_GNSRECORD_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
                                        const char *label,
                                        struct GNUNET_HashCode *query)
 {