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;
91 * Handle to a lookup operation from api
93 struct VerifyRequestHandle
97 * We keep these in a DLL.
99 struct VerifyRequestHandle *next;
102 * We keep these in a DLL.
104 struct VerifyRequestHandle *prev;
107 * Handle to the requesting client
109 struct GNUNET_SERVICE_Client *client;
112 * Handle to GNS lookup
114 struct GNUNET_GNS_LookupRequest *lookup_request;
119 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
124 struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
129 struct CredentialRecordEntry *cred_chain_head;
134 struct CredentialRecordEntry *cred_chain_tail;
139 struct AttributeRecordEntry *attr_queue_head;
144 struct AttributeRecordEntry *attr_queue_tail;
157 static struct VerifyRequestHandle *vrh_head;
162 static struct VerifyRequestHandle *vrh_tail;
165 * Handle to the statistics service
167 static struct GNUNET_STATISTICS_Handle *statistics;
172 * Handle to GNS service.
174 static struct GNUNET_GNS_Handle *gns;
177 * Task run during shutdown.
183 shutdown_task (void *cls)
185 struct VerifyRequestHandle *vrh;
187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 while (NULL != (vrh = vrh_head))
191 //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
192 GNUNET_CONTAINER_DLL_remove (vrh_head,
199 if (NULL != statistics)
201 GNUNET_STATISTICS_destroy (statistics,
209 * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
211 * @param cls client sending the message
212 * @param v_msg message of type `struct VerifyMessage`
213 * @return #GNUNET_OK if @a v_msg is well-formed
216 check_verify (void *cls,
217 const struct VerifyMessage *v_msg)
224 msg_size = ntohs (v_msg->header.size);
225 if (msg_size < sizeof (struct VerifyMessage))
228 return GNUNET_SYSERR;
230 i_attr = (const char *) &v_msg[1];
231 if ( ('\0' != i_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
232 (strlen (i_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
235 return GNUNET_SYSERR;
237 attr_len = strlen (i_attr);
238 s_attr = ((const char *) &v_msg[1]) + attr_len + 1;
239 if ( ('\0' != s_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
240 (strlen (s_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
243 return GNUNET_SYSERR;
250 * Result from GNS lookup.
252 * @param cls the closure (our client lookup handle)
253 * @param rd_count the number of records in @a rd
254 * @param rd the record data
257 send_lookup_response (void* cls,
259 const struct GNUNET_GNSRECORD_Data *rd)
261 struct VerifyRequestHandle *vrh = cls;
264 int cred_record_count;
265 struct GNUNET_MQ_Envelope *env;
266 struct VerifyResultMessage *rmsg;
267 const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
268 struct CredentialRecordEntry *cr_entry;
271 cred_record_count = 0;
272 for (i=0; i < rd_count; i++)
274 if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
280 * Check if we have already found our credential here
281 * If so return success
283 * Save all found attributes/issues and prepare forward
284 * resolution of issuer attribute
286 cr_entry = GNUNET_new (struct CredentialRecordEntry);
287 cr_entry->record_data = *crd;
288 GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
289 vrh->cred_chain_tail,
292 if(GNUNET_OK == GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL,
294 &crd->sig, &crd->issuer_key))
296 cred_verified = GNUNET_YES;
306 * Start resolution of Attribute delegations from issuer
308 * - Build adequate data structures for attribute(s) to lookup
309 * - Use GNUNET_GNSRECORD_TYPE_XXX
310 * - recursively try to find match(es) with results found top
311 * - return one found credential chain
316 * Get serialized record data size
318 len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData);
321 * Prepare a lookup result response message for the client
323 env = GNUNET_MQ_msg_extra (rmsg,
325 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
326 //Assign id so that client can find associated request
327 rmsg->id = vrh->request_id;
328 rmsg->ad_count = htonl (cred_record_count);
331 * Get serialized record data
332 * Append at the end of rmsg
335 struct GNUNET_CREDENTIAL_CredentialRecordData *tmp_record = (struct GNUNET_CREDENTIAL_CredentialRecordData*) &rmsg[1];
336 for (cr_entry = vrh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next)
339 &cr_entry->record_data,
340 sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData));
343 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
346 GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
351 * - Refactor into cleanup_handle() function for this
355 GNUNET_STATISTICS_update (statistics,
356 "Completed verifications", 1,
358 GNUNET_STATISTICS_update (statistics,
359 "Credentials resolved",
365 * Handle Credential verification requests from client
367 * @param cls the closure
368 * @param client the client
369 * @param message the message
372 handle_verify (void *cls,
373 const struct VerifyMessage *v_msg)
375 char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
376 char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
377 size_t issuer_attribute_len;
378 struct VerifyRequestHandle *vrh;
379 struct GNUNET_SERVICE_Client *client = cls;
380 char *attrptr = issuer_attribute;
383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384 "Received VERIFY message\n");
386 utf_in = (const char *) &v_msg[1];
387 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
388 issuer_attribute_len = strlen (utf_in);
389 utf_in = (const char *) (&v_msg[1] + issuer_attribute_len + 1);
390 attrptr = subject_attribute;
391 GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
392 vrh = GNUNET_new (struct VerifyRequestHandle);
393 GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
394 vrh->client = client;
395 vrh->request_id = v_msg->id;
396 vrh->issuer_key = v_msg->issuer_key;
397 vrh->subject_key = v_msg->subject_key;
399 if (NULL == subject_attribute)
401 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
402 "No subject attribute provided!\n");
403 send_lookup_response (vrh, 0, NULL);
406 if (NULL == issuer_attribute)
408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
409 "No issuer attribute provided!\n");
410 send_lookup_response (vrh, 0, NULL);
414 * First, get attribute from subject
416 vrh->lookup_request = GNUNET_GNS_lookup (gns,
418 &v_msg->subject_key, //subject_pkey,
419 GNUNET_GNSRECORD_TYPE_CREDENTIAL,
420 GNUNET_GNS_LO_DEFAULT,
421 NULL, //shorten_key, always NULL
422 &send_lookup_response,
428 * One of our clients disconnected, clean up after it.
431 * @param client the client that disconnected
434 client_disconnect_cb (void *cls,
435 struct GNUNET_SERVICE_Client *client,
438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
439 "Client %p disconnected\n",
444 * Add a client to our list of active clients.
447 * @param client client to add
448 * @param mq message queue for @a client
449 * @return this client
452 client_connect_cb (void *cls,
453 struct GNUNET_SERVICE_Client *client,
454 struct GNUNET_MQ_Handle *mq)
456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457 "Client %p connected\n",
463 * Process Credential requests.
466 * @param server the initialized server
467 * @param c configuration to use
471 const struct GNUNET_CONFIGURATION_Handle *c,
472 struct GNUNET_SERVICE_Handle *handle)
475 gns = GNUNET_GNS_connect (c);
479 _("Failed to connect to GNS\n"));
482 statistics = GNUNET_STATISTICS_create ("credential", c);
483 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
488 * Define "main" method using service macro
492 GNUNET_SERVICE_OPTION_NONE,
495 &client_disconnect_cb,
497 GNUNET_MQ_hd_var_size (verify,
498 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
499 struct VerifyMessage,
501 GNUNET_MQ_handler_end());
503 /* end of gnunet-service-credential.c */