Merge remote-tracking branch 'origin/master' into identity_abe
[oweals/gnunet.git] / src / credential / gnunet-service-credential.c
index 8843abfd6a29dcda6f6105a2de2aec3a2b0fdc86..be75e485ec375f65b2e573615e93fe7f1f9ad95c 100644 (file)
 #include "gnunet_protocols.h"
 #include "gnunet_signatures.h"
 
-// For Looking up GNS request
 #include <gnunet_dnsparser_lib.h>
 #include <gnunet_identity_service.h>
 #include <gnunet_gnsrecord_lib.h>
 #include <gnunet_namestore_service.h>
 #include <gnunet_gns_service.h>
-#include "gnunet_gns_service.h"
-
-
 
 
 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
 
 struct VerifyRequestHandle;
 
-struct DelegationSetEntry;
+struct DelegationSetQueueEntry;
 
 
 struct DelegationChainEntry
@@ -96,17 +92,16 @@ struct CredentialRecordEntry
    * DLL
    */
   struct CredentialRecordEntry *prev;
-
-
+  
   /**
-   * Payload
+   * Number of references in delegation chains
    */
-  struct GNUNET_CREDENTIAL_CredentialRecordData *data;
+  uint32_t refcount;
 
   /**
-   * Size
+   * Payload
    */
-  uint64_t data_size;
+  struct GNUNET_CREDENTIAL_Credential *credential;
 };
 
 /**
@@ -128,17 +123,17 @@ struct DelegationQueueEntry
   /**
    * Sets under this Queue
    */
-  struct DelegationSetEntry *set_entries_head;
+  struct DelegationSetQueueEntry *set_entries_head;
 
   /**
    * Sets under this Queue
    */
-  struct DelegationSetEntry *set_entries_tail;
+  struct DelegationSetQueueEntry *set_entries_tail;
 
   /**
    * Parent set
    */
-  struct DelegationSetEntry *parent_set;
+  struct DelegationSetQueueEntry *parent_set;
 
   /**
    * Required solutions
@@ -150,17 +145,17 @@ struct DelegationQueueEntry
  * DLL for delegation sets
  * Used for AND delegation set
  */
-struct DelegationSetEntry
+struct DelegationSetQueueEntry
 {
   /**
    * DLL
    */
-  struct DelegationSetEntry *next;
+  struct DelegationSetQueueEntry *next;
 
   /**
    * DLL
    */
-  struct DelegationSetEntry *prev;
+  struct DelegationSetQueueEntry *prev;
 
     /**
    * GNS handle
@@ -282,19 +277,24 @@ struct VerifyRequestHandle
   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
 
   /**
-   * Credential Chain
+   * Credential DLL
    */
   struct CredentialRecordEntry *cred_chain_head;
 
   /**
-   * Credential Chain
+   * Credential DLL
    */
   struct CredentialRecordEntry *cred_chain_tail;
 
+  /**
+   * Credential DLL size
+   */
+  uint32_t cred_chain_size;
+
   /**
    * Root Delegation Set
    */
-  struct DelegationSetEntry *root_set;
+  struct DelegationSetQueueEntry *root_set;
 
   /**
    * Current Delegation Pointer
@@ -302,24 +302,24 @@ struct VerifyRequestHandle
   struct DelegationQueueEntry *current_delegation;
 
   /**
-   * The found credential
+   * request id
    */
-  struct GNUNET_CREDENTIAL_CredentialRecordData *credential;
+  uint32_t request_id;
 
   /**
-   * Length of the credential
+   * Pending lookups
    */
-  uint32_t credential_size;
+  uint64_t pending_lookups;
 
   /**
-   * request id
+   * Credential iterator
    */
-  uint32_t request_id;
+  struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter;
 
   /**
-   * Pending lookups
+   * Collect task
    */
-  uint64_t pending_lookups;
+  struct GNUNET_SCHEDULER_Task *collect_next_task;
 
 };
 
@@ -345,11 +345,16 @@ static struct GNUNET_STATISTICS_Handle *statistics;
 static struct GNUNET_GNS_Handle *gns;
 
 
+/**
+ * Handle to namestore service
+ */
+static struct GNUNET_NAMESTORE_Handle *namestore;
+
 static void
-cleanup_delegation_set (struct DelegationSetEntry *ds_entry)
+cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
 {
   struct DelegationQueueEntry *dq_entry;
-  struct DelegationSetEntry *child;
+  struct DelegationSetQueueEntry *child;
 
   if (NULL == ds_entry)
     return;
@@ -402,15 +407,13 @@ static void
 cleanup_handle (struct VerifyRequestHandle *vrh)
 {
   struct CredentialRecordEntry *cr_entry;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Cleaning up...\n");
   if (NULL != vrh->lookup_request)
   {
     GNUNET_GNS_lookup_cancel (vrh->lookup_request);
     vrh->lookup_request = NULL;
   }
-  if (NULL != vrh->credential)
-    GNUNET_free (vrh->credential);
   cleanup_delegation_set (vrh->root_set);
   if (NULL != vrh->issuer_attribute)
     GNUNET_free (vrh->issuer_attribute);
@@ -421,8 +424,8 @@ cleanup_handle (struct VerifyRequestHandle *vrh)
     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
                                  vrh->cred_chain_tail,
                                  cr_entry);
-    if (NULL != cr_entry->data)
-      GNUNET_free (cr_entry->data);
+    if (NULL != cr_entry->credential);
+      GNUNET_free (cr_entry->credential);
     GNUNET_free (cr_entry);
   }
   GNUNET_free (vrh);
@@ -439,7 +442,7 @@ shutdown_task (void *cls)
 {
   struct VerifyRequestHandle *vrh;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Shutting down!\n");
 
   while (NULL != (vrh = vrh_head))
@@ -456,6 +459,11 @@ shutdown_task (void *cls)
     GNUNET_GNS_disconnect (gns);
     gns = NULL;
   }
+  if (NULL != namestore)
+  {
+    GNUNET_NAMESTORE_disconnect (namestore);
+    namestore = NULL;
+  }
   if (NULL != statistics)
   {
     GNUNET_STATISTICS_destroy (statistics,
@@ -465,42 +473,7 @@ shutdown_task (void *cls)
 
 }
 
-/**
- * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
- *
- * @param cls client sending the message
- * @param v_msg message of type `struct VerifyMessage`
- * @return #GNUNET_OK if @a v_msg is well-formed
- */
-static int
-check_verify (void *cls,
-              const struct VerifyMessage *v_msg)
-{
-  size_t msg_size;
-  const char* attrs;
-
-  msg_size = ntohs (v_msg->header.size);
-  if (msg_size < sizeof (struct VerifyMessage))
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if ((ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) ||
-      (ntohs (v_msg->subject_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH))
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  attrs = (const char *) &v_msg[1];
 
-  if ( ('\0' != attrs[ntohs(v_msg->header.size) - sizeof (struct VerifyMessage) - 1]) ||
-       (strlen (attrs) > GNUNET_CREDENTIAL_MAX_LENGTH * 2) )
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
 
 /**
  * Send.
@@ -511,64 +484,93 @@ static void
 send_lookup_response (struct VerifyRequestHandle *vrh)
 {
   struct GNUNET_MQ_Envelope *env;
-  struct VerifyResultMessage *rmsg;
+  struct DelegationChainResultMessage *rmsg;
   struct DelegationChainEntry *dce;
-  size_t size = vrh->credential_size;
   struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
-  struct GNUNET_CREDENTIAL_Credential cred;
+  struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
+  struct CredentialRecordEntry *cd;
+  struct CredentialRecordEntry *tmp;
+  size_t size;
   int i;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Sending response\n");
-  i = 0;
-  for (dce = vrh->delegation_chain_head;
-       NULL != dce;
-       dce = dce->next)
+  dce = vrh->delegation_chain_head;
+  for (i=0;i<vrh->delegation_chain_size;i++)
   {
     dd[i].issuer_key = dce->issuer_key;
     dd[i].subject_key = dce->subject_key;
     dd[i].issuer_attribute = dce->issuer_attribute;
     dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
     dd[i].subject_attribute_len = 0;
+    dd[i].subject_attribute = NULL;
     if (NULL != dce->subject_attribute)
     {
       dd[i].subject_attribute = dce->subject_attribute;
       dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
     }
-    i++;
+    dce = dce->next;
+  }
+
+  /**
+   * Remove all credentials not needed
+   */
+  for (cd = vrh->cred_chain_head; NULL != cd;)
+  {
+    if (cd->refcount > 0)
+    {
+      cd = cd->next;
+      continue;
+    }
+    tmp = cd;
+    cd = cd->next;
+    GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
+                                 vrh->cred_chain_tail,
+                                 tmp);
+    GNUNET_free (tmp->credential);
+    GNUNET_free (tmp);
+    vrh->cred_chain_size--;
   }
 
   /**
    * Get serialized record data
    * Append at the end of rmsg
    */
-  cred.issuer_key = vrh->credential->issuer_key;
-  cred.subject_key = vrh->credential->subject_key;
-  cred.issuer_attribute_len = strlen((char*)&vrh->credential[1])+1;
-  cred.issuer_attribute = (char*)&vrh->credential[1];
+  cd = vrh->cred_chain_head;
+  for (i=0;i<vrh->cred_chain_size;i++)
+  {
+    cred[i].issuer_key = cd->credential->issuer_key;
+    cred[i].subject_key = cd->credential->subject_key;
+    cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1;
+    cred[i].issuer_attribute = cd->credential->issuer_attribute;
+    cred[i].expiration = cd->credential->expiration;
+    cred[i].signature = cd->credential->signature;
+    cd = cd->next;
+  }
   size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
                                                       dd,
-                                                      &cred);
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "SIZE; %llu count: %d\n",size,vrh->delegation_chain_size);
+                                                      vrh->cred_chain_size,
+                                                      cred);
   env = GNUNET_MQ_msg_extra (rmsg,
                              size,
                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
   //Assign id so that client can find associated request
   rmsg->id = vrh->request_id;
   rmsg->d_count = htonl (vrh->delegation_chain_size);
+  rmsg->c_count = htonl (vrh->cred_chain_size);
 
-  if (NULL != vrh->credential)
+  if (0 < vrh->cred_chain_size)
     rmsg->cred_found = htonl (GNUNET_YES);
   else
     rmsg->cred_found = htonl (GNUNET_NO);
 
   GNUNET_assert (-1 != 
-               GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
-                                                             dd,
-                                                             &cred,
-                                                             size,
-                                                             (char*)&rmsg[1]));
+                 GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
+                                                               dd,
+                                                               vrh->cred_chain_size,
+                                                               cred,
+                                                               size,
+                                                               (char*)&rmsg[1]));
 
   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
                   env);
@@ -588,12 +590,11 @@ backward_resolution (void* cls,
 {
 
   struct VerifyRequestHandle *vrh;
-  struct GNUNET_CREDENTIAL_CredentialRecordData *cred;
-  const struct GNUNET_CREDENTIAL_DelegationRecordData *sets;
+  const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
   struct CredentialRecordEntry *cred_pointer;
-  struct DelegationSetEntry *current_set;
-  struct DelegationSetEntry *ds_entry;
-  struct DelegationSetEntry *tmp_set;
+  struct DelegationSetQueueEntry *current_set;
+  struct DelegationSetQueueEntry *ds_entry;
+  struct DelegationSetQueueEntry *tmp_set;
   struct DelegationQueueEntry *dq_entry;
   char *expanded_attr;
   char *lookup_attribute;
@@ -605,7 +606,7 @@ backward_resolution (void* cls,
   current_set->lookup_request = NULL;
   vrh = current_set->handle;
   vrh->pending_lookups--;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Got %d attrs\n", rd_count);
 
   // Each OR
@@ -615,15 +616,15 @@ backward_resolution (void* cls,
       continue;
 
     sets = rd[i].data;
-    struct GNUNET_CREDENTIAL_DelegationSetRecord set[ntohl(sets->set_count)];
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+    struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)];
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Found new attribute delegation with %d sets. Creating new Job...\n",
-               ntohl (sets->set_count));
+                ntohl (sets->set_count));
 
     if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
-                                                  (const char*)&sets[1],
-                                                  ntohl(sets->set_count),
-                                                  set))
+                                                                  (const char*)&sets[1],
+                                                                  ntohl(sets->set_count),
+                                                                  set))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Failed to deserialize!\n");
@@ -638,7 +639,7 @@ backward_resolution (void* cls,
     // Each AND
     for (j=0; j<ntohl(sets->set_count); j++)
     {
-      ds_entry = GNUNET_new (struct DelegationSetEntry);
+      ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
       if (NULL != current_set->attr_trailer)
       {
         if (0 == set[j].subject_attribute_len)
@@ -653,13 +654,13 @@ backward_resolution (void* cls,
                            set[j].subject_attribute,
                            current_set->attr_trailer);
         }
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                     "Expanded to %s\n", expanded_attr);
         ds_entry->unresolved_attribute_delegation = expanded_attr;
       } else {
         if (0 != set[j].subject_attribute_len)
         {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       "Not Expanding %s\n", set[j].subject_attribute);
           ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
         }
@@ -682,7 +683,7 @@ backward_resolution (void* cls,
                                    dq_entry->set_entries_tail,
                                    ds_entry);
 
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Checking for cred match\n");
       /**
        * Check if this delegation already matches one of our credentials
@@ -690,21 +691,22 @@ backward_resolution (void* cls,
       for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
           cred_pointer = cred_pointer->next)
       {
-        cred = cred_pointer->data;
         if(0 != memcmp (&set->subject_key, 
-                        &cred_pointer->data->issuer_key,
+                        &cred_pointer->credential->issuer_key,
                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
           continue;
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                     "Checking if %s matches %s\n",
-                    ds_entry->unresolved_attribute_delegation, (char*)&cred[1]);
+                    ds_entry->unresolved_attribute_delegation,
+                    cred_pointer->credential->issuer_attribute);
 
-        if (0 != strcmp (ds_entry->unresolved_attribute_delegation, (char*)&cred[1]))
+        if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
+                         cred_pointer->credential->issuer_attribute))
           continue;
 
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                     "Found issuer\n");
-
+        cred_pointer->refcount++;
         //Backtrack
         for (tmp_set = ds_entry;
              NULL != tmp_set->parent_queue_entry;
@@ -724,20 +726,18 @@ backward_resolution (void* cls,
 
         if (NULL == tmp_set->parent_queue_entry)
         {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       "All solutions found\n");
-          vrh->credential = GNUNET_malloc (cred_pointer->data_size);
-          memcpy (vrh->credential,
-                  cred,
-                  cred_pointer->data_size);
-          vrh->credential_size = cred_pointer->data_size;
           //Found match
           send_lookup_response (vrh);
           return;
         }
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Not all solutions found yet.\n");
+        continue;
 
       }
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Building new lookup request from %s\n",
                   ds_entry->unresolved_attribute_delegation);
       //Continue with backward resolution
@@ -759,10 +759,10 @@ backward_resolution (void* cls,
         ds_entry->attr_trailer = GNUNET_strdup (next_attr);
       }
 
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Looking up %s\n", ds_entry->lookup_attribute);
       if (NULL != ds_entry->attr_trailer)
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                     "%s still to go...\n", ds_entry->attr_trailer);
 
       vrh->pending_lookups++;
@@ -772,7 +772,6 @@ backward_resolution (void* cls,
                                                     ds_entry->issuer_key, //issuer_key,
                                                     GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
                                                     GNUNET_GNS_LO_DEFAULT,
-                                                    NULL, //shorten_key, always NULL
                                                     &backward_resolution,
                                                     ds_entry);
       GNUNET_free (lookup_attribute);
@@ -781,7 +780,7 @@ backward_resolution (void* cls,
 
   if(0 == vrh->pending_lookups)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "We are all out of attributes...\n");
     send_lookup_response (vrh);
     return;
@@ -798,55 +797,30 @@ backward_resolution (void* cls,
  * @param rd the record data
  */
 static void
-handle_credential_query (void* cls,
-                         uint32_t rd_count,
-                         const struct GNUNET_GNSRECORD_Data *rd)
+delegation_chain_resolution_start (void* cls)
 {
   struct VerifyRequestHandle *vrh = cls;
-  struct DelegationSetEntry *ds_entry;
-  const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
+  struct DelegationSetQueueEntry *ds_entry;
   struct CredentialRecordEntry *cr_entry;
-  int cred_record_count;
-  int i;
-
   vrh->lookup_request = NULL;
-  cred_record_count = 0;
-  for (i=0; i < rd_count; i++)
+
+  if (0 == vrh->cred_chain_size)
   {
-    if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
-      continue;
-    cred_record_count++;
-    crd = rd[i].data;
-    if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
-                                               &crd->purpose,
-                                               &crd->signature,
-                                               &crd->issuer_key))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Invalid credential found\n");
-      continue;
-    }
-    cr_entry = GNUNET_new (struct CredentialRecordEntry);
-    cr_entry->data = GNUNET_malloc (rd[i].data_size);
-    memcpy (cr_entry->data,
-            crd,
-            rd[i].data_size);
-    cr_entry->data_size = rd[i].data_size;
-    GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
-                                      vrh->cred_chain_tail,
-                                      cr_entry);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "No credentials found\n");
+    send_lookup_response (vrh);
+    return;
+  }
 
-    if (0 != memcmp (&crd->issuer_key,
+  for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next)
+  {
+    if (0 != memcmp (&cr_entry->credential->issuer_key,
                      &vrh->issuer_key,
                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
       continue;
-    if (0 != strcmp ((char*)&crd[1], vrh->issuer_attribute))
+    if (0 != strcmp (cr_entry->credential->issuer_attribute, vrh->issuer_attribute))
       continue;
-    vrh->credential = GNUNET_malloc (rd[i].data_size);
-    memcpy (vrh->credential,
-            rd[i].data,
-            rd[i].data_size);
-    vrh->credential_size = rd[i].data_size;
+    cr_entry->refcount++;
     //Found match prematurely
     send_lookup_response (vrh);
     return;
@@ -862,9 +836,9 @@ handle_credential_query (void* cls,
           vrh->issuer_attribute);
   strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
           ".gnu");
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Looking up %s\n", issuer_attribute_name);
-  ds_entry = GNUNET_new (struct DelegationSetEntry);
+  ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
   ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
   memcpy (ds_entry->issuer_key,
           &vrh->issuer_key,
@@ -880,11 +854,44 @@ handle_credential_query (void* cls,
                                                 &vrh->issuer_key, //issuer_key,
                                                 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
                                                 GNUNET_GNS_LO_DEFAULT,
-                                                NULL, //shorten_key, always NULL
                                                 &backward_resolution,
                                                 ds_entry);
 }
 
+/**
+ * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
+ *
+ * @param cls client sending the message
+ * @param v_msg message of type `struct VerifyMessage`
+ * @return #GNUNET_OK if @a v_msg is well-formed
+ */
+static int
+check_verify (void *cls,
+              const struct VerifyMessage *v_msg)
+{
+  size_t msg_size;
+  const char* attr;
+
+  msg_size = ntohs (v_msg->header.size);
+  if (msg_size < sizeof (struct VerifyMessage))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  attr = (const char *) &v_msg[1];
+
+  if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
 
 /**
  * Handle Credential verification requests from client
@@ -897,26 +904,24 @@ static void
 handle_verify (void *cls,
                const struct VerifyMessage *v_msg) 
 {
-  char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
-  char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
-  char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1 + 4];
   struct VerifyRequestHandle *vrh;
   struct GNUNET_SERVICE_Client *client = cls;
-  char *attrptr = attrs;
+  struct CredentialRecordEntry *cr_entry;
+  uint32_t credentials_count;
+  uint32_t credential_data_size;
+  int i;
+  char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char *attrptr = attr;
+  char *credential_data;
   const char *utf_in;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received VERIFY message\n");
-
   utf_in = (const char *) &v_msg[1];
   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
-
-  GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
+  GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
-  GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
-  strcpy (subject_attribute+ntohs (v_msg->subject_attribute_len),
-          ".gnu");
-  subject_attribute[ntohs (v_msg->subject_attribute_len)+4] = '\0';
   vrh = GNUNET_new (struct VerifyRequestHandle);
   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
   vrh->client = client;
@@ -924,14 +929,167 @@ handle_verify (void *cls,
   vrh->issuer_key = v_msg->issuer_key;
   vrh->subject_key = v_msg->subject_key;
   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
-
-  if (NULL == subject_attribute)
+  if (NULL == issuer_attribute)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                "No subject attribute provided!\n");
+                "No issuer attribute provided!\n");
     send_lookup_response (vrh);
     return;
   }
+  /**
+   * First, collect credentials
+   * TODO: cleanup!
+   */
+  credentials_count = ntohl(v_msg->c_count);
+  credential_data_size = ntohs (v_msg->header.size) 
+    - sizeof (struct VerifyMessage)
+    - ntohs (v_msg->issuer_attribute_len)
+    - 1;
+  struct GNUNET_CREDENTIAL_Credential credentials[credentials_count];
+  credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
+  if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size,
+                                                              credential_data,
+                                                              credentials_count,
+                                                              credentials))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "Cannot deserialize credentials!\n");
+    send_lookup_response (vrh);
+    return;
+  }
+
+  for (i=0;i<credentials_count;i++) {
+    cr_entry = GNUNET_new (struct CredentialRecordEntry);
+    cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) +
+                                          credentials[i].issuer_attribute_len);
+    GNUNET_memcpy (cr_entry->credential,
+                   &credentials[i],
+                   sizeof (struct GNUNET_CREDENTIAL_Credential));
+    GNUNET_memcpy (&cr_entry->credential[1],
+                   credentials[i].issuer_attribute,
+                   credentials[i].issuer_attribute_len);
+    cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1];
+    GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
+                                      vrh->cred_chain_tail,
+                                      cr_entry);
+    vrh->cred_chain_size++;
+  }
+
+  delegation_chain_resolution_start (vrh);
+
+}
+
+/**
+ * We encountered an error while collecting
+ */
+static void
+handle_cred_collection_error_cb (void *cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Got disconnected from namestore database.\n");
+  vrh->cred_collection_iter = NULL;
+  send_lookup_response (vrh);
+}
+
+static void
+collect_next (void *cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  vrh->collect_next_task = NULL;
+  GNUNET_assert (NULL != vrh->cred_collection_iter);
+  GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter);
+}
+
+/**
+ * Store credential
+ */
+static void
+handle_cred_collection_cb (void *cls,
+                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+                           const char *label,
+                           unsigned int rd_count,
+                           const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  struct GNUNET_CREDENTIAL_Credential *crd;
+  struct CredentialRecordEntry *cr_entry;
+  int cred_record_count;
+  int i;
+
+  cred_record_count = 0;
+  for (i=0; i < rd_count; i++)
+  {
+    if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
+      continue;
+    cred_record_count++;
+    crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
+                                                    rd[i].data_size);
+    if (NULL == crd)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Invalid credential found\n");
+      continue;
+    }
+    cr_entry = GNUNET_new (struct CredentialRecordEntry);
+    cr_entry->credential = crd;
+    GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
+                                      vrh->cred_chain_tail,
+                                      cr_entry);
+    vrh->cred_chain_size++;
+  }
+  vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next,
+                                                     vrh);
+}
+
+/**
+ * We encountered an error while collecting
+ */
+static void
+handle_cred_collection_finished_cb (void *cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Done collecting credentials.\n");
+  vrh->cred_collection_iter = NULL;
+  delegation_chain_resolution_start (vrh);
+}
+
+/**
+ * Handle Credential collection requests from client
+ *
+ * @param cls the closure
+ * @param client the client
+ * @param message the message
+ */
+static void
+handle_collect (void *cls,
+                const struct CollectMessage *c_msg) 
+{
+  char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  struct VerifyRequestHandle *vrh;
+  struct GNUNET_SERVICE_Client *client = cls;
+  char *attrptr = attr;
+  const char *utf_in;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received COLLECT message\n");
+
+  utf_in = (const char *) &c_msg[1];
+  GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
+
+  GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
+  issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
+  vrh = GNUNET_new (struct VerifyRequestHandle);
+  GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
+  vrh->client = client;
+  vrh->request_id = c_msg->id;
+  vrh->issuer_key = c_msg->issuer_key;
+  GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key,
+                                      &vrh->subject_key);
+  vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
+
   if (NULL == issuer_attribute)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
@@ -939,23 +1097,58 @@ handle_verify (void *cls,
     send_lookup_response (vrh);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Looking up %s\n",
-              subject_attribute);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Getting credentials for subject\n");
   /**
    * First, get attribute from subject
    */
-  vrh->lookup_request = GNUNET_GNS_lookup (gns,
-                                           subject_attribute,
-                                           &v_msg->subject_key, //subject_pkey,
-                                           GNUNET_GNSRECORD_TYPE_CREDENTIAL,
-                                           GNUNET_GNS_LO_DEFAULT,
-                                           NULL, //shorten_key, always NULL
-                                           &handle_credential_query,
-                                           vrh);
+  vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore,
+                                                                     &c_msg->subject_key,
+                                                                     &handle_cred_collection_error_cb,
+                                                                     vrh,
+                                                                     &handle_cred_collection_cb,
+                                                                     vrh,
+                                                                     &handle_cred_collection_finished_cb,
+                                                                     vrh);
 }
 
 
+/**
+ * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT message
+ *
+ * @param cls client sending the message
+ * @param v_msg message of type `struct CollectMessage`
+ * @return #GNUNET_OK if @a v_msg is well-formed
+ */
+static int
+check_collect (void *cls,
+               const struct CollectMessage *c_msg)
+{
+  size_t msg_size;
+  const char* attr;
+
+  msg_size = ntohs (c_msg->header.size);
+  if (msg_size < sizeof (struct CollectMessage))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  attr = (const char *) &c_msg[1];
+
+  if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) ||
+       (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
 /**
  * One of our clients disconnected, clean up after it.
  *
@@ -967,7 +1160,7 @@ client_disconnect_cb (void *cls,
                       struct GNUNET_SERVICE_Client *client,
                       void *app_ctx)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Client %p disconnected\n",
               client);
 }
@@ -985,7 +1178,7 @@ client_connect_cb (void *cls,
                    struct GNUNET_SERVICE_Client *client,
                    struct GNUNET_MQ_Handle *mq)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Client %p connected\n",
               client);
   return client;
@@ -1010,6 +1203,12 @@ run (void *cls,
     fprintf (stderr,
              _("Failed to connect to GNS\n"));
   }
+  namestore = GNUNET_NAMESTORE_connect (c);
+  if (NULL == namestore)
+  {
+    fprintf (stderr,
+             _("Failed to connect to namestore\n"));
+  }
 
   statistics = GNUNET_STATISTICS_create ("credential", c);
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
@@ -1030,6 +1229,10 @@ GNUNET_SERVICE_MAIN
                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
                         struct VerifyMessage,
                         NULL),
+ GNUNET_MQ_hd_var_size (collect,
+                        GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT,
+                        struct CollectMessage,
+                        NULL),
  GNUNET_MQ_handler_end());
 
 /* end of gnunet-service-credential.c */