X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fcredential%2Fgnunet-service-credential.c;h=be75e485ec375f65b2e573615e93fe7f1f9ad95c;hb=1eb75229e02e5bd678f1a99eae9a6062330ecb46;hp=047ea00753b33681603bccec4b8ff474032b9761;hpb=0f854e736bf6f2d62649fe38e25967dd71aec97f;p=oweals%2Fgnunet.git diff --git a/src/credential/gnunet-service-credential.c b/src/credential/gnunet-service-credential.c index 047ea0075..be75e485e 100644 --- a/src/credential/gnunet-service-credential.c +++ b/src/credential/gnunet-service-credential.c @@ -27,21 +27,56 @@ #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 @@ -57,34 +92,131 @@ struct CredentialRecordEntry * DLL */ 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 for attributes - Used as a queue - * Insert tail - Pop head + * DLL used for delegations + * Used for OR delegations */ -struct AttributeRecordEntry +struct DelegationQueueEntry { /** * DLL */ - struct AttributeRecordEntry *next; + struct DelegationQueueEntry *next; /** * DLL */ - struct AttributeRecordEntry *prev; + struct DelegationQueueEntry *prev; /** - * Payload + * 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 */ - 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; + }; @@ -110,15 +242,30 @@ 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 */ @@ -130,35 +277,50 @@ 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; /** - * Attribute Queue + * Credential DLL size */ - struct AttributeRecordEntry *attr_queue_head; - + uint32_t cred_chain_size; + /** - * Attribute Queue + * Root Delegation Set */ - struct AttributeRecordEntry *attr_queue_tail; - + struct DelegationSetQueueEntry *root_set; + /** - * Current Attribute Pointer + * Current Delegation Pointer */ - struct AttributeRecordEntry* attr_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; + }; @@ -177,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. * @@ -194,121 +441,354 @@ 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 + * Send. * - * @param cls client sending the message - * @param v_msg message of type `struct VerifyMessage` - * @return #GNUNET_OK if @a v_msg is well-formed + * @param handle the handle to the request */ -static int -check_verify (void *cls, - const struct VerifyMessage *v_msg) +static void +send_lookup_response (struct VerifyRequestHandle *vrh) { - size_t msg_size; - size_t attr_len; - const char* s_attr; - const char* i_attr; + 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; - msg_size = ntohs (v_msg->header.size); - if (msg_size < sizeof (struct VerifyMessage)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending response\n"); + dce = vrh->delegation_chain_head; + for (i=0;idelegation_chain_size;i++) { - GNUNET_break (0); - return GNUNET_SYSERR; + 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; } - 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) ) + + /** + * Remove all credentials not needed + */ + for (cd = vrh->cred_chain_head; NULL != cd;) { - GNUNET_break (0); - return GNUNET_SYSERR; + 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--; } - 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) ) + + /** + * Get serialized record data + * Append at the end of rmsg + */ + cd = vrh->cred_chain_head; + for (i=0;icred_chain_size;i++) { - GNUNET_break (0); - return GNUNET_SYSERR; + 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; } - return GNUNET_OK; + 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 -start_backward_resolution (void* cls, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) +backward_resolution (void* cls, + uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) { - struct VerifyRequestHandle *vrh = cls; + + 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; - struct GNUNET_CREDENTIAL_CredentialRecordData *cred; - struct GNUNET_CREDENTIAL_AttributeRecordData *attr; - struct CredentialRecordEntry *cred_pointer; - const char *attribute; - const char *cred_attribute; - char *issuer_key; - char *cred_issuer_key; - const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key_ecdsa; - const struct GNUNET_CRYPTO_EcdsaPublicKey *cred_issuer_key_ecdsa; - - for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; - cred_pointer = cred_pointer->next){ - cred = &cred_pointer->record_data; - issuer_key_ecdsa = &vrh->attr_pointer->record_data.subject_key; - cred_issuer_key_ecdsa = &cred_pointer->record_data.issuer_key; - - issuer_key = GNUNET_CRYPTO_ecdsa_public_key_to_string(issuer_key_ecdsa); - cred_issuer_key = GNUNET_CRYPTO_ecdsa_public_key_to_string(cred_issuer_key_ecdsa); - if(0 == strcmp(issuer_key,cred_issuer_key)) + 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_DEBUG, - "Found issuer\n"); - } + 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); + } - - //Start from next to head - for(vrh->attr_pointer = vrh->attr_queue_head->next ; vrh->attr_pointer->next != NULL ; - vrh->attr_pointer = vrh->attr_pointer->next ){ - - //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); + 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. * @@ -317,142 +797,100 @@ start_backward_resolution (void* cls, * @param rd the record data */ static void -send_lookup_response (void* cls, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) +delegation_chain_resolution_start (void* cls) { struct VerifyRequestHandle *vrh = cls; - size_t len; - int i; - int cred_record_count; - struct GNUNET_MQ_Envelope *env; - struct VerifyResultMessage *rmsg; - const struct GNUNET_CREDENTIAL_CredentialRecordData *crd; + struct DelegationSetQueueEntry *ds_entry; struct CredentialRecordEntry *cr_entry; - int cred_verified; + vrh->lookup_request = NULL; - cred_record_count = 0; - struct AttributeRecordEntry *attr_entry; + if (0 == vrh->cred_chain_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No credentials found\n"); + send_lookup_response (vrh); + return; + } - struct GNUNET_CREDENTIAL_AttributeRecordData *ard = - GNUNET_new(struct GNUNET_CREDENTIAL_AttributeRecordData); - - attr_entry->record_data = *ard; - ard->subject_key = vrh->issuer_key; - GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_queue_head, - vrh->attr_queue_tail, - attr_entry); - for (i=0; i < rd_count; i++) + for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next) { - if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type) + if (0 != memcmp (&cr_entry->credential->issuer_key, + &vrh->issuer_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) 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; - 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)) - { - cred_verified = GNUNET_YES; - break; - } + 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 */ - if(cred_verified != GNUNET_YES){ - + 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); +} - vrh->attr_pointer = vrh->attr_queue_head; +/** + * 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; - //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; } - - - - /** - * 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 - * - */ - - /** - * Get serialized record data size - */ - len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData); - - /** - * 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 (cred_record_count); - - /** - * Get serialized record data - * Append at the end of rmsg - */ - i = 0; - struct GNUNET_CREDENTIAL_CredentialRecordData *tmp_record = (struct GNUNET_CREDENTIAL_CredentialRecordData*) &rmsg[1]; - for (cr_entry = vrh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next) + if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) { - memcpy (tmp_record, - &cr_entry->record_data, - sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData)); - tmp_record++; + GNUNET_break (0); + return GNUNET_SYSERR; } - 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); + attr = (const char *) &v_msg[1]; - GNUNET_STATISTICS_update (statistics, - "Completed verifications", 1, - GNUNET_NO); - GNUNET_STATISTICS_update (statistics, - "Credentials resolved", - rd_count, - GNUNET_NO); + if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; } /** @@ -466,59 +904,251 @@ static void handle_verify (void *cls, const struct VerifyMessage *v_msg) { - 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; + 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_DEBUG, "Received VERIFY 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; - 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 = issuer_attribute; - - if (NULL == subject_attribute) + vrh->issuer_attribute = GNUNET_strdup (issuer_attribute); + if (NULL == issuer_attribute) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "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, - "No subject attribute provided!\n"); - send_lookup_response (vrh, 0, NULL); + "Cannot deserialize credentials!\n"); + send_lookup_response (vrh); return; } + + 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++; + } + + 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, "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_CREDENTIAL, - 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. * @@ -573,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); @@ -593,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 */