2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @author Martin Schanzenbach
23 * @file src/reclaim/gnunet-service-reclaim_tickets.c
24 * @brief reclaim tickets
27 #include "gnunet-service-reclaim_tickets.h"
30 * A reference to a ticket stored in GNS
32 struct TicketReference
37 struct TicketReference *next;
42 struct TicketReference *prev;
47 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
52 struct GNUNET_RECLAIM_Ticket ticket;
57 * Ticket issue request handle
59 struct TicketIssueHandle
64 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
69 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
74 struct GNUNET_RECLAIM_Ticket ticket;
79 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
82 * Ticket reference list
84 struct TicketReference *ticket_refs_head;
87 * Ticket reference list
89 struct TicketReference *ticket_refs_tail;
92 * Number of references
94 uint32_t ticket_ref_num;
99 RECLAIM_TICKETS_TicketResult cb;
111 struct RECLAIM_TICKETS_Iterator
116 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
121 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
124 * Namestore queue entry
126 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
131 RECLAIM_TICKETS_TicketIter cb;
139 * Ticket reference list
141 struct TicketReference *tickets_head;
144 * Ticket reference list
146 struct TicketReference *tickets_tail;
149 static struct GNUNET_NAMESTORE_Handle *nsh;
152 * Cleanup ticket consume handle
153 * @param handle the handle to clean up
156 cleanup_issue_handle (struct TicketIssueHandle *handle)
158 struct TicketReference *tr;
159 struct TicketReference *tr_tmp;
160 if (NULL != handle->attrs)
161 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
162 if (NULL != handle->ns_qe)
163 GNUNET_NAMESTORE_cancel (handle->ns_qe);
164 for (tr = handle->ticket_refs_head; NULL != tr;)
166 if (NULL != tr->attrs)
167 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (tr->attrs);
170 GNUNET_free (tr_tmp);
172 GNUNET_free (handle);
178 store_ticket_refs_cont (void *cls,
182 struct TicketIssueHandle *handle = cls;
183 handle->ns_qe = NULL;
184 if (GNUNET_OK != success)
186 handle->cb (handle->cb_cls,
189 "Error storing updated ticket refs in GNS");
190 cleanup_issue_handle (handle);
193 handle->cb (handle->cb_cls,
197 cleanup_issue_handle (handle);
203 update_ticket_refs (void* cls)
205 struct TicketIssueHandle *handle = cls;
206 struct GNUNET_GNSRECORD_Data refs_rd[handle->ticket_ref_num];
207 struct TicketReference *tr;
211 tr = handle->ticket_refs_head;
212 for (int i = 0; i < handle->ticket_ref_num; i++)
214 buf_size = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (tr->attrs);
215 buf_size += sizeof (struct GNUNET_RECLAIM_Ticket);
216 buf = GNUNET_malloc (buf_size);
217 memcpy (buf, &tr->ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
218 GNUNET_RECLAIM_ATTRIBUTE_list_serialize (tr->attrs,
219 buf + sizeof (struct GNUNET_RECLAIM_Ticket));
220 refs_rd[i].data = buf;
221 refs_rd[i].data_size = buf_size;
222 refs_rd[i].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
223 refs_rd[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKETREF;
224 refs_rd[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION |
225 GNUNET_GNSRECORD_RF_PRIVATE;
229 handle->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
231 GNUNET_GNS_EMPTY_LABEL_AT,
232 handle->ticket_ref_num,
234 &store_ticket_refs_cont,
236 for (int i = 0; i < handle->ticket_ref_num; i++)
237 GNUNET_free ((char*)refs_rd[i].data);
243 ticket_lookup_cb (void *cls,
244 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
246 unsigned int rd_count,
247 const struct GNUNET_GNSRECORD_Data *rd)
249 struct TicketIssueHandle *handle = cls;
250 struct TicketReference *tr;
251 const char* attr_data;
252 size_t attr_data_len;
253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254 "Received tickets from local namestore.\n");
255 handle->ns_qe = NULL;
256 for (int i = 0; i < rd_count; i++)
258 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKETREF != rd[i].record_type)
260 tr = GNUNET_new (struct TicketReference);
261 memcpy (&tr->ticket, rd[i].data,
262 sizeof (struct GNUNET_RECLAIM_Ticket));
263 if (0 != memcmp (&tr->ticket.identity,
264 &handle->ticket.identity,
265 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
271 attr_data = rd[i].data + sizeof (struct GNUNET_RECLAIM_Ticket);
272 attr_data_len = rd[i].data_size - sizeof (struct GNUNET_RECLAIM_Ticket);
273 tr->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attr_data,
275 GNUNET_CONTAINER_DLL_insert (handle->ticket_refs_head,
276 handle->ticket_refs_tail,
278 handle->ticket_ref_num++;
280 tr = GNUNET_new (struct TicketReference);
281 tr->ticket = handle->ticket;
282 tr->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (handle->attrs);
283 GNUNET_CONTAINER_DLL_insert (handle->ticket_refs_head,
284 handle->ticket_refs_tail,
286 handle->ticket_ref_num++;
287 GNUNET_SCHEDULER_add_now (&update_ticket_refs, handle);
291 ticket_lookup_error_cb (void *cls)
293 struct TicketIssueHandle *handle = cls;
294 handle->ns_qe = NULL;
295 handle->cb (handle->cb_cls,
298 "Error checking for ticketsin GNS\n");
299 cleanup_issue_handle (handle);
303 store_ticket_issue_cont (void *cls,
307 struct TicketIssueHandle *handle = cls;
309 handle->ns_qe = NULL;
310 if (GNUNET_SYSERR == success)
312 handle->cb (handle->cb_cls,
315 "Error storing AuthZ ticket in GNS");
318 /* First, local references to tickets */
319 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
321 GNUNET_GNS_EMPTY_LABEL_AT,
322 &ticket_lookup_error_cb,
329 create_sym_key_from_ecdh (const struct GNUNET_HashCode *new_key_hash,
330 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
331 struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
333 struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
335 GNUNET_CRYPTO_hash_to_enc (new_key_hash,
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
338 static const char ctx_key[] = "gnuid-aes-ctx-key";
339 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
340 new_key_hash, sizeof (struct GNUNET_HashCode),
341 ctx_key, strlen (ctx_key),
343 static const char ctx_iv[] = "gnuid-aes-ctx-iv";
344 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
345 new_key_hash, sizeof (struct GNUNET_HashCode),
346 ctx_iv, strlen (ctx_iv),
353 serialize_authz_record (const struct GNUNET_RECLAIM_Ticket *ticket,
354 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
355 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
358 struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
359 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
360 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
361 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
362 struct GNUNET_HashCode new_key_hash;
370 GNUNET_assert (NULL != attrs->list_head);
372 for (le = attrs->list_head; NULL != le; le = le->next) {
373 attrs_str_len += 15 + 1; //TODO propery calculate
375 buf = GNUNET_malloc (attrs_str_len);
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Writing attributes\n");
379 for (le = attrs->list_head; NULL != le; le = le->next) {
380 label = GNUNET_STRINGS_data_to_string_alloc (&le->claim->id,
382 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
383 "Adding attribute to record: %s\n", label);
385 GNUNET_memcpy (write_ptr,
388 write_ptr[strlen (label)] = ',';
389 write_ptr += strlen (label) + 1;
393 write_ptr[0] = '\0'; //replace last , with a 0-terminator
394 // ECDH keypair E = eG
395 *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
396 GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
398 enc_keyinfo = GNUNET_malloc (attrs_str_len);
399 // Derived key K = H(eB)
400 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
403 create_sym_key_from_ecdh (&new_key_hash, &skey, &iv);
404 enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf,
408 *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+
410 GNUNET_memcpy (*result,
412 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
413 GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
416 GNUNET_free (enc_keyinfo);
418 return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size;
424 issue_ticket (struct TicketIssueHandle *ih)
426 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
427 struct GNUNET_GNSRECORD_Data code_record[1];
428 char *authz_record_data;
429 size_t authz_record_len;
432 //TODO rename function
433 authz_record_len = serialize_authz_record (&ih->ticket,
437 code_record[0].data = authz_record_data;
438 code_record[0].data_size = authz_record_len;
439 code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
440 code_record[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_AUTHZ;
441 code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
443 label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
446 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
451 &store_ticket_issue_cont,
453 GNUNET_free (ecdhe_privkey);
455 GNUNET_free (authz_record_data);
462 RECLAIM_TICKETS_issue_ticket (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
463 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
464 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
465 RECLAIM_TICKETS_TicketResult cb,
468 struct TicketIssueHandle *tih;
469 tih = GNUNET_new (struct TicketIssueHandle);
471 tih->cb_cls = cb_cls;
472 tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
473 tih->identity = *identity;
474 GNUNET_CRYPTO_ecdsa_key_get_public (identity,
475 &tih->ticket.identity);
477 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
479 tih->ticket.audience = *audience;
485 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
487 struct TicketReference *tr;
488 struct TicketReference *tr_tmp;
489 if (NULL != iter->ns_qe)
490 GNUNET_NAMESTORE_cancel (iter->ns_qe);
491 for (tr = iter->tickets_head; NULL != tr;)
493 if (NULL != tr->attrs)
494 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (tr->attrs);
497 GNUNET_free (tr_tmp);
503 do_cleanup_iter (void* cls)
505 struct RECLAIM_TICKETS_Iterator *iter = cls;
510 * Perform ticket iteration step
512 * @param ti ticket iterator to process
515 run_ticket_iteration_round (struct RECLAIM_TICKETS_Iterator *iter)
517 struct TicketReference *tr;
518 if (NULL == iter->tickets_head)
521 iter->cb (iter->cb_cls,
523 GNUNET_SCHEDULER_add_now (&do_cleanup_iter, iter);
526 tr = iter->tickets_head;
527 GNUNET_CONTAINER_DLL_remove (iter->tickets_head,
530 iter->cb (iter->cb_cls,
532 if (NULL != tr->attrs)
533 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (tr->attrs);
538 collect_tickets_cb (void *cls,
539 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
541 unsigned int rd_count,
542 const struct GNUNET_GNSRECORD_Data *rd)
544 struct RECLAIM_TICKETS_Iterator *iter = cls;
545 struct TicketReference *tr;
546 size_t attr_data_len;
547 const char* attr_data;
550 for (int i = 0; i < rd_count; i++)
552 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKETREF != rd[i].record_type)
554 tr = GNUNET_new (struct TicketReference);
555 memcpy (&tr->ticket, rd[i].data,
556 sizeof (struct GNUNET_RECLAIM_Ticket));
557 if (0 != memcmp (&tr->ticket.identity,
559 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
565 attr_data = rd[i].data + sizeof (struct GNUNET_RECLAIM_Ticket);
566 attr_data_len = rd[i].data_size - sizeof (struct GNUNET_RECLAIM_Ticket);
567 tr->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attr_data,
569 GNUNET_CONTAINER_DLL_insert (iter->tickets_head,
573 run_ticket_iteration_round (iter);
577 collect_tickets_error_cb (void *cls)
579 struct RECLAIM_TICKETS_Iterator *iter = cls;
581 iter->cb (iter->cb_cls,
587 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
589 run_ticket_iteration_round (iter);
593 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
598 struct RECLAIM_TICKETS_Iterator*
599 RECLAIM_TICKETS_iteration_start (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
600 RECLAIM_TICKETS_TicketIter cb,
603 struct RECLAIM_TICKETS_Iterator *iter;
605 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
606 iter->identity = *identity;
607 GNUNET_CRYPTO_ecdsa_key_get_public (identity,
608 &iter->identity_pub);
610 iter->cb_cls = cb_cls;
611 iter->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
613 GNUNET_GNS_EMPTY_LABEL_AT,
614 &collect_tickets_error_cb,
625 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
627 //Connect to identity and namestore services
628 nsh = GNUNET_NAMESTORE_connect (c);
631 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
632 "Error connecting to namestore\n");
633 return GNUNET_SYSERR;
639 RECLAIM_TICKETS_deinit (void)
642 GNUNET_NAMESTORE_disconnect (nsh);