Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020-2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Affero General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
12 :
13 : You should have received a copy of the GNU Affero General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-exchange-httpd_keys.c
18 : * @brief management of our various keys
19 : * @author Christian Grothoff
20 : * @author Özgür Kesim
21 : */
22 : #include "taler/platform.h"
23 : #include "taler/taler_json_lib.h"
24 : #include "taler/taler_mhd_lib.h"
25 : #include "taler/taler_kyclogic_lib.h"
26 : #include "taler/taler_dbevents.h"
27 : #include "taler-exchange-httpd.h"
28 : #include "taler-exchange-httpd_config.h"
29 : #include "taler-exchange-httpd_keys.h"
30 : #include "taler-exchange-httpd_responses.h"
31 : #include "taler/taler_exchangedb_plugin.h"
32 : #include "taler/taler_extensions.h"
33 :
34 :
35 : /**
36 : * How many /keys request do we hold in suspension at
37 : * most at any time?
38 : */
39 : #define SKR_LIMIT 32
40 :
41 :
42 : /**
43 : * When do we forcefully timeout a /keys request?
44 : * Matches the 120s hard-coded into exchange_api_handle.c
45 : */
46 : #define KEYS_TIMEOUT \
47 : GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
48 :
49 :
50 : /**
51 : * Information about a denomination on offer by the denomination helper.
52 : */
53 : struct HelperDenomination
54 : {
55 :
56 : /**
57 : * When will the helper start to use this key for signing?
58 : */
59 : struct GNUNET_TIME_Timestamp start_time;
60 :
61 : /**
62 : * For how long will the helper allow signing? 0 if
63 : * the key was revoked or purged.
64 : */
65 : struct GNUNET_TIME_Relative validity_duration;
66 :
67 : /**
68 : * Hash of the full denomination key.
69 : */
70 : struct TALER_DenominationHashP h_denom_pub;
71 :
72 : /**
73 : * Signature over this key from the security module's key.
74 : */
75 : struct TALER_SecurityModuleSignatureP sm_sig;
76 :
77 : /**
78 : * The (full) public key.
79 : */
80 : struct TALER_DenominationPublicKey denom_pub;
81 :
82 : /**
83 : * Details depend on the @e denom_pub.cipher type.
84 : */
85 : union
86 : {
87 :
88 : /**
89 : * Hash of the RSA key.
90 : */
91 : struct TALER_RsaPubHashP h_rsa;
92 :
93 : /**
94 : * Hash of the CS key.
95 : */
96 : struct TALER_CsPubHashP h_cs;
97 :
98 : } h_details;
99 :
100 : /**
101 : * Name in configuration section for this denomination type.
102 : */
103 : char *section_name;
104 :
105 :
106 : };
107 :
108 :
109 : /**
110 : * Signatures of an auditor over a denomination key of this exchange.
111 : */
112 : struct TEH_AuditorSignature
113 : {
114 : /**
115 : * We store the signatures in a DLL.
116 : */
117 : struct TEH_AuditorSignature *prev;
118 :
119 : /**
120 : * We store the signatures in a DLL.
121 : */
122 : struct TEH_AuditorSignature *next;
123 :
124 : /**
125 : * A signature from the auditor.
126 : */
127 : struct TALER_AuditorSignatureP asig;
128 :
129 : /**
130 : * Public key of the auditor.
131 : */
132 : struct TALER_AuditorPublicKeyP apub;
133 :
134 : };
135 :
136 :
137 : /**
138 : * Information about a signing key on offer by the esign helper.
139 : */
140 : struct HelperSignkey
141 : {
142 : /**
143 : * When will the helper start to use this key for signing?
144 : */
145 : struct GNUNET_TIME_Timestamp start_time;
146 :
147 : /**
148 : * For how long will the helper allow signing? 0 if
149 : * the key was revoked or purged.
150 : */
151 : struct GNUNET_TIME_Relative validity_duration;
152 :
153 : /**
154 : * The public key.
155 : */
156 : struct TALER_ExchangePublicKeyP exchange_pub;
157 :
158 : /**
159 : * Signature over this key from the security module's key.
160 : */
161 : struct TALER_SecurityModuleSignatureP sm_sig;
162 :
163 : };
164 :
165 :
166 : /**
167 : * State associated with the crypto helpers / security modules. NOT updated
168 : * when the #key_generation is updated (instead constantly kept in sync
169 : * whenever #TEH_keys_get_state() is called).
170 : */
171 : struct HelperState
172 : {
173 :
174 : /**
175 : * Handle for the esign/EdDSA helper.
176 : */
177 : struct TALER_CRYPTO_ExchangeSignHelper *esh;
178 :
179 : /**
180 : * Handle for the denom/RSA helper.
181 : */
182 : struct TALER_CRYPTO_RsaDenominationHelper *rsadh;
183 :
184 : /**
185 : * Handle for the denom/CS helper.
186 : */
187 : struct TALER_CRYPTO_CsDenominationHelper *csdh;
188 :
189 : /**
190 : * Map from H(denom_pub) to `struct HelperDenomination` entries.
191 : */
192 : struct GNUNET_CONTAINER_MultiHashMap *denom_keys;
193 :
194 : /**
195 : * Map from H(rsa_pub) to `struct HelperDenomination` entries.
196 : */
197 : struct GNUNET_CONTAINER_MultiHashMap *rsa_keys;
198 :
199 : /**
200 : * Map from H(cs_pub) to `struct HelperDenomination` entries.
201 : */
202 : struct GNUNET_CONTAINER_MultiHashMap *cs_keys;
203 :
204 : /**
205 : * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey`
206 : * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also
207 : * an EdDSA public key.
208 : */
209 : struct GNUNET_CONTAINER_MultiPeerMap *esign_keys;
210 :
211 : };
212 :
213 :
214 : /**
215 : * Entry in (sorted) array with possible pre-build responses for /keys.
216 : * We keep pre-build responses for the various (valid) cherry-picking
217 : * values around.
218 : */
219 : struct KeysResponseData
220 : {
221 :
222 : /**
223 : * Response to return if the client supports (deflate) compression.
224 : */
225 : struct MHD_Response *response_compressed;
226 :
227 : /**
228 : * Response to return if the client does not support compression.
229 : */
230 : struct MHD_Response *response_uncompressed;
231 :
232 : /**
233 : * ETag for these responses.
234 : */
235 : char *etag;
236 :
237 : /**
238 : * Cherry-picking timestamp the client must have set for this
239 : * response to be valid. 0 if this is the "full" response.
240 : * The client's request must include this date or a higher one
241 : * for this response to be applicable.
242 : */
243 : struct GNUNET_TIME_Timestamp cherry_pick_date;
244 :
245 : };
246 :
247 :
248 : /**
249 : * @brief All information about an exchange online signing key (which is used to
250 : * sign messages from the exchange).
251 : */
252 : struct SigningKey
253 : {
254 :
255 : /**
256 : * The exchange's (online signing) public key.
257 : */
258 : struct TALER_ExchangePublicKeyP exchange_pub;
259 :
260 : /**
261 : * Meta data about the signing key, such as validity periods.
262 : */
263 : struct TALER_EXCHANGEDB_SignkeyMetaData meta;
264 :
265 : /**
266 : * The long-term offline master key's signature for this signing key.
267 : * Signs over @e exchange_pub and @e meta.
268 : */
269 : struct TALER_MasterSignatureP master_sig;
270 :
271 : };
272 :
273 : struct TEH_KeyStateHandle
274 : {
275 :
276 : /**
277 : * Mapping from denomination keys to denomination key issue struct.
278 : * Used to lookup the key by hash.
279 : */
280 : struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
281 :
282 : /**
283 : * Mapping from serial ID's to denomination key issue struct.
284 : * Used to lookup the key by serial ID.
285 : *
286 : * FIXME: We need a 64-bit version of this in GNUNET.
287 : */
288 : struct GNUNET_CONTAINER_MultiHashMap32 *denomserial_map;
289 :
290 : /**
291 : * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey`
292 : * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also
293 : * an EdDSA public key.
294 : */
295 : struct GNUNET_CONTAINER_MultiPeerMap *signkey_map;
296 :
297 : /**
298 : * Head of DLL of our global fees.
299 : */
300 : struct TEH_GlobalFee *gf_head;
301 :
302 : /**
303 : * Tail of DLL of our global fees.
304 : */
305 : struct TEH_GlobalFee *gf_tail;
306 :
307 : /**
308 : * json array with the auditors of this exchange. Contains exactly
309 : * the information needed for the "auditors" field of the /keys response.
310 : */
311 : json_t *auditors;
312 :
313 : /**
314 : * json array with the global fees of this exchange. Contains exactly
315 : * the information needed for the "global_fees" field of the /keys response.
316 : */
317 : json_t *global_fees;
318 :
319 : /**
320 : * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of
321 : * length @e krd_array_length;
322 : */
323 : struct KeysResponseData *krd_array;
324 :
325 : /**
326 : * Length of the @e krd_array.
327 : */
328 : unsigned int krd_array_length;
329 :
330 : /**
331 : * Information we track for thecrypto helpers. Preserved
332 : * when the @e key_generation changes, thus kept separate.
333 : */
334 : struct HelperState *helpers;
335 :
336 : /**
337 : * Cached reply for a GET /management/keys request. Used so we do not
338 : * re-create the reply every time.
339 : */
340 : json_t *management_keys_reply;
341 :
342 : /**
343 : * For which (global) key_generation was this data structure created?
344 : * Used to check when we are outdated and need to be re-generated.
345 : */
346 : uint64_t key_generation;
347 :
348 : /**
349 : * When did we initiate the key reloading?
350 : */
351 : struct GNUNET_TIME_Timestamp reload_time;
352 :
353 : /**
354 : * What is the period at which we rotate keys
355 : * (signing or denomination keys)?
356 : */
357 : struct GNUNET_TIME_Relative rekey_frequency;
358 :
359 : /**
360 : * When does our online signing key expire and we
361 : * thus need to re-generate this response?
362 : */
363 : struct GNUNET_TIME_Timestamp signature_expires;
364 :
365 : /**
366 : * True if #finish_keys_response() was not yet run and this key state
367 : * is only suitable for the /management/keys API.
368 : */
369 : bool management_only;
370 :
371 : };
372 :
373 :
374 : /**
375 : * Entry of /keys requests that are currently suspended because we are
376 : * waiting for /keys to become ready.
377 : */
378 : struct SuspendedKeysRequests
379 : {
380 : /**
381 : * Kept in a DLL.
382 : */
383 : struct SuspendedKeysRequests *next;
384 :
385 : /**
386 : * Kept in a DLL.
387 : */
388 : struct SuspendedKeysRequests *prev;
389 :
390 : /**
391 : * The suspended connection.
392 : */
393 : struct MHD_Connection *connection;
394 :
395 : /**
396 : * When does this request timeout?
397 : */
398 : struct GNUNET_TIME_Absolute timeout;
399 : };
400 :
401 :
402 : /**
403 : * Information we track about wire fees.
404 : */
405 : struct WireFeeSet
406 : {
407 :
408 : /**
409 : * Kept in a DLL.
410 : */
411 : struct WireFeeSet *next;
412 :
413 : /**
414 : * Kept in a DLL.
415 : */
416 : struct WireFeeSet *prev;
417 :
418 : /**
419 : * Actual fees.
420 : */
421 : struct TALER_WireFeeSet fees;
422 :
423 : /**
424 : * Start date of fee validity (inclusive).
425 : */
426 : struct GNUNET_TIME_Timestamp start_date;
427 :
428 : /**
429 : * End date of fee validity (exclusive).
430 : */
431 : struct GNUNET_TIME_Timestamp end_date;
432 :
433 : /**
434 : * Wire method the fees apply to.
435 : */
436 : char *method;
437 : };
438 :
439 :
440 : /**
441 : * State we keep per thread to cache the wire part of the /keys response.
442 : */
443 : struct WireStateHandle
444 : {
445 :
446 : /**
447 : * JSON reply for wire response.
448 : */
449 : json_t *json_reply;
450 :
451 : /**
452 : * ETag for this response (if any).
453 : */
454 : char *etag;
455 :
456 : /**
457 : * head of DLL of wire fees.
458 : */
459 : struct WireFeeSet *wfs_head;
460 :
461 : /**
462 : * Tail of DLL of wire fees.
463 : */
464 : struct WireFeeSet *wfs_tail;
465 :
466 : /**
467 : * Earliest timestamp of all the wire methods when we have no more fees.
468 : */
469 : struct GNUNET_TIME_Absolute cache_expiration;
470 :
471 : /**
472 : * @e cache_expiration time, formatted.
473 : */
474 : char dat[128];
475 :
476 : /**
477 : * For which (global) wire_generation was this data structure created?
478 : * Used to check when we are outdated and need to be re-generated.
479 : */
480 : uint64_t wire_generation;
481 :
482 : /**
483 : * Is the wire data ready?
484 : */
485 : bool ready;
486 :
487 : };
488 :
489 :
490 : /**
491 : * Stores the latest generation of our wire response.
492 : */
493 : static struct WireStateHandle *wire_state;
494 :
495 : /**
496 : * Handler listening for wire updates by other exchange
497 : * services.
498 : */
499 : static struct GNUNET_DB_EventHandler *wire_eh;
500 :
501 : /**
502 : * Counter incremented whenever we have a reason to re-build the #wire_state
503 : * because something external changed.
504 : */
505 : static uint64_t wire_generation;
506 :
507 :
508 : /**
509 : * Stores the latest generation of our key state.
510 : */
511 : static struct TEH_KeyStateHandle *key_state;
512 :
513 : /**
514 : * Counter incremented whenever we have a reason to re-build the keys because
515 : * something external changed. See #TEH_keys_get_state() and
516 : * #TEH_keys_update_states() for uses of this variable.
517 : */
518 : static uint64_t key_generation;
519 :
520 : /**
521 : * Handler listening for wire updates by other exchange
522 : * services.
523 : */
524 : static struct GNUNET_DB_EventHandler *keys_eh;
525 :
526 : /**
527 : * Head of DLL of suspended /keys requests.
528 : */
529 : static struct SuspendedKeysRequests *skr_head;
530 :
531 : /**
532 : * Tail of DLL of suspended /keys requests.
533 : */
534 : static struct SuspendedKeysRequests *skr_tail;
535 :
536 : /**
537 : * Number of entries in the @e skr_head DLL.
538 : */
539 : static unsigned int skr_size;
540 :
541 : /**
542 : * Handle to a connection that should be force-resumed
543 : * with a hard error due to @a skr_size hitting
544 : * #SKR_LIMIT.
545 : */
546 : static struct MHD_Connection *skr_connection;
547 :
548 : /**
549 : * Task to force timeouts on /keys requests.
550 : */
551 : static struct GNUNET_SCHEDULER_Task *keys_tt;
552 :
553 : /**
554 : * For how long should a signing key be legally retained?
555 : * Configuration value.
556 : */
557 : static struct GNUNET_TIME_Relative signkey_legal_duration;
558 :
559 : /**
560 : * What type of asset are we dealing with here?
561 : */
562 : static char *asset_type;
563 :
564 : /**
565 : * RSA security module public key, all zero if not known.
566 : */
567 : static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub;
568 :
569 : /**
570 : * CS security module public key, all zero if not known.
571 : */
572 : static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub;
573 :
574 : /**
575 : * EdDSA security module public key, all zero if not known.
576 : */
577 : static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
578 :
579 : /**
580 : * Are we shutting down?
581 : */
582 : static bool terminating;
583 :
584 :
585 : /**
586 : * Free memory associated with @a wsh
587 : *
588 : * @param[in] wsh wire state to destroy
589 : */
590 : static void
591 29 : destroy_wire_state (struct WireStateHandle *wsh)
592 : {
593 : struct WireFeeSet *wfs;
594 :
595 52 : while (NULL != (wfs = wsh->wfs_head))
596 : {
597 23 : GNUNET_CONTAINER_DLL_remove (wsh->wfs_head,
598 : wsh->wfs_tail,
599 : wfs);
600 23 : GNUNET_free (wfs->method);
601 23 : GNUNET_free (wfs);
602 : }
603 29 : json_decref (wsh->json_reply);
604 29 : GNUNET_free (wsh->etag);
605 29 : GNUNET_free (wsh);
606 29 : }
607 :
608 :
609 : /**
610 : * Function called whenever another exchange process has updated
611 : * the wire data in the database.
612 : *
613 : * @param cls NULL
614 : * @param extra unused
615 : * @param extra_size number of bytes in @a extra unused
616 : */
617 : static void
618 56 : wire_update_event_cb (void *cls,
619 : const void *extra,
620 : size_t extra_size)
621 : {
622 : (void) cls;
623 : (void) extra;
624 : (void) extra_size;
625 56 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
626 : "Received wire update event\n");
627 56 : TEH_check_invariants ();
628 56 : wire_generation++;
629 56 : key_generation++;
630 56 : TEH_resume_keys_requests (false);
631 56 : }
632 :
633 :
634 : enum GNUNET_GenericReturnValue
635 21 : TEH_wire_init ()
636 : {
637 21 : struct GNUNET_DB_EventHeaderP es = {
638 21 : .size = htons (sizeof (es)),
639 21 : .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
640 : };
641 :
642 42 : wire_eh = TEH_plugin->event_listen (TEH_plugin->cls,
643 21 : GNUNET_TIME_UNIT_FOREVER_REL,
644 : &es,
645 : &wire_update_event_cb,
646 : NULL);
647 21 : if (NULL == wire_eh)
648 : {
649 0 : GNUNET_break (0);
650 0 : return GNUNET_SYSERR;
651 : }
652 21 : return GNUNET_OK;
653 : }
654 :
655 :
656 : void
657 21 : TEH_wire_done ()
658 : {
659 21 : if (NULL != wire_state)
660 : {
661 19 : destroy_wire_state (wire_state);
662 19 : wire_state = NULL;
663 : }
664 21 : if (NULL != wire_eh)
665 : {
666 21 : TEH_plugin->event_listen_cancel (TEH_plugin->cls,
667 : wire_eh);
668 21 : wire_eh = NULL;
669 : }
670 21 : }
671 :
672 :
673 : /**
674 : * Add information about a wire account to @a cls.
675 : *
676 : * @param cls a `json_t *` object to expand with wire account details
677 : * @param payto_uri the exchange bank account URI to add
678 : * @param conversion_url URL of a conversion service, NULL if there is no conversion
679 : * @param debit_restrictions JSON array with debit restrictions on the account
680 : * @param credit_restrictions JSON array with credit restrictions on the account
681 : * @param master_sig master key signature affirming that this is a bank
682 : * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS)
683 : * @param bank_label label the wallet should use to display the account, can be NULL
684 : * @param priority priority for ordering bank account labels
685 : */
686 : static void
687 25 : add_wire_account (void *cls,
688 : const struct TALER_FullPayto payto_uri,
689 : const char *conversion_url,
690 : const json_t *debit_restrictions,
691 : const json_t *credit_restrictions,
692 : const struct TALER_MasterSignatureP *master_sig,
693 : const char *bank_label,
694 : int64_t priority)
695 : {
696 25 : json_t *a = cls;
697 :
698 25 : if (GNUNET_OK !=
699 25 : TALER_exchange_wire_signature_check (
700 : payto_uri,
701 : conversion_url,
702 : debit_restrictions,
703 : credit_restrictions,
704 : &TEH_master_public_key,
705 : master_sig))
706 : {
707 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
708 : "Database has wire account with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
709 0 : return;
710 : }
711 25 : if (0 !=
712 25 : json_array_append_new (
713 : a,
714 25 : GNUNET_JSON_PACK (
715 : TALER_JSON_pack_full_payto ("payto_uri",
716 : payto_uri),
717 : GNUNET_JSON_pack_allow_null (
718 : GNUNET_JSON_pack_string ("conversion_url",
719 : conversion_url)),
720 : GNUNET_JSON_pack_allow_null (
721 : GNUNET_JSON_pack_string ("bank_label",
722 : bank_label)),
723 : GNUNET_JSON_pack_int64 ("priority",
724 : priority),
725 : GNUNET_JSON_pack_array_incref ("debit_restrictions",
726 : (json_t *) debit_restrictions),
727 : GNUNET_JSON_pack_array_incref ("credit_restrictions",
728 : (json_t *) credit_restrictions),
729 : GNUNET_JSON_pack_data_auto ("master_sig",
730 : master_sig))))
731 : {
732 0 : GNUNET_break (0); /* out of memory!? */
733 0 : return;
734 : }
735 : }
736 :
737 :
738 : /**
739 : * Closure for #add_wire_fee().
740 : */
741 : struct AddContext
742 : {
743 : /**
744 : * Wire method the fees are for.
745 : */
746 : char *wire_method;
747 :
748 : /**
749 : * Wire state we are building.
750 : */
751 : struct WireStateHandle *wsh;
752 :
753 : /**
754 : * Array to append the fee to.
755 : */
756 : json_t *a;
757 :
758 : /**
759 : * Set to the maximum end-date seen.
760 : */
761 : struct GNUNET_TIME_Absolute max_seen;
762 : };
763 :
764 :
765 : /**
766 : * Add information about a wire account to @a cls.
767 : *
768 : * @param cls a `struct AddContext`
769 : * @param fees the wire fees we charge
770 : * @param start_date from when are these fees valid (start date)
771 : * @param end_date until when are these fees valid (end date, exclusive)
772 : * @param master_sig master key signature affirming that this is the correct
773 : * fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES)
774 : */
775 : static void
776 23 : add_wire_fee (void *cls,
777 : const struct TALER_WireFeeSet *fees,
778 : struct GNUNET_TIME_Timestamp start_date,
779 : struct GNUNET_TIME_Timestamp end_date,
780 : const struct TALER_MasterSignatureP *master_sig)
781 : {
782 23 : struct AddContext *ac = cls;
783 : struct WireFeeSet *wfs;
784 :
785 23 : if (GNUNET_OK !=
786 23 : TALER_exchange_offline_wire_fee_verify (
787 23 : ac->wire_method,
788 : start_date,
789 : end_date,
790 : fees,
791 : &TEH_master_public_key,
792 : master_sig))
793 : {
794 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
795 : "Database has wire fee with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
796 0 : return;
797 : }
798 23 : ac->max_seen = GNUNET_TIME_absolute_max (ac->max_seen,
799 : end_date.abs_time);
800 23 : wfs = GNUNET_new (struct WireFeeSet);
801 23 : wfs->start_date = start_date;
802 23 : wfs->end_date = end_date;
803 23 : wfs->fees = *fees;
804 23 : wfs->method = GNUNET_strdup (ac->wire_method);
805 23 : GNUNET_CONTAINER_DLL_insert (ac->wsh->wfs_head,
806 : ac->wsh->wfs_tail,
807 : wfs);
808 23 : if (0 !=
809 23 : json_array_append_new (
810 : ac->a,
811 23 : GNUNET_JSON_PACK (
812 : TALER_JSON_pack_amount ("wire_fee",
813 : &fees->wire),
814 : TALER_JSON_pack_amount ("closing_fee",
815 : &fees->closing),
816 : GNUNET_JSON_pack_timestamp ("start_date",
817 : start_date),
818 : GNUNET_JSON_pack_timestamp ("end_date",
819 : end_date),
820 : GNUNET_JSON_pack_data_auto ("sig",
821 : master_sig))))
822 : {
823 0 : GNUNET_break (0); /* out of memory!? */
824 0 : return;
825 : }
826 : }
827 :
828 :
829 : /**
830 : * Create the wire response from our database state.
831 : *
832 : * @return NULL on error
833 : */
834 : static struct WireStateHandle *
835 29 : build_wire_state (void)
836 : {
837 : json_t *wire_accounts_array;
838 : json_t *wire_fee_object;
839 29 : uint64_t wg = wire_generation; /* must be obtained FIRST */
840 : enum GNUNET_DB_QueryStatus qs;
841 : struct WireStateHandle *wsh;
842 : json_t *wads;
843 :
844 29 : wsh = GNUNET_new (struct WireStateHandle);
845 29 : wsh->wire_generation = wg;
846 29 : wire_accounts_array = json_array ();
847 29 : GNUNET_assert (NULL != wire_accounts_array);
848 29 : qs = TEH_plugin->get_wire_accounts (TEH_plugin->cls,
849 : &add_wire_account,
850 : wire_accounts_array);
851 29 : if (0 > qs)
852 : {
853 0 : GNUNET_break (0);
854 0 : json_decref (wire_accounts_array);
855 0 : wsh->ready = false;
856 0 : return wsh;
857 : }
858 29 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
859 : "Built wire data with %u accounts\n",
860 : (unsigned int) json_array_size (wire_accounts_array));
861 29 : wire_fee_object = json_object ();
862 29 : GNUNET_assert (NULL != wire_fee_object);
863 29 : wsh->cache_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
864 : {
865 : json_t *account;
866 : size_t index;
867 :
868 54 : json_array_foreach (wire_accounts_array,
869 : index,
870 : account)
871 : {
872 : char *wire_method;
873 25 : const char *payto_uri = json_string_value (json_object_get (account,
874 : "payto_uri"));
875 :
876 25 : GNUNET_assert (NULL != payto_uri);
877 25 : wire_method = TALER_payto_get_method (payto_uri);
878 25 : if (NULL == wire_method)
879 : {
880 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 : "No wire method in `%s'\n",
882 : payto_uri);
883 0 : wsh->ready = false;
884 0 : json_decref (wire_accounts_array);
885 0 : json_decref (wire_fee_object);
886 0 : return wsh;
887 : }
888 25 : if (NULL == json_object_get (wire_fee_object,
889 : wire_method))
890 : {
891 46 : struct AddContext ac = {
892 : .wire_method = wire_method,
893 : .wsh = wsh,
894 23 : .a = json_array ()
895 : };
896 :
897 23 : GNUNET_assert (NULL != ac.a);
898 23 : qs = TEH_plugin->get_wire_fees (TEH_plugin->cls,
899 : wire_method,
900 : &add_wire_fee,
901 : &ac);
902 23 : if (0 > qs)
903 : {
904 0 : GNUNET_break (0);
905 0 : json_decref (ac.a);
906 0 : json_decref (wire_fee_object);
907 0 : json_decref (wire_accounts_array);
908 0 : GNUNET_free (wire_method);
909 0 : wsh->ready = false;
910 0 : return wsh;
911 : }
912 23 : if (0 != json_array_size (ac.a))
913 : {
914 : wsh->cache_expiration
915 23 : = GNUNET_TIME_absolute_min (ac.max_seen,
916 : wsh->cache_expiration);
917 23 : GNUNET_assert (0 ==
918 : json_object_set_new (wire_fee_object,
919 : wire_method,
920 : ac.a));
921 : }
922 : else
923 : {
924 0 : json_decref (ac.a);
925 : }
926 : }
927 25 : GNUNET_free (wire_method);
928 : }
929 : }
930 :
931 29 : wads = json_array (); /* #7271 */
932 29 : GNUNET_assert (NULL != wads);
933 29 : wsh->json_reply = GNUNET_JSON_PACK (
934 : GNUNET_JSON_pack_array_steal ("accounts",
935 : wire_accounts_array),
936 : GNUNET_JSON_pack_array_steal ("wads",
937 : wads),
938 : GNUNET_JSON_pack_object_steal ("fees",
939 : wire_fee_object));
940 29 : wsh->ready = true;
941 29 : return wsh;
942 : }
943 :
944 :
945 : void
946 52 : TEH_wire_update_state (void)
947 : {
948 52 : struct GNUNET_DB_EventHeaderP es = {
949 52 : .size = htons (sizeof (es)),
950 52 : .type = htons (TALER_DBEVENT_EXCHANGE_WIRE_UPDATED),
951 : };
952 :
953 52 : TEH_plugin->event_notify (TEH_plugin->cls,
954 : &es,
955 : NULL,
956 : 0);
957 52 : wire_generation++;
958 52 : key_generation++;
959 52 : }
960 :
961 :
962 : /**
963 : * Return the current key state for this thread. Possibly
964 : * re-builds the key state if we have reason to believe
965 : * that something changed.
966 : *
967 : * @return NULL on error
968 : */
969 : static struct WireStateHandle *
970 933 : get_wire_state (void)
971 : {
972 : struct WireStateHandle *old_wsh;
973 :
974 933 : old_wsh = wire_state;
975 933 : if ( (NULL == old_wsh) ||
976 914 : (old_wsh->wire_generation < wire_generation) )
977 : {
978 : struct WireStateHandle *wsh;
979 :
980 29 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
981 : "Rebuilding wire, generation upgrade from %llu to %llu\n",
982 : (unsigned long long) (NULL == old_wsh) ? 0LL :
983 : old_wsh->wire_generation,
984 : (unsigned long long) wire_generation);
985 29 : TEH_check_invariants ();
986 29 : wsh = build_wire_state ();
987 29 : wire_state = wsh;
988 29 : if (NULL != old_wsh)
989 10 : destroy_wire_state (old_wsh);
990 29 : TEH_check_invariants ();
991 29 : return wsh;
992 : }
993 904 : return old_wsh;
994 : }
995 :
996 :
997 : const struct TALER_WireFeeSet *
998 2 : TEH_wire_fees_by_time (
999 : struct GNUNET_TIME_Timestamp ts,
1000 : const char *method)
1001 : {
1002 2 : struct WireStateHandle *wsh = get_wire_state ();
1003 :
1004 2 : for (struct WireFeeSet *wfs = wsh->wfs_head;
1005 2 : NULL != wfs;
1006 0 : wfs = wfs->next)
1007 : {
1008 2 : if (0 != strcmp (method,
1009 2 : wfs->method))
1010 0 : continue;
1011 2 : if ( (GNUNET_TIME_timestamp_cmp (wfs->start_date,
1012 : >,
1013 2 : ts)) ||
1014 2 : (GNUNET_TIME_timestamp_cmp (ts,
1015 : >=,
1016 : wfs->end_date)) )
1017 0 : continue;
1018 2 : return &wfs->fees;
1019 : }
1020 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1021 : "No wire fees for method `%s' at %s configured\n",
1022 : method,
1023 : GNUNET_TIME_timestamp2s (ts));
1024 0 : return NULL;
1025 : }
1026 :
1027 :
1028 : /**
1029 : * Function called to forcefully resume suspended keys requests.
1030 : *
1031 : * @param cls unused, NULL
1032 : */
1033 : static void
1034 0 : keys_timeout_cb (void *cls)
1035 : {
1036 : struct SuspendedKeysRequests *skr;
1037 :
1038 : (void) cls;
1039 0 : keys_tt = NULL;
1040 0 : while (NULL != (skr = skr_head))
1041 : {
1042 0 : if (GNUNET_TIME_absolute_is_future (skr->timeout))
1043 0 : break;
1044 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1045 : "Resuming /keys request due to timeout\n");
1046 0 : GNUNET_CONTAINER_DLL_remove (skr_head,
1047 : skr_tail,
1048 : skr);
1049 0 : MHD_resume_connection (skr->connection);
1050 0 : TALER_MHD_daemon_trigger ();
1051 0 : GNUNET_free (skr);
1052 : }
1053 0 : if (NULL == skr)
1054 0 : return;
1055 0 : keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
1056 : &keys_timeout_cb,
1057 : NULL);
1058 : }
1059 :
1060 :
1061 : /**
1062 : * Suspend /keys request while we (hopefully) are waiting to be
1063 : * provisioned with key material.
1064 : *
1065 : * @param[in] connection to suspend
1066 : */
1067 : static MHD_RESULT
1068 10 : suspend_request (struct MHD_Connection *connection)
1069 : {
1070 : struct SuspendedKeysRequests *skr;
1071 :
1072 10 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1073 : "Suspending /keys request until key material changes\n");
1074 10 : if (terminating)
1075 : {
1076 0 : return TALER_MHD_reply_with_error (connection,
1077 : MHD_HTTP_INTERNAL_SERVER_ERROR,
1078 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
1079 : "Exchange terminating");
1080 : }
1081 10 : skr = GNUNET_new (struct SuspendedKeysRequests);
1082 10 : skr->connection = connection;
1083 10 : MHD_suspend_connection (connection);
1084 10 : GNUNET_CONTAINER_DLL_insert (skr_head,
1085 : skr_tail,
1086 : skr);
1087 10 : skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
1088 10 : if (NULL == keys_tt)
1089 : {
1090 2 : keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
1091 : &keys_timeout_cb,
1092 : NULL);
1093 : }
1094 10 : skr_size++;
1095 10 : if (skr_size > SKR_LIMIT)
1096 : {
1097 0 : skr = skr_tail;
1098 0 : GNUNET_CONTAINER_DLL_remove (skr_head,
1099 : skr_tail,
1100 : skr);
1101 0 : skr_size--;
1102 0 : skr_connection = skr->connection;
1103 0 : MHD_resume_connection (skr->connection);
1104 0 : TALER_MHD_daemon_trigger ();
1105 0 : GNUNET_free (skr);
1106 : }
1107 10 : return MHD_YES;
1108 : }
1109 :
1110 :
1111 : /**
1112 : * Called on each denomination key. Checks that the key still works.
1113 : *
1114 : * @param cls NULL
1115 : * @param hc denomination hash (unused)
1116 : * @param value a `struct TEH_DenominationKey`
1117 : * @return #GNUNET_OK
1118 : */
1119 : static enum GNUNET_GenericReturnValue
1120 0 : check_dk (void *cls,
1121 : const struct GNUNET_HashCode *hc,
1122 : void *value)
1123 : {
1124 0 : struct TEH_DenominationKey *dk = value;
1125 :
1126 : (void) cls;
1127 : (void) hc;
1128 0 : switch (dk->denom_pub.bsign_pub_key->cipher)
1129 : {
1130 0 : case GNUNET_CRYPTO_BSA_INVALID:
1131 0 : break;
1132 0 : case GNUNET_CRYPTO_BSA_RSA:
1133 0 : GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check (
1134 : dk->denom_pub.bsign_pub_key->details.rsa_public_key));
1135 0 : return GNUNET_OK;
1136 0 : case GNUNET_CRYPTO_BSA_CS:
1137 : /* nothing to do for GNUNET_CRYPTO_BSA_CS */
1138 0 : return GNUNET_OK;
1139 : }
1140 0 : GNUNET_assert (0);
1141 : return GNUNET_SYSERR;
1142 : }
1143 :
1144 :
1145 : void
1146 28914 : TEH_check_invariants ()
1147 : {
1148 : struct TEH_KeyStateHandle *ksh;
1149 :
1150 28914 : if (0 == TEH_check_invariants_flag)
1151 28914 : return;
1152 0 : ksh = TEH_keys_get_state ();
1153 0 : if (NULL == ksh)
1154 0 : return;
1155 0 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
1156 : &check_dk,
1157 : NULL);
1158 : }
1159 :
1160 :
1161 : void
1162 10779 : TEH_resume_keys_requests (bool do_shutdown)
1163 : {
1164 : struct SuspendedKeysRequests *skr;
1165 :
1166 10779 : if (do_shutdown)
1167 21 : terminating = true;
1168 10789 : while (NULL != (skr = skr_head))
1169 : {
1170 10 : GNUNET_CONTAINER_DLL_remove (skr_head,
1171 : skr_tail,
1172 : skr);
1173 10 : skr_size--;
1174 10 : MHD_resume_connection (skr->connection);
1175 10 : TALER_MHD_daemon_trigger ();
1176 10 : GNUNET_free (skr);
1177 : }
1178 10779 : }
1179 :
1180 :
1181 : /**
1182 : * Clear memory for responses to "/keys" in @a ksh.
1183 : *
1184 : * @param[in,out] ksh key state to update
1185 : */
1186 : static void
1187 89 : clear_response_cache (struct TEH_KeyStateHandle *ksh)
1188 : {
1189 985 : for (unsigned int i = 0; i<ksh->krd_array_length; i++)
1190 : {
1191 896 : struct KeysResponseData *krd = &ksh->krd_array[i];
1192 :
1193 896 : MHD_destroy_response (krd->response_compressed);
1194 896 : MHD_destroy_response (krd->response_uncompressed);
1195 896 : GNUNET_free (krd->etag);
1196 : }
1197 89 : GNUNET_array_grow (ksh->krd_array,
1198 : ksh->krd_array_length,
1199 : 0);
1200 89 : }
1201 :
1202 :
1203 : /**
1204 : * Check that the given RSA security module's public key is the one
1205 : * we have pinned. If it does not match, we die hard.
1206 : *
1207 : * @param sm_pub RSA security module public key to check
1208 : */
1209 : static void
1210 7799 : check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
1211 : {
1212 7799 : if (0 !=
1213 7799 : GNUNET_memcmp (sm_pub,
1214 : &denom_rsa_sm_pub))
1215 : {
1216 12 : if (! GNUNET_is_zero (&denom_rsa_sm_pub))
1217 : {
1218 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1219 : "Our RSA security module changed its key. This must not happen.\n");
1220 0 : GNUNET_assert (0);
1221 : }
1222 12 : denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) */
1223 : }
1224 7799 : }
1225 :
1226 :
1227 : /**
1228 : * Check that the given CS security module's public key is the one
1229 : * we have pinned. If it does not match, we die hard.
1230 : *
1231 : * @param sm_pub RSA security module public key to check
1232 : */
1233 : static void
1234 2663 : check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
1235 : {
1236 2663 : if (0 !=
1237 2663 : GNUNET_memcmp (sm_pub,
1238 : &denom_cs_sm_pub))
1239 : {
1240 7 : if (! GNUNET_is_zero (&denom_cs_sm_pub))
1241 : {
1242 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1243 : "Our CS security module changed its key. This must not happen.\n");
1244 0 : GNUNET_assert (0);
1245 : }
1246 7 : denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */
1247 : }
1248 2663 : }
1249 :
1250 :
1251 : /**
1252 : * Check that the given EdDSA security module's public key is the one
1253 : * we have pinned. If it does not match, we die hard.
1254 : *
1255 : * @param sm_pub EdDSA security module public key to check
1256 : */
1257 : static void
1258 117 : check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
1259 : {
1260 117 : if (0 !=
1261 117 : GNUNET_memcmp (sm_pub,
1262 : &esign_sm_pub))
1263 : {
1264 19 : if (! GNUNET_is_zero (&esign_sm_pub))
1265 : {
1266 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1267 : "Our EdDSA security module changed its key. This must not happen.\n");
1268 0 : GNUNET_assert (0);
1269 : }
1270 19 : esign_sm_pub = *sm_pub; /* TOFU ;-) */
1271 : }
1272 117 : }
1273 :
1274 :
1275 : /**
1276 : * Helper function for #destroy_key_helpers to free all entries
1277 : * in the `denom_keys` map.
1278 : *
1279 : * @param cls the `struct HelperDenomination`
1280 : * @param h_denom_pub hash of the denomination public key
1281 : * @param value the `struct HelperDenomination` to release
1282 : * @return #GNUNET_OK (continue to iterate)
1283 : */
1284 : static enum GNUNET_GenericReturnValue
1285 10462 : free_denom_cb (void *cls,
1286 : const struct GNUNET_HashCode *h_denom_pub,
1287 : void *value)
1288 : {
1289 10462 : struct HelperDenomination *hd = value;
1290 :
1291 : (void) cls;
1292 : (void) h_denom_pub;
1293 10462 : TALER_denom_pub_free (&hd->denom_pub);
1294 10462 : GNUNET_free (hd->section_name);
1295 10462 : GNUNET_free (hd);
1296 10462 : return GNUNET_OK;
1297 : }
1298 :
1299 :
1300 : /**
1301 : * Helper function for #destroy_key_helpers to free all entries
1302 : * in the `esign_keys` map.
1303 : *
1304 : * @param cls the `struct HelperSignkey`
1305 : * @param pid unused, matches the exchange public key
1306 : * @param value the `struct HelperSignkey` to release
1307 : * @return #GNUNET_OK (continue to iterate)
1308 : */
1309 : static enum GNUNET_GenericReturnValue
1310 117 : free_esign_cb (void *cls,
1311 : const struct GNUNET_PeerIdentity *pid,
1312 : void *value)
1313 : {
1314 117 : struct HelperSignkey *hsk = value;
1315 :
1316 : (void) cls;
1317 : (void) pid;
1318 117 : GNUNET_free (hsk);
1319 117 : return GNUNET_OK;
1320 : }
1321 :
1322 :
1323 : /**
1324 : * Destroy helper state. Does NOT call free() on @a hs, as that
1325 : * state is not separately allocated! Dual to #setup_key_helpers().
1326 : *
1327 : * @param[in] hs helper state to free, but NOT the @a hs pointer itself!
1328 : */
1329 : static void
1330 29 : destroy_key_helpers (struct HelperState *hs)
1331 : {
1332 29 : GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys,
1333 : &free_denom_cb,
1334 : hs);
1335 29 : GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys);
1336 29 : hs->rsa_keys = NULL;
1337 29 : GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys);
1338 29 : hs->cs_keys = NULL;
1339 29 : GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys);
1340 29 : hs->denom_keys = NULL;
1341 29 : GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys,
1342 : &free_esign_cb,
1343 : hs);
1344 29 : GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys);
1345 29 : hs->esign_keys = NULL;
1346 29 : if (NULL != hs->rsadh)
1347 : {
1348 29 : TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh);
1349 29 : hs->rsadh = NULL;
1350 : }
1351 29 : if (NULL != hs->csdh)
1352 : {
1353 29 : TALER_CRYPTO_helper_cs_disconnect (hs->csdh);
1354 29 : hs->csdh = NULL;
1355 : }
1356 29 : if (NULL != hs->esh)
1357 : {
1358 29 : TALER_CRYPTO_helper_esign_disconnect (hs->esh);
1359 29 : hs->esh = NULL;
1360 : }
1361 29 : }
1362 :
1363 :
1364 : /**
1365 : * Looks up the AGE_RESTRICTED setting for a denomination in the config and
1366 : * returns the age restriction (mask) accordingly.
1367 : *
1368 : * @param section_name Section in the configuration for the particular
1369 : * denomination.
1370 : */
1371 : static struct TALER_AgeMask
1372 29122 : load_age_mask (const char *section_name)
1373 : {
1374 : static const struct TALER_AgeMask null_mask = {0};
1375 : enum GNUNET_GenericReturnValue ret;
1376 :
1377 29122 : if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
1378 : TEH_cfg,
1379 : section_name,
1380 : "AGE_RESTRICTED")))
1381 18442 : return null_mask;
1382 :
1383 10680 : if (GNUNET_SYSERR ==
1384 10680 : (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
1385 : section_name,
1386 : "AGE_RESTRICTED")))
1387 : {
1388 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1389 : section_name,
1390 : "AGE_RESTRICTED",
1391 : "Value must be YES or NO\n");
1392 0 : return null_mask;
1393 : }
1394 :
1395 10680 : if (GNUNET_OK == ret)
1396 : {
1397 10680 : if (! TEH_age_restriction_enabled)
1398 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1399 : "age restriction set in section %s, yet, age restriction is not enabled\n",
1400 : section_name);
1401 10680 : return TEH_age_restriction_config.mask;
1402 : }
1403 :
1404 :
1405 0 : return null_mask;
1406 : }
1407 :
1408 :
1409 : /**
1410 : * Function called with information about available keys for signing. Usually
1411 : * only called once per key upon connect. Also called again in case a key is
1412 : * being revoked, in that case with an @a end_time of zero.
1413 : *
1414 : * @param cls closure with the `struct HelperState *`
1415 : * @param section_name name of the denomination type in the configuration;
1416 : * NULL if the key has been revoked or purged
1417 : * @param start_time when does the key become available for signing;
1418 : * zero if the key has been revoked or purged
1419 : * @param validity_duration how long does the key remain available for signing;
1420 : * zero if the key has been revoked or purged
1421 : * @param h_rsa hash of the @a denom_pub that is available (or was purged)
1422 : * @param bs_pub the public key itself, NULL if the key was revoked or purged
1423 : * @param sm_pub public key of the security module, NULL if the key was revoked or purged
1424 : * @param sm_sig signature from the security module, NULL if the key was revoked or purged
1425 : * The signature was already verified against @a sm_pub.
1426 : */
1427 : static void
1428 7799 : helper_rsa_cb (
1429 : void *cls,
1430 : const char *section_name,
1431 : struct GNUNET_TIME_Timestamp start_time,
1432 : struct GNUNET_TIME_Relative validity_duration,
1433 : const struct TALER_RsaPubHashP *h_rsa,
1434 : struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub,
1435 : const struct TALER_SecurityModulePublicKeyP *sm_pub,
1436 : const struct TALER_SecurityModuleSignatureP *sm_sig)
1437 : {
1438 7799 : struct HelperState *hs = cls;
1439 : struct HelperDenomination *hd;
1440 :
1441 7799 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1442 : "RSA helper announces key %s for denomination type %s with validity %s\n",
1443 : GNUNET_h2s (&h_rsa->hash),
1444 : section_name,
1445 : GNUNET_STRINGS_relative_time_to_string (validity_duration,
1446 : GNUNET_NO));
1447 7799 : key_generation++;
1448 7799 : TEH_resume_keys_requests (false);
1449 7799 : hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys,
1450 : &h_rsa->hash);
1451 7799 : if (NULL != hd)
1452 : {
1453 : /* should be just an update (revocation!), so update existing entry */
1454 0 : hd->validity_duration = validity_duration;
1455 0 : return;
1456 : }
1457 7799 : GNUNET_assert (NULL != sm_pub);
1458 7799 : check_denom_rsa_sm_pub (sm_pub);
1459 7799 : hd = GNUNET_new (struct HelperDenomination);
1460 7799 : hd->start_time = start_time;
1461 7799 : hd->validity_duration = validity_duration;
1462 7799 : hd->h_details.h_rsa = *h_rsa;
1463 7799 : hd->sm_sig = *sm_sig;
1464 7799 : GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == bs_pub->cipher);
1465 7799 : hd->denom_pub.bsign_pub_key =
1466 7799 : GNUNET_CRYPTO_bsign_pub_incref (bs_pub);
1467 : /* load the age mask for the denomination, if applicable */
1468 7799 : hd->denom_pub.age_mask = load_age_mask (section_name);
1469 7799 : TALER_denom_pub_hash (&hd->denom_pub,
1470 : &hd->h_denom_pub);
1471 7799 : hd->section_name = GNUNET_strdup (section_name);
1472 7799 : GNUNET_assert (
1473 : GNUNET_OK ==
1474 : GNUNET_CONTAINER_multihashmap_put (
1475 : hs->denom_keys,
1476 : &hd->h_denom_pub.hash,
1477 : hd,
1478 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1479 7799 : GNUNET_assert (
1480 : GNUNET_OK ==
1481 : GNUNET_CONTAINER_multihashmap_put (
1482 : hs->rsa_keys,
1483 : &hd->h_details.h_rsa.hash,
1484 : hd,
1485 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1486 : }
1487 :
1488 :
1489 : /**
1490 : * Function called with information about available CS keys for signing. Usually
1491 : * only called once per key upon connect. Also called again in case a key is
1492 : * being revoked, in that case with an @a end_time of zero.
1493 : *
1494 : * @param cls closure with the `struct HelperState *`
1495 : * @param section_name name of the denomination type in the configuration;
1496 : * NULL if the key has been revoked or purged
1497 : * @param start_time when does the key become available for signing;
1498 : * zero if the key has been revoked or purged
1499 : * @param validity_duration how long does the key remain available for signing;
1500 : * zero if the key has been revoked or purged
1501 : * @param h_cs hash of the @a denom_pub that is available (or was purged)
1502 : * @param bs_pub the public key itself, NULL if the key was revoked or purged
1503 : * @param sm_pub public key of the security module, NULL if the key was revoked or purged
1504 : * @param sm_sig signature from the security module, NULL if the key was revoked or purged
1505 : * The signature was already verified against @a sm_pub.
1506 : */
1507 : static void
1508 2663 : helper_cs_cb (
1509 : void *cls,
1510 : const char *section_name,
1511 : struct GNUNET_TIME_Timestamp start_time,
1512 : struct GNUNET_TIME_Relative validity_duration,
1513 : const struct TALER_CsPubHashP *h_cs,
1514 : struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub,
1515 : const struct TALER_SecurityModulePublicKeyP *sm_pub,
1516 : const struct TALER_SecurityModuleSignatureP *sm_sig)
1517 : {
1518 2663 : struct HelperState *hs = cls;
1519 : struct HelperDenomination *hd;
1520 :
1521 2663 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 : "CS helper announces key %s for denomination type %s with validity %s\n",
1523 : GNUNET_h2s (&h_cs->hash),
1524 : section_name,
1525 : GNUNET_STRINGS_relative_time_to_string (validity_duration,
1526 : GNUNET_NO));
1527 2663 : key_generation++;
1528 2663 : TEH_resume_keys_requests (false);
1529 2663 : hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys,
1530 : &h_cs->hash);
1531 2663 : if (NULL != hd)
1532 : {
1533 : /* should be just an update (revocation!), so update existing entry */
1534 0 : hd->validity_duration = validity_duration;
1535 0 : return;
1536 : }
1537 2663 : GNUNET_assert (NULL != sm_pub);
1538 2663 : check_denom_cs_sm_pub (sm_pub);
1539 2663 : hd = GNUNET_new (struct HelperDenomination);
1540 2663 : hd->start_time = start_time;
1541 2663 : hd->validity_duration = validity_duration;
1542 2663 : hd->h_details.h_cs = *h_cs;
1543 2663 : hd->sm_sig = *sm_sig;
1544 2663 : GNUNET_assert (GNUNET_CRYPTO_BSA_CS == bs_pub->cipher);
1545 : hd->denom_pub.bsign_pub_key
1546 2663 : = GNUNET_CRYPTO_bsign_pub_incref (bs_pub);
1547 : /* load the age mask for the denomination, if applicable */
1548 2663 : hd->denom_pub.age_mask = load_age_mask (section_name);
1549 2663 : TALER_denom_pub_hash (&hd->denom_pub,
1550 : &hd->h_denom_pub);
1551 2663 : hd->section_name = GNUNET_strdup (section_name);
1552 2663 : GNUNET_assert (
1553 : GNUNET_OK ==
1554 : GNUNET_CONTAINER_multihashmap_put (
1555 : hs->denom_keys,
1556 : &hd->h_denom_pub.hash,
1557 : hd,
1558 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1559 2663 : GNUNET_assert (
1560 : GNUNET_OK ==
1561 : GNUNET_CONTAINER_multihashmap_put (
1562 : hs->cs_keys,
1563 : &hd->h_details.h_cs.hash,
1564 : hd,
1565 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1566 : }
1567 :
1568 :
1569 : /**
1570 : * Function called with information about available keys for signing. Usually
1571 : * only called once per key upon connect. Also called again in case a key is
1572 : * being revoked, in that case with an @a end_time of zero.
1573 : *
1574 : * @param cls closure with the `struct HelperState *`
1575 : * @param start_time when does the key become available for signing;
1576 : * zero if the key has been revoked or purged
1577 : * @param validity_duration how long does the key remain available for signing;
1578 : * zero if the key has been revoked or purged
1579 : * @param exchange_pub the public key itself, NULL if the key was revoked or purged
1580 : * @param sm_pub public key of the security module, NULL if the key was revoked or purged
1581 : * @param sm_sig signature from the security module, NULL if the key was revoked or purged
1582 : * The signature was already verified against @a sm_pub.
1583 : */
1584 : static void
1585 117 : helper_esign_cb (
1586 : void *cls,
1587 : struct GNUNET_TIME_Timestamp start_time,
1588 : struct GNUNET_TIME_Relative validity_duration,
1589 : const struct TALER_ExchangePublicKeyP *exchange_pub,
1590 : const struct TALER_SecurityModulePublicKeyP *sm_pub,
1591 : const struct TALER_SecurityModuleSignatureP *sm_sig)
1592 : {
1593 117 : struct HelperState *hs = cls;
1594 : struct HelperSignkey *hsk;
1595 : struct GNUNET_PeerIdentity pid;
1596 :
1597 117 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1598 : "EdDSA helper announces signing key %s with validity %s\n",
1599 : TALER_B2S (exchange_pub),
1600 : GNUNET_STRINGS_relative_time_to_string (validity_duration,
1601 : GNUNET_NO));
1602 117 : key_generation++;
1603 117 : TEH_resume_keys_requests (false);
1604 117 : pid.public_key = exchange_pub->eddsa_pub;
1605 117 : hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
1606 : &pid);
1607 117 : if (NULL != hsk)
1608 : {
1609 : /* should be just an update (revocation!), so update existing entry */
1610 0 : hsk->validity_duration = validity_duration;
1611 0 : return;
1612 : }
1613 117 : GNUNET_assert (NULL != sm_pub);
1614 117 : check_esign_sm_pub (sm_pub);
1615 117 : hsk = GNUNET_new (struct HelperSignkey);
1616 117 : hsk->start_time = start_time;
1617 117 : hsk->validity_duration = validity_duration;
1618 117 : hsk->exchange_pub = *exchange_pub;
1619 117 : hsk->sm_sig = *sm_sig;
1620 117 : GNUNET_assert (
1621 : GNUNET_OK ==
1622 : GNUNET_CONTAINER_multipeermap_put (
1623 : hs->esign_keys,
1624 : &pid,
1625 : hsk,
1626 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1627 : }
1628 :
1629 :
1630 : /**
1631 : * Setup helper state.
1632 : *
1633 : * @param[out] hs helper state to initialize
1634 : * @return #GNUNET_OK on success
1635 : */
1636 : static enum GNUNET_GenericReturnValue
1637 29 : setup_key_helpers (struct HelperState *hs)
1638 : {
1639 : hs->denom_keys
1640 29 : = GNUNET_CONTAINER_multihashmap_create (1024,
1641 : GNUNET_YES);
1642 : hs->rsa_keys
1643 29 : = GNUNET_CONTAINER_multihashmap_create (1024,
1644 : GNUNET_YES);
1645 : hs->cs_keys
1646 29 : = GNUNET_CONTAINER_multihashmap_create (1024,
1647 : GNUNET_YES);
1648 : hs->esign_keys
1649 29 : = GNUNET_CONTAINER_multipeermap_create (32,
1650 : GNUNET_NO /* MUST BE NO! */);
1651 29 : hs->rsadh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg,
1652 : "taler-exchange",
1653 : &helper_rsa_cb,
1654 : hs);
1655 29 : if (NULL == hs->rsadh)
1656 : {
1657 0 : destroy_key_helpers (hs);
1658 0 : return GNUNET_SYSERR;
1659 : }
1660 29 : hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg,
1661 : "taler-exchange",
1662 : &helper_cs_cb,
1663 : hs);
1664 29 : if (NULL == hs->csdh)
1665 : {
1666 0 : destroy_key_helpers (hs);
1667 0 : return GNUNET_SYSERR;
1668 : }
1669 29 : hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg,
1670 : "taler-exchange",
1671 : &helper_esign_cb,
1672 : hs);
1673 29 : if (NULL == hs->esh)
1674 : {
1675 0 : destroy_key_helpers (hs);
1676 0 : return GNUNET_SYSERR;
1677 : }
1678 29 : return GNUNET_OK;
1679 : }
1680 :
1681 :
1682 : /**
1683 : * Synchronize helper state. Polls the key helper for updates.
1684 : *
1685 : * @param[in,out] hs helper state to synchronize
1686 : */
1687 : static void
1688 852 : sync_key_helpers (struct HelperState *hs)
1689 : {
1690 852 : TALER_CRYPTO_helper_rsa_poll (hs->rsadh);
1691 852 : TALER_CRYPTO_helper_cs_poll (hs->csdh);
1692 852 : TALER_CRYPTO_helper_esign_poll (hs->esh);
1693 852 : }
1694 :
1695 :
1696 : /**
1697 : * Free denomination key data.
1698 : *
1699 : * @param cls a `struct TEH_KeyStateHandle`, unused
1700 : * @param h_denom_pub hash of the denomination public key, unused
1701 : * @param value a `struct TEH_DenominationKey` to free
1702 : * @return #GNUNET_OK (continue to iterate)
1703 : */
1704 : static enum GNUNET_GenericReturnValue
1705 10896 : clear_denomination_cb (void *cls,
1706 : const struct GNUNET_HashCode *h_denom_pub,
1707 : void *value)
1708 : {
1709 10896 : struct TEH_DenominationKey *dk = value;
1710 : struct TEH_AuditorSignature *as;
1711 :
1712 : (void) cls;
1713 : (void) h_denom_pub;
1714 10896 : TALER_denom_pub_free (&dk->denom_pub);
1715 10896 : while (NULL != (as = dk->as_head))
1716 : {
1717 0 : GNUNET_CONTAINER_DLL_remove (dk->as_head,
1718 : dk->as_tail,
1719 : as);
1720 0 : GNUNET_free (as);
1721 : }
1722 10896 : GNUNET_free (dk);
1723 10896 : return GNUNET_OK;
1724 : }
1725 :
1726 :
1727 : /**
1728 : * Free denomination key data.
1729 : *
1730 : * @param cls a `struct TEH_KeyStateHandle`, unused
1731 : * @param pid the online signing key (type-disguised), unused
1732 : * @param value a `struct SigningKey` to free
1733 : * @return #GNUNET_OK (continue to iterate)
1734 : */
1735 : static enum GNUNET_GenericReturnValue
1736 119 : clear_signkey_cb (void *cls,
1737 : const struct GNUNET_PeerIdentity *pid,
1738 : void *value)
1739 : {
1740 119 : struct SigningKey *sk = value;
1741 :
1742 : (void) cls;
1743 : (void) pid;
1744 119 : GNUNET_free (sk);
1745 119 : return GNUNET_OK;
1746 : }
1747 :
1748 :
1749 : /**
1750 : * Free resources associated with @a cls, possibly excluding
1751 : * the helper data.
1752 : *
1753 : * @param[in] ksh key state to release
1754 : * @param free_helper true to also release the helper state
1755 : */
1756 : static void
1757 89 : destroy_key_state (struct TEH_KeyStateHandle *ksh,
1758 : bool free_helper)
1759 : {
1760 : struct TEH_GlobalFee *gf;
1761 :
1762 89 : clear_response_cache (ksh);
1763 134 : while (NULL != (gf = ksh->gf_head))
1764 : {
1765 45 : GNUNET_CONTAINER_DLL_remove (ksh->gf_head,
1766 : ksh->gf_tail,
1767 : gf);
1768 45 : GNUNET_free (gf);
1769 : }
1770 89 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
1771 : &clear_denomination_cb,
1772 : ksh);
1773 89 : GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map);
1774 89 : GNUNET_CONTAINER_multihashmap32_destroy (ksh->denomserial_map);
1775 89 : GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
1776 : &clear_signkey_cb,
1777 : ksh);
1778 89 : GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map);
1779 89 : json_decref (ksh->auditors);
1780 89 : ksh->auditors = NULL;
1781 89 : json_decref (ksh->global_fees);
1782 89 : ksh->global_fees = NULL;
1783 89 : if (free_helper)
1784 : {
1785 29 : destroy_key_helpers (ksh->helpers);
1786 29 : GNUNET_free (ksh->helpers);
1787 : }
1788 89 : if (NULL != ksh->management_keys_reply)
1789 : {
1790 40 : json_decref (ksh->management_keys_reply);
1791 40 : ksh->management_keys_reply = NULL;
1792 : }
1793 89 : GNUNET_free (ksh);
1794 89 : }
1795 :
1796 :
1797 : /**
1798 : * Function called whenever another exchange process has updated
1799 : * the keys data in the database.
1800 : *
1801 : * @param cls NULL
1802 : * @param extra unused
1803 : * @param extra_size number of bytes in @a extra unused
1804 : */
1805 : static void
1806 56 : keys_update_event_cb (void *cls,
1807 : const void *extra,
1808 : size_t extra_size)
1809 : {
1810 : (void) cls;
1811 : (void) extra;
1812 : (void) extra_size;
1813 56 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1814 : "Received /keys update event\n");
1815 56 : TEH_check_invariants ();
1816 56 : key_generation++;
1817 56 : TEH_resume_keys_requests (false);
1818 56 : TEH_check_invariants ();
1819 56 : }
1820 :
1821 :
1822 : enum GNUNET_GenericReturnValue
1823 21 : TEH_keys_init ()
1824 : {
1825 21 : struct GNUNET_DB_EventHeaderP es = {
1826 21 : .size = htons (sizeof (es)),
1827 21 : .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
1828 : };
1829 :
1830 21 : if (GNUNET_OK !=
1831 21 : GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
1832 : "exchange",
1833 : "SIGNKEY_LEGAL_DURATION",
1834 : &signkey_legal_duration))
1835 : {
1836 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1837 : "exchange",
1838 : "SIGNKEY_LEGAL_DURATION");
1839 0 : return GNUNET_SYSERR;
1840 : }
1841 21 : if (GNUNET_OK !=
1842 21 : GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
1843 : "exchange",
1844 : "ASSET_TYPE",
1845 : &asset_type))
1846 : {
1847 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
1848 : "exchange",
1849 : "ASSET_TYPE");
1850 0 : asset_type = GNUNET_strdup ("fiat");
1851 : }
1852 42 : keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
1853 21 : GNUNET_TIME_UNIT_FOREVER_REL,
1854 : &es,
1855 : &keys_update_event_cb,
1856 : NULL);
1857 21 : if (NULL == keys_eh)
1858 : {
1859 0 : GNUNET_break (0);
1860 0 : return GNUNET_SYSERR;
1861 : }
1862 21 : return GNUNET_OK;
1863 : }
1864 :
1865 :
1866 : /**
1867 : * Fully clean up our state.
1868 : */
1869 : void
1870 21 : TEH_keys_finished ()
1871 : {
1872 21 : if (NULL != keys_tt)
1873 : {
1874 2 : GNUNET_SCHEDULER_cancel (keys_tt);
1875 2 : keys_tt = NULL;
1876 : }
1877 21 : if (NULL != key_state)
1878 19 : destroy_key_state (key_state,
1879 : true);
1880 21 : if (NULL != keys_eh)
1881 : {
1882 21 : TEH_plugin->event_listen_cancel (TEH_plugin->cls,
1883 : keys_eh);
1884 21 : keys_eh = NULL;
1885 : }
1886 21 : }
1887 :
1888 :
1889 : /**
1890 : * Function called with information about the exchange's denomination keys.
1891 : *
1892 : * @param cls closure with a `struct TEH_KeyStateHandle *`
1893 : * @param denom_pub public key of the denomination
1894 : * @param h_denom_pub hash of @a denom_pub
1895 : * @param meta meta data information about the denomination type (value, expirations, fees)
1896 : * @param master_sig master signature affirming the validity of this denomination
1897 : * @param recoup_possible true if the key was revoked and clients can currently recoup
1898 : * coins of this denomination
1899 : */
1900 : static void
1901 10896 : denomination_info_cb (
1902 : void *cls,
1903 : const struct TALER_DenominationPublicKey *denom_pub,
1904 : const struct TALER_DenominationHashP *h_denom_pub,
1905 : const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
1906 : const struct TALER_MasterSignatureP *master_sig,
1907 : bool recoup_possible)
1908 : {
1909 10896 : struct TEH_KeyStateHandle *ksh = cls;
1910 : struct TEH_DenominationKey *dk;
1911 :
1912 10896 : if (GNUNET_OK !=
1913 10896 : TALER_exchange_offline_denom_validity_verify (
1914 : h_denom_pub,
1915 : meta->start,
1916 : meta->expire_withdraw,
1917 : meta->expire_deposit,
1918 : meta->expire_legal,
1919 : &meta->value,
1920 : &meta->fees,
1921 : &TEH_master_public_key,
1922 : master_sig))
1923 : {
1924 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1925 : "Database has denomination with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
1926 0 : return;
1927 : }
1928 :
1929 10896 : GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID !=
1930 : denom_pub->bsign_pub_key->cipher);
1931 21792 : if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) ||
1932 21792 : GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) ||
1933 21792 : GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) ||
1934 10896 : GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) )
1935 : {
1936 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1937 : "Database contains invalid denomination key %s\n",
1938 : GNUNET_h2s (&h_denom_pub->hash));
1939 0 : return;
1940 : }
1941 10896 : dk = GNUNET_new (struct TEH_DenominationKey);
1942 10896 : TALER_denom_pub_copy (&dk->denom_pub,
1943 : denom_pub);
1944 10896 : dk->h_denom_pub = *h_denom_pub;
1945 10896 : dk->meta = *meta;
1946 10896 : dk->master_sig = *master_sig;
1947 10896 : dk->recoup_possible = recoup_possible;
1948 10896 : dk->denom_pub.age_mask = meta->age_mask;
1949 :
1950 10896 : GNUNET_assert (
1951 : GNUNET_OK ==
1952 : GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map,
1953 : &dk->h_denom_pub.hash,
1954 : dk,
1955 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1956 : {
1957 10896 : uint32_t serial32 = (uint32_t) dk->meta.serial;
1958 :
1959 10896 : GNUNET_assert (dk->meta.serial == (uint64_t) serial32);
1960 10896 : GNUNET_assert (
1961 : GNUNET_OK ==
1962 : GNUNET_CONTAINER_multihashmap32_put (ksh->denomserial_map,
1963 : serial32,
1964 : dk,
1965 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1966 : }
1967 : }
1968 :
1969 :
1970 : /**
1971 : * Function called with information about the exchange's online signing keys.
1972 : *
1973 : * @param cls closure with a `struct TEH_KeyStateHandle *`
1974 : * @param exchange_pub the public key
1975 : * @param meta meta data information about the denomination type (expirations)
1976 : * @param master_sig master signature affirming the validity of this denomination
1977 : */
1978 : static void
1979 119 : signkey_info_cb (
1980 : void *cls,
1981 : const struct TALER_ExchangePublicKeyP *exchange_pub,
1982 : const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
1983 : const struct TALER_MasterSignatureP *master_sig)
1984 : {
1985 119 : struct TEH_KeyStateHandle *ksh = cls;
1986 : struct SigningKey *sk;
1987 : struct GNUNET_PeerIdentity pid;
1988 :
1989 119 : if (GNUNET_OK !=
1990 119 : TALER_exchange_offline_signkey_validity_verify (
1991 : exchange_pub,
1992 : meta->start,
1993 : meta->expire_sign,
1994 : meta->expire_legal,
1995 : &TEH_master_public_key,
1996 : master_sig))
1997 : {
1998 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1999 : "Database has signing key with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
2000 0 : return;
2001 : }
2002 119 : sk = GNUNET_new (struct SigningKey);
2003 119 : sk->exchange_pub = *exchange_pub;
2004 119 : sk->meta = *meta;
2005 119 : sk->master_sig = *master_sig;
2006 119 : pid.public_key = exchange_pub->eddsa_pub;
2007 119 : GNUNET_assert (
2008 : GNUNET_OK ==
2009 : GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map,
2010 : &pid,
2011 : sk,
2012 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2013 : }
2014 :
2015 :
2016 : /**
2017 : * Closure for #get_auditor_sigs.
2018 : */
2019 : struct GetAuditorSigsContext
2020 : {
2021 : /**
2022 : * Where to store the matching signatures.
2023 : */
2024 : json_t *denom_keys;
2025 :
2026 : /**
2027 : * Public key of the auditor to match against.
2028 : */
2029 : const struct TALER_AuditorPublicKeyP *auditor_pub;
2030 : };
2031 :
2032 :
2033 : /**
2034 : * Extract the auditor signatures matching the auditor's public
2035 : * key from the @a value and generate the respective JSON.
2036 : *
2037 : * @param cls a `struct GetAuditorSigsContext`
2038 : * @param h_denom_pub hash of the denomination public key
2039 : * @param value a `struct TEH_DenominationKey`
2040 : * @return #GNUNET_OK (continue to iterate)
2041 : */
2042 : static enum GNUNET_GenericReturnValue
2043 3816 : get_auditor_sigs (void *cls,
2044 : const struct GNUNET_HashCode *h_denom_pub,
2045 : void *value)
2046 : {
2047 3816 : struct GetAuditorSigsContext *ctx = cls;
2048 3816 : struct TEH_DenominationKey *dk = value;
2049 :
2050 3816 : for (struct TEH_AuditorSignature *as = dk->as_head;
2051 3816 : NULL != as;
2052 0 : as = as->next)
2053 : {
2054 0 : if (0 !=
2055 0 : GNUNET_memcmp (ctx->auditor_pub,
2056 : &as->apub))
2057 0 : continue;
2058 0 : GNUNET_break (0 ==
2059 : json_array_append_new (
2060 : ctx->denom_keys,
2061 : GNUNET_JSON_PACK (
2062 : GNUNET_JSON_pack_data_auto ("denom_pub_h",
2063 : h_denom_pub),
2064 : GNUNET_JSON_pack_data_auto ("auditor_sig",
2065 : &as->asig))));
2066 : }
2067 3816 : return GNUNET_OK;
2068 : }
2069 :
2070 :
2071 : /**
2072 : * Function called with information about the exchange's auditors.
2073 : *
2074 : * @param cls closure with a `struct TEH_KeyStateHandle *`
2075 : * @param auditor_pub the public key of the auditor
2076 : * @param auditor_url URL of the REST API of the auditor
2077 : * @param auditor_name human readable official name of the auditor
2078 : */
2079 : static void
2080 8 : auditor_info_cb (
2081 : void *cls,
2082 : const struct TALER_AuditorPublicKeyP *auditor_pub,
2083 : const char *auditor_url,
2084 : const char *auditor_name)
2085 : {
2086 8 : struct TEH_KeyStateHandle *ksh = cls;
2087 : struct GetAuditorSigsContext ctx;
2088 :
2089 8 : ctx.denom_keys = json_array ();
2090 8 : GNUNET_assert (NULL != ctx.denom_keys);
2091 8 : ctx.auditor_pub = auditor_pub;
2092 8 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
2093 : &get_auditor_sigs,
2094 : &ctx);
2095 8 : GNUNET_break (0 ==
2096 : json_array_append_new (
2097 : ksh->auditors,
2098 : GNUNET_JSON_PACK (
2099 : GNUNET_JSON_pack_string ("auditor_name",
2100 : auditor_name),
2101 : GNUNET_JSON_pack_data_auto ("auditor_pub",
2102 : auditor_pub),
2103 : GNUNET_JSON_pack_string ("auditor_url",
2104 : auditor_url),
2105 : GNUNET_JSON_pack_array_steal ("denomination_keys",
2106 : ctx.denom_keys))));
2107 8 : }
2108 :
2109 :
2110 : /**
2111 : * Function called with information about the denominations
2112 : * audited by the exchange's auditors.
2113 : *
2114 : * @param cls closure with a `struct TEH_KeyStateHandle *`
2115 : * @param auditor_pub the public key of an auditor
2116 : * @param h_denom_pub hash of a denomination key audited by this auditor
2117 : * @param auditor_sig signature from the auditor affirming this
2118 : */
2119 : static void
2120 0 : auditor_denom_cb (
2121 : void *cls,
2122 : const struct TALER_AuditorPublicKeyP *auditor_pub,
2123 : const struct TALER_DenominationHashP *h_denom_pub,
2124 : const struct TALER_AuditorSignatureP *auditor_sig)
2125 : {
2126 0 : struct TEH_KeyStateHandle *ksh = cls;
2127 : struct TEH_DenominationKey *dk;
2128 : struct TEH_AuditorSignature *as;
2129 :
2130 0 : dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
2131 : &h_denom_pub->hash);
2132 0 : if (NULL == dk)
2133 : {
2134 : /* Odd, this should be impossible as per foreign key
2135 : constraint on 'auditor_denom_sigs'! Well, we can
2136 : safely continue anyway, so let's just log it. */
2137 0 : GNUNET_break (0);
2138 0 : return;
2139 : }
2140 0 : as = GNUNET_new (struct TEH_AuditorSignature);
2141 0 : as->asig = *auditor_sig;
2142 0 : as->apub = *auditor_pub;
2143 0 : GNUNET_CONTAINER_DLL_insert (dk->as_head,
2144 : dk->as_tail,
2145 : as);
2146 : }
2147 :
2148 :
2149 : /**
2150 : * Closure for #add_sign_key_cb.
2151 : */
2152 : struct SignKeyCtx
2153 : {
2154 : /**
2155 : * What is the current rotation frequency for signing keys. Updated.
2156 : */
2157 : struct GNUNET_TIME_Relative min_sk_frequency;
2158 :
2159 : /**
2160 : * JSON array of signing keys (being created).
2161 : */
2162 : json_t *signkeys;
2163 : };
2164 :
2165 :
2166 : /**
2167 : * Function called for all signing keys, used to build up the
2168 : * respective JSON response.
2169 : *
2170 : * @param cls a `struct SignKeyCtx *` with the array to append keys to
2171 : * @param pid the exchange public key (in type disguise)
2172 : * @param value a `struct SigningKey`
2173 : * @return #GNUNET_OK (continue to iterate)
2174 : */
2175 : static enum GNUNET_GenericReturnValue
2176 89 : add_sign_key_cb (void *cls,
2177 : const struct GNUNET_PeerIdentity *pid,
2178 : void *value)
2179 : {
2180 89 : struct SignKeyCtx *ctx = cls;
2181 89 : struct SigningKey *sk = value;
2182 :
2183 : (void) pid;
2184 89 : if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time))
2185 : {
2186 : ctx->min_sk_frequency =
2187 89 : GNUNET_TIME_relative_min (ctx->min_sk_frequency,
2188 : GNUNET_TIME_absolute_get_difference (
2189 : sk->meta.start.abs_time,
2190 : sk->meta.expire_sign.abs_time));
2191 : }
2192 89 : GNUNET_assert (
2193 : 0 ==
2194 : json_array_append_new (
2195 : ctx->signkeys,
2196 : GNUNET_JSON_PACK (
2197 : GNUNET_JSON_pack_timestamp ("stamp_start",
2198 : sk->meta.start),
2199 : GNUNET_JSON_pack_timestamp ("stamp_expire",
2200 : sk->meta.expire_sign),
2201 : GNUNET_JSON_pack_timestamp ("stamp_end",
2202 : sk->meta.expire_legal),
2203 : GNUNET_JSON_pack_data_auto ("master_sig",
2204 : &sk->master_sig),
2205 : GNUNET_JSON_pack_data_auto ("key",
2206 : &sk->exchange_pub))));
2207 89 : return GNUNET_OK;
2208 : }
2209 :
2210 :
2211 : /**
2212 : * Closure for #add_denom_key_cb.
2213 : */
2214 : struct DenomKeyCtx
2215 : {
2216 : /**
2217 : * Heap for sorting active denomination keys by start time.
2218 : */
2219 : struct GNUNET_CONTAINER_Heap *heap;
2220 :
2221 : /**
2222 : * JSON array of revoked denomination keys.
2223 : */
2224 : json_t *recoup;
2225 :
2226 : /**
2227 : * What is the minimum key rotation frequency of
2228 : * valid denomination keys?
2229 : */
2230 : struct GNUNET_TIME_Relative min_dk_frequency;
2231 : };
2232 :
2233 :
2234 : /**
2235 : * Function called for all denomination keys, used to build up the
2236 : * JSON list of *revoked* denomination keys and the
2237 : * heap of non-revoked denomination keys by timeout.
2238 : *
2239 : * @param cls a `struct DenomKeyCtx`
2240 : * @param h_denom_pub hash of the denomination key
2241 : * @param value a `struct TEH_DenominationKey`
2242 : * @return #GNUNET_OK (continue to iterate)
2243 : */
2244 : static enum GNUNET_GenericReturnValue
2245 8140 : add_denom_key_cb (void *cls,
2246 : const struct GNUNET_HashCode *h_denom_pub,
2247 : void *value)
2248 : {
2249 8140 : struct DenomKeyCtx *dkc = cls;
2250 8140 : struct TEH_DenominationKey *dk = value;
2251 :
2252 8140 : if (dk->recoup_possible)
2253 : {
2254 0 : GNUNET_assert (
2255 : 0 ==
2256 : json_array_append_new (
2257 : dkc->recoup,
2258 : GNUNET_JSON_PACK (
2259 : GNUNET_JSON_pack_data_auto ("h_denom_pub",
2260 : h_denom_pub))));
2261 : }
2262 : else
2263 : {
2264 8140 : if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
2265 : {
2266 : dkc->min_dk_frequency =
2267 7968 : GNUNET_TIME_relative_min (dkc->min_dk_frequency,
2268 : GNUNET_TIME_absolute_get_difference (
2269 : dk->meta.start.abs_time,
2270 : dk->meta.expire_withdraw.abs_time));
2271 : }
2272 8140 : (void) GNUNET_CONTAINER_heap_insert (dkc->heap,
2273 : dk,
2274 : dk->meta.start.abs_time.abs_value_us);
2275 : }
2276 8140 : return GNUNET_OK;
2277 : }
2278 :
2279 :
2280 : /**
2281 : * Add the headers we want to set for every /keys response.
2282 : *
2283 : * @param cls the key state to use
2284 : * @param[in,out] response the response to modify
2285 : */
2286 : static void
2287 1792 : setup_general_response_headers (void *cls,
2288 : struct MHD_Response *response)
2289 : {
2290 1792 : struct TEH_KeyStateHandle *ksh = cls;
2291 : char dat[128];
2292 :
2293 1792 : TALER_MHD_add_global_headers (response,
2294 : true);
2295 1792 : GNUNET_break (MHD_YES ==
2296 : MHD_add_response_header (response,
2297 : MHD_HTTP_HEADER_CONTENT_TYPE,
2298 : "application/json"));
2299 1792 : GNUNET_break (MHD_YES ==
2300 : MHD_add_response_header (response,
2301 : MHD_HTTP_HEADER_CACHE_CONTROL,
2302 : "public,must-revalidate,max-age=86400")
2303 : );
2304 1792 : if (! GNUNET_TIME_relative_is_zero (ksh->rekey_frequency))
2305 : {
2306 : struct GNUNET_TIME_Relative r;
2307 : struct GNUNET_TIME_Absolute a;
2308 : struct GNUNET_TIME_Timestamp km;
2309 : struct GNUNET_TIME_Timestamp m;
2310 : struct GNUNET_TIME_Timestamp we;
2311 :
2312 1792 : r = GNUNET_TIME_relative_min (TEH_max_keys_caching,
2313 : ksh->rekey_frequency);
2314 1792 : a = GNUNET_TIME_relative_to_absolute (r);
2315 : /* Round up to next full day to ensure the expiration
2316 : time does not become a fingerprint! */
2317 1792 : a = GNUNET_TIME_absolute_round_down (a,
2318 : GNUNET_TIME_UNIT_DAYS);
2319 1792 : a = GNUNET_TIME_absolute_add (a,
2320 : GNUNET_TIME_UNIT_DAYS);
2321 1792 : km = GNUNET_TIME_absolute_to_timestamp (a);
2322 1792 : we = GNUNET_TIME_absolute_to_timestamp (wire_state->cache_expiration);
2323 1792 : m = GNUNET_TIME_timestamp_min (we,
2324 : km);
2325 1792 : TALER_MHD_get_date_string (m.abs_time,
2326 : dat);
2327 1792 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2328 : "Setting /keys 'Expires' header to '%s' (rekey frequency is %s)\n",
2329 : dat,
2330 : GNUNET_TIME_relative2s (ksh->rekey_frequency,
2331 : false));
2332 1792 : GNUNET_break (MHD_YES ==
2333 : MHD_add_response_header (response,
2334 : MHD_HTTP_HEADER_EXPIRES,
2335 : dat));
2336 : ksh->signature_expires
2337 1792 : = GNUNET_TIME_timestamp_min (m,
2338 : ksh->signature_expires);
2339 : }
2340 : /* Set cache control headers: our response varies depending on these headers */
2341 1792 : GNUNET_break (MHD_YES ==
2342 : MHD_add_response_header (response,
2343 : MHD_HTTP_HEADER_VARY,
2344 : MHD_HTTP_HEADER_ACCEPT_ENCODING));
2345 1792 : }
2346 :
2347 :
2348 : /**
2349 : * Initialize @a krd using the given values for @a signkeys,
2350 : * @a recoup and @a denoms.
2351 : *
2352 : * @param[in,out] ksh key state handle we build @a krd for
2353 : * @param[in] denom_keys_hash hash over all the denomination keys in @a denoms
2354 : * @param last_cherry_pick_date timestamp to use
2355 : * @param[in,out] signkeys list of sign keys to return
2356 : * @param[in,out] recoup list of revoked keys to return
2357 : * @param[in,out] grouped_denominations list of grouped denominations to return
2358 : * @return #GNUNET_OK on success
2359 : */
2360 : static enum GNUNET_GenericReturnValue
2361 896 : create_krd (struct TEH_KeyStateHandle *ksh,
2362 : const struct GNUNET_HashCode *denom_keys_hash,
2363 : struct GNUNET_TIME_Timestamp last_cherry_pick_date,
2364 : json_t *signkeys,
2365 : json_t *recoup,
2366 : json_t *grouped_denominations)
2367 : {
2368 : struct KeysResponseData krd;
2369 : struct TALER_ExchangePublicKeyP exchange_pub;
2370 : struct TALER_ExchangeSignatureP exchange_sig;
2371 : struct WireStateHandle *wsh;
2372 : json_t *keys;
2373 :
2374 896 : wsh = get_wire_state ();
2375 896 : if (! wsh->ready)
2376 : {
2377 0 : GNUNET_break (0);
2378 0 : return GNUNET_SYSERR;
2379 : }
2380 896 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
2381 : last_cherry_pick_date.abs_time));
2382 896 : GNUNET_assert (NULL != signkeys);
2383 896 : GNUNET_assert (NULL != recoup);
2384 896 : GNUNET_assert (NULL != grouped_denominations);
2385 896 : GNUNET_assert (NULL != ksh->auditors);
2386 896 : GNUNET_assert (NULL != TEH_currency);
2387 896 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2388 : "Creating /keys at cherry pick date %s\n",
2389 : GNUNET_TIME_timestamp2s (last_cherry_pick_date));
2390 :
2391 : /* Sign hash over master signatures of all denomination keys until this time
2392 : (in reverse order). */
2393 : {
2394 : enum TALER_ErrorCode ec;
2395 :
2396 896 : if (TALER_EC_NONE !=
2397 : (ec =
2398 896 : TALER_exchange_online_key_set_sign (
2399 : &TEH_keys_exchange_sign2_,
2400 : ksh,
2401 : last_cherry_pick_date,
2402 : denom_keys_hash,
2403 : &exchange_pub,
2404 : &exchange_sig)))
2405 : {
2406 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2407 : "Could not create key response data: cannot sign (%s)\n",
2408 : TALER_ErrorCode_get_hint (ec));
2409 0 : return GNUNET_SYSERR;
2410 : }
2411 : }
2412 :
2413 : {
2414 : const struct SigningKey *sk;
2415 :
2416 896 : sk = GNUNET_CONTAINER_multipeermap_get (
2417 896 : ksh->signkey_map,
2418 : (const struct GNUNET_PeerIdentity *) &exchange_pub);
2419 896 : ksh->signature_expires = GNUNET_TIME_timestamp_min (sk->meta.expire_sign,
2420 : ksh->signature_expires);
2421 : }
2422 :
2423 896 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2424 : "Build /keys data with %u wire accounts\n",
2425 : (unsigned int) json_array_size (
2426 : json_object_get (wsh->json_reply,
2427 : "accounts")));
2428 :
2429 896 : keys = GNUNET_JSON_PACK (
2430 : GNUNET_JSON_pack_string ("version",
2431 : EXCHANGE_PROTOCOL_VERSION),
2432 : GNUNET_JSON_pack_string ("base_url",
2433 : TEH_base_url),
2434 : GNUNET_JSON_pack_string ("currency",
2435 : TEH_currency),
2436 : GNUNET_JSON_pack_allow_null (
2437 : GNUNET_JSON_pack_string (
2438 : "bank_compliance_language",
2439 : TEH_bank_compliance_language)),
2440 : GNUNET_JSON_pack_object_steal (
2441 : "currency_specification",
2442 : TALER_JSON_currency_specs_to_json (TEH_cspec)),
2443 : GNUNET_JSON_pack_array_incref (
2444 : "hard_limits",
2445 : TEH_hard_limits),
2446 : GNUNET_JSON_pack_array_incref (
2447 : "zero_limits",
2448 : TEH_zero_limits),
2449 : TALER_JSON_pack_amount ("stefan_abs",
2450 : &TEH_stefan_abs),
2451 : TALER_JSON_pack_amount ("stefan_log",
2452 : &TEH_stefan_log),
2453 : GNUNET_JSON_pack_double ("stefan_lin",
2454 : (double) TEH_stefan_lin),
2455 : GNUNET_JSON_pack_string ("asset_type",
2456 : asset_type),
2457 : GNUNET_JSON_pack_bool ("kyc_enabled",
2458 : GNUNET_YES == TEH_enable_kyc),
2459 : GNUNET_JSON_pack_bool ("rewards_allowed",
2460 : false),
2461 : GNUNET_JSON_pack_data_auto ("master_public_key",
2462 : &TEH_master_public_key),
2463 : GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
2464 : TEH_reserve_closing_delay),
2465 : GNUNET_JSON_pack_array_incref ("signkeys",
2466 : signkeys),
2467 : GNUNET_JSON_pack_array_incref ("recoup",
2468 : recoup),
2469 : GNUNET_JSON_pack_array_incref ("wads",
2470 : json_object_get (wsh->json_reply,
2471 : "wads")),
2472 : GNUNET_JSON_pack_array_incref ("accounts",
2473 : json_object_get (wsh->json_reply,
2474 : "accounts")),
2475 : GNUNET_JSON_pack_object_incref ("wire_fees",
2476 : json_object_get (wsh->json_reply,
2477 : "fees")),
2478 : GNUNET_JSON_pack_array_incref ("denominations",
2479 : grouped_denominations),
2480 : GNUNET_JSON_pack_array_incref ("auditors",
2481 : ksh->auditors),
2482 : GNUNET_JSON_pack_array_incref ("global_fees",
2483 : ksh->global_fees),
2484 : GNUNET_JSON_pack_timestamp ("list_issue_date",
2485 : last_cherry_pick_date),
2486 : GNUNET_JSON_pack_allow_null (
2487 : GNUNET_JSON_pack_array_steal (
2488 : "wallet_balance_limit_without_kyc",
2489 : TALER_KYCLOGIC_get_wallet_thresholds ())),
2490 : GNUNET_JSON_pack_allow_null (
2491 : GNUNET_JSON_pack_string ("shopping_url",
2492 : TEH_shopping_url)),
2493 : GNUNET_JSON_pack_allow_null (
2494 : TALER_amount_is_zero (&TEH_tiny_amount)
2495 : ? GNUNET_JSON_pack_string ("dummy",
2496 : NULL)
2497 : : TALER_JSON_pack_amount ("tiny_amount",
2498 : &TEH_tiny_amount)),
2499 : GNUNET_JSON_pack_data_auto ("exchange_pub",
2500 : &exchange_pub),
2501 : GNUNET_JSON_pack_data_auto ("exchange_sig",
2502 : &exchange_sig));
2503 896 : GNUNET_assert (NULL != keys);
2504 : /* Signal support for the configured, enabled extensions. */
2505 : {
2506 896 : json_t *extensions = json_object ();
2507 896 : bool has_extensions = false;
2508 :
2509 896 : GNUNET_assert (NULL != extensions);
2510 : /* Fill in the configurations of the enabled extensions */
2511 896 : for (const struct TALER_Extensions *iter = TALER_extensions_get_head ();
2512 1536 : NULL != iter && NULL != iter->extension;
2513 640 : iter = iter->next)
2514 : {
2515 640 : const struct TALER_Extension *extension = iter->extension;
2516 : json_t *manifest;
2517 : int r;
2518 :
2519 : /* skip if not enabled */
2520 640 : if (! extension->enabled)
2521 0 : continue;
2522 :
2523 : /* flag our findings so far */
2524 640 : has_extensions = true;
2525 :
2526 :
2527 640 : manifest = extension->manifest (extension);
2528 640 : GNUNET_assert (manifest);
2529 :
2530 640 : r = json_object_set_new (
2531 : extensions,
2532 640 : extension->name,
2533 : manifest);
2534 640 : GNUNET_assert (0 == r);
2535 : }
2536 :
2537 : /* Update the keys object with the extensions and its signature */
2538 896 : if (has_extensions)
2539 : {
2540 : json_t *sig;
2541 : int r;
2542 :
2543 640 : r = json_object_set_new (
2544 : keys,
2545 : "extensions",
2546 : extensions);
2547 640 : GNUNET_assert (0 == r);
2548 :
2549 : /* Add the signature of the extensions, if it is not zero */
2550 640 : if (TEH_extensions_signed)
2551 : {
2552 0 : sig = GNUNET_JSON_PACK (
2553 : GNUNET_JSON_pack_data_auto ("extensions_sig",
2554 : &TEH_extensions_sig));
2555 :
2556 0 : r = json_object_update (keys, sig);
2557 0 : GNUNET_assert (0 == r);
2558 : }
2559 : }
2560 : else
2561 : {
2562 256 : json_decref (extensions);
2563 : }
2564 : }
2565 :
2566 :
2567 : {
2568 : char *keys_json;
2569 : void *keys_jsonz;
2570 : size_t keys_jsonz_size;
2571 : int comp;
2572 : char etag[sizeof (struct GNUNET_HashCode) * 2];
2573 :
2574 : /* Convert /keys response to UTF8-String */
2575 896 : keys_json = json_dumps (keys,
2576 : JSON_INDENT (2));
2577 896 : json_decref (keys);
2578 896 : GNUNET_assert (NULL != keys_json);
2579 :
2580 : /* Keep copy for later compression... */
2581 896 : keys_jsonz = GNUNET_strdup (keys_json);
2582 896 : keys_jsonz_size = strlen (keys_json);
2583 :
2584 : /* hash to compute etag */
2585 : {
2586 : struct GNUNET_HashCode ehash;
2587 : char *end;
2588 :
2589 896 : GNUNET_CRYPTO_hash (keys_jsonz,
2590 : keys_jsonz_size,
2591 : &ehash);
2592 896 : end = GNUNET_STRINGS_data_to_string (&ehash,
2593 : sizeof (ehash),
2594 : etag,
2595 : sizeof (etag));
2596 896 : *end = '\0';
2597 : }
2598 :
2599 : /* Create uncompressed response */
2600 : krd.response_uncompressed
2601 896 : = MHD_create_response_from_buffer (keys_jsonz_size,
2602 : keys_json,
2603 : MHD_RESPMEM_MUST_FREE);
2604 896 : GNUNET_assert (NULL != krd.response_uncompressed);
2605 896 : setup_general_response_headers (ksh,
2606 : krd.response_uncompressed);
2607 : /* Information is always public, revalidate after 1 day */
2608 896 : GNUNET_break (MHD_YES ==
2609 : MHD_add_response_header (krd.response_uncompressed,
2610 : MHD_HTTP_HEADER_ETAG,
2611 : etag));
2612 : /* Also compute compressed version of /keys response */
2613 896 : comp = TALER_MHD_body_compress (&keys_jsonz,
2614 : &keys_jsonz_size);
2615 : krd.response_compressed
2616 896 : = MHD_create_response_from_buffer (keys_jsonz_size,
2617 : keys_jsonz,
2618 : MHD_RESPMEM_MUST_FREE);
2619 896 : GNUNET_assert (NULL != krd.response_compressed);
2620 : /* If the response is actually compressed, set the
2621 : respective header. */
2622 896 : GNUNET_assert ( (MHD_YES != comp) ||
2623 : (MHD_YES ==
2624 : MHD_add_response_header (krd.response_compressed,
2625 : MHD_HTTP_HEADER_CONTENT_ENCODING,
2626 : "deflate")) );
2627 896 : setup_general_response_headers (ksh,
2628 : krd.response_compressed);
2629 : /* Information is always public, revalidate after 1 day */
2630 896 : GNUNET_break (MHD_YES ==
2631 : MHD_add_response_header (krd.response_compressed,
2632 : MHD_HTTP_HEADER_ETAG,
2633 : etag));
2634 896 : krd.etag = GNUNET_strdup (etag);
2635 : }
2636 896 : krd.cherry_pick_date = last_cherry_pick_date;
2637 896 : GNUNET_array_append (ksh->krd_array,
2638 : ksh->krd_array_length,
2639 : krd);
2640 896 : return GNUNET_OK;
2641 : }
2642 :
2643 :
2644 : /**
2645 : * Element in the `struct SignatureContext` array.
2646 : */
2647 : struct SignatureElement
2648 : {
2649 :
2650 : /**
2651 : * Offset of the denomination in the group array,
2652 : * for sorting (2nd rank, ascending).
2653 : */
2654 : unsigned int offset;
2655 :
2656 : /**
2657 : * Offset of the group in the denominations array,
2658 : * for sorting (2nd rank, ascending).
2659 : */
2660 : unsigned int group_offset;
2661 :
2662 : /**
2663 : * Pointer to actual master signature to hash over.
2664 : */
2665 : struct TALER_MasterSignatureP master_sig;
2666 : };
2667 :
2668 : /**
2669 : * Context for collecting the array of master signatures
2670 : * needed to verify the exchange_sig online signature.
2671 : */
2672 : struct SignatureContext
2673 : {
2674 : /**
2675 : * Array of signatures to hash over.
2676 : */
2677 : struct SignatureElement *elements;
2678 :
2679 : /**
2680 : * Write offset in the @e elements array.
2681 : */
2682 : unsigned int elements_pos;
2683 :
2684 : /**
2685 : * Allocated space for @e elements.
2686 : */
2687 : unsigned int elements_size;
2688 : };
2689 :
2690 :
2691 : /**
2692 : * Determine order to sort two elements by before
2693 : * we hash the master signatures. Used for
2694 : * sorting with qsort().
2695 : *
2696 : * @param a pointer to a `struct SignatureElement`
2697 : * @param b pointer to a `struct SignatureElement`
2698 : * @return 0 if equal, -1 if a < b, 1 if a > b.
2699 : */
2700 : static int
2701 904085 : signature_context_sort_cb (const void *a,
2702 : const void *b)
2703 : {
2704 904085 : const struct SignatureElement *sa = a;
2705 904085 : const struct SignatureElement *sb = b;
2706 :
2707 904085 : if (sa->group_offset < sb->group_offset)
2708 160466 : return -1;
2709 743619 : if (sa->group_offset > sb->group_offset)
2710 38119 : return 1;
2711 705500 : if (sa->offset < sb->offset)
2712 705500 : return -1;
2713 0 : if (sa->offset > sb->offset)
2714 0 : return 1;
2715 : /* We should never have two disjoint elements
2716 : with same time and offset */
2717 0 : GNUNET_assert (sa == sb);
2718 0 : return 0;
2719 : }
2720 :
2721 :
2722 : /**
2723 : * Append a @a master_sig to the @a sig_ctx using the
2724 : * given attributes for (later) sorting.
2725 : *
2726 : * @param[in,out] sig_ctx signature context to update
2727 : * @param group_offset offset for the group
2728 : * @param offset offset for the entry
2729 : * @param master_sig master signature for the entry
2730 : */
2731 : static void
2732 8140 : append_signature (struct SignatureContext *sig_ctx,
2733 : unsigned int group_offset,
2734 : unsigned int offset,
2735 : const struct TALER_MasterSignatureP *master_sig)
2736 : {
2737 : struct SignatureElement *element;
2738 : unsigned int new_size;
2739 :
2740 8140 : if (sig_ctx->elements_pos == sig_ctx->elements_size)
2741 : {
2742 25 : if (0 == sig_ctx->elements_size)
2743 25 : new_size = 1024;
2744 : else
2745 0 : new_size = sig_ctx->elements_size * 2;
2746 25 : GNUNET_array_grow (sig_ctx->elements,
2747 : sig_ctx->elements_size,
2748 : new_size);
2749 : }
2750 8140 : element = &sig_ctx->elements[sig_ctx->elements_pos++];
2751 8140 : element->offset = offset;
2752 8140 : element->group_offset = group_offset;
2753 8140 : element->master_sig = *master_sig;
2754 8140 : }
2755 :
2756 :
2757 : /**
2758 : *GroupData is the value we store for each group meta-data */
2759 : struct GroupData
2760 : {
2761 : /**
2762 : * The json blob with the group meta-data and list of denominations
2763 : */
2764 : json_t *json;
2765 :
2766 : /**
2767 : * List of denominations for the group,
2768 : * included in @e json, do not free separately!
2769 : */
2770 : json_t *list;
2771 :
2772 : /**
2773 : * Offset of the group in the final array.
2774 : */
2775 : unsigned int group_off;
2776 :
2777 : };
2778 :
2779 :
2780 : /**
2781 : * Helper function called to clean up the group data
2782 : * in the denominations_by_group below.
2783 : *
2784 : * @param cls unused
2785 : * @param key unused
2786 : * @param value a `struct GroupData` to free
2787 : * @return #GNUNET_OK
2788 : */
2789 : static int
2790 170 : free_group (void *cls,
2791 : const struct GNUNET_HashCode *key,
2792 : void *value)
2793 : {
2794 170 : struct GroupData *gd = value;
2795 :
2796 : (void) cls;
2797 : (void) key;
2798 170 : GNUNET_free (gd);
2799 170 : return GNUNET_OK;
2800 : }
2801 :
2802 :
2803 : static void
2804 896 : compute_msig_hash (struct SignatureContext *sig_ctx,
2805 : struct GNUNET_HashCode *hc)
2806 : {
2807 : struct GNUNET_HashContext *hash_context;
2808 :
2809 896 : hash_context = GNUNET_CRYPTO_hash_context_start ();
2810 896 : qsort (sig_ctx->elements,
2811 896 : sig_ctx->elements_pos,
2812 : sizeof (struct SignatureElement),
2813 : &signature_context_sort_cb);
2814 218654 : for (unsigned int i = 0; i<sig_ctx->elements_pos; i++)
2815 : {
2816 217758 : struct SignatureElement *element = &sig_ctx->elements[i];
2817 :
2818 217758 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2819 : "Adding %u,%u,%s\n",
2820 : element->group_offset,
2821 : element->offset,
2822 : TALER_B2S (&element->master_sig));
2823 217758 : GNUNET_CRYPTO_hash_context_read (hash_context,
2824 217758 : &element->master_sig,
2825 : sizeof (element->master_sig));
2826 : }
2827 896 : GNUNET_CRYPTO_hash_context_finish (hash_context,
2828 : hc);
2829 896 : }
2830 :
2831 :
2832 : /**
2833 : * Update the "/keys" responses in @a ksh, computing the detailed replies.
2834 : *
2835 : * This function is to recompute all (including cherry-picked) responses we
2836 : * might want to return, based on the state already in @a ksh.
2837 : *
2838 : * @param[in,out] ksh state handle to update
2839 : * @return #GNUNET_OK on success
2840 : */
2841 : static enum GNUNET_GenericReturnValue
2842 35 : finish_keys_response (struct TEH_KeyStateHandle *ksh)
2843 : {
2844 35 : enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
2845 : json_t *recoup;
2846 35 : struct SignKeyCtx sctx = {
2847 : .min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL
2848 : };
2849 35 : json_t *grouped_denominations = NULL;
2850 : struct GNUNET_TIME_Timestamp last_cherry_pick_date;
2851 : struct GNUNET_CONTAINER_Heap *heap;
2852 35 : struct SignatureContext sig_ctx = { 0 };
2853 : /* Remember if we have any denomination with age restriction */
2854 35 : bool has_age_restricted_denomination = false;
2855 : struct WireStateHandle *wsh;
2856 :
2857 35 : wsh = get_wire_state ();
2858 35 : if (! wsh->ready)
2859 : {
2860 0 : GNUNET_break (0);
2861 0 : return GNUNET_SYSERR;
2862 : }
2863 35 : if (0 ==
2864 35 : json_array_size (json_object_get (wsh->json_reply,
2865 : "accounts")) )
2866 : {
2867 10 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2868 : "No wire accounts available. Refusing to generate /keys response.\n");
2869 10 : return GNUNET_NO;
2870 : }
2871 25 : sctx.signkeys = json_array ();
2872 25 : GNUNET_assert (NULL != sctx.signkeys);
2873 25 : recoup = json_array ();
2874 25 : GNUNET_assert (NULL != recoup);
2875 25 : grouped_denominations = json_array ();
2876 25 : GNUNET_assert (NULL != grouped_denominations);
2877 :
2878 25 : GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
2879 : &add_sign_key_cb,
2880 : &sctx);
2881 25 : if (0 == json_array_size (sctx.signkeys))
2882 : {
2883 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2884 : "No online signing keys available. Refusing to generate /keys response.\n");
2885 0 : ret = GNUNET_NO;
2886 0 : goto CLEANUP;
2887 : }
2888 25 : heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
2889 : {
2890 25 : struct DenomKeyCtx dkc = {
2891 : .recoup = recoup,
2892 : .heap = heap,
2893 : .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
2894 : };
2895 :
2896 25 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
2897 : &add_denom_key_cb,
2898 : &dkc);
2899 : ksh->rekey_frequency
2900 25 : = GNUNET_TIME_relative_min (dkc.min_dk_frequency,
2901 : sctx.min_sk_frequency);
2902 : }
2903 :
2904 25 : last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS;
2905 :
2906 : {
2907 : struct TEH_DenominationKey *dk;
2908 : struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group;
2909 :
2910 : denominations_by_group =
2911 25 : GNUNET_CONTAINER_multihashmap_create (1024,
2912 : GNUNET_NO /* NO, because keys are only on the stack */
2913 : );
2914 : /* heap = max heap, sorted by start time */
2915 8165 : while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
2916 : {
2917 8140 : if (GNUNET_TIME_timestamp_cmp (last_cherry_pick_date,
2918 : !=,
2919 896 : dk->meta.start) &&
2920 896 : (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) )
2921 : {
2922 : /*
2923 : * This is not the first entry in the heap (because last_cherry_pick_date !=
2924 : * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different
2925 : * start time. Therefore, we create a new entry in ksh.
2926 : */
2927 : struct GNUNET_HashCode hc;
2928 :
2929 871 : compute_msig_hash (&sig_ctx,
2930 : &hc);
2931 871 : if (GNUNET_OK !=
2932 871 : create_krd (ksh,
2933 : &hc,
2934 : last_cherry_pick_date,
2935 : sctx.signkeys,
2936 : recoup,
2937 : grouped_denominations))
2938 : {
2939 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2940 : "Failed to generate key response data for %s\n",
2941 : GNUNET_TIME_timestamp2s (last_cherry_pick_date));
2942 : /* drain heap before destroying it */
2943 0 : while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
2944 : /* intentionally empty */;
2945 0 : GNUNET_CONTAINER_heap_destroy (heap);
2946 0 : goto CLEANUP;
2947 : }
2948 : }
2949 :
2950 8140 : last_cherry_pick_date = dk->meta.start;
2951 : /*
2952 : * Group the denominations by {cipher, value, fees, age_mask}.
2953 : *
2954 : * For each group we save the group meta-data and the list of
2955 : * denominations in this group as a json-blob in the multihashmap
2956 : * denominations_by_group.
2957 : */
2958 : {
2959 : struct GroupData *group;
2960 : json_t *entry;
2961 : struct GNUNET_HashCode key;
2962 8140 : struct TALER_DenominationGroup meta = {
2963 8140 : .cipher = dk->denom_pub.bsign_pub_key->cipher,
2964 : .value = dk->meta.value,
2965 : .fees = dk->meta.fees,
2966 : .age_mask = dk->meta.age_mask,
2967 : };
2968 :
2969 : /* Search the group/JSON-blob for the key */
2970 8140 : TALER_denomination_group_get_key (&meta,
2971 : &key);
2972 8140 : group = GNUNET_CONTAINER_multihashmap_get (
2973 : denominations_by_group,
2974 : &key);
2975 8140 : if (NULL == group)
2976 : {
2977 : /* There is no group for this meta-data yet, so we create a new group */
2978 170 : bool age_restricted = meta.age_mask.bits != 0;
2979 : const char *cipher;
2980 :
2981 170 : group = GNUNET_new (struct GroupData);
2982 170 : switch (meta.cipher)
2983 : {
2984 107 : case GNUNET_CRYPTO_BSA_RSA:
2985 107 : cipher = age_restricted ? "RSA+age_restricted" : "RSA";
2986 107 : break;
2987 63 : case GNUNET_CRYPTO_BSA_CS:
2988 63 : cipher = age_restricted ? "CS+age_restricted" : "CS";
2989 63 : break;
2990 0 : default:
2991 0 : GNUNET_assert (false);
2992 : }
2993 : /* Create a new array for the denominations in this group */
2994 170 : group->list = json_array ();
2995 170 : GNUNET_assert (NULL != group->list);
2996 170 : group->json = GNUNET_JSON_PACK (
2997 : GNUNET_JSON_pack_string ("cipher",
2998 : cipher),
2999 : GNUNET_JSON_pack_array_steal ("denoms",
3000 : group->list),
3001 : TALER_JSON_PACK_DENOM_FEES ("fee",
3002 : &meta.fees),
3003 : TALER_JSON_pack_amount ("value",
3004 : &meta.value));
3005 170 : GNUNET_assert (NULL != group->json);
3006 170 : if (age_restricted)
3007 : {
3008 65 : GNUNET_assert (
3009 : 0 ==
3010 : json_object_set_new (group->json,
3011 : "age_mask",
3012 : json_integer (
3013 : meta.age_mask.bits)));
3014 : /* Remember that we have found at least _one_ age restricted denomination */
3015 65 : has_age_restricted_denomination = true;
3016 : }
3017 : group->group_off
3018 170 : = json_array_size (grouped_denominations);
3019 170 : GNUNET_assert (0 ==
3020 : json_array_append_new (
3021 : grouped_denominations,
3022 : group->json));
3023 170 : GNUNET_assert (
3024 : GNUNET_OK ==
3025 : GNUNET_CONTAINER_multihashmap_put (denominations_by_group,
3026 : &key,
3027 : group,
3028 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3029 : }
3030 :
3031 : /* Now that we have found/created the right group, add the
3032 : denomination to the list */
3033 : {
3034 : struct HelperDenomination *hd;
3035 : struct GNUNET_JSON_PackSpec key_spec;
3036 : bool private_key_lost;
3037 :
3038 8140 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3039 8140 : &dk->h_denom_pub.hash);
3040 : private_key_lost
3041 16280 : = (NULL == hd) ||
3042 8140 : GNUNET_TIME_absolute_is_past (
3043 : GNUNET_TIME_absolute_add (
3044 : hd->start_time.abs_time,
3045 : hd->validity_duration));
3046 8140 : switch (meta.cipher)
3047 : {
3048 4942 : case GNUNET_CRYPTO_BSA_RSA:
3049 : key_spec =
3050 4942 : GNUNET_JSON_pack_rsa_public_key (
3051 : "rsa_pub",
3052 4942 : dk->denom_pub.bsign_pub_key->details.rsa_public_key);
3053 4942 : break;
3054 3198 : case GNUNET_CRYPTO_BSA_CS:
3055 : key_spec =
3056 3198 : GNUNET_JSON_pack_data_varsize (
3057 : "cs_pub",
3058 3198 : &dk->denom_pub.bsign_pub_key->details.cs_public_key,
3059 : sizeof (dk->denom_pub.bsign_pub_key->details.cs_public_key));
3060 3198 : break;
3061 0 : default:
3062 0 : GNUNET_assert (false);
3063 : }
3064 :
3065 8140 : entry = GNUNET_JSON_PACK (
3066 : GNUNET_JSON_pack_data_auto ("master_sig",
3067 : &dk->master_sig),
3068 : GNUNET_JSON_pack_allow_null (
3069 : private_key_lost
3070 : ? GNUNET_JSON_pack_bool ("lost",
3071 : true)
3072 : : GNUNET_JSON_pack_string ("dummy",
3073 : NULL)),
3074 : GNUNET_JSON_pack_timestamp ("stamp_start",
3075 : dk->meta.start),
3076 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
3077 : dk->meta.expire_withdraw),
3078 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
3079 : dk->meta.expire_deposit),
3080 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
3081 : dk->meta.expire_legal),
3082 : key_spec
3083 : );
3084 8140 : GNUNET_assert (NULL != entry);
3085 : }
3086 :
3087 : /* Build up the running hash of all master signatures of the
3088 : denominations */
3089 8140 : append_signature (&sig_ctx,
3090 : group->group_off,
3091 8140 : (unsigned int) json_array_size (group->list),
3092 8140 : &dk->master_sig);
3093 : /* Finally, add the denomination to the list of denominations in this
3094 : group */
3095 8140 : GNUNET_assert (json_is_array (group->list));
3096 8140 : GNUNET_assert (0 ==
3097 : json_array_append_new (group->list,
3098 : entry));
3099 : }
3100 : } /* loop over heap ends */
3101 :
3102 25 : GNUNET_CONTAINER_multihashmap_iterate (denominations_by_group,
3103 : &free_group,
3104 : NULL);
3105 25 : GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group);
3106 : }
3107 25 : GNUNET_CONTAINER_heap_destroy (heap);
3108 :
3109 25 : if (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time))
3110 : {
3111 : struct GNUNET_HashCode hc;
3112 :
3113 25 : compute_msig_hash (&sig_ctx,
3114 : &hc);
3115 25 : if (GNUNET_OK !=
3116 25 : create_krd (ksh,
3117 : &hc,
3118 : last_cherry_pick_date,
3119 : sctx.signkeys,
3120 : recoup,
3121 : grouped_denominations))
3122 : {
3123 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3124 : "Failed to generate key response data for %s\n",
3125 : GNUNET_TIME_timestamp2s (last_cherry_pick_date));
3126 0 : goto CLEANUP;
3127 : }
3128 25 : ksh->management_only = false;
3129 :
3130 : /* Sanity check: Make sure that age restriction is enabled IFF at least
3131 : * one age restricted denomination exist */
3132 25 : if (! has_age_restricted_denomination && TEH_age_restriction_enabled)
3133 : {
3134 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3135 : "Age restriction is enabled, but NO denominations with age restriction found!\n");
3136 0 : goto CLEANUP;
3137 : }
3138 25 : else if (has_age_restricted_denomination && ! TEH_age_restriction_enabled)
3139 : {
3140 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3141 : "Age restriction is NOT enabled, but denominations with age restriction found!\n");
3142 0 : goto CLEANUP;
3143 : }
3144 : }
3145 : else
3146 : {
3147 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3148 : "No denomination keys available. Refusing to generate /keys response.\n");
3149 : }
3150 25 : ret = GNUNET_OK;
3151 :
3152 25 : CLEANUP:
3153 25 : GNUNET_array_grow (sig_ctx.elements,
3154 : sig_ctx.elements_size,
3155 : 0);
3156 25 : json_decref (grouped_denominations);
3157 25 : if (NULL != sctx.signkeys)
3158 25 : json_decref (sctx.signkeys);
3159 25 : json_decref (recoup);
3160 25 : return ret;
3161 : }
3162 :
3163 :
3164 : /**
3165 : * Called with information about global fees.
3166 : *
3167 : * @param cls `struct TEH_KeyStateHandle *` we are building
3168 : * @param fees the global fees we charge
3169 : * @param purse_timeout when do purses time out
3170 : * @param history_expiration how long are account histories preserved
3171 : * @param purse_account_limit how many purses are free per account
3172 : * @param start_date from when are these fees valid (start date)
3173 : * @param end_date until when are these fees valid (end date, exclusive)
3174 : * @param master_sig master key signature affirming that this is the correct
3175 : * fee (of purpose #TALER_SIGNATURE_MASTER_GLOBAL_FEES)
3176 : */
3177 : static void
3178 45 : global_fee_info_cb (
3179 : void *cls,
3180 : const struct TALER_GlobalFeeSet *fees,
3181 : struct GNUNET_TIME_Relative purse_timeout,
3182 : struct GNUNET_TIME_Relative history_expiration,
3183 : uint32_t purse_account_limit,
3184 : struct GNUNET_TIME_Timestamp start_date,
3185 : struct GNUNET_TIME_Timestamp end_date,
3186 : const struct TALER_MasterSignatureP *master_sig)
3187 : {
3188 45 : struct TEH_KeyStateHandle *ksh = cls;
3189 : struct TEH_GlobalFee *gf;
3190 :
3191 45 : if (GNUNET_OK !=
3192 45 : TALER_exchange_offline_global_fee_verify (
3193 : start_date,
3194 : end_date,
3195 : fees,
3196 : purse_timeout,
3197 : history_expiration,
3198 : purse_account_limit,
3199 : &TEH_master_public_key,
3200 : master_sig))
3201 : {
3202 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3203 : "Database has global fee with invalid signature. Skipping entry. Did the exchange offline public key change?\n");
3204 0 : return;
3205 : }
3206 45 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3207 : "Found global fees with %u purses\n",
3208 : purse_account_limit);
3209 45 : gf = GNUNET_new (struct TEH_GlobalFee);
3210 45 : gf->start_date = start_date;
3211 45 : gf->end_date = end_date;
3212 45 : gf->fees = *fees;
3213 45 : gf->purse_timeout = purse_timeout;
3214 45 : gf->history_expiration = history_expiration;
3215 45 : gf->purse_account_limit = purse_account_limit;
3216 45 : gf->master_sig = *master_sig;
3217 45 : GNUNET_CONTAINER_DLL_insert (ksh->gf_head,
3218 : ksh->gf_tail,
3219 : gf);
3220 45 : GNUNET_assert (
3221 : 0 ==
3222 : json_array_append_new (
3223 : ksh->global_fees,
3224 : GNUNET_JSON_PACK (
3225 : GNUNET_JSON_pack_timestamp ("start_date",
3226 : start_date),
3227 : GNUNET_JSON_pack_timestamp ("end_date",
3228 : end_date),
3229 : TALER_JSON_PACK_GLOBAL_FEES (fees),
3230 : GNUNET_JSON_pack_time_rel ("history_expiration",
3231 : history_expiration),
3232 : GNUNET_JSON_pack_time_rel ("purse_timeout",
3233 : purse_timeout),
3234 : GNUNET_JSON_pack_uint64 ("purse_account_limit",
3235 : purse_account_limit),
3236 : GNUNET_JSON_pack_data_auto ("master_sig",
3237 : master_sig))));
3238 : }
3239 :
3240 :
3241 : /**
3242 : * Create a key state.
3243 : *
3244 : * @param[in] hs helper state to (re)use, NULL if not available
3245 : * @param management_only if we should NOT run 'finish_keys_response()'
3246 : * because we only need the state for the /management/keys API
3247 : * @return NULL on error (i.e. failed to access database)
3248 : */
3249 : static struct TEH_KeyStateHandle *
3250 89 : build_key_state (struct HelperState *hs,
3251 : bool management_only)
3252 : {
3253 : struct TEH_KeyStateHandle *ksh;
3254 : enum GNUNET_DB_QueryStatus qs;
3255 :
3256 89 : ksh = GNUNET_new (struct TEH_KeyStateHandle);
3257 89 : ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS;
3258 89 : ksh->reload_time = GNUNET_TIME_timestamp_get ();
3259 : /* We must use the key_generation from when we STARTED the process! */
3260 89 : ksh->key_generation = key_generation;
3261 89 : if (NULL == hs)
3262 : {
3263 29 : ksh->helpers = GNUNET_new (struct HelperState);
3264 29 : if (GNUNET_OK !=
3265 29 : setup_key_helpers (ksh->helpers))
3266 : {
3267 0 : GNUNET_free (ksh->helpers);
3268 0 : GNUNET_assert (NULL == ksh->management_keys_reply);
3269 0 : GNUNET_free (ksh);
3270 0 : return NULL;
3271 : }
3272 : }
3273 : else
3274 : {
3275 60 : ksh->helpers = hs;
3276 : }
3277 89 : ksh->denomserial_map = GNUNET_CONTAINER_multihashmap32_create (1024);
3278 89 : ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
3279 : true);
3280 89 : ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
3281 : false /* MUST be false! */
3282 : );
3283 89 : ksh->auditors = json_array ();
3284 89 : GNUNET_assert (NULL != ksh->auditors);
3285 : /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
3286 89 : GNUNET_break (GNUNET_OK ==
3287 : TEH_plugin->preflight (TEH_plugin->cls));
3288 89 : if (NULL != ksh->global_fees)
3289 0 : json_decref (ksh->global_fees);
3290 89 : ksh->global_fees = json_array ();
3291 89 : qs = TEH_plugin->get_global_fees (TEH_plugin->cls,
3292 : &global_fee_info_cb,
3293 : ksh);
3294 89 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3295 : "Loading global fees from DB: %d\n",
3296 : qs);
3297 89 : if (qs < 0)
3298 : {
3299 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
3300 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
3301 0 : destroy_key_state (ksh,
3302 : true);
3303 0 : return NULL;
3304 : }
3305 89 : qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
3306 : &denomination_info_cb,
3307 : ksh);
3308 89 : if (qs < 0)
3309 : {
3310 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
3311 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
3312 0 : destroy_key_state (ksh,
3313 : true);
3314 0 : return NULL;
3315 : }
3316 : /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
3317 89 : qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
3318 : &signkey_info_cb,
3319 : ksh);
3320 89 : if (qs < 0)
3321 : {
3322 0 : GNUNET_break (0);
3323 0 : destroy_key_state (ksh,
3324 : true);
3325 0 : return NULL;
3326 : }
3327 89 : qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
3328 : &auditor_denom_cb,
3329 : ksh);
3330 89 : if (qs < 0)
3331 : {
3332 0 : GNUNET_break (0);
3333 0 : destroy_key_state (ksh,
3334 : true);
3335 0 : return NULL;
3336 : }
3337 89 : qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
3338 : &auditor_info_cb,
3339 : ksh);
3340 89 : if (qs < 0)
3341 : {
3342 0 : GNUNET_break (0);
3343 0 : destroy_key_state (ksh,
3344 : true);
3345 0 : return NULL;
3346 : }
3347 :
3348 89 : if (management_only)
3349 : {
3350 54 : ksh->management_only = true;
3351 54 : return ksh;
3352 : }
3353 :
3354 35 : if (GNUNET_OK !=
3355 35 : finish_keys_response (ksh))
3356 : {
3357 10 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3358 : "Could not finish /keys response (required data not configured yet)\n");
3359 10 : destroy_key_state (ksh,
3360 : true);
3361 10 : return NULL;
3362 : }
3363 :
3364 25 : return ksh;
3365 : }
3366 :
3367 :
3368 : void
3369 67 : TEH_keys_update_states ()
3370 : {
3371 67 : struct GNUNET_DB_EventHeaderP es = {
3372 67 : .size = htons (sizeof (es)),
3373 67 : .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
3374 : };
3375 :
3376 67 : TEH_plugin->event_notify (TEH_plugin->cls,
3377 : &es,
3378 : NULL,
3379 : 0);
3380 67 : key_generation++;
3381 67 : TEH_resume_keys_requests (false);
3382 67 : }
3383 :
3384 :
3385 : static struct TEH_KeyStateHandle *
3386 901 : keys_get_state (bool management_only)
3387 : {
3388 : struct TEH_KeyStateHandle *old_ksh;
3389 : struct TEH_KeyStateHandle *ksh;
3390 :
3391 901 : old_ksh = key_state;
3392 901 : if (NULL == old_ksh)
3393 : {
3394 29 : ksh = build_key_state (NULL,
3395 : management_only);
3396 29 : if (NULL == ksh)
3397 4 : return NULL;
3398 25 : key_state = ksh;
3399 25 : return ksh;
3400 : }
3401 1684 : if ( (old_ksh->key_generation < key_generation) ||
3402 812 : (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) )
3403 : {
3404 60 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3405 : "Rebuilding /keys, generation upgrade from %llu to %llu\n",
3406 : (unsigned long long) old_ksh->key_generation,
3407 : (unsigned long long) key_generation);
3408 60 : ksh = build_key_state (old_ksh->helpers,
3409 : management_only);
3410 60 : key_state = ksh;
3411 60 : old_ksh->helpers = NULL;
3412 60 : destroy_key_state (old_ksh,
3413 : false);
3414 60 : return ksh;
3415 : }
3416 812 : sync_key_helpers (old_ksh->helpers);
3417 812 : return old_ksh;
3418 : }
3419 :
3420 :
3421 : struct TEH_KeyStateHandle *
3422 128 : TEH_keys_get_state_for_management_only (void)
3423 : {
3424 128 : return keys_get_state (true);
3425 : }
3426 :
3427 :
3428 : struct TEH_KeyStateHandle *
3429 773 : TEH_keys_get_state (void)
3430 : {
3431 : struct TEH_KeyStateHandle *ksh;
3432 :
3433 773 : ksh = keys_get_state (false);
3434 773 : if (NULL == ksh)
3435 10 : return NULL;
3436 :
3437 763 : if (ksh->management_only)
3438 : {
3439 0 : if (GNUNET_OK !=
3440 0 : finish_keys_response (ksh))
3441 0 : return NULL;
3442 : }
3443 :
3444 763 : return ksh;
3445 : }
3446 :
3447 :
3448 : const struct TEH_GlobalFee *
3449 31 : TEH_keys_global_fee_by_time (
3450 : struct TEH_KeyStateHandle *ksh,
3451 : struct GNUNET_TIME_Timestamp ts)
3452 : {
3453 31 : for (const struct TEH_GlobalFee *gf = ksh->gf_head;
3454 31 : NULL != gf;
3455 0 : gf = gf->next)
3456 : {
3457 31 : if (GNUNET_TIME_timestamp_cmp (ts,
3458 : >=,
3459 31 : gf->start_date) &&
3460 31 : GNUNET_TIME_timestamp_cmp (ts,
3461 : <,
3462 : gf->end_date))
3463 31 : return gf;
3464 : }
3465 0 : return NULL;
3466 : }
3467 :
3468 :
3469 : struct TEH_DenominationKey *
3470 142 : TEH_keys_denomination_by_hash (
3471 : const struct TALER_DenominationHashP *h_denom_pub,
3472 : struct MHD_Connection *conn,
3473 : MHD_RESULT *mret)
3474 : {
3475 : struct TEH_KeyStateHandle *ksh;
3476 :
3477 142 : ksh = TEH_keys_get_state ();
3478 142 : if (NULL == ksh)
3479 : {
3480 0 : *mret = TALER_MHD_reply_with_error (conn,
3481 : MHD_HTTP_INTERNAL_SERVER_ERROR,
3482 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
3483 : NULL);
3484 0 : return NULL;
3485 : }
3486 :
3487 142 : return TEH_keys_denomination_by_hash_from_state (ksh,
3488 : h_denom_pub,
3489 : conn,
3490 : mret);
3491 : }
3492 :
3493 :
3494 : struct TEH_DenominationKey *
3495 628 : TEH_keys_denomination_by_hash_from_state (
3496 : const struct TEH_KeyStateHandle *ksh,
3497 : const struct TALER_DenominationHashP *h_denom_pub,
3498 : struct MHD_Connection *conn,
3499 : MHD_RESULT *mret)
3500 : {
3501 : struct TEH_DenominationKey *dk;
3502 :
3503 628 : dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
3504 : &h_denom_pub->hash);
3505 628 : if (NULL == dk)
3506 : {
3507 0 : if (NULL == conn)
3508 0 : return NULL;
3509 0 : *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
3510 : h_denom_pub);
3511 0 : return NULL;
3512 : }
3513 628 : return dk;
3514 : }
3515 :
3516 :
3517 : struct TEH_DenominationKey *
3518 151 : TEH_keys_denomination_by_serial_from_state (
3519 : const struct TEH_KeyStateHandle *ksh,
3520 : uint64_t denom_serial)
3521 : {
3522 : struct TEH_DenominationKey *dk;
3523 151 : uint32_t serial32 = (uint32_t) denom_serial;
3524 :
3525 151 : GNUNET_assert (denom_serial == (uint64_t) serial32);
3526 151 : dk = GNUNET_CONTAINER_multihashmap32_get (ksh->denomserial_map,
3527 : serial32);
3528 151 : return dk;
3529 : }
3530 :
3531 :
3532 : enum TALER_ErrorCode
3533 113 : TEH_keys_denomination_batch_sign (
3534 : unsigned int csds_length,
3535 : const struct TEH_CoinSignData csds[static csds_length],
3536 : bool for_melt,
3537 : struct TALER_BlindedDenominationSignature bss[static csds_length])
3538 113 : {
3539 : struct TEH_KeyStateHandle *ksh;
3540 : struct HelperDenomination *hd;
3541 113 : struct TALER_CRYPTO_RsaSignRequest rsrs[csds_length];
3542 113 : struct TALER_CRYPTO_CsSignRequest csrs[csds_length];
3543 113 : struct TALER_BlindedDenominationSignature rs[csds_length];
3544 113 : struct TALER_BlindedDenominationSignature cs[csds_length];
3545 113 : unsigned int rsrs_pos = 0;
3546 113 : unsigned int csrs_pos = 0;
3547 : enum TALER_ErrorCode ec;
3548 :
3549 113 : ksh = TEH_keys_get_state ();
3550 113 : if (NULL == ksh)
3551 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
3552 450 : for (unsigned int i = 0; i<csds_length; i++)
3553 : {
3554 337 : const struct TALER_DenominationHashP *h_denom_pub = csds[i].h_denom_pub;
3555 337 : const struct TALER_BlindedPlanchet *bp = csds[i].bp;
3556 :
3557 337 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3558 : &h_denom_pub->hash);
3559 337 : if (NULL == hd)
3560 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
3561 337 : if (bp->blinded_message->cipher !=
3562 337 : hd->denom_pub.bsign_pub_key->cipher)
3563 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
3564 337 : switch (hd->denom_pub.bsign_pub_key->cipher)
3565 : {
3566 240 : case GNUNET_CRYPTO_BSA_RSA:
3567 240 : rsrs[rsrs_pos].h_rsa = &hd->h_details.h_rsa;
3568 : rsrs[rsrs_pos].msg
3569 240 : = bp->blinded_message->details.rsa_blinded_message.blinded_msg;
3570 : rsrs[rsrs_pos].msg_size
3571 240 : = bp->blinded_message->details.rsa_blinded_message.blinded_msg_size;
3572 240 : rsrs_pos++;
3573 240 : break;
3574 97 : case GNUNET_CRYPTO_BSA_CS:
3575 97 : csrs[csrs_pos].h_cs = &hd->h_details.h_cs;
3576 : csrs[csrs_pos].blinded_planchet
3577 97 : = &bp->blinded_message->details.cs_blinded_message;
3578 97 : csrs_pos++;
3579 97 : break;
3580 0 : default:
3581 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
3582 : }
3583 : }
3584 :
3585 113 : if (0 != rsrs_pos)
3586 : {
3587 64 : memset (rs,
3588 : 0,
3589 : sizeof (rs));
3590 : }
3591 113 : if (0 != csrs_pos)
3592 : {
3593 49 : memset (cs,
3594 : 0,
3595 : sizeof (cs));
3596 : }
3597 113 : ec = TALER_EC_NONE;
3598 113 : if (0 != csrs_pos)
3599 : {
3600 49 : ec = TALER_CRYPTO_helper_cs_batch_sign (
3601 49 : ksh->helpers->csdh,
3602 : csrs_pos,
3603 : csrs,
3604 : for_melt,
3605 : (0 == rsrs_pos) ? bss : cs);
3606 49 : if (TALER_EC_NONE != ec)
3607 : {
3608 0 : for (unsigned int i = 0; i<csrs_pos; i++)
3609 0 : TALER_blinded_denom_sig_free (&cs[i]);
3610 0 : return ec;
3611 : }
3612 49 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS] += csrs_pos;
3613 : }
3614 113 : if (0 != rsrs_pos)
3615 : {
3616 64 : ec = TALER_CRYPTO_helper_rsa_batch_sign (
3617 64 : ksh->helpers->rsadh,
3618 : rsrs_pos,
3619 : rsrs,
3620 : (0 == csrs_pos) ? bss : rs);
3621 64 : if (TALER_EC_NONE != ec)
3622 : {
3623 0 : for (unsigned int i = 0; i<csrs_pos; i++)
3624 0 : TALER_blinded_denom_sig_free (&cs[i]);
3625 0 : for (unsigned int i = 0; i<rsrs_pos; i++)
3626 0 : TALER_blinded_denom_sig_free (&rs[i]);
3627 0 : return ec;
3628 : }
3629 64 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA] += rsrs_pos;
3630 : }
3631 :
3632 113 : if ( (0 != csrs_pos) &&
3633 : (0 != rsrs_pos) )
3634 : {
3635 0 : rsrs_pos = 0;
3636 0 : csrs_pos = 0;
3637 0 : for (unsigned int i = 0; i<csds_length; i++)
3638 : {
3639 0 : const struct TALER_BlindedPlanchet *bp = csds[i].bp;
3640 :
3641 0 : switch (bp->blinded_message->cipher)
3642 : {
3643 0 : case GNUNET_CRYPTO_BSA_RSA:
3644 0 : bss[i] = rs[rsrs_pos++];
3645 0 : break;
3646 0 : case GNUNET_CRYPTO_BSA_CS:
3647 0 : bss[i] = cs[csrs_pos++];
3648 0 : break;
3649 0 : default:
3650 0 : GNUNET_assert (0);
3651 : }
3652 : }
3653 : }
3654 113 : return TALER_EC_NONE;
3655 : }
3656 :
3657 :
3658 : enum TALER_ErrorCode
3659 0 : TEH_keys_denomination_cs_r_pub (
3660 : const struct TEH_CsDeriveData *cdd,
3661 : bool for_melt,
3662 : struct GNUNET_CRYPTO_CSPublicRPairP *r_pub)
3663 : {
3664 0 : const struct TALER_DenominationHashP *h_denom_pub = cdd->h_denom_pub;
3665 0 : const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdd->nonce;
3666 : struct TEH_KeyStateHandle *ksh;
3667 : struct HelperDenomination *hd;
3668 :
3669 0 : ksh = TEH_keys_get_state ();
3670 0 : if (NULL == ksh)
3671 : {
3672 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
3673 : }
3674 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3675 : &h_denom_pub->hash);
3676 0 : if (NULL == hd)
3677 : {
3678 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
3679 : }
3680 0 : if (GNUNET_CRYPTO_BSA_CS !=
3681 0 : hd->denom_pub.bsign_pub_key->cipher)
3682 : {
3683 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
3684 : }
3685 :
3686 : {
3687 0 : struct TALER_CRYPTO_CsDeriveRequest cdr = {
3688 0 : .h_cs = &hd->h_details.h_cs,
3689 : .nonce = nonce
3690 : };
3691 0 : return TALER_CRYPTO_helper_cs_r_derive (ksh->helpers->csdh,
3692 : &cdr,
3693 : for_melt,
3694 : r_pub);
3695 : }
3696 : }
3697 :
3698 :
3699 : enum TALER_ErrorCode
3700 49 : TEH_keys_denomination_cs_batch_r_pub_simple (
3701 : unsigned int cdds_length,
3702 : const struct TEH_CsDeriveData cdds[static cdds_length],
3703 : bool for_melt,
3704 : struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length])
3705 49 : {
3706 : struct TEH_KeyStateHandle *ksh;
3707 : struct HelperDenomination *hd;
3708 49 : struct TALER_CRYPTO_CsDeriveRequest cdrs[cdds_length];
3709 :
3710 49 : ksh = TEH_keys_get_state ();
3711 49 : if (NULL == ksh)
3712 : {
3713 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
3714 : }
3715 146 : for (unsigned int i = 0; i<cdds_length; i++)
3716 : {
3717 97 : const struct TALER_DenominationHashP *h_denom_pub = cdds[i].h_denom_pub;
3718 97 : const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdds[i].nonce;
3719 :
3720 97 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3721 : &h_denom_pub->hash);
3722 97 : if (NULL == hd)
3723 : {
3724 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
3725 : }
3726 97 : if (GNUNET_CRYPTO_BSA_CS !=
3727 97 : hd->denom_pub.bsign_pub_key->cipher)
3728 : {
3729 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
3730 : }
3731 97 : cdrs[i].h_cs = &hd->h_details.h_cs;
3732 97 : cdrs[i].nonce = nonce;
3733 : }
3734 :
3735 49 : return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh,
3736 : cdds_length,
3737 : cdrs,
3738 : for_melt,
3739 : r_pubs);
3740 : }
3741 :
3742 :
3743 : enum TALER_ErrorCode
3744 50 : TEH_keys_denomination_cs_batch_r_pub (
3745 : const struct TEH_KeyStateHandle *ksh,
3746 : size_t num,
3747 : const struct TALER_DenominationHashP h_denom_pubs[static num],
3748 : const struct GNUNET_CRYPTO_CsSessionNonce nonces[static num],
3749 : bool for_melt,
3750 : struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static num],
3751 : size_t *err_idx)
3752 50 : {
3753 50 : struct TALER_CRYPTO_CsDeriveRequest cdrs[num];
3754 :
3755 148 : for (unsigned int i = 0; i<num; i++)
3756 : {
3757 : const struct TEH_DenominationKey *dk;
3758 : const struct HelperDenomination *hd;
3759 :
3760 98 : *err_idx = i;
3761 :
3762 : /* FIXME: right now we need both,
3763 : * TEH_DenominationKey and HelperDenomination,
3764 : * because only TEH_DenominationKey has .recoup_possible
3765 : */
3766 98 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3767 98 : &h_denom_pubs[i].hash);
3768 98 : dk = TEH_keys_denomination_by_hash_from_state (ksh,
3769 98 : &h_denom_pubs[i],
3770 : NULL,
3771 : NULL);
3772 98 : if (NULL == hd)
3773 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
3774 :
3775 98 : GNUNET_assert (NULL != dk);
3776 :
3777 98 : if (GNUNET_CRYPTO_BSA_CS !=
3778 98 : hd->denom_pub.bsign_pub_key->cipher)
3779 0 : return TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION
3780 : ;
3781 :
3782 98 : if (GNUNET_TIME_absolute_is_future (hd->start_time.abs_time))
3783 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE;
3784 :
3785 98 : if (dk->recoup_possible)
3786 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED;
3787 :
3788 98 : if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
3789 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED;
3790 :
3791 98 : cdrs[i].h_cs = &hd->h_details.h_cs;
3792 98 : cdrs[i].nonce = &nonces[i];
3793 : }
3794 :
3795 50 : return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh,
3796 : num,
3797 : cdrs,
3798 : for_melt,
3799 : r_pubs);
3800 : }
3801 :
3802 :
3803 : void
3804 0 : TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub)
3805 : {
3806 : struct TEH_KeyStateHandle *ksh;
3807 : struct HelperDenomination *hd;
3808 :
3809 0 : ksh = TEH_keys_get_state ();
3810 0 : if (NULL == ksh)
3811 : {
3812 0 : GNUNET_break (0);
3813 0 : return;
3814 : }
3815 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3816 : &h_denom_pub->hash);
3817 0 : if (NULL == hd)
3818 : {
3819 0 : GNUNET_break (0);
3820 0 : return;
3821 : }
3822 0 : switch (hd->denom_pub.bsign_pub_key->cipher)
3823 : {
3824 0 : case GNUNET_CRYPTO_BSA_INVALID:
3825 0 : break;
3826 0 : case GNUNET_CRYPTO_BSA_RSA:
3827 0 : TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh,
3828 0 : &hd->h_details.h_rsa);
3829 0 : TEH_keys_update_states ();
3830 0 : return;
3831 0 : case GNUNET_CRYPTO_BSA_CS:
3832 0 : TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh,
3833 0 : &hd->h_details.h_cs);
3834 0 : TEH_keys_update_states ();
3835 0 : return;
3836 : }
3837 0 : GNUNET_break (0);
3838 0 : return;
3839 : }
3840 :
3841 :
3842 : enum TALER_ErrorCode
3843 170 : TEH_keys_exchange_sign_ (
3844 : const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
3845 : struct TALER_ExchangePublicKeyP *pub,
3846 : struct TALER_ExchangeSignatureP *sig)
3847 : {
3848 : struct TEH_KeyStateHandle *ksh;
3849 :
3850 170 : ksh = TEH_keys_get_state ();
3851 170 : if (NULL == ksh)
3852 : {
3853 : /* This *can* happen if the exchange's crypto helper is not running
3854 : or had some bad error. */
3855 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3856 : "Cannot sign request, no valid signing keys available.\n");
3857 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
3858 : }
3859 170 : return TEH_keys_exchange_sign2_ (ksh,
3860 : purpose,
3861 : pub,
3862 : sig);
3863 : }
3864 :
3865 :
3866 : enum TALER_ErrorCode
3867 1066 : TEH_keys_exchange_sign2_ (
3868 : void *cls,
3869 : const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
3870 : struct TALER_ExchangePublicKeyP *pub,
3871 : struct TALER_ExchangeSignatureP *sig)
3872 : {
3873 1066 : struct TEH_KeyStateHandle *ksh = cls;
3874 : enum TALER_ErrorCode ec;
3875 :
3876 1066 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_EDDSA]++;
3877 1066 : ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh,
3878 : purpose,
3879 : pub,
3880 : sig);
3881 1066 : if (TALER_EC_NONE != ec)
3882 0 : return ec;
3883 : {
3884 : /* Here we check here that 'pub' is set to an exchange public key that is
3885 : actually signed by the master key! Otherwise, we happily continue to
3886 : use key material even if the offline signatures have not been made
3887 : yet! */
3888 : struct GNUNET_PeerIdentity pid;
3889 : struct SigningKey *sk;
3890 :
3891 1066 : pid.public_key = pub->eddsa_pub;
3892 1066 : sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map,
3893 : &pid);
3894 1066 : if (NULL == sk)
3895 : {
3896 : /* just to be safe, zero out the (valid) signature, as the key
3897 : should not or no longer be used */
3898 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3899 : "Cannot sign, offline key signatures are missing!\n");
3900 0 : memset (sig,
3901 : 0,
3902 : sizeof (*sig));
3903 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
3904 : }
3905 : }
3906 1066 : return ec;
3907 : }
3908 :
3909 :
3910 : void
3911 0 : TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
3912 : {
3913 : struct TEH_KeyStateHandle *ksh;
3914 :
3915 0 : ksh = TEH_keys_get_state ();
3916 0 : if (NULL == ksh)
3917 : {
3918 0 : GNUNET_break (0);
3919 0 : return;
3920 : }
3921 0 : TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh,
3922 : exchange_pub);
3923 0 : TEH_keys_update_states ();
3924 : }
3925 :
3926 :
3927 : /**
3928 : * Comparator used for a binary search by cherry_pick_date for @a key in the
3929 : * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
3930 : *
3931 : * @param key pointer to a `struct GNUNET_TIME_Timestamp`
3932 : * @param value pointer to a `struct KeysResponseData` array entry
3933 : * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
3934 : */
3935 : static int
3936 240 : krd_search_comparator (const void *key,
3937 : const void *value)
3938 : {
3939 240 : const struct GNUNET_TIME_Timestamp *kd = key;
3940 240 : const struct KeysResponseData *krd = value;
3941 :
3942 240 : if (GNUNET_TIME_timestamp_cmp (*kd,
3943 : >,
3944 : krd->cherry_pick_date))
3945 22 : return -1;
3946 218 : if (GNUNET_TIME_timestamp_cmp (*kd,
3947 : <,
3948 : krd->cherry_pick_date))
3949 210 : return 1;
3950 8 : return 0;
3951 : }
3952 :
3953 :
3954 : MHD_RESULT
3955 69 : TEH_keys_get_handler (struct TEH_RequestContext *rc,
3956 : const char *const args[])
3957 : {
3958 : struct GNUNET_TIME_Timestamp last_issue_date;
3959 : const char *etag;
3960 :
3961 69 : etag = MHD_lookup_connection_value (rc->connection,
3962 : MHD_HEADER_KIND,
3963 : MHD_HTTP_HEADER_IF_NONE_MATCH);
3964 : (void) args;
3965 : {
3966 : const char *have_cherrypick;
3967 :
3968 69 : have_cherrypick = MHD_lookup_connection_value (rc->connection,
3969 : MHD_GET_ARGUMENT_KIND,
3970 : "last_issue_date");
3971 69 : if (NULL != have_cherrypick)
3972 : {
3973 : unsigned long long cherrypickn;
3974 :
3975 8 : if (1 !=
3976 8 : sscanf (have_cherrypick,
3977 : "%llu",
3978 : &cherrypickn))
3979 : {
3980 0 : GNUNET_break_op (0);
3981 0 : return TALER_MHD_reply_with_error (rc->connection,
3982 : MHD_HTTP_BAD_REQUEST,
3983 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
3984 : have_cherrypick);
3985 : }
3986 : /* The following multiplication may overflow; but this should not really
3987 : be a problem, as giving back 'older' data than what the client asks for
3988 : (given that the client asks for data in the distant future) is not
3989 : problematic */
3990 8 : last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn);
3991 : }
3992 : else
3993 : {
3994 61 : last_issue_date = GNUNET_TIME_UNIT_ZERO_TS;
3995 : }
3996 : }
3997 :
3998 : {
3999 : struct TEH_KeyStateHandle *ksh;
4000 : const struct KeysResponseData *krd;
4001 :
4002 69 : ksh = TEH_keys_get_state ();
4003 69 : if ( (NULL == ksh) ||
4004 59 : (0 == ksh->krd_array_length) )
4005 : {
4006 10 : if ( ( (SKR_LIMIT == skr_size) &&
4007 10 : (rc->connection == skr_connection) ) ||
4008 : TEH_suicide)
4009 : {
4010 0 : return TALER_MHD_reply_with_error (
4011 : rc->connection,
4012 : MHD_HTTP_SERVICE_UNAVAILABLE,
4013 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
4014 : TEH_suicide
4015 0 : ? "server terminating"
4016 : : "too many connections suspended waiting on /keys");
4017 : }
4018 10 : return suspend_request (rc->connection);
4019 : }
4020 59 : krd = bsearch (&last_issue_date,
4021 59 : ksh->krd_array,
4022 59 : ksh->krd_array_length,
4023 : sizeof (struct KeysResponseData),
4024 : &krd_search_comparator);
4025 59 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4026 : "Filtering /keys by cherry pick date %s found entry %u/%u\n",
4027 : GNUNET_TIME_timestamp2s (last_issue_date),
4028 : (unsigned int) (krd - ksh->krd_array),
4029 : ksh->krd_array_length);
4030 59 : if ( (NULL == krd) &&
4031 51 : (ksh->krd_array_length > 0) )
4032 : {
4033 51 : if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time))
4034 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4035 : "Client provided invalid cherry picking timestamp %s, returning full response\n",
4036 : GNUNET_TIME_timestamp2s (last_issue_date));
4037 51 : krd = &ksh->krd_array[ksh->krd_array_length - 1];
4038 : }
4039 59 : if (NULL == krd)
4040 : {
4041 : /* Likely keys not ready *yet*.
4042 : Wait until they are. */
4043 0 : return suspend_request (rc->connection);
4044 : }
4045 59 : if ( (NULL != etag) &&
4046 0 : (0 == strcmp (etag,
4047 0 : krd->etag)) )
4048 0 : return TEH_RESPONSE_reply_not_modified (rc->connection,
4049 0 : krd->etag,
4050 : &setup_general_response_headers,
4051 : ksh);
4052 :
4053 59 : return MHD_queue_response (
4054 : rc->connection,
4055 : MHD_HTTP_OK,
4056 : (TALER_MHD_CT_DEFLATE ==
4057 59 : TALER_MHD_can_compress (rc->connection,
4058 : TALER_MHD_CT_DEFLATE))
4059 : ? krd->response_compressed
4060 : : krd->response_uncompressed);
4061 : }
4062 : }
4063 :
4064 :
4065 : /**
4066 : * Load extension data, like fees, expiration times (!) and age restriction
4067 : * flags for the denomination type configured in section @a section_name.
4068 : * Before calling this function, the `start` and `validity_duration` times must
4069 : * already be initialized in @a meta.
4070 : *
4071 : * @param section_name section in the configuration to use
4072 : * @param[in,out] meta denomination type data to complete
4073 : * @return #GNUNET_OK on success
4074 : */
4075 : static enum GNUNET_GenericReturnValue
4076 18660 : load_extension_data (const char *section_name,
4077 : struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
4078 : {
4079 : struct GNUNET_TIME_Relative deposit_duration;
4080 : struct GNUNET_TIME_Relative legal_duration;
4081 :
4082 18660 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (meta->start.abs_time)); /* caller bug */
4083 18660 : if (GNUNET_OK !=
4084 18660 : GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
4085 : section_name,
4086 : "DURATION_SPEND",
4087 : &deposit_duration))
4088 : {
4089 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4090 : section_name,
4091 : "DURATION_SPEND");
4092 0 : return GNUNET_SYSERR;
4093 : }
4094 18660 : if (GNUNET_OK !=
4095 18660 : GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
4096 : section_name,
4097 : "DURATION_LEGAL",
4098 : &legal_duration))
4099 : {
4100 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4101 : section_name,
4102 : "DURATION_LEGAL");
4103 0 : return GNUNET_SYSERR;
4104 : }
4105 : meta->expire_deposit
4106 18660 : = GNUNET_TIME_absolute_to_timestamp (
4107 : GNUNET_TIME_absolute_add (meta->expire_withdraw.abs_time,
4108 : deposit_duration));
4109 18660 : meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
4110 : GNUNET_TIME_absolute_add (meta->expire_deposit.abs_time,
4111 : legal_duration));
4112 18660 : if (GNUNET_OK !=
4113 18660 : TALER_config_get_amount (TEH_cfg,
4114 : section_name,
4115 : "VALUE",
4116 : &meta->value))
4117 : {
4118 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
4119 : "Need amount for option `%s' in section `%s'\n",
4120 : "VALUE",
4121 : section_name);
4122 0 : return GNUNET_SYSERR;
4123 : }
4124 18660 : if (0 != strcasecmp (TEH_currency,
4125 18660 : meta->value.currency))
4126 : {
4127 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4128 : "Need denomination value in section `%s' to use currency `%s'\n",
4129 : section_name,
4130 : TEH_currency);
4131 0 : return GNUNET_SYSERR;
4132 : }
4133 18660 : if (GNUNET_OK !=
4134 18660 : TALER_config_get_denom_fees (TEH_cfg,
4135 : TEH_currency,
4136 : section_name,
4137 : &meta->fees))
4138 0 : return GNUNET_SYSERR;
4139 18660 : meta->age_mask = load_age_mask (section_name);
4140 18660 : return GNUNET_OK;
4141 : }
4142 :
4143 :
4144 : enum GNUNET_GenericReturnValue
4145 6220 : TEH_keys_load_fees (struct TEH_KeyStateHandle *ksh,
4146 : const struct TALER_DenominationHashP *h_denom_pub,
4147 : struct TALER_DenominationPublicKey *denom_pub,
4148 : struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
4149 : {
4150 : struct HelperDenomination *hd;
4151 : enum GNUNET_GenericReturnValue ok;
4152 :
4153 6220 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
4154 : &h_denom_pub->hash);
4155 6220 : if (NULL == hd)
4156 : {
4157 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4158 : "Denomination %s not known\n",
4159 : GNUNET_h2s (&h_denom_pub->hash));
4160 0 : return GNUNET_NO;
4161 : }
4162 6220 : meta->start = hd->start_time;
4163 6220 : meta->expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
4164 : GNUNET_TIME_absolute_add (meta->start.abs_time,
4165 : hd->validity_duration));
4166 6220 : ok = load_extension_data (hd->section_name,
4167 : meta);
4168 6220 : if (GNUNET_OK == ok)
4169 : {
4170 6220 : GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID !=
4171 : hd->denom_pub.bsign_pub_key->cipher);
4172 6220 : TALER_denom_pub_copy (denom_pub,
4173 6220 : &hd->denom_pub);
4174 : }
4175 : else
4176 : {
4177 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4178 : "No fees for `%s', voiding key\n",
4179 : hd->section_name);
4180 0 : memset (denom_pub,
4181 : 0,
4182 : sizeof (*denom_pub));
4183 : }
4184 6220 : return ok;
4185 : }
4186 :
4187 :
4188 : enum GNUNET_GenericReturnValue
4189 67 : TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
4190 : struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
4191 : {
4192 : struct TEH_KeyStateHandle *ksh;
4193 : struct HelperSignkey *hsk;
4194 : struct GNUNET_PeerIdentity pid;
4195 :
4196 67 : ksh = TEH_keys_get_state_for_management_only ();
4197 67 : if (NULL == ksh)
4198 : {
4199 0 : GNUNET_break (0);
4200 0 : return GNUNET_SYSERR;
4201 : }
4202 :
4203 67 : pid.public_key = exchange_pub->eddsa_pub;
4204 67 : hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys,
4205 : &pid);
4206 67 : if (NULL == hsk)
4207 : {
4208 0 : GNUNET_break (0);
4209 0 : return GNUNET_NO;
4210 : }
4211 67 : meta->start = hsk->start_time;
4212 :
4213 67 : meta->expire_sign = GNUNET_TIME_absolute_to_timestamp (
4214 : GNUNET_TIME_absolute_add (meta->start.abs_time,
4215 : hsk->validity_duration));
4216 67 : meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
4217 : GNUNET_TIME_absolute_add (meta->expire_sign.abs_time,
4218 : signkey_legal_duration));
4219 67 : return GNUNET_OK;
4220 : }
4221 :
4222 :
4223 : /**
4224 : * Closure for #add_future_denomkey_cb and #add_future_signkey_cb.
4225 : */
4226 : struct FutureBuilderContext
4227 : {
4228 : /**
4229 : * Our key state.
4230 : */
4231 : struct TEH_KeyStateHandle *ksh;
4232 :
4233 : /**
4234 : * Array of denomination keys.
4235 : */
4236 : json_t *denoms;
4237 :
4238 : /**
4239 : * Array of signing keys.
4240 : */
4241 : json_t *signkeys;
4242 :
4243 : };
4244 :
4245 :
4246 : /**
4247 : * Function called on all of our current and future denomination keys
4248 : * known to the helper process. Filters out those that are current
4249 : * and adds the remaining denomination keys (with their configuration
4250 : * data) to the JSON array.
4251 : *
4252 : * @param cls the `struct FutureBuilderContext *`
4253 : * @param h_denom_pub hash of the denomination public key
4254 : * @param value a `struct HelperDenomination`
4255 : * @return #GNUNET_OK (continue to iterate)
4256 : */
4257 : static enum GNUNET_GenericReturnValue
4258 13500 : add_future_denomkey_cb (void *cls,
4259 : const struct GNUNET_HashCode *h_denom_pub,
4260 : void *value)
4261 : {
4262 13500 : struct FutureBuilderContext *fbc = cls;
4263 13500 : struct HelperDenomination *hd = value;
4264 : struct TEH_DenominationKey *dk;
4265 13500 : struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
4266 :
4267 13500 : dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
4268 : h_denom_pub);
4269 13500 : if (NULL != dk)
4270 1060 : return GNUNET_OK; /* skip: this key is already active! */
4271 12440 : if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
4272 0 : return GNUNET_OK; /* this key already expired! */
4273 12440 : meta.start = hd->start_time;
4274 12440 : meta.expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
4275 : GNUNET_TIME_absolute_add (meta.start.abs_time,
4276 : hd->validity_duration));
4277 12440 : if (GNUNET_OK !=
4278 12440 : load_extension_data (hd->section_name,
4279 : &meta))
4280 : {
4281 : /* Woops, couldn't determine fee structure!? */
4282 0 : return GNUNET_OK;
4283 : }
4284 12440 : GNUNET_assert (
4285 : 0 ==
4286 : json_array_append_new (
4287 : fbc->denoms,
4288 : GNUNET_JSON_PACK (
4289 : TALER_JSON_pack_amount ("value",
4290 : &meta.value),
4291 : GNUNET_JSON_pack_timestamp ("stamp_start",
4292 : meta.start),
4293 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
4294 : meta.expire_withdraw),
4295 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
4296 : meta.expire_deposit),
4297 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
4298 : meta.expire_legal),
4299 : TALER_JSON_pack_denom_pub ("denom_pub",
4300 : &hd->denom_pub),
4301 : TALER_JSON_PACK_DENOM_FEES ("fee",
4302 : &meta.fees),
4303 : GNUNET_JSON_pack_data_auto ("denom_secmod_sig",
4304 : &hd->sm_sig),
4305 : GNUNET_JSON_pack_string ("section_name",
4306 : hd->section_name))));
4307 12440 : return GNUNET_OK;
4308 : }
4309 :
4310 :
4311 : /**
4312 : * Function called on all of our current and future exchange signing keys
4313 : * known to the helper process. Filters out those that are current
4314 : * and adds the remaining signing keys (with their configuration
4315 : * data) to the JSON array.
4316 : *
4317 : * @param cls the `struct FutureBuilderContext *`
4318 : * @param pid actually the exchange public key (type disguised)
4319 : * @param value a `struct HelperDenomination`
4320 : * @return #GNUNET_OK (continue to iterate)
4321 : */
4322 : static enum GNUNET_GenericReturnValue
4323 144 : add_future_signkey_cb (void *cls,
4324 : const struct GNUNET_PeerIdentity *pid,
4325 : void *value)
4326 : {
4327 144 : struct FutureBuilderContext *fbc = cls;
4328 144 : struct HelperSignkey *hsk = value;
4329 : struct SigningKey *sk;
4330 : struct GNUNET_TIME_Timestamp stamp_expire;
4331 : struct GNUNET_TIME_Timestamp legal_end;
4332 :
4333 144 : sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
4334 : pid);
4335 144 : if (NULL != sk)
4336 10 : return GNUNET_OK; /* skip: this key is already active */
4337 134 : if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
4338 0 : return GNUNET_OK; /* this key already expired! */
4339 134 : stamp_expire = GNUNET_TIME_absolute_to_timestamp (
4340 : GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
4341 : hsk->validity_duration));
4342 134 : legal_end = GNUNET_TIME_absolute_to_timestamp (
4343 : GNUNET_TIME_absolute_add (stamp_expire.abs_time,
4344 : signkey_legal_duration));
4345 134 : GNUNET_assert (0 ==
4346 : json_array_append_new (
4347 : fbc->signkeys,
4348 : GNUNET_JSON_PACK (
4349 : GNUNET_JSON_pack_data_auto ("key",
4350 : &hsk->exchange_pub),
4351 : GNUNET_JSON_pack_timestamp ("stamp_start",
4352 : hsk->start_time),
4353 : GNUNET_JSON_pack_timestamp ("stamp_expire",
4354 : stamp_expire),
4355 : GNUNET_JSON_pack_timestamp ("stamp_end",
4356 : legal_end),
4357 : GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
4358 : &hsk->sm_sig))));
4359 134 : return GNUNET_OK;
4360 : }
4361 :
4362 :
4363 : MHD_RESULT
4364 40 : TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
4365 : struct MHD_Connection *connection)
4366 : {
4367 : struct TEH_KeyStateHandle *ksh;
4368 : json_t *reply;
4369 :
4370 : (void) rh;
4371 40 : ksh = TEH_keys_get_state_for_management_only ();
4372 40 : if (NULL == ksh)
4373 : {
4374 0 : return TALER_MHD_reply_with_error (connection,
4375 : MHD_HTTP_SERVICE_UNAVAILABLE,
4376 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
4377 : "no key state");
4378 : }
4379 40 : sync_key_helpers (ksh->helpers);
4380 40 : if (NULL == ksh->management_keys_reply)
4381 : {
4382 120 : struct FutureBuilderContext fbc = {
4383 : .ksh = ksh,
4384 40 : .denoms = json_array (),
4385 40 : .signkeys = json_array ()
4386 : };
4387 :
4388 55 : if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) &&
4389 15 : (GNUNET_is_zero (&denom_cs_sm_pub)) )
4390 : {
4391 : /* Either IPC failed, or neither helper had any denominations configured. */
4392 0 : return TALER_MHD_reply_with_error (connection,
4393 : MHD_HTTP_BAD_GATEWAY,
4394 : TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
4395 : NULL);
4396 : }
4397 40 : if (GNUNET_is_zero (&esign_sm_pub))
4398 : {
4399 0 : return TALER_MHD_reply_with_error (connection,
4400 : MHD_HTTP_BAD_GATEWAY,
4401 : TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
4402 : NULL);
4403 : }
4404 40 : GNUNET_assert (NULL != fbc.denoms);
4405 40 : GNUNET_assert (NULL != fbc.signkeys);
4406 40 : GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
4407 : &add_future_denomkey_cb,
4408 : &fbc);
4409 40 : GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
4410 : &add_future_signkey_cb,
4411 : &fbc);
4412 40 : reply = GNUNET_JSON_PACK (
4413 : GNUNET_JSON_pack_array_steal ("future_denoms",
4414 : fbc.denoms),
4415 : GNUNET_JSON_pack_array_steal ("future_signkeys",
4416 : fbc.signkeys),
4417 : GNUNET_JSON_pack_data_auto ("master_pub",
4418 : &TEH_master_public_key),
4419 : GNUNET_JSON_pack_data_auto ("denom_secmod_public_key",
4420 : &denom_rsa_sm_pub),
4421 : GNUNET_JSON_pack_data_auto ("denom_secmod_cs_public_key",
4422 : &denom_cs_sm_pub),
4423 : GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
4424 : &esign_sm_pub));
4425 40 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4426 : "Returning GET /management/keys response:\n");
4427 40 : if (NULL == reply)
4428 0 : return TALER_MHD_reply_with_error (connection,
4429 : MHD_HTTP_INTERNAL_SERVER_ERROR,
4430 : TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
4431 : NULL);
4432 40 : GNUNET_assert (NULL == ksh->management_keys_reply);
4433 40 : ksh->management_keys_reply = reply;
4434 : }
4435 : else
4436 : {
4437 0 : reply = ksh->management_keys_reply;
4438 : }
4439 40 : return TALER_MHD_reply_json (connection,
4440 : reply,
4441 : MHD_HTTP_OK);
4442 : }
4443 :
4444 :
4445 : /* end of taler-exchange-httpd_keys.c */
|