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 "gnunet_protocols.h"
31 #include "gnunet_signatures.h"
33 // For Looking up GNS request
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>
39 #include "gnunet_gns_service.h"
44 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
49 struct CredentialRecordEntry
54 struct CredentialRecordEntry *next;
59 struct CredentialRecordEntry *prev;
65 struct GNUNET_CREDENTIAL_CredentialRecordData record_data;
69 * DLL for attributes - Used as a queue
70 * Insert tail - Pop head
72 struct AttributeRecordEntry
77 struct AttributeRecordEntry *next;
82 struct AttributeRecordEntry *prev;
87 struct GNUNET_CREDENTIAL_AttributeRecordData record_data;
92 * Handle to a lookup operation from api
94 struct VerifyRequestHandle
98 * We keep these in a DLL.
100 struct VerifyRequestHandle *next;
103 * We keep these in a DLL.
105 struct VerifyRequestHandle *prev;
108 * Handle to the requesting client
110 struct GNUNET_SERVICE_Client *client;
113 * Handle to GNS lookup
115 struct GNUNET_GNS_LookupRequest *lookup_request;
120 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
125 char *issuer_attribute;
130 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
135 struct CredentialRecordEntry *cred_chain_head;
140 struct CredentialRecordEntry *cred_chain_tail;
145 struct AttributeRecordEntry *attr_queue_head;
150 struct AttributeRecordEntry *attr_queue_tail;
153 * Current Attribute Pointer
155 struct AttributeRecordEntry* attr_pointer;
168 static struct VerifyRequestHandle *vrh_head;
173 static struct VerifyRequestHandle *vrh_tail;
176 * Handle to the statistics service
178 static struct GNUNET_STATISTICS_Handle *statistics;
183 * Handle to GNS service.
185 static struct GNUNET_GNS_Handle *gns;
188 * Task run during shutdown.
194 shutdown_task (void *cls)
196 struct VerifyRequestHandle *vrh;
198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 while (NULL != (vrh = vrh_head))
202 //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
203 GNUNET_CONTAINER_DLL_remove (vrh_head,
210 if (NULL != statistics)
212 GNUNET_STATISTICS_destroy (statistics,
220 * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
222 * @param cls client sending the message
223 * @param v_msg message of type `struct VerifyMessage`
224 * @return #GNUNET_OK if @a v_msg is well-formed
227 check_verify (void *cls,
228 const struct VerifyMessage *v_msg)
233 msg_size = ntohs (v_msg->header.size);
234 if (msg_size < sizeof (struct VerifyMessage))
237 return GNUNET_SYSERR;
239 if ((ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) ||
240 (ntohs (v_msg->subject_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH))
243 return GNUNET_SYSERR;
245 attrs = (const char *) &v_msg[1];
247 if ( ('\0' != attrs[ntohs(v_msg->header.size) - sizeof (struct VerifyMessage) - 1]) ||
248 (strlen (attrs) > GNUNET_CREDENTIAL_MAX_LENGTH * 2) )
251 return GNUNET_SYSERR;
257 start_backward_resolution (void* cls,
259 const struct GNUNET_GNSRECORD_Data *rd)
261 struct VerifyRequestHandle *vrh = cls;
263 struct GNUNET_CREDENTIAL_CredentialRecordData *cred;
264 struct GNUNET_CREDENTIAL_AttributeRecordData *attr;
265 struct CredentialRecordEntry *cred_pointer;
266 const char *attribute;
267 const char *cred_attribute;
269 for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL;
270 cred_pointer = cred_pointer->next){
271 cred = &cred_pointer->record_data;
273 if(0 == memcmp (&vrh->attr_pointer->record_data.subject_key,
274 &cred_pointer->record_data.issuer_key,
275 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))){
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
289 //Start from next to head
290 vrh->attr_pointer = vrh->attr_pointer->next;
294 if(vrh->attr_pointer->next != NULL){
295 //Start with backward resolution
296 vrh->lookup_request = GNUNET_GNS_lookup (gns,
297 vrh->issuer_attribute,
298 &vrh->issuer_key, //issuer_key,
299 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
300 GNUNET_GNS_LO_DEFAULT,
301 NULL, //shorten_key, always NULL
302 &start_backward_resolution,
311 * Result from GNS lookup.
313 * @param cls the closure (our client lookup handle)
314 * @param rd_count the number of records in @a rd
315 * @param rd the record data
318 send_lookup_response (void* cls,
320 const struct GNUNET_GNSRECORD_Data *rd)
322 struct VerifyRequestHandle *vrh = cls;
325 int cred_record_count;
326 struct GNUNET_MQ_Envelope *env;
327 struct VerifyResultMessage *rmsg;
328 const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
329 struct GNUNET_CRYPTO_EccSignaturePurpose *purp;
330 struct CredentialRecordEntry *cr_entry;
331 uint32_t cred_verified;
333 cred_record_count = 0;
334 struct AttributeRecordEntry *attr_entry;
336 struct GNUNET_CREDENTIAL_AttributeRecordData *ard =
337 GNUNET_new(struct GNUNET_CREDENTIAL_AttributeRecordData);
339 attr_entry->record_data = *ard;
340 ard->subject_key = vrh->issuer_key;
341 GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_queue_head,
342 vrh->attr_queue_tail,
344 for (i=0; i < rd_count; i++)
346 if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
352 * Check if we have already found our credential here
353 * If so return success
355 * Save all found attributes/issues and prepare forward
356 * resolution of issuer attribute
358 cr_entry = GNUNET_new (struct CredentialRecordEntry);
359 cr_entry->record_data = *crd;
360 GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
361 vrh->cred_chain_tail,
363 purp = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
364 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
365 strlen ((char*)&crd[1]) +1 );
366 purp->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
367 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
368 strlen ((char*)&crd[1]) +1 );
370 purp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
371 if(GNUNET_OK == GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL,
385 * Check for attributes from the issuer and follow the chain
386 * till you get the required subject's attributes
388 if(cred_verified != GNUNET_YES){
391 vrh->attr_pointer = vrh->attr_pointer->next;
392 if(vrh->attr_pointer != NULL){
394 //Start with backward resolution
395 GNUNET_GNS_lookup (gns,
396 vrh->issuer_attribute,
397 &vrh->issuer_key, //issuer_key,
398 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
399 GNUNET_GNS_LO_DEFAULT,
400 NULL, //shorten_key, always NULL
401 &start_backward_resolution,
409 * Start resolution of Attribute delegations from issuer
411 * - Build adequate data structures for attribute(s) to lookup
412 * - Use GNUNET_GNSRECORD_TYPE_XXX
413 * - recursively try to find match(es) with results found top
414 * - return one found credential chain
419 * Get serialized record data size
421 len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData);
424 * Prepare a lookup result response message for the client
426 env = GNUNET_MQ_msg_extra (rmsg,
428 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
429 //Assign id so that client can find associated request
430 rmsg->id = vrh->request_id;
431 rmsg->ad_count = htonl (cred_record_count);
434 * Get serialized record data
435 * Append at the end of rmsg
438 struct GNUNET_CREDENTIAL_CredentialRecordData *tmp_record = (struct GNUNET_CREDENTIAL_CredentialRecordData*) &rmsg[1];
439 for (cr_entry = vrh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next)
442 &cr_entry->record_data,
443 sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData));
446 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
449 GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
454 * - Refactor into cleanup_handle() function for this
458 GNUNET_STATISTICS_update (statistics,
459 "Completed verifications", 1,
461 GNUNET_STATISTICS_update (statistics,
462 "Credentials resolved",
468 * Handle Credential verification requests from client
470 * @param cls the closure
471 * @param client the client
472 * @param message the message
475 handle_verify (void *cls,
476 const struct VerifyMessage *v_msg)
478 char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
479 char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
480 char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
481 struct VerifyRequestHandle *vrh;
482 struct GNUNET_SERVICE_Client *client = cls;
483 char *attrptr = attrs;
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 "Received VERIFY message\n");
489 utf_in = (const char *) &v_msg[1];
490 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
492 GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
493 issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
494 GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
495 subject_attribute[ntohs (v_msg->subject_attribute_len)] = '\0';
496 vrh = GNUNET_new (struct VerifyRequestHandle);
497 GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
498 vrh->client = client;
499 vrh->request_id = v_msg->id;
500 vrh->issuer_key = v_msg->issuer_key;
501 vrh->subject_key = v_msg->subject_key;
502 vrh->issuer_attribute = issuer_attribute;
504 if (NULL == subject_attribute)
506 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507 "No subject attribute provided!\n");
508 send_lookup_response (vrh, 0, NULL);
511 if (NULL == issuer_attribute)
513 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
514 "No issuer attribute provided!\n");
515 send_lookup_response (vrh, 0, NULL);
519 * First, get attribute from subject
521 vrh->lookup_request = GNUNET_GNS_lookup (gns,
523 &v_msg->subject_key, //subject_pkey,
524 GNUNET_GNSRECORD_TYPE_CREDENTIAL,
525 GNUNET_GNS_LO_DEFAULT,
526 NULL, //shorten_key, always NULL
527 &send_lookup_response,
533 * One of our clients disconnected, clean up after it.
536 * @param client the client that disconnected
539 client_disconnect_cb (void *cls,
540 struct GNUNET_SERVICE_Client *client,
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Client %p disconnected\n",
549 * Add a client to our list of active clients.
552 * @param client client to add
553 * @param mq message queue for @a client
554 * @return this client
557 client_connect_cb (void *cls,
558 struct GNUNET_SERVICE_Client *client,
559 struct GNUNET_MQ_Handle *mq)
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562 "Client %p connected\n",
568 * Process Credential requests.
571 * @param server the initialized server
572 * @param c configuration to use
576 const struct GNUNET_CONFIGURATION_Handle *c,
577 struct GNUNET_SERVICE_Handle *handle)
580 gns = GNUNET_GNS_connect (c);
584 _("Failed to connect to GNS\n"));
587 statistics = GNUNET_STATISTICS_create ("credential", c);
588 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
593 * Define "main" method using service macro
597 GNUNET_SERVICE_OPTION_NONE,
600 &client_disconnect_cb,
602 GNUNET_MQ_hd_var_size (verify,
603 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
604 struct VerifyMessage,
606 GNUNET_MQ_handler_end());
608 /* end of gnunet-service-credential.c */