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"
32 // For Looking up GNS request
33 #include <gnunet_dnsparser_lib.h>
34 #include <gnunet_identity_service.h>
35 #include <gnunet_gnsrecord_lib.h>
36 #include <gnunet_namestore_service.h>
37 #include <gnunet_gns_service.h>
38 #include "gnunet_gns_service.h"
43 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
48 struct CredentialRecordEntry
53 struct CredentialRecordEntry *next;
58 struct CredentialRecordEntry *prev;
64 struct GNUNET_CREDENTIAL_CredentialRecordData record_data;
68 * DLL for attributes - Used as a queue
69 * Insert tail - Pop head
71 struct AttributeRecordEntry
76 struct AttributeRecordEntry *next;
81 struct AttributeRecordEntry *prev;
86 struct GNUNET_CREDENTIAL_AttributeDelegationRecordData;
90 * Handle to a lookup operation from api
92 struct VerifyRequestHandle
96 * We keep these in a DLL.
98 struct VerifyRequestHandle *next;
101 * We keep these in a DLL.
103 struct VerifyRequestHandle *prev;
106 * Handle to the requesting client
108 struct GNUNET_SERVICE_Client *client;
111 * Handle to GNS lookup
113 struct GNUNET_GNS_LookupRequest *lookup_request;
118 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
123 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
128 struct CredentialRecordEntry *cred_chain_head;
133 struct CredentialRecordEntry *cred_chain_tail;
138 struct AttributeRecordEntry *attr_queue_head;
143 struct AttributeRecordEntry *attr_queue_tail;
156 static struct VerifyRequestHandle *vrh_head;
161 static struct VerifyRequestHandle *vrh_tail;
164 * Handle to the statistics service
166 static struct GNUNET_STATISTICS_Handle *statistics;
171 * Handle to GNS service.
173 static struct GNUNET_GNS_Handle *gns;
176 * Task run during shutdown.
182 shutdown_task (void *cls)
184 struct VerifyRequestHandle *vrh;
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
188 while (NULL != (vrh = vrh_head))
190 //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
191 GNUNET_CONTAINER_DLL_remove (vrh_head,
198 if (NULL != statistics)
200 GNUNET_STATISTICS_destroy (statistics,
208 * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
210 * @param cls client sending the message
211 * @param v_msg message of type `struct VerifyMessage`
212 * @return #GNUNET_OK if @a v_msg is well-formed
215 check_verify (void *cls,
216 const struct VerifyMessage *v_msg)
223 msg_size = ntohs (v_msg->header.size);
224 if (msg_size < sizeof (struct VerifyMessage))
227 return GNUNET_SYSERR;
229 i_attr = (const char *) &v_msg[1];
230 if ( ('\0' != i_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
231 (strlen (i_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
234 return GNUNET_SYSERR;
236 attr_len = strlen (i_attr);
237 s_attr = ((const char *) &v_msg[1]) + attr_len + 1;
238 if ( ('\0' != s_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
239 (strlen (s_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
242 return GNUNET_SYSERR;
249 * Result from GNS lookup.
251 * @param cls the closure (our client lookup handle)
252 * @param rd_count the number of records in @a rd
253 * @param rd the record data
256 send_lookup_response (void* cls,
258 const struct GNUNET_GNSRECORD_Data *rd)
260 struct VerifyRequestHandle *vrh = cls;
263 int cred_record_count;
264 struct GNUNET_MQ_Envelope *env;
265 struct VerifyResultMessage *rmsg;
266 const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
267 struct GNUNET_CREDENTIAL_AttributeDelegationRecordData *adrd;
268 struct CredentialRecordEntry *cr_entry;
269 struct AttributeRecordEntry *attr_entry;
272 cred_record_count = 0;
273 adrd = GNUNET_CREDENTIAL_AttributeDelegationRecordData
274 GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_queue_head,
275 vrh->attr_queue_tail,
277 for (i=0; i < rd_count; i++)
279 if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
285 * Check if we have already found our credential here
286 * If so return success
288 * Save all found attributes/issues and prepare forward
289 * resolution of issuer attribute
291 cr_entry = GNUNET_new (struct CredentialRecordEntry);
292 cr_entry->record_data = *crd;
293 GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
294 vrh->cred_chain_tail,
297 if(GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, purpose, sig, issuer_key))
299 cred_verified = true;
307 * Check for attributes from the issuer and follow the chain
308 * till you get the required subject's attributes
310 if(cred_verified != true){
311 for(i=0 ; i < rd_count ; i++){
316 * Start resolution of Attribute delegations from issuer
318 * - Build adequate data structures for attribute(s) to lookup
319 * - Use GNUNET_GNSRECORD_TYPE_XXX
320 * - recursively try to find match(es) with results found top
321 * - return one found credential chain
326 * Get serialized record data size
328 len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData);
331 * Prepare a lookup result response message for the client
333 env = GNUNET_MQ_msg_extra (rmsg,
335 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
336 //Assign id so that client can find associated request
337 rmsg->id = vrh->request_id;
338 rmsg->ad_count = htonl (attr_record_count);
341 * Get serialized record data
342 * Append at the end of rmsg
345 struct GNUNET_CREDENTIAL_CredentialRecordData *tmp_record = (struct GNUNET_CREDENTIAL_CredentialRecordData*) &rmsg[1];
346 for (ar_entry = vrh->attr_chain_head; NULL != ar_entry; ar_entry = ar_entry->next)
349 &ar_entry->record_data,
350 sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData));
353 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
356 GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
361 * - Refactor into cleanup_handle() function for this
365 GNUNET_STATISTICS_update (statistics,
366 "Completed verifications", 1,
368 GNUNET_STATISTICS_update (statistics,
369 "Credentials resolved",
375 * Handle Credential verification requests from client
377 * @param cls the closure
378 * @param client the client
379 * @param message the message
382 handle_verify (void *cls,
383 const struct VerifyMessage *v_msg)
385 char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
386 char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
387 size_t issuer_attribute_len;
388 struct VerifyRequestHandle *vrh;
389 struct GNUNET_SERVICE_Client *client = cls;
390 char *attrptr = issuer_attribute;
393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
394 "Received VERIFY message\n");
396 utf_in = (const char *) &v_msg[1];
397 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
398 issuer_attribute_len = strlen (utf_in);
399 utf_in = (const char *) (&v_msg[1] + issuer_attribute_len + 1);
400 attrptr = subject_attribute;
401 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
402 vrh = GNUNET_new (struct VerifyRequestHandle);
403 GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
404 vrh->client = client;
405 vrh->request_id = v_msg->id;
406 vrh->issuer_key = v_msg->issuer_key;
407 vrh->subject_key = v_msg->subject_key;
409 if (NULL == subject_attribute)
411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
412 "No subject attribute provided!\n");
413 send_lookup_response (vrh, 0, NULL);
416 if (NULL == issuer_attribute)
418 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
419 "No issuer attribute provided!\n");
420 send_lookup_response (vrh, 0, NULL);
424 * First, get attribute from subject
426 vrh->lookup_request = GNUNET_GNS_lookup (gns,
428 &v_msg->subject_key, //subject_pkey,
429 GNUNET_GNSRECORD_TYPE_CREDENTIAL,
430 GNUNET_GNS_LO_DEFAULT,
431 NULL, //shorten_key, always NULL
432 &send_lookup_response,
438 * One of our clients disconnected, clean up after it.
441 * @param client the client that disconnected
444 client_disconnect_cb (void *cls,
445 struct GNUNET_SERVICE_Client *client,
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "Client %p disconnected\n",
454 * Add a client to our list of active clients.
457 * @param client client to add
458 * @param mq message queue for @a client
459 * @return this client
462 client_connect_cb (void *cls,
463 struct GNUNET_SERVICE_Client *client,
464 struct GNUNET_MQ_Handle *mq)
466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
467 "Client %p connected\n",
473 * Process Credential requests.
476 * @param server the initialized server
477 * @param c configuration to use
481 const struct GNUNET_CONFIGURATION_Handle *c,
482 struct GNUNET_SERVICE_Handle *handle)
485 gns = GNUNET_GNS_connect (c);
489 _("Failed to connect to GNS\n"));
492 statistics = GNUNET_STATISTICS_create ("credential", c);
493 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
498 * Define "main" method using service macro
502 GNUNET_SERVICE_OPTION_NONE,
505 &client_disconnect_cb,
507 GNUNET_MQ_hd_var_size (verify,
508 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
509 struct VerifyMessage,
511 GNUNET_MQ_handler_end());
513 /* end of gnunet-service-credential.c */