Boston, MA 02110-1301, USA.
*/
/**
- * @file gns/gnunet-service-credential.c
- * @brief GNU Credential Service (main service)
- * @author Adnan Husain
+ * @file credential/gnunet-service-credential.c
+ * @brief GNUnet Credential Service (main service)
+ * @author Martin Schanzenbach
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_credential_service.h"
#include "gnunet_statistics_service.h"
#include "credential.h"
+#include "credential_serialization.h"
#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;
-#define GNUNET_CREDENTIAL_MAX_LENGTH 255
+struct DelegationSetQueueEntry;
+
+
+struct DelegationChainEntry
+{
+ /**
+ * DLL
+ */
+ struct DelegationChainEntry *next;
+
+ /**
+ * DLL
+ */
+ struct DelegationChainEntry *prev;
+
+ /**
+ * The issuer
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+ /**
+ * The subject
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+ /**
+ * The issued attribute
+ */
+ char *issuer_attribute;
+
+ /**
+ * The delegated attribute
+ */
+ char *subject_attribute;
+};
/**
* DLL for record
*/
struct CredentialRecordEntry *prev;
+ /**
+ * Number of references in delegation chains
+ */
+ uint32_t refcount;
/**
* Payload
*/
- struct GNUNET_CREDENTIAL_CredentialRecordData record_data;
+ struct GNUNET_CREDENTIAL_Credential *credential;
+};
+
+/**
+ * DLL used for delegations
+ * Used for OR delegations
+ */
+struct DelegationQueueEntry
+{
+ /**
+ * DLL
+ */
+ struct DelegationQueueEntry *next;
+
+ /**
+ * DLL
+ */
+ struct DelegationQueueEntry *prev;
+
+ /**
+ * Sets under this Queue
+ */
+ struct DelegationSetQueueEntry *set_entries_head;
+
+ /**
+ * Sets under this Queue
+ */
+ struct DelegationSetQueueEntry *set_entries_tail;
+
+ /**
+ * Parent set
+ */
+ struct DelegationSetQueueEntry *parent_set;
/**
- * Size
+ * Required solutions
*/
- uint64_t record_data_size;
+ uint32_t required_solutions;
};
/**
- * DLL for attributes - Used as a queue
- * Insert tail - Pop head
+ * DLL for delegation sets
+ * Used for AND delegation set
*/
-struct AttributeRecordEntry
+struct DelegationSetQueueEntry
{
/**
* DLL
*/
- struct AttributeRecordEntry *next;
+ struct DelegationSetQueueEntry *next;
/**
* DLL
*/
- struct AttributeRecordEntry *prev;
+ struct DelegationSetQueueEntry *prev;
+
+ /**
+ * GNS handle
+ */
+ struct GNUNET_GNS_LookupRequest *lookup_request;
/**
- * Payload
+ * Verify handle
+ */
+ struct VerifyRequestHandle *handle;
+
+ /**
+ * Parent attribute delegation
+ */
+ struct DelegationQueueEntry *parent;
+
+ /**
+ * Issuer key
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
+
+ /**
+ * Queue entries of this set
+ */
+ struct DelegationQueueEntry *queue_entries_head;
+
+ /**
+ * Queue entries of this set
+ */
+ struct DelegationQueueEntry *queue_entries_tail;
+
+ /**
+ * Parent QueueEntry
+ */
+ struct DelegationQueueEntry *parent_queue_entry;
+
+ /**
+ * Issuer attribute delegated to
+ */
+ char *issuer_attribute;
+
+ /**
+ * The current attribute to look up
*/
- struct GNUNET_CREDENTIAL_AttributeRecordData record_data;
+ char *lookup_attribute;
+
+ /**
+ * Trailing attribute context
+ */
+ char *attr_trailer;
+
+ /**
+ * Still to resolve delegation as string
+ */
+ char *unresolved_attribute_delegation;
+
+ /**
+ * The delegation chain entry
+ */
+ struct DelegationChainEntry *delegation_chain_entry;
+
};
struct GNUNET_SERVICE_Client *client;
/**
- * Handle to GNS lookup
+ * GNS handle
*/
struct GNUNET_GNS_LookupRequest *lookup_request;
+ /**
+ * Size of delegation tree
+ */
+ uint32_t delegation_chain_size;
+
+ /**
+ * Children of this attribute
+ */
+ struct DelegationChainEntry *delegation_chain_head;
+
+ /**
+ * Children of this attribute
+ */
+ struct DelegationChainEntry *delegation_chain_tail;
+
/**
* Issuer public key
*/
struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
-
+
/**
* Issuer attribute
*/
struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
/**
- * Credential Chain
+ * Credential DLL
*/
struct CredentialRecordEntry *cred_chain_head;
/**
- * Credential Chain
+ * Credential DLL
*/
struct CredentialRecordEntry *cred_chain_tail;
/**
- * Number of chain entries
+ * Credential DLL size
*/
- uint32_t cred_chain_entries;
+ uint32_t cred_chain_size;
/**
- * Attribute Queue
+ * Root Delegation Set
*/
- struct AttributeRecordEntry *attr_queue_head;
-
+ struct DelegationSetQueueEntry *root_set;
+
/**
- * Attribute Queue
+ * Current Delegation Pointer
*/
- struct AttributeRecordEntry *attr_queue_tail;
-
+ struct DelegationQueueEntry *current_delegation;
+
/**
- * Current Attribute Pointer
+ * request id
*/
- struct AttributeRecordEntry* attr_pointer;
+ uint32_t request_id;
/**
- * The found credential
+ * Pending lookups
*/
- struct GNUNET_CREDENTIAL_CredentialRecordData *credential;
+ uint64_t pending_lookups;
/**
- * Length of the credential
+ * Credential iterator
*/
- uint32_t credential_size;
+ struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter;
/**
- * request id
+ * Collect task
*/
- uint32_t request_id;
+ struct GNUNET_SCHEDULER_Task *collect_next_task;
};
*/
static struct GNUNET_STATISTICS_Handle *statistics;
-
-
/**
* Handle to GNS service.
*/
static struct GNUNET_GNS_Handle *gns;
+
/**
- * Task run during shutdown.
- *
- * @param cls unused
- * @param tc unused
+ * Handle to namestore service
*/
+static struct GNUNET_NAMESTORE_Handle *namestore;
+
+static void
+cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
+{
+ struct DelegationQueueEntry *dq_entry;
+ struct DelegationSetQueueEntry *child;
+
+ if (NULL == ds_entry)
+ return;
+
+ for (dq_entry = ds_entry->queue_entries_head;
+ NULL != dq_entry;
+ dq_entry = ds_entry->queue_entries_head)
+ {
+ GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
+ ds_entry->queue_entries_tail,
+ dq_entry);
+ for (child = dq_entry->set_entries_head;
+ NULL != child;
+ child = dq_entry->set_entries_head)
+ {
+ GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
+ dq_entry->set_entries_tail,
+ child);
+ cleanup_delegation_set (child);
+ }
+ GNUNET_free (dq_entry);
+ }
+ GNUNET_free_non_null (ds_entry->issuer_key);
+ GNUNET_free_non_null (ds_entry->lookup_attribute);
+ GNUNET_free_non_null (ds_entry->issuer_attribute);
+ GNUNET_free_non_null (ds_entry->unresolved_attribute_delegation);
+ GNUNET_free_non_null (ds_entry->attr_trailer);
+ if (NULL != ds_entry->lookup_request)
+ {
+ GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
+ ds_entry->lookup_request = NULL;
+ }
+ if (NULL != ds_entry->delegation_chain_entry)
+ {
+ GNUNET_free_non_null (ds_entry->delegation_chain_entry->subject_attribute);
+ GNUNET_free_non_null (ds_entry->delegation_chain_entry->issuer_attribute);
+ GNUNET_free (ds_entry->delegation_chain_entry);
+ }
+ GNUNET_free (ds_entry);
+}
+
+static void
+cleanup_handle (struct VerifyRequestHandle *vrh)
+{
+ struct CredentialRecordEntry *cr_entry;
+ 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;
+ }
+ cleanup_delegation_set (vrh->root_set);
+ GNUNET_free_non_null (vrh->issuer_attribute);
+ for (cr_entry = vrh->cred_chain_head;
+ NULL != vrh->cred_chain_head;
+ cr_entry = vrh->cred_chain_head)
+ {
+ GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
+ vrh->cred_chain_tail,
+ cr_entry);
+ GNUNET_free_non_null (cr_entry->credential);
+ GNUNET_free (cr_entry);
+ }
+ GNUNET_free (vrh);
+}
+
static void
shutdown_task (void *cls)
{
struct VerifyRequestHandle *vrh;
-
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Shutting down!\n");
+ "Shutting down!\n");
+
while (NULL != (vrh = vrh_head))
{
//CREDENTIAL_resolver_lookup_cancel (clh->lookup);
GNUNET_CONTAINER_DLL_remove (vrh_head,
vrh_tail,
vrh);
- GNUNET_free (vrh);
+ cleanup_handle (vrh);
}
if (NULL != gns)
GNUNET_GNS_disconnect (gns);
gns = NULL;
}
+ if (NULL != namestore)
+ {
+ GNUNET_NAMESTORE_disconnect (namestore);
+ namestore = NULL;
+ }
if (NULL != statistics)
{
GNUNET_STATISTICS_destroy (statistics,
GNUNET_NO);
statistics = NULL;
}
-
-}
-
-/**
- * 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;
}
-static void
-start_backward_resolution (void* cls,
- uint32_t rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct VerifyRequestHandle *vrh = cls;
- struct GNUNET_CREDENTIAL_CredentialRecordData *cred;
- struct CredentialRecordEntry *cred_pointer;
-
- for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL;
- cred_pointer = cred_pointer->next){
- cred = &cred_pointer->record_data;
-
- if(0 != memcmp (&vrh->attr_pointer->record_data.subject_key,
- &cred_pointer->record_data.issuer_key,
- sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
- continue;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Found issuer\n");
-
- }
-
-
-
- //Start from next to head
- vrh->attr_pointer = vrh->attr_pointer->next;
-
- if(vrh->attr_pointer->next != NULL){
- //Start with backward resolution
- vrh->lookup_request = GNUNET_GNS_lookup (gns,
- vrh->issuer_attribute,
- &vrh->issuer_key, //issuer_key,
- GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
- GNUNET_GNS_LO_DEFAULT,
- NULL, //shorten_key, always NULL
- &start_backward_resolution,
- vrh);
- }
-
-
-
-}
-
-
-/**
- * Send.
- *
- * @param handle the handle to the request
- */
static void
send_lookup_response (struct VerifyRequestHandle *vrh)
{
- size_t len;
struct GNUNET_MQ_Envelope *env;
- struct VerifyResultMessage *rmsg;
- struct CredentialRecordEntry *cr_entry;
- uint32_t cred_verified;
+ struct DelegationChainResultMessage *rmsg;
+ struct DelegationChainEntry *dce;
+ struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
+ struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
+ struct CredentialRecordEntry *cd;
+ struct CredentialRecordEntry *tmp;
+ size_t size;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending response\n");
+ dce = vrh->delegation_chain_head;
+ for (uint32_t 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;
+ }
+ dce = dce->next;
+ }
/**
- * Get serialized record data size
+ * Remove all credentials not needed
*/
- len = vrh->credential_size; //TODO max length of attr
+ 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--;
+ }
- //TODO add attr chain
/**
- * Prepare a lookup result response message for the client
+ * Get serialized record data
+ * Append at the end of rmsg
*/
+ cd = vrh->cred_chain_head;
+ for (uint32_t 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,
+ vrh->cred_chain_size,
+ cred);
env = GNUNET_MQ_msg_extra (rmsg,
- len,
+ size,
GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
//Assign id so that client can find associated request
rmsg->id = vrh->request_id;
- rmsg->cd_count = htonl (vrh->cred_chain_entries);
+ rmsg->d_count = htonl (vrh->delegation_chain_size);
+ rmsg->c_count = htonl (vrh->cred_chain_size);
- /**
- * Get serialized record data
- * Append at the end of rmsg
- */
- rmsg->cred_found = htonl (GNUNET_NO);
- if (NULL != vrh->credential)
- {
- memcpy (&rmsg[1],
- vrh->credential,
- vrh->credential_size);
+ 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,
+ vrh->cred_chain_size,
+ cred,
+ size,
+ (char*)&rmsg[1]));
- /*char* tmp_entry = (char*)&rmsg[1];
- for (cr_entry = vrh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next)
- {
- memcpy (tmp_entry,
- &cr_entry->record_data,
- cr_entry->record_data_size);
- tmp_entry += cr_entry->record_data_size;
- }*/
GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
env);
-
GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
-
- /**
- * TODO:
- * - Free DLL
- * - Refactor into cleanup_handle() function for this
- */
- GNUNET_free (vrh);
+ cleanup_handle(vrh);
GNUNET_STATISTICS_update (statistics,
"Completed verifications", 1,
}
+static void
+backward_resolution (void* cls,
+ uint32_t rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+
+ struct VerifyRequestHandle *vrh;
+ const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
+ struct CredentialRecordEntry *cred_pointer;
+ struct DelegationSetQueueEntry *current_set;
+ struct DelegationSetQueueEntry *ds_entry;
+ struct DelegationSetQueueEntry *tmp_set;
+ struct DelegationQueueEntry *dq_entry;
+ char *expanded_attr;
+ char *lookup_attribute;
+
+
+ current_set = cls;
+ current_set->lookup_request = NULL;
+ vrh = current_set->handle;
+ vrh->pending_lookups--;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got %d attrs\n", rd_count);
+
+ // Each OR
+ for (uint32_t i=0; i < rd_count; i++)
+ {
+ if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
+ continue;
+
+ sets = rd[i].data;
+ 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));
+
+ if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
+ (const char*)&sets[1],
+ ntohl(sets->set_count),
+ set))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to deserialize!\n");
+ continue;
+ }
+ dq_entry = GNUNET_new (struct DelegationQueueEntry);
+ dq_entry->required_solutions = ntohl(sets->set_count);
+ dq_entry->parent_set = current_set;
+ GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
+ current_set->queue_entries_tail,
+ dq_entry);
+ // Each AND
+ for (uint32_t j=0; j<ntohl(sets->set_count); j++)
+ {
+ ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
+ if (NULL != current_set->attr_trailer)
+ {
+ if (0 == set[j].subject_attribute_len)
+ {
+ GNUNET_asprintf (&expanded_attr,
+ "%s",
+ current_set->attr_trailer);
+
+ } else {
+ GNUNET_asprintf (&expanded_attr,
+ "%s.%s",
+ set[j].subject_attribute,
+ current_set->attr_trailer);
+ }
+ 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_DEBUG,
+ "Not Expanding %s\n", set[j].subject_attribute);
+ ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
+ }
+ }
+
+ //Add a credential chain entry
+ ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
+ ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
+ ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ GNUNET_memcpy (ds_entry->issuer_key,
+ &set[j].subject_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ if (0 < set[j].subject_attribute_len)
+ ds_entry->delegation_chain_entry->subject_attribute = GNUNET_strdup (set[j].subject_attribute);
+ ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
+ ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
+
+ ds_entry->parent_queue_entry = dq_entry; //current_delegation;
+ GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
+ dq_entry->set_entries_tail,
+ ds_entry);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Checking for cred match\n");
+ /**
+ * Check if this delegation already matches one of our credentials
+ */
+ for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL;
+ cred_pointer = cred_pointer->next)
+ {
+ if(0 != memcmp (&set->subject_key,
+ &cred_pointer->credential->issuer_key,
+ sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
+ continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Checking if %s matches %s\n",
+ ds_entry->unresolved_attribute_delegation,
+ cred_pointer->credential->issuer_attribute);
+
+ if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
+ cred_pointer->credential->issuer_attribute))
+ continue;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Found issuer\n");
+ cred_pointer->refcount++;
+ //Backtrack
+ for (tmp_set = ds_entry;
+ NULL != tmp_set->parent_queue_entry;
+ tmp_set = tmp_set->parent_queue_entry->parent_set)
+ {
+ tmp_set->parent_queue_entry->required_solutions--;
+ if (NULL != tmp_set->delegation_chain_entry)
+ {
+ vrh->delegation_chain_size++;
+ GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
+ vrh->delegation_chain_tail,
+ tmp_set->delegation_chain_entry);
+ }
+ if (0 < tmp_set->parent_queue_entry->required_solutions)
+ break;
+ }
+
+ if (NULL == tmp_set->parent_queue_entry)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "All solutions found\n");
+ //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_DEBUG,
+ "Building new lookup request from %s\n",
+ ds_entry->unresolved_attribute_delegation);
+ //Continue with backward resolution
+ char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1];
+ strcpy (issuer_attribute_name,
+ ds_entry->unresolved_attribute_delegation);
+ char *next_attr = strtok (issuer_attribute_name, ".");
+ if (NULL == next_attr)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse next attribute\n");
+ continue;
+ }
+ GNUNET_asprintf (&lookup_attribute,
+ "%s.gnu",
+ next_attr);
+ GNUNET_asprintf (&ds_entry->lookup_attribute,
+ "%s",
+ next_attr);
+ if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation))
+ {
+ ds_entry->attr_trailer = NULL;
+ } else {
+ next_attr += strlen (next_attr) + 1;
+ ds_entry->attr_trailer = GNUNET_strdup (next_attr);
+ }
+
+ 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_DEBUG,
+ "%s still to go...\n", ds_entry->attr_trailer);
+
+ vrh->pending_lookups++;
+ ds_entry->handle = vrh;
+ ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
+ lookup_attribute,
+ ds_entry->issuer_key, //issuer_key,
+ GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
+ GNUNET_GNS_LO_DEFAULT,
+ &backward_resolution,
+ ds_entry);
+ GNUNET_free (lookup_attribute);
+ }
+ }
+
+ if(0 == vrh->pending_lookups)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "We are all out of attributes...\n");
+ send_lookup_response (vrh);
+ return;
+
+ }
+}
+
+
/**
* Result from GNS lookup.
*
* @param cls the closure (our client lookup handle)
- * @param rd_count the number of records in @a rd
- * @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;
- int cred_record_count;
- int i;
- const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
+ struct DelegationSetQueueEntry *ds_entry;
struct CredentialRecordEntry *cr_entry;
- uint32_t cred_verified;
+ 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;
- /**
- * TODO:
- * Check if we have already found our credential here
- * If so return success
- * Else
- * Save all found attributes/issues and prepare forward
- * resolution of issuer attribute
- */
- cr_entry = GNUNET_new (struct CredentialRecordEntry);
- cr_entry->record_data = *crd;
- cr_entry->record_data_size = rd[i].data_size;
- GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
- vrh->cred_chain_tail,
- cr_entry);
- /*if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL,
- &crd->purpose,
- &crd->sig,
- &crd->issuer_key))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Invalid credential found\n");
- continue;
- }*/
- if (0 != memcmp (&crd->issuer_key,
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No credentials found\n");
+ send_lookup_response (vrh);
+ return;
+ }
+
+ 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;
}
- GNUNET_break (0); //TODO remove when implemented
-
/**
- * Check for attributes from the issuer and follow the chain
+ * Check for attributes from the issuer and follow the chain
* till you get the required subject's attributes
*/
- if(cred_verified != GNUNET_YES){
-
+ char issuer_attribute_name[strlen (vrh->issuer_attribute) + strlen (".gnu") + 1];
+ strcpy (issuer_attribute_name,
+ vrh->issuer_attribute);
+ strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
+ ".gnu");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Looking up %s\n", issuer_attribute_name);
+ ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
+ ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ GNUNET_memcpy (ds_entry->issuer_key,
+ &vrh->issuer_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
+ ds_entry->handle = vrh;
+ ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
+ vrh->root_set = ds_entry;
+ vrh->pending_lookups = 1;
+ //Start with backward resolution
+ ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
+ issuer_attribute_name,
+ &vrh->issuer_key, //issuer_key,
+ GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
+ GNUNET_GNS_LO_DEFAULT,
+ &backward_resolution,
+ ds_entry);
+}
- vrh->attr_pointer = vrh->attr_pointer->next;
- if(vrh->attr_pointer != NULL){
+static int
+check_verify (void *cls,
+ const struct VerifyMessage *v_msg)
+{
+ size_t msg_size;
+ const char* attr;
- //Start with backward resolution
- GNUNET_GNS_lookup (gns,
- vrh->issuer_attribute,
- &vrh->issuer_key, //issuer_key,
- GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
- GNUNET_GNS_LO_DEFAULT,
- NULL, //shorten_key, always NULL
- &start_backward_resolution,
- vrh);
- }
+ 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];
-
- /**
- * TODO
- * Start resolution of Attribute delegations from issuer
- *
- * - Build adequate data structures for attribute(s) to lookup
- * - Use GNUNET_GNSRECORD_TYPE_XXX
- * - recursively try to find match(es) with results found top
- * - return one found credential chain
- *
- */
+ if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
}
-
-/**
- * Handle Credential verification requests from client
- *
- * @param cls the closure
- * @param client the client
- * @param message the message
- */
static void
handle_verify (void *cls,
- const struct VerifyMessage *v_msg)
+ 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;
+ 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_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;
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 (0 == strlen (issuer_attribute))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No subject attribute provided!\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No issuer attribute provided!\n");
send_lookup_response (vrh);
return;
}
- if (NULL == issuer_attribute)
+ /**
+ * 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,
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Cannot deserialize credentials!\n");
+ send_lookup_response (vrh);
+ return;
+ }
+
+ for (uint32_t 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);
+
+}
+
+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,
+ 1);
+}
+
+
+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;
+
+ cred_record_count = 0;
+ for (uint32_t 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);
+}
+
+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);
+}
+
+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 (0 == strlen (issuer_attribute))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"No issuer attribute provided!\n");
send_lookup_response (vrh);
return;
}
+ 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);
}
-/**
- * One of our clients disconnected, clean up after it.
- *
- * @param cls NULL
- * @param client the client that disconnected
- */
+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[msg_size - sizeof (struct CollectMessage) - 1]) ||
+ (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
static void
client_disconnect_cb (void *cls,
struct GNUNET_SERVICE_Client *client,
client);
}
-/**
- * Add a client to our list of active clients.
- *
- * @param cls NULL
- * @param client client to add
- * @param mq message queue for @a client
- * @return this client
- */
static void *
client_connect_cb (void *cls,
struct GNUNET_SERVICE_Client *client,
* Process Credential requests.
*
* @param cls closure
- * @param server the initialized server
* @param c configuration to use
+ * @param handle service handle
*/
static void
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);
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 */