2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file gns/gnunet-service-credential.c
22 * @brief GNU Credential Service (main service)
23 * @author Adnan Husain
26 #include "gnunet_util_lib.h"
27 #include "gnunet_credential_service.h"
28 #include "gnunet_statistics_service.h"
29 #include "credential.h"
30 #include "credential_serialization.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_signatures.h"
34 #include <gnunet_dnsparser_lib.h>
35 #include <gnunet_identity_service.h>
36 #include <gnunet_gnsrecord_lib.h>
37 #include <gnunet_namestore_service.h>
38 #include <gnunet_gns_service.h>
41 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
43 struct VerifyRequestHandle;
45 struct DelegationSetQueueEntry;
48 struct DelegationChainEntry
53 struct DelegationChainEntry *next;
58 struct DelegationChainEntry *prev;
63 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
68 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
71 * The issued attribute
73 char *issuer_attribute;
76 * The delegated attribute
78 char *subject_attribute;
84 struct CredentialRecordEntry
89 struct CredentialRecordEntry *next;
94 struct CredentialRecordEntry *prev;
97 * Number of references in delegation chains
104 struct GNUNET_CREDENTIAL_Credential *credential;
108 * DLL used for delegations
109 * Used for OR delegations
111 struct DelegationQueueEntry
116 struct DelegationQueueEntry *next;
121 struct DelegationQueueEntry *prev;
124 * Sets under this Queue
126 struct DelegationSetQueueEntry *set_entries_head;
129 * Sets under this Queue
131 struct DelegationSetQueueEntry *set_entries_tail;
136 struct DelegationSetQueueEntry *parent_set;
141 uint32_t required_solutions;
145 * DLL for delegation sets
146 * Used for AND delegation set
148 struct DelegationSetQueueEntry
153 struct DelegationSetQueueEntry *next;
158 struct DelegationSetQueueEntry *prev;
163 struct GNUNET_GNS_LookupRequest *lookup_request;
168 struct VerifyRequestHandle *handle;
171 * Parent attribute delegation
173 struct DelegationQueueEntry *parent;
178 struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
181 * Queue entries of this set
183 struct DelegationQueueEntry *queue_entries_head;
186 * Queue entries of this set
188 struct DelegationQueueEntry *queue_entries_tail;
193 struct DelegationQueueEntry *parent_queue_entry;
196 * Issuer attribute delegated to
198 char *issuer_attribute;
201 * The current attribute to look up
203 char *lookup_attribute;
206 * Trailing attribute context
211 * Still to resolve delegation as string
213 char *unresolved_attribute_delegation;
216 * The delegation chain entry
218 struct DelegationChainEntry *delegation_chain_entry;
224 * Handle to a lookup operation from api
226 struct VerifyRequestHandle
230 * We keep these in a DLL.
232 struct VerifyRequestHandle *next;
235 * We keep these in a DLL.
237 struct VerifyRequestHandle *prev;
240 * Handle to the requesting client
242 struct GNUNET_SERVICE_Client *client;
247 struct GNUNET_GNS_LookupRequest *lookup_request;
250 * Size of delegation tree
252 uint32_t delegation_chain_size;
255 * Children of this attribute
257 struct DelegationChainEntry *delegation_chain_head;
260 * Children of this attribute
262 struct DelegationChainEntry *delegation_chain_tail;
267 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
272 char *issuer_attribute;
277 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
282 struct CredentialRecordEntry *cred_chain_head;
287 struct CredentialRecordEntry *cred_chain_tail;
290 * Credential DLL size
292 uint32_t cred_chain_size;
295 * Root Delegation Set
297 struct DelegationSetQueueEntry *root_set;
300 * Current Delegation Pointer
302 struct DelegationQueueEntry *current_delegation;
312 uint64_t pending_lookups;
315 * Credential iterator
317 struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter;
322 struct GNUNET_SCHEDULER_Task *collect_next_task;
330 static struct VerifyRequestHandle *vrh_head;
335 static struct VerifyRequestHandle *vrh_tail;
338 * Handle to the statistics service
340 static struct GNUNET_STATISTICS_Handle *statistics;
343 * Handle to GNS service.
345 static struct GNUNET_GNS_Handle *gns;
349 * Handle to namestore service
351 static struct GNUNET_NAMESTORE_Handle *namestore;
354 cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
356 struct DelegationQueueEntry *dq_entry;
357 struct DelegationSetQueueEntry *child;
359 if (NULL == ds_entry)
362 for (dq_entry = ds_entry->queue_entries_head;
364 dq_entry = ds_entry->queue_entries_head)
366 GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
367 ds_entry->queue_entries_tail,
369 for (child = dq_entry->set_entries_head;
371 child = dq_entry->set_entries_head)
373 GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
374 dq_entry->set_entries_tail,
376 cleanup_delegation_set (child);
378 GNUNET_free (dq_entry);
380 if (NULL != ds_entry->issuer_key)
381 GNUNET_free (ds_entry->issuer_key);
382 if (NULL != ds_entry->lookup_attribute)
383 GNUNET_free (ds_entry->lookup_attribute);
384 if (NULL != ds_entry->issuer_attribute)
385 GNUNET_free (ds_entry->issuer_attribute);
386 if (NULL != ds_entry->unresolved_attribute_delegation)
387 GNUNET_free (ds_entry->unresolved_attribute_delegation);
388 if (NULL != ds_entry->attr_trailer)
389 GNUNET_free (ds_entry->attr_trailer);
390 if (NULL != ds_entry->lookup_request)
392 GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
393 ds_entry->lookup_request = NULL;
395 if (NULL != ds_entry->delegation_chain_entry)
397 if (NULL != ds_entry->delegation_chain_entry->subject_attribute)
398 GNUNET_free (ds_entry->delegation_chain_entry->subject_attribute);
399 if (NULL != ds_entry->delegation_chain_entry->issuer_attribute)
400 GNUNET_free (ds_entry->delegation_chain_entry->issuer_attribute);
401 GNUNET_free (ds_entry->delegation_chain_entry);
403 GNUNET_free (ds_entry);
407 cleanup_handle (struct VerifyRequestHandle *vrh)
409 struct CredentialRecordEntry *cr_entry;
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 if (NULL != vrh->lookup_request)
414 GNUNET_GNS_lookup_cancel (vrh->lookup_request);
415 vrh->lookup_request = NULL;
417 cleanup_delegation_set (vrh->root_set);
418 if (NULL != vrh->issuer_attribute)
419 GNUNET_free (vrh->issuer_attribute);
420 for (cr_entry = vrh->cred_chain_head;
421 NULL != vrh->cred_chain_head;
422 cr_entry = vrh->cred_chain_head)
424 GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
425 vrh->cred_chain_tail,
427 if (NULL != cr_entry->credential);
428 GNUNET_free (cr_entry->credential);
429 GNUNET_free (cr_entry);
435 * Task run during shutdown.
441 shutdown_task (void *cls)
443 struct VerifyRequestHandle *vrh;
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 while (NULL != (vrh = vrh_head))
450 //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
451 GNUNET_CONTAINER_DLL_remove (vrh_head,
454 cleanup_handle (vrh);
459 GNUNET_GNS_disconnect (gns);
462 if (NULL != namestore)
464 GNUNET_NAMESTORE_disconnect (namestore);
467 if (NULL != statistics)
469 GNUNET_STATISTICS_destroy (statistics,
481 * @param handle the handle to the request
484 send_lookup_response (struct VerifyRequestHandle *vrh)
486 struct GNUNET_MQ_Envelope *env;
487 struct DelegationChainResultMessage *rmsg;
488 struct DelegationChainEntry *dce;
489 struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
490 struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
491 struct CredentialRecordEntry *cd;
492 struct CredentialRecordEntry *tmp;
496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497 "Sending response\n");
498 dce = vrh->delegation_chain_head;
499 for (i=0;i<vrh->delegation_chain_size;i++)
501 dd[i].issuer_key = dce->issuer_key;
502 dd[i].subject_key = dce->subject_key;
503 dd[i].issuer_attribute = dce->issuer_attribute;
504 dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
505 dd[i].subject_attribute_len = 0;
506 dd[i].subject_attribute = NULL;
507 if (NULL != dce->subject_attribute)
509 dd[i].subject_attribute = dce->subject_attribute;
510 dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
516 * Remove all credentials not needed
518 for (cd = vrh->cred_chain_head; NULL != cd;)
520 if (cd->refcount > 0)
527 GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
528 vrh->cred_chain_tail,
530 GNUNET_free (tmp->credential);
532 vrh->cred_chain_size--;
536 * Get serialized record data
537 * Append at the end of rmsg
539 cd = vrh->cred_chain_head;
540 for (i=0;i<vrh->cred_chain_size;i++)
542 cred[i].issuer_key = cd->credential->issuer_key;
543 cred[i].subject_key = cd->credential->subject_key;
544 cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1;
545 cred[i].issuer_attribute = cd->credential->issuer_attribute;
546 cred[i].expiration = cd->credential->expiration;
547 cred[i].signature = cd->credential->signature;
550 size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
552 vrh->cred_chain_size,
554 env = GNUNET_MQ_msg_extra (rmsg,
556 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
557 //Assign id so that client can find associated request
558 rmsg->id = vrh->request_id;
559 rmsg->d_count = htonl (vrh->delegation_chain_size);
560 rmsg->c_count = htonl (vrh->cred_chain_size);
562 if (0 < vrh->cred_chain_size)
563 rmsg->cred_found = htonl (GNUNET_YES);
565 rmsg->cred_found = htonl (GNUNET_NO);
568 GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
570 vrh->cred_chain_size,
575 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
577 GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
580 GNUNET_STATISTICS_update (statistics,
581 "Completed verifications", 1,
587 backward_resolution (void* cls,
589 const struct GNUNET_GNSRECORD_Data *rd)
592 struct VerifyRequestHandle *vrh;
593 const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
594 struct CredentialRecordEntry *cred_pointer;
595 struct DelegationSetQueueEntry *current_set;
596 struct DelegationSetQueueEntry *ds_entry;
597 struct DelegationSetQueueEntry *tmp_set;
598 struct DelegationQueueEntry *dq_entry;
600 char *lookup_attribute;
606 current_set->lookup_request = NULL;
607 vrh = current_set->handle;
608 vrh->pending_lookups--;
609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610 "Got %d attrs\n", rd_count);
613 for (i=0; i < rd_count; i++)
615 if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
619 struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)];
620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
621 "Found new attribute delegation with %d sets. Creating new Job...\n",
622 ntohl (sets->set_count));
624 if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
625 (const char*)&sets[1],
626 ntohl(sets->set_count),
629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630 "Failed to deserialize!\n");
633 dq_entry = GNUNET_new (struct DelegationQueueEntry);
634 dq_entry->required_solutions = ntohl(sets->set_count);
635 dq_entry->parent_set = current_set;
636 GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
637 current_set->queue_entries_tail,
640 for (j=0; j<ntohl(sets->set_count); j++)
642 ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
643 if (NULL != current_set->attr_trailer)
645 if (0 == set[j].subject_attribute_len)
647 GNUNET_asprintf (&expanded_attr,
649 current_set->attr_trailer);
652 GNUNET_asprintf (&expanded_attr,
654 set[j].subject_attribute,
655 current_set->attr_trailer);
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Expanded to %s\n", expanded_attr);
659 ds_entry->unresolved_attribute_delegation = expanded_attr;
661 if (0 != set[j].subject_attribute_len)
663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664 "Not Expanding %s\n", set[j].subject_attribute);
665 ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
669 //Add a credential chain entry
670 ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
671 ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
672 ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
673 GNUNET_memcpy (ds_entry->issuer_key,
675 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
676 if (0 < set[j].subject_attribute_len)
677 ds_entry->delegation_chain_entry->subject_attribute = GNUNET_strdup (set[j].subject_attribute);
678 ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
679 ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
681 ds_entry->parent_queue_entry = dq_entry; //current_delegation;
682 GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
683 dq_entry->set_entries_tail,
686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687 "Checking for cred match\n");
689 * Check if this delegation already matches one of our credentials
691 for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL;
692 cred_pointer = cred_pointer->next)
694 if(0 != memcmp (&set->subject_key,
695 &cred_pointer->credential->issuer_key,
696 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699 "Checking if %s matches %s\n",
700 ds_entry->unresolved_attribute_delegation,
701 cred_pointer->credential->issuer_attribute);
703 if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
704 cred_pointer->credential->issuer_attribute))
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 cred_pointer->refcount++;
711 for (tmp_set = ds_entry;
712 NULL != tmp_set->parent_queue_entry;
713 tmp_set = tmp_set->parent_queue_entry->parent_set)
715 tmp_set->parent_queue_entry->required_solutions--;
716 if (NULL != tmp_set->delegation_chain_entry)
718 vrh->delegation_chain_size++;
719 GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
720 vrh->delegation_chain_tail,
721 tmp_set->delegation_chain_entry);
723 if (0 < tmp_set->parent_queue_entry->required_solutions)
727 if (NULL == tmp_set->parent_queue_entry)
729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730 "All solutions found\n");
732 send_lookup_response (vrh);
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736 "Not all solutions found yet.\n");
740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
741 "Building new lookup request from %s\n",
742 ds_entry->unresolved_attribute_delegation);
743 //Continue with backward resolution
744 char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1];
745 strcpy (issuer_attribute_name,
746 ds_entry->unresolved_attribute_delegation);
747 char *next_attr = strtok (issuer_attribute_name, ".");
748 GNUNET_asprintf (&lookup_attribute,
751 GNUNET_asprintf (&ds_entry->lookup_attribute,
754 if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation))
756 ds_entry->attr_trailer = NULL;
758 next_attr += strlen (next_attr) + 1;
759 ds_entry->attr_trailer = GNUNET_strdup (next_attr);
762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763 "Looking up %s\n", ds_entry->lookup_attribute);
764 if (NULL != ds_entry->attr_trailer)
765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
766 "%s still to go...\n", ds_entry->attr_trailer);
768 vrh->pending_lookups++;
769 ds_entry->handle = vrh;
770 ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
772 ds_entry->issuer_key, //issuer_key,
773 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
774 GNUNET_GNS_LO_DEFAULT,
775 &backward_resolution,
777 GNUNET_free (lookup_attribute);
781 if(0 == vrh->pending_lookups)
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784 "We are all out of attributes...\n");
785 send_lookup_response (vrh);
793 * Result from GNS lookup.
795 * @param cls the closure (our client lookup handle)
796 * @param rd_count the number of records in @a rd
797 * @param rd the record data
800 delegation_chain_resolution_start (void* cls)
802 struct VerifyRequestHandle *vrh = cls;
803 struct DelegationSetQueueEntry *ds_entry;
804 struct CredentialRecordEntry *cr_entry;
805 vrh->lookup_request = NULL;
807 if (0 == vrh->cred_chain_size)
809 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
810 "No credentials found\n");
811 send_lookup_response (vrh);
815 for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next)
817 if (0 != memcmp (&cr_entry->credential->issuer_key,
819 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
821 if (0 != strcmp (cr_entry->credential->issuer_attribute, vrh->issuer_attribute))
823 cr_entry->refcount++;
824 //Found match prematurely
825 send_lookup_response (vrh);
831 * Check for attributes from the issuer and follow the chain
832 * till you get the required subject's attributes
834 char issuer_attribute_name[strlen (vrh->issuer_attribute)];
835 strcpy (issuer_attribute_name,
836 vrh->issuer_attribute);
837 strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
840 "Looking up %s\n", issuer_attribute_name);
841 ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
842 ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
843 memcpy (ds_entry->issuer_key,
845 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
846 ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
847 ds_entry->handle = vrh;
848 ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
849 vrh->root_set = ds_entry;
850 vrh->pending_lookups = 1;
851 //Start with backward resolution
852 ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
853 issuer_attribute_name,
854 &vrh->issuer_key, //issuer_key,
855 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
856 GNUNET_GNS_LO_DEFAULT,
857 &backward_resolution,
862 * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
864 * @param cls client sending the message
865 * @param v_msg message of type `struct VerifyMessage`
866 * @return #GNUNET_OK if @a v_msg is well-formed
869 check_verify (void *cls,
870 const struct VerifyMessage *v_msg)
875 msg_size = ntohs (v_msg->header.size);
876 if (msg_size < sizeof (struct VerifyMessage))
879 return GNUNET_SYSERR;
881 if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
884 return GNUNET_SYSERR;
886 attr = (const char *) &v_msg[1];
888 if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH)
891 return GNUNET_SYSERR;
897 * Handle Credential verification requests from client
899 * @param cls the closure
900 * @param client the client
901 * @param message the message
904 handle_verify (void *cls,
905 const struct VerifyMessage *v_msg)
907 struct VerifyRequestHandle *vrh;
908 struct GNUNET_SERVICE_Client *client = cls;
909 struct CredentialRecordEntry *cr_entry;
910 uint32_t credentials_count;
911 uint32_t credential_data_size;
913 char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
914 char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
915 char *attrptr = attr;
916 char *credential_data;
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920 "Received VERIFY message\n");
921 utf_in = (const char *) &v_msg[1];
922 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
923 GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
924 issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
925 vrh = GNUNET_new (struct VerifyRequestHandle);
926 GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
927 vrh->client = client;
928 vrh->request_id = v_msg->id;
929 vrh->issuer_key = v_msg->issuer_key;
930 vrh->subject_key = v_msg->subject_key;
931 vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
932 if (NULL == issuer_attribute)
934 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
935 "No issuer attribute provided!\n");
936 send_lookup_response (vrh);
940 * First, collect credentials
943 credentials_count = ntohl(v_msg->c_count);
944 credential_data_size = ntohs (v_msg->header.size)
945 - sizeof (struct VerifyMessage)
946 - ntohs (v_msg->issuer_attribute_len)
948 struct GNUNET_CREDENTIAL_Credential credentials[credentials_count];
949 credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
950 if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size,
955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
956 "Cannot deserialize credentials!\n");
957 send_lookup_response (vrh);
961 for (i=0;i<credentials_count;i++) {
962 cr_entry = GNUNET_new (struct CredentialRecordEntry);
963 cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) +
964 credentials[i].issuer_attribute_len);
965 GNUNET_memcpy (cr_entry->credential,
967 sizeof (struct GNUNET_CREDENTIAL_Credential));
968 GNUNET_memcpy (&cr_entry->credential[1],
969 credentials[i].issuer_attribute,
970 credentials[i].issuer_attribute_len);
971 cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1];
972 GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
973 vrh->cred_chain_tail,
975 vrh->cred_chain_size++;
978 delegation_chain_resolution_start (vrh);
983 * We encountered an error while collecting
986 handle_cred_collection_error_cb (void *cls)
988 struct VerifyRequestHandle *vrh = cls;
989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
990 "Got disconnected from namestore database.\n");
991 vrh->cred_collection_iter = NULL;
992 send_lookup_response (vrh);
996 collect_next (void *cls)
998 struct VerifyRequestHandle *vrh = cls;
999 vrh->collect_next_task = NULL;
1000 GNUNET_assert (NULL != vrh->cred_collection_iter);
1001 GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter);
1008 handle_cred_collection_cb (void *cls,
1009 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
1011 unsigned int rd_count,
1012 const struct GNUNET_GNSRECORD_Data *rd)
1014 struct VerifyRequestHandle *vrh = cls;
1015 struct GNUNET_CREDENTIAL_Credential *crd;
1016 struct CredentialRecordEntry *cr_entry;
1017 int cred_record_count;
1020 cred_record_count = 0;
1021 for (i=0; i < rd_count; i++)
1023 if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
1025 cred_record_count++;
1026 crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
1030 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1031 "Invalid credential found\n");
1034 cr_entry = GNUNET_new (struct CredentialRecordEntry);
1035 cr_entry->credential = crd;
1036 GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
1037 vrh->cred_chain_tail,
1039 vrh->cred_chain_size++;
1041 vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next,
1046 * We encountered an error while collecting
1049 handle_cred_collection_finished_cb (void *cls)
1051 struct VerifyRequestHandle *vrh = cls;
1052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053 "Done collecting credentials.\n");
1054 vrh->cred_collection_iter = NULL;
1055 delegation_chain_resolution_start (vrh);
1059 * Handle Credential collection requests from client
1061 * @param cls the closure
1062 * @param client the client
1063 * @param message the message
1066 handle_collect (void *cls,
1067 const struct CollectMessage *c_msg)
1069 char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1070 char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1071 struct VerifyRequestHandle *vrh;
1072 struct GNUNET_SERVICE_Client *client = cls;
1073 char *attrptr = attr;
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "Received COLLECT message\n");
1079 utf_in = (const char *) &c_msg[1];
1080 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
1082 GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
1083 issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
1084 vrh = GNUNET_new (struct VerifyRequestHandle);
1085 GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
1086 vrh->client = client;
1087 vrh->request_id = c_msg->id;
1088 vrh->issuer_key = c_msg->issuer_key;
1089 GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key,
1091 vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
1093 if (NULL == issuer_attribute)
1095 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1096 "No issuer attribute provided!\n");
1097 send_lookup_response (vrh);
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "Getting credentials for subject\n");
1103 * First, get attribute from subject
1105 vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore,
1106 &c_msg->subject_key,
1107 &handle_cred_collection_error_cb,
1109 &handle_cred_collection_cb,
1111 &handle_cred_collection_finished_cb,
1117 * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT message
1119 * @param cls client sending the message
1120 * @param v_msg message of type `struct CollectMessage`
1121 * @return #GNUNET_OK if @a v_msg is well-formed
1124 check_collect (void *cls,
1125 const struct CollectMessage *c_msg)
1130 msg_size = ntohs (c_msg->header.size);
1131 if (msg_size < sizeof (struct CollectMessage))
1134 return GNUNET_SYSERR;
1136 if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
1139 return GNUNET_SYSERR;
1141 attr = (const char *) &c_msg[1];
1143 if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) ||
1144 (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
1147 return GNUNET_SYSERR;
1153 * One of our clients disconnected, clean up after it.
1156 * @param client the client that disconnected
1159 client_disconnect_cb (void *cls,
1160 struct GNUNET_SERVICE_Client *client,
1163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164 "Client %p disconnected\n",
1169 * Add a client to our list of active clients.
1172 * @param client client to add
1173 * @param mq message queue for @a client
1174 * @return this client
1177 client_connect_cb (void *cls,
1178 struct GNUNET_SERVICE_Client *client,
1179 struct GNUNET_MQ_Handle *mq)
1181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1182 "Client %p connected\n",
1188 * Process Credential requests.
1190 * @param cls closure
1191 * @param server the initialized server
1192 * @param c configuration to use
1196 const struct GNUNET_CONFIGURATION_Handle *c,
1197 struct GNUNET_SERVICE_Handle *handle)
1200 gns = GNUNET_GNS_connect (c);
1204 _("Failed to connect to GNS\n"));
1206 namestore = GNUNET_NAMESTORE_connect (c);
1207 if (NULL == namestore)
1210 _("Failed to connect to namestore\n"));
1213 statistics = GNUNET_STATISTICS_create ("credential", c);
1214 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1219 * Define "main" method using service macro
1223 GNUNET_SERVICE_OPTION_NONE,
1226 &client_disconnect_cb,
1228 GNUNET_MQ_hd_var_size (verify,
1229 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
1230 struct VerifyMessage,
1232 GNUNET_MQ_hd_var_size (collect,
1233 GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT,
1234 struct CollectMessage,
1236 GNUNET_MQ_handler_end());
1238 /* end of gnunet-service-credential.c */