X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fcredential%2Fgnunet-service-credential.c;h=be75e485ec375f65b2e573615e93fe7f1f9ad95c;hb=1eb75229e02e5bd678f1a99eae9a6062330ecb46;hp=3ad2e2e1dd580c057e72569d00e2f529c47fd9a9;hpb=3664423a917b4cf3773445b40b5ad8f5dd8e35e8;p=oweals%2Fgnunet.git diff --git a/src/credential/gnunet-service-credential.c b/src/credential/gnunet-service-credential.c index 3ad2e2e1d..be75e485e 100644 --- a/src/credential/gnunet-service-credential.c +++ b/src/credential/gnunet-service-credential.c @@ -27,43 +27,199 @@ #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 #include #include #include #include -#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 AttributeRecordEntry +struct CredentialRecordEntry { /** * DLL */ - struct AttributeRecordEntry *next; + struct CredentialRecordEntry *next; /** * DLL */ - struct AttributeRecordEntry *prev; - + struct CredentialRecordEntry *prev; + + /** + * Number of references in delegation chains + */ + uint32_t refcount; /** * Payload */ - struct GNUNET_CREDENTIAL_AttributeRecordData 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; + + /** + * Required solutions + */ + uint32_t required_solutions; +}; + +/** + * DLL for delegation sets + * Used for AND delegation set + */ +struct DelegationSetQueueEntry +{ + /** + * DLL + */ + struct DelegationSetQueueEntry *next; + + /** + * DLL + */ + struct DelegationSetQueueEntry *prev; + + /** + * GNS handle + */ + struct GNUNET_GNS_LookupRequest *lookup_request; + + /** + * 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 + */ + 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; + }; + /** * Handle to a lookup operation from api */ @@ -86,35 +242,85 @@ struct VerifyRequestHandle 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 + */ + char *issuer_attribute; + /** * Subject public key */ struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; /** - * Attribute Chain + * Credential DLL */ - struct AttributeRecordEntry *attr_chain_head; + struct CredentialRecordEntry *cred_chain_head; /** - * Attribute Chain + * Credential DLL */ - struct AttributeRecordEntry *attr_chain_tail; + struct CredentialRecordEntry *cred_chain_tail; + + /** + * Credential DLL size + */ + uint32_t cred_chain_size; + + /** + * Root Delegation Set + */ + struct DelegationSetQueueEntry *root_set; + + /** + * Current Delegation Pointer + */ + struct DelegationQueueEntry *current_delegation; /** * request id */ uint32_t request_id; + /** + * Pending lookups + */ + uint64_t pending_lookups; + + /** + * Credential iterator + */ + struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter; + + /** + * Collect task + */ + struct GNUNET_SCHEDULER_Task *collect_next_task; + }; @@ -133,13 +339,98 @@ static struct VerifyRequestHandle *vrh_tail; */ static struct GNUNET_STATISTICS_Handle *statistics; - - /** * Handle to GNS service. */ static struct GNUNET_GNS_Handle *gns; + +/** + * 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); + } + if (NULL != ds_entry->issuer_key) + GNUNET_free (ds_entry->issuer_key); + if (NULL != ds_entry->lookup_attribute) + GNUNET_free (ds_entry->lookup_attribute); + if (NULL != ds_entry->issuer_attribute) + GNUNET_free (ds_entry->issuer_attribute); + if (NULL != ds_entry->unresolved_attribute_delegation) + GNUNET_free (ds_entry->unresolved_attribute_delegation); + if (NULL != ds_entry->attr_trailer) + GNUNET_free (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) + { + if (NULL != ds_entry->delegation_chain_entry->subject_attribute) + GNUNET_free (ds_entry->delegation_chain_entry->subject_attribute); + if (NULL != ds_entry->delegation_chain_entry->issuer_attribute) + GNUNET_free (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); + if (NULL != vrh->issuer_attribute) + GNUNET_free (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); + if (NULL != cr_entry->credential); + GNUNET_free (cr_entry->credential); + GNUNET_free (cr_entry); + } + GNUNET_free (vrh); +} + /** * Task run during shutdown. * @@ -150,26 +441,421 @@ 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; } - + +} + + + +/** + * Send. + * + * @param handle the handle to the request + */ +static void +send_lookup_response (struct VerifyRequestHandle *vrh) +{ + struct GNUNET_MQ_Envelope *env; + 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; + int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending response\n"); + dce = vrh->delegation_chain_head; + for (i=0;idelegation_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; + } + + /** + * 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 + */ + cd = vrh->cred_chain_head; + for (i=0;icred_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, + 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 (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])); + + GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client), + env); + GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh); + cleanup_handle(vrh); + + GNUNET_STATISTICS_update (statistics, + "Completed verifications", 1, + GNUNET_NO); +} + + +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; + int i; + int j; + + + 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 (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 (j=0; jset_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, "."); + 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 +delegation_chain_resolution_start (void* cls) +{ + struct VerifyRequestHandle *vrh = cls; + struct DelegationSetQueueEntry *ds_entry; + struct CredentialRecordEntry *cr_entry; + vrh->lookup_request = NULL; + + if (0 == vrh->cred_chain_size) + { + 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 (cr_entry->credential->issuer_attribute, vrh->issuer_attribute)) + continue; + cr_entry->refcount++; + //Found match prematurely + send_lookup_response (vrh); + return; + + } + + /** + * Check for attributes from the issuer and follow the chain + * till you get the required subject's attributes + */ + char issuer_attribute_name[strlen (vrh->issuer_attribute)]; + 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); + 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); } /** @@ -181,12 +867,10 @@ shutdown_task (void *cls) */ static int check_verify (void *cls, - const struct VerifyMessage *v_msg) + const struct VerifyMessage *v_msg) { size_t msg_size; - size_t attr_len; - const char* s_attr; - const char* i_attr; + const char* attr; msg_size = ntohs (v_msg->header.size); if (msg_size < sizeof (struct VerifyMessage)) @@ -194,17 +878,14 @@ check_verify (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - i_attr = (const char *) &v_msg[1]; - if ( ('\0' != i_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) || - (strlen (i_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) ) + if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) { GNUNET_break (0); return GNUNET_SYSERR; } - attr_len = strlen (i_attr); - s_attr = ((const char *) &v_msg[1]) + attr_len + 1; - if ( ('\0' != s_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) || - (strlen (s_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) ) + attr = (const char *) &v_msg[1]; + + if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) { GNUNET_break (0); return GNUNET_SYSERR; @@ -212,174 +893,262 @@ check_verify (void *cls, return GNUNET_OK; } - /** - * Result from GNS lookup. + * Handle Credential verification requests from client * - * @param cls the closure (our client lookup handle) - * @param rd_count the number of records in @a rd - * @param rd the record data + * @param cls the closure + * @param client the client + * @param message the message */ static void -send_lookup_response (void* cls, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) +handle_verify (void *cls, + const struct VerifyMessage *v_msg) { - struct VerifyRequestHandle *vrh = cls; - size_t len; + struct VerifyRequestHandle *vrh; + struct GNUNET_SERVICE_Client *client = cls; + struct CredentialRecordEntry *cr_entry; + uint32_t credentials_count; + uint32_t credential_data_size; int i; - int attr_record_count; - struct GNUNET_MQ_Envelope *env; - struct VerifyResultMessage *rmsg; - const struct GNUNET_CREDENTIAL_AttributeRecordData *ard; - struct AttributeRecordEntry *ar_entry; + 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; - attr_record_count = 0; - for (i=0; i < rd_count; i++) + 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, attr, ntohs (v_msg->issuer_attribute_len)); + issuer_attribute[ntohs (v_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 = v_msg->id; + vrh->issuer_key = v_msg->issuer_key; + vrh->subject_key = v_msg->subject_key; + vrh->issuer_attribute = GNUNET_strdup (issuer_attribute); + if (NULL == issuer_attribute) { - if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type) - continue; - attr_record_count++; - ard = 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 - */ - ar_entry = GNUNET_new (struct AttributeRecordEntry); - ar_entry->record_data = *ard; - GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_chain_head, - vrh->attr_chain_tail, - ar_entry); - + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No issuer attribute provided!\n"); + send_lookup_response (vrh); + return; } - /** - * 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 - * + * 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; + } - /** - * Get serialized record data size - */ - len = attr_record_count * sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData); + for (i=0;icredential = 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++; + } - /** - * Prepare a lookup result response message for the client - */ - env = GNUNET_MQ_msg_extra (rmsg, - len, - GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT); - //Assign id so that client can find associated request - rmsg->id = vrh->request_id; - rmsg->ad_count = htonl (attr_record_count); + delegation_chain_resolution_start (vrh); - /** - * Get serialized record data - * Append at the end of rmsg - */ - i = 0; - struct GNUNET_CREDENTIAL_AttributeRecordData *tmp_record = (struct GNUNET_CREDENTIAL_AttributeRecordData*) &rmsg[1]; - for (ar_entry = vrh->attr_chain_head; NULL != ar_entry; ar_entry = ar_entry->next) - { - memcpy (tmp_record, - &ar_entry->record_data, - sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData)); - tmp_record++; - } - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client), - env); +} - GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, 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); +} - /** - * TODO: - * - Free DLL - * - Refactor into cleanup_handle() function for this - */ - GNUNET_free (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); +} - GNUNET_STATISTICS_update (statistics, - "Completed verifications", 1, - GNUNET_NO); - GNUNET_STATISTICS_update (statistics, - "Attributes resolved", - rd_count, - GNUNET_NO); +/** + * 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); } /** - * Handle attribute verification requests from client + * 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_verify (void *cls, - const struct VerifyMessage *v_msg) +handle_collect (void *cls, + const struct CollectMessage *c_msg) { + char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; - char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; - size_t issuer_attribute_len; struct VerifyRequestHandle *vrh; struct GNUNET_SERVICE_Client *client = cls; - char *attrptr = issuer_attribute; + char *attrptr = attr; const char *utf_in; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received VERIFY message\n"); + "Received COLLECT message\n"); - utf_in = (const char *) &v_msg[1]; - GNUNET_STRINGS_utf8_tolower (utf_in, attrptr); - issuer_attribute_len = strlen (utf_in); - utf_in = (const char *) (&v_msg[1] + issuer_attribute_len + 1); - attrptr = subject_attribute; + 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 = v_msg->id; - vrh->issuer_key = v_msg->issuer_key; - vrh->subject_key = v_msg->subject_key; + 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 == subject_attribute) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No subject attribute provided!\n"); - send_lookup_response (vrh, 0, NULL); - return; - } if (NULL == issuer_attribute) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer attribute provided!\n"); - send_lookup_response (vrh, 0, NULL); + 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_ATTRIBUTE, - GNUNET_GNS_LO_DEFAULT, - NULL, //shorten_key, always NULL - &send_lookup_response, - 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. * @@ -434,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); @@ -454,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 */