Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020-2022 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 : */
21 : #include "platform.h"
22 : #include "taler_json_lib.h"
23 : #include "taler_mhd_lib.h"
24 : #include "taler_kyclogic_lib.h"
25 : #include "taler_dbevents.h"
26 : #include "taler-exchange-httpd.h"
27 : #include "taler-exchange-httpd_keys.h"
28 : #include "taler-exchange-httpd_responses.h"
29 : #include "taler_exchangedb_plugin.h"
30 : #include "taler_extensions.h"
31 :
32 :
33 : /**
34 : * How many /keys request do we hold in suspension at
35 : * most at any time?
36 : */
37 : #define SKR_LIMIT 32
38 :
39 :
40 : /**
41 : * When do we forcefully timeout a /keys request?
42 : */
43 : #define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES
44 :
45 :
46 : /**
47 : * Taler protocol version in the format CURRENT:REVISION:AGE
48 : * as used by GNU libtool. See
49 : * https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
50 : *
51 : * Please be very careful when updating and follow
52 : * https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
53 : * precisely. Note that this version has NOTHING to do with the
54 : * release version, and the format is NOT the same that semantic
55 : * versioning uses either.
56 : *
57 : * When changing this version, you likely want to also update
58 : * #TALER_PROTOCOL_CURRENT and #TALER_PROTOCOL_AGE in
59 : * exchange_api_handle.c!
60 : */
61 : #define EXCHANGE_PROTOCOL_VERSION "14:0:2"
62 :
63 :
64 : /**
65 : * Information about a denomination on offer by the denomination helper.
66 : */
67 : struct HelperDenomination
68 : {
69 :
70 : /**
71 : * When will the helper start to use this key for signing?
72 : */
73 : struct GNUNET_TIME_Timestamp start_time;
74 :
75 : /**
76 : * For how long will the helper allow signing? 0 if
77 : * the key was revoked or purged.
78 : */
79 : struct GNUNET_TIME_Relative validity_duration;
80 :
81 : /**
82 : * Hash of the full denomination key.
83 : */
84 : struct TALER_DenominationHashP h_denom_pub;
85 :
86 : /**
87 : * Signature over this key from the security module's key.
88 : */
89 : struct TALER_SecurityModuleSignatureP sm_sig;
90 :
91 : /**
92 : * The (full) public key.
93 : */
94 : struct TALER_DenominationPublicKey denom_pub;
95 :
96 : /**
97 : * Details depend on the @e denom_pub.cipher type.
98 : */
99 : union
100 : {
101 :
102 : /**
103 : * Hash of the RSA key.
104 : */
105 : struct TALER_RsaPubHashP h_rsa;
106 :
107 : /**
108 : * Hash of the CS key.
109 : */
110 : struct TALER_CsPubHashP h_cs;
111 :
112 : } h_details;
113 :
114 : /**
115 : * Name in configuration section for this denomination type.
116 : */
117 : char *section_name;
118 :
119 :
120 : };
121 :
122 :
123 : /**
124 : * Signatures of an auditor over a denomination key of this exchange.
125 : */
126 : struct TEH_AuditorSignature
127 : {
128 : /**
129 : * We store the signatures in a DLL.
130 : */
131 : struct TEH_AuditorSignature *prev;
132 :
133 : /**
134 : * We store the signatures in a DLL.
135 : */
136 : struct TEH_AuditorSignature *next;
137 :
138 : /**
139 : * A signature from the auditor.
140 : */
141 : struct TALER_AuditorSignatureP asig;
142 :
143 : /**
144 : * Public key of the auditor.
145 : */
146 : struct TALER_AuditorPublicKeyP apub;
147 :
148 : };
149 :
150 :
151 : /**
152 : * Information about a signing key on offer by the esign helper.
153 : */
154 : struct HelperSignkey
155 : {
156 : /**
157 : * When will the helper start to use this key for signing?
158 : */
159 : struct GNUNET_TIME_Timestamp start_time;
160 :
161 : /**
162 : * For how long will the helper allow signing? 0 if
163 : * the key was revoked or purged.
164 : */
165 : struct GNUNET_TIME_Relative validity_duration;
166 :
167 : /**
168 : * The public key.
169 : */
170 : struct TALER_ExchangePublicKeyP exchange_pub;
171 :
172 : /**
173 : * Signature over this key from the security module's key.
174 : */
175 : struct TALER_SecurityModuleSignatureP sm_sig;
176 :
177 : };
178 :
179 :
180 : /**
181 : * State associated with the crypto helpers / security modules. NOT updated
182 : * when the #key_generation is updated (instead constantly kept in sync
183 : * whenever #TEH_keys_get_state() is called).
184 : */
185 : struct HelperState
186 : {
187 :
188 : /**
189 : * Handle for the esign/EdDSA helper.
190 : */
191 : struct TALER_CRYPTO_ExchangeSignHelper *esh;
192 :
193 : /**
194 : * Handle for the denom/RSA helper.
195 : */
196 : struct TALER_CRYPTO_RsaDenominationHelper *rsadh;
197 :
198 : /**
199 : * Handle for the denom/CS helper.
200 : */
201 : struct TALER_CRYPTO_CsDenominationHelper *csdh;
202 :
203 : /**
204 : * Map from H(denom_pub) to `struct HelperDenomination` entries.
205 : */
206 : struct GNUNET_CONTAINER_MultiHashMap *denom_keys;
207 :
208 : /**
209 : * Map from H(rsa_pub) to `struct HelperDenomination` entries.
210 : */
211 : struct GNUNET_CONTAINER_MultiHashMap *rsa_keys;
212 :
213 : /**
214 : * Map from H(cs_pub) to `struct HelperDenomination` entries.
215 : */
216 : struct GNUNET_CONTAINER_MultiHashMap *cs_keys;
217 :
218 : /**
219 : * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey`
220 : * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also
221 : * an EdDSA public key.
222 : */
223 : struct GNUNET_CONTAINER_MultiPeerMap *esign_keys;
224 :
225 : };
226 :
227 :
228 : /**
229 : * Entry in (sorted) array with possible pre-build responses for /keys.
230 : * We keep pre-build responses for the various (valid) cherry-picking
231 : * values around.
232 : */
233 : struct KeysResponseData
234 : {
235 :
236 : /**
237 : * Response to return if the client supports (deflate) compression.
238 : */
239 : struct MHD_Response *response_compressed;
240 :
241 : /**
242 : * Response to return if the client does not support compression.
243 : */
244 : struct MHD_Response *response_uncompressed;
245 :
246 : /**
247 : * ETag for these responses.
248 : */
249 : char *etag;
250 :
251 : /**
252 : * Cherry-picking timestamp the client must have set for this
253 : * response to be valid. 0 if this is the "full" response.
254 : * The client's request must include this date or a higher one
255 : * for this response to be applicable.
256 : */
257 : struct GNUNET_TIME_Timestamp cherry_pick_date;
258 :
259 : };
260 :
261 :
262 : /**
263 : * @brief All information about an exchange online signing key (which is used to
264 : * sign messages from the exchange).
265 : */
266 : struct SigningKey
267 : {
268 :
269 : /**
270 : * The exchange's (online signing) public key.
271 : */
272 : struct TALER_ExchangePublicKeyP exchange_pub;
273 :
274 : /**
275 : * Meta data about the signing key, such as validity periods.
276 : */
277 : struct TALER_EXCHANGEDB_SignkeyMetaData meta;
278 :
279 : /**
280 : * The long-term offline master key's signature for this signing key.
281 : * Signs over @e exchange_pub and @e meta.
282 : */
283 : struct TALER_MasterSignatureP master_sig;
284 :
285 : };
286 :
287 : struct TEH_KeyStateHandle
288 : {
289 :
290 : /**
291 : * Mapping from denomination keys to denomination key issue struct.
292 : * Used to lookup the key by hash.
293 : */
294 : struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
295 :
296 : /**
297 : * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey`
298 : * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also
299 : * an EdDSA public key.
300 : */
301 : struct GNUNET_CONTAINER_MultiPeerMap *signkey_map;
302 :
303 : /**
304 : * Head of DLL of our global fees.
305 : */
306 : struct TEH_GlobalFee *gf_head;
307 :
308 : /**
309 : * Tail of DLL of our global fees.
310 : */
311 : struct TEH_GlobalFee *gf_tail;
312 :
313 : /**
314 : * json array with the auditors of this exchange. Contains exactly
315 : * the information needed for the "auditors" field of the /keys response.
316 : */
317 : json_t *auditors;
318 :
319 : /**
320 : * json array with the global fees of this exchange. Contains exactly
321 : * the information needed for the "global_fees" field of the /keys response.
322 : */
323 : json_t *global_fees;
324 :
325 : /**
326 : * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of
327 : * length @e krd_array_length;
328 : */
329 : struct KeysResponseData *krd_array;
330 :
331 : /**
332 : * Length of the @e krd_array.
333 : */
334 : unsigned int krd_array_length;
335 :
336 : /**
337 : * Information we track for thecrypto helpers. Preserved
338 : * when the @e key_generation changes, thus kept separate.
339 : */
340 : struct HelperState *helpers;
341 :
342 : /**
343 : * Cached reply for a GET /management/keys request. Used so we do not
344 : * re-create the reply every time.
345 : */
346 : json_t *management_keys_reply;
347 :
348 : /**
349 : * For which (global) key_generation was this data structure created?
350 : * Used to check when we are outdated and need to be re-generated.
351 : */
352 : uint64_t key_generation;
353 :
354 : /**
355 : * When did we initiate the key reloading?
356 : */
357 : struct GNUNET_TIME_Timestamp reload_time;
358 :
359 : /**
360 : * What is the period at which we rotate keys
361 : * (signing or denomination keys)?
362 : */
363 : struct GNUNET_TIME_Relative rekey_frequency;
364 :
365 : /**
366 : * When does our online signing key expire and we
367 : * thus need to re-generate this response?
368 : */
369 : struct GNUNET_TIME_Timestamp signature_expires;
370 :
371 : /**
372 : * True if #finish_keys_response() was not yet run and this key state
373 : * is only suitable for the /management/keys API.
374 : */
375 : bool management_only;
376 :
377 : };
378 :
379 :
380 : /**
381 : * Entry of /keys requests that are currently suspended because we are
382 : * waiting for /keys to become ready.
383 : */
384 : struct SuspendedKeysRequests
385 : {
386 : /**
387 : * Kept in a DLL.
388 : */
389 : struct SuspendedKeysRequests *next;
390 :
391 : /**
392 : * Kept in a DLL.
393 : */
394 : struct SuspendedKeysRequests *prev;
395 :
396 : /**
397 : * The suspended connection.
398 : */
399 : struct MHD_Connection *connection;
400 :
401 : /**
402 : * When does this request timeout?
403 : */
404 : struct GNUNET_TIME_Absolute timeout;
405 : };
406 :
407 : /**
408 : * Stores the latest generation of our key state.
409 : */
410 : static struct TEH_KeyStateHandle *key_state;
411 :
412 : /**
413 : * Counter incremented whenever we have a reason to re-build the keys because
414 : * something external changed. See #TEH_keys_get_state() and
415 : * #TEH_keys_update_states() for uses of this variable.
416 : */
417 : static uint64_t key_generation;
418 :
419 : /**
420 : * Handler listening for wire updates by other exchange
421 : * services.
422 : */
423 : static struct GNUNET_DB_EventHandler *keys_eh;
424 :
425 : /**
426 : * Head of DLL of suspended /keys requests.
427 : */
428 : static struct SuspendedKeysRequests *skr_head;
429 :
430 : /**
431 : * Tail of DLL of suspended /keys requests.
432 : */
433 : static struct SuspendedKeysRequests *skr_tail;
434 :
435 : /**
436 : * Number of entries in the @e skr_head DLL.
437 : */
438 : static unsigned int skr_size;
439 :
440 : /**
441 : * Handle to a connection that should be force-resumed
442 : * with a hard error due to @a skr_size hitting
443 : * #SKR_LIMIT.
444 : */
445 : static struct MHD_Connection *skr_connection;
446 :
447 : /**
448 : * Task to force timeouts on /keys requests.
449 : */
450 : static struct GNUNET_SCHEDULER_Task *keys_tt;
451 :
452 : /**
453 : * For how long should a signing key be legally retained?
454 : * Configuration value.
455 : */
456 : static struct GNUNET_TIME_Relative signkey_legal_duration;
457 :
458 : /**
459 : * RSA security module public key, all zero if not known.
460 : */
461 : static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub;
462 :
463 : /**
464 : * CS security module public key, all zero if not known.
465 : */
466 : static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub;
467 :
468 : /**
469 : * EdDSA security module public key, all zero if not known.
470 : */
471 : static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
472 :
473 : /**
474 : * Are we shutting down?
475 : */
476 : static bool terminating;
477 :
478 :
479 : /**
480 : * Function called to forcefully resume suspended keys requests.
481 : *
482 : * @param cls unused, NULL
483 : */
484 : static void
485 0 : keys_timeout_cb (void *cls)
486 : {
487 : struct SuspendedKeysRequests *skr;
488 :
489 : (void) cls;
490 0 : keys_tt = NULL;
491 0 : while (NULL != (skr = skr_head))
492 : {
493 0 : if (GNUNET_TIME_absolute_is_future (skr->timeout))
494 0 : break;
495 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
496 : "Resuming /keys request due to timeout\n");
497 0 : GNUNET_CONTAINER_DLL_remove (skr_head,
498 : skr_tail,
499 : skr);
500 0 : MHD_resume_connection (skr->connection);
501 0 : TALER_MHD_daemon_trigger ();
502 0 : GNUNET_free (skr);
503 : }
504 0 : if (NULL == skr)
505 0 : return;
506 0 : keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
507 : &keys_timeout_cb,
508 : NULL);
509 : }
510 :
511 :
512 : /**
513 : * Suspend /keys request while we (hopefully) are waiting to be
514 : * provisioned with key material.
515 : *
516 : * @param[in] connection to suspend
517 : */
518 : static MHD_RESULT
519 0 : suspend_request (struct MHD_Connection *connection)
520 : {
521 : struct SuspendedKeysRequests *skr;
522 :
523 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
524 : "Suspending /keys request until key material changes\n");
525 0 : if (terminating)
526 : {
527 0 : return TALER_MHD_reply_with_error (connection,
528 : MHD_HTTP_INTERNAL_SERVER_ERROR,
529 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
530 : "Exchange terminating");
531 : }
532 0 : skr = GNUNET_new (struct SuspendedKeysRequests);
533 0 : skr->connection = connection;
534 0 : MHD_suspend_connection (connection);
535 0 : GNUNET_CONTAINER_DLL_insert (skr_head,
536 : skr_tail,
537 : skr);
538 0 : skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
539 0 : if (NULL == keys_tt)
540 : {
541 0 : keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
542 : &keys_timeout_cb,
543 : NULL);
544 : }
545 0 : skr_size++;
546 0 : if (skr_size > SKR_LIMIT)
547 : {
548 0 : skr = skr_tail;
549 0 : GNUNET_CONTAINER_DLL_remove (skr_head,
550 : skr_tail,
551 : skr);
552 0 : skr_size--;
553 0 : skr_connection = skr->connection;
554 0 : MHD_resume_connection (skr->connection);
555 0 : TALER_MHD_daemon_trigger ();
556 0 : GNUNET_free (skr);
557 : }
558 0 : return MHD_YES;
559 : }
560 :
561 :
562 : /**
563 : * Called on each denomination key. Checks that the key still works.
564 : *
565 : * @param cls NULL
566 : * @param hc denomination hash (unused)
567 : * @param value a `struct TEH_DenominationKey`
568 : * @return #GNUNET_OK
569 : */
570 : static enum GNUNET_GenericReturnValue
571 0 : check_dk (void *cls,
572 : const struct GNUNET_HashCode *hc,
573 : void *value)
574 : {
575 0 : struct TEH_DenominationKey *dk = value;
576 :
577 : (void) cls;
578 : (void) hc;
579 0 : GNUNET_assert (TALER_DENOMINATION_INVALID != dk->denom_pub.cipher);
580 0 : if (TALER_DENOMINATION_RSA == dk->denom_pub.cipher)
581 0 : GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check (
582 : dk->denom_pub.details.rsa_public_key));
583 : // nothing to do for TALER_DENOMINATION_CS
584 0 : return GNUNET_OK;
585 : }
586 :
587 :
588 : void
589 0 : TEH_check_invariants ()
590 : {
591 : struct TEH_KeyStateHandle *ksh;
592 :
593 0 : if (0 == TEH_check_invariants_flag)
594 0 : return;
595 0 : ksh = TEH_keys_get_state ();
596 0 : if (NULL == ksh)
597 0 : return;
598 0 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
599 : &check_dk,
600 : NULL);
601 : }
602 :
603 :
604 : void
605 0 : TEH_resume_keys_requests (bool do_shutdown)
606 : {
607 : struct SuspendedKeysRequests *skr;
608 :
609 0 : if (do_shutdown)
610 0 : terminating = true;
611 0 : while (NULL != (skr = skr_head))
612 : {
613 0 : GNUNET_CONTAINER_DLL_remove (skr_head,
614 : skr_tail,
615 : skr);
616 0 : skr_size--;
617 0 : MHD_resume_connection (skr->connection);
618 0 : TALER_MHD_daemon_trigger ();
619 0 : GNUNET_free (skr);
620 : }
621 0 : }
622 :
623 :
624 : /**
625 : * Clear memory for responses to "/keys" in @a ksh.
626 : *
627 : * @param[in,out] ksh key state to update
628 : */
629 : static void
630 0 : clear_response_cache (struct TEH_KeyStateHandle *ksh)
631 : {
632 0 : for (unsigned int i = 0; i<ksh->krd_array_length; i++)
633 : {
634 0 : struct KeysResponseData *krd = &ksh->krd_array[i];
635 :
636 0 : MHD_destroy_response (krd->response_compressed);
637 0 : MHD_destroy_response (krd->response_uncompressed);
638 0 : GNUNET_free (krd->etag);
639 : }
640 0 : GNUNET_array_grow (ksh->krd_array,
641 : ksh->krd_array_length,
642 : 0);
643 0 : }
644 :
645 :
646 : /**
647 : * Check that the given RSA security module's public key is the one
648 : * we have pinned. If it does not match, we die hard.
649 : *
650 : * @param sm_pub RSA security module public key to check
651 : */
652 : static void
653 0 : check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
654 : {
655 0 : if (0 !=
656 0 : GNUNET_memcmp (sm_pub,
657 : &denom_rsa_sm_pub))
658 : {
659 0 : if (! GNUNET_is_zero (&denom_rsa_sm_pub))
660 : {
661 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
662 : "Our RSA security module changed its key. This must not happen.\n");
663 0 : GNUNET_assert (0);
664 : }
665 0 : denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) */
666 : }
667 0 : }
668 :
669 :
670 : /**
671 : * Check that the given CS security module's public key is the one
672 : * we have pinned. If it does not match, we die hard.
673 : *
674 : * @param sm_pub RSA security module public key to check
675 : */
676 : static void
677 0 : check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
678 : {
679 0 : if (0 !=
680 0 : GNUNET_memcmp (sm_pub,
681 : &denom_cs_sm_pub))
682 : {
683 0 : if (! GNUNET_is_zero (&denom_cs_sm_pub))
684 : {
685 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
686 : "Our CS security module changed its key. This must not happen.\n");
687 0 : GNUNET_assert (0);
688 : }
689 0 : denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */
690 : }
691 0 : }
692 :
693 :
694 : /**
695 : * Check that the given EdDSA security module's public key is the one
696 : * we have pinned. If it does not match, we die hard.
697 : *
698 : * @param sm_pub EdDSA security module public key to check
699 : */
700 : static void
701 0 : check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
702 : {
703 0 : if (0 !=
704 0 : GNUNET_memcmp (sm_pub,
705 : &esign_sm_pub))
706 : {
707 0 : if (! GNUNET_is_zero (&esign_sm_pub))
708 : {
709 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
710 : "Our EdDSA security module changed its key. This must not happen.\n");
711 0 : GNUNET_assert (0);
712 : }
713 0 : esign_sm_pub = *sm_pub; /* TOFU ;-) */
714 : }
715 0 : }
716 :
717 :
718 : /**
719 : * Helper function for #destroy_key_helpers to free all entries
720 : * in the `denom_keys` map.
721 : *
722 : * @param cls the `struct HelperDenomination`
723 : * @param h_denom_pub hash of the denomination public key
724 : * @param value the `struct HelperDenomination` to release
725 : * @return #GNUNET_OK (continue to iterate)
726 : */
727 : static enum GNUNET_GenericReturnValue
728 0 : free_denom_cb (void *cls,
729 : const struct GNUNET_HashCode *h_denom_pub,
730 : void *value)
731 : {
732 0 : struct HelperDenomination *hd = value;
733 :
734 : (void) cls;
735 : (void) h_denom_pub;
736 0 : TALER_denom_pub_free (&hd->denom_pub);
737 0 : GNUNET_free (hd->section_name);
738 0 : GNUNET_free (hd);
739 0 : return GNUNET_OK;
740 : }
741 :
742 :
743 : /**
744 : * Helper function for #destroy_key_helpers to free all entries
745 : * in the `esign_keys` map.
746 : *
747 : * @param cls the `struct HelperSignkey`
748 : * @param pid unused, matches the exchange public key
749 : * @param value the `struct HelperSignkey` to release
750 : * @return #GNUNET_OK (continue to iterate)
751 : */
752 : static int
753 0 : free_esign_cb (void *cls,
754 : const struct GNUNET_PeerIdentity *pid,
755 : void *value)
756 : {
757 0 : struct HelperSignkey *hsk = value;
758 :
759 : (void) cls;
760 : (void) pid;
761 0 : GNUNET_free (hsk);
762 0 : return GNUNET_OK;
763 : }
764 :
765 :
766 : /**
767 : * Destroy helper state. Does NOT call free() on @a hs, as that
768 : * state is not separately allocated! Dual to #setup_key_helpers().
769 : *
770 : * @param[in] hs helper state to free, but NOT the @a hs pointer itself!
771 : */
772 : static void
773 0 : destroy_key_helpers (struct HelperState *hs)
774 : {
775 0 : GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys,
776 : &free_denom_cb,
777 : hs);
778 0 : GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys);
779 0 : hs->rsa_keys = NULL;
780 0 : GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys);
781 0 : hs->cs_keys = NULL;
782 0 : GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys);
783 0 : hs->denom_keys = NULL;
784 0 : GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys,
785 : &free_esign_cb,
786 : hs);
787 0 : GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys);
788 0 : hs->esign_keys = NULL;
789 0 : if (NULL != hs->rsadh)
790 : {
791 0 : TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh);
792 0 : hs->rsadh = NULL;
793 : }
794 0 : if (NULL != hs->csdh)
795 : {
796 0 : TALER_CRYPTO_helper_cs_disconnect (hs->csdh);
797 0 : hs->csdh = NULL;
798 : }
799 0 : if (NULL != hs->esh)
800 : {
801 0 : TALER_CRYPTO_helper_esign_disconnect (hs->esh);
802 0 : hs->esh = NULL;
803 : }
804 0 : }
805 :
806 :
807 : /**
808 : * Looks up the AGE_RESTRICTED setting for a denomination in the config and
809 : * returns the age restriction (mask) accordingly.
810 : *
811 : * @param section_name Section in the configuration for the particular
812 : * denomination.
813 : */
814 : static struct TALER_AgeMask
815 0 : load_age_mask (const char*section_name)
816 : {
817 : static const struct TALER_AgeMask null_mask = {0};
818 0 : struct TALER_AgeMask age_mask = TALER_extensions_age_restriction_ageMask ();
819 :
820 0 : if (age_mask.bits == 0)
821 0 : return null_mask;
822 :
823 0 : if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
824 : TEH_cfg,
825 : section_name,
826 : "AGE_RESTRICTED")))
827 0 : return null_mask;
828 :
829 : {
830 : enum GNUNET_GenericReturnValue ret;
831 :
832 0 : if (GNUNET_SYSERR ==
833 0 : (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
834 : section_name,
835 : "AGE_RESTRICTED")))
836 : {
837 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
838 : section_name,
839 : "AGE_RESTRICTED",
840 : "Value must be YES or NO\n");
841 0 : return null_mask;
842 : }
843 : }
844 0 : return age_mask;
845 : }
846 :
847 :
848 : /**
849 : * Function called with information about available keys for signing. Usually
850 : * only called once per key upon connect. Also called again in case a key is
851 : * being revoked, in that case with an @a end_time of zero.
852 : *
853 : * @param cls closure with the `struct HelperState *`
854 : * @param section_name name of the denomination type in the configuration;
855 : * NULL if the key has been revoked or purged
856 : * @param start_time when does the key become available for signing;
857 : * zero if the key has been revoked or purged
858 : * @param validity_duration how long does the key remain available for signing;
859 : * zero if the key has been revoked or purged
860 : * @param h_rsa hash of the @a denom_pub that is available (or was purged)
861 : * @param denom_pub the public key itself, NULL if the key was revoked or purged
862 : * @param sm_pub public key of the security module, NULL if the key was revoked or purged
863 : * @param sm_sig signature from the security module, NULL if the key was revoked or purged
864 : * The signature was already verified against @a sm_pub.
865 : */
866 : static void
867 0 : helper_rsa_cb (
868 : void *cls,
869 : const char *section_name,
870 : struct GNUNET_TIME_Timestamp start_time,
871 : struct GNUNET_TIME_Relative validity_duration,
872 : const struct TALER_RsaPubHashP *h_rsa,
873 : const struct TALER_DenominationPublicKey *denom_pub,
874 : const struct TALER_SecurityModulePublicKeyP *sm_pub,
875 : const struct TALER_SecurityModuleSignatureP *sm_sig)
876 : {
877 0 : struct HelperState *hs = cls;
878 : struct HelperDenomination *hd;
879 :
880 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
881 : "RSA helper announces key %s for denomination type %s with validity %s\n",
882 : GNUNET_h2s (&h_rsa->hash),
883 : section_name,
884 : GNUNET_STRINGS_relative_time_to_string (validity_duration,
885 : GNUNET_NO));
886 0 : key_generation++;
887 0 : TEH_resume_keys_requests (false);
888 0 : hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys,
889 : &h_rsa->hash);
890 0 : if (NULL != hd)
891 : {
892 : /* should be just an update (revocation!), so update existing entry */
893 0 : hd->validity_duration = validity_duration;
894 0 : return;
895 : }
896 0 : GNUNET_assert (NULL != sm_pub);
897 0 : check_denom_rsa_sm_pub (sm_pub);
898 0 : hd = GNUNET_new (struct HelperDenomination);
899 0 : hd->start_time = start_time;
900 0 : hd->validity_duration = validity_duration;
901 0 : hd->h_details.h_rsa = *h_rsa;
902 0 : hd->sm_sig = *sm_sig;
903 0 : GNUNET_assert (TALER_DENOMINATION_RSA == denom_pub->cipher);
904 0 : TALER_denom_pub_deep_copy (&hd->denom_pub,
905 : denom_pub);
906 0 : GNUNET_assert (TALER_DENOMINATION_RSA == hd->denom_pub.cipher);
907 : /* load the age mask for the denomination, if applicable */
908 0 : hd->denom_pub.age_mask = load_age_mask (section_name);
909 0 : TALER_denom_pub_hash (&hd->denom_pub,
910 : &hd->h_denom_pub);
911 0 : hd->section_name = GNUNET_strdup (section_name);
912 0 : GNUNET_assert (
913 : GNUNET_OK ==
914 : GNUNET_CONTAINER_multihashmap_put (
915 : hs->denom_keys,
916 : &hd->h_denom_pub.hash,
917 : hd,
918 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
919 0 : GNUNET_assert (
920 : GNUNET_OK ==
921 : GNUNET_CONTAINER_multihashmap_put (
922 : hs->rsa_keys,
923 : &hd->h_details.h_rsa.hash,
924 : hd,
925 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
926 : }
927 :
928 :
929 : /**
930 : * Function called with information about available CS keys for signing. Usually
931 : * only called once per key upon connect. Also called again in case a key is
932 : * being revoked, in that case with an @a end_time of zero.
933 : *
934 : * @param cls closure with the `struct HelperState *`
935 : * @param section_name name of the denomination type in the configuration;
936 : * NULL if the key has been revoked or purged
937 : * @param start_time when does the key become available for signing;
938 : * zero if the key has been revoked or purged
939 : * @param validity_duration how long does the key remain available for signing;
940 : * zero if the key has been revoked or purged
941 : * @param h_cs hash of the @a denom_pub that is available (or was purged)
942 : * @param denom_pub the public key itself, NULL if the key was revoked or purged
943 : * @param sm_pub public key of the security module, NULL if the key was revoked or purged
944 : * @param sm_sig signature from the security module, NULL if the key was revoked or purged
945 : * The signature was already verified against @a sm_pub.
946 : */
947 : static void
948 0 : helper_cs_cb (
949 : void *cls,
950 : const char *section_name,
951 : struct GNUNET_TIME_Timestamp start_time,
952 : struct GNUNET_TIME_Relative validity_duration,
953 : const struct TALER_CsPubHashP *h_cs,
954 : const struct TALER_DenominationPublicKey *denom_pub,
955 : const struct TALER_SecurityModulePublicKeyP *sm_pub,
956 : const struct TALER_SecurityModuleSignatureP *sm_sig)
957 : {
958 0 : struct HelperState *hs = cls;
959 : struct HelperDenomination *hd;
960 :
961 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
962 : "CS helper announces key %s for denomination type %s with validity %s\n",
963 : GNUNET_h2s (&h_cs->hash),
964 : section_name,
965 : GNUNET_STRINGS_relative_time_to_string (validity_duration,
966 : GNUNET_NO));
967 0 : key_generation++;
968 0 : TEH_resume_keys_requests (false);
969 0 : hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys,
970 : &h_cs->hash);
971 0 : if (NULL != hd)
972 : {
973 : /* should be just an update (revocation!), so update existing entry */
974 0 : hd->validity_duration = validity_duration;
975 0 : return;
976 : }
977 0 : GNUNET_assert (NULL != sm_pub);
978 0 : check_denom_cs_sm_pub (sm_pub);
979 0 : hd = GNUNET_new (struct HelperDenomination);
980 0 : hd->start_time = start_time;
981 0 : hd->validity_duration = validity_duration;
982 0 : hd->h_details.h_cs = *h_cs;
983 0 : hd->sm_sig = *sm_sig;
984 0 : GNUNET_assert (TALER_DENOMINATION_CS == denom_pub->cipher);
985 0 : TALER_denom_pub_deep_copy (&hd->denom_pub,
986 : denom_pub);
987 : /* load the age mask for the denomination, if applicable */
988 0 : hd->denom_pub.age_mask = load_age_mask (section_name);
989 0 : TALER_denom_pub_hash (&hd->denom_pub,
990 : &hd->h_denom_pub);
991 0 : hd->section_name = GNUNET_strdup (section_name);
992 0 : GNUNET_assert (
993 : GNUNET_OK ==
994 : GNUNET_CONTAINER_multihashmap_put (
995 : hs->denom_keys,
996 : &hd->h_denom_pub.hash,
997 : hd,
998 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
999 0 : GNUNET_assert (
1000 : GNUNET_OK ==
1001 : GNUNET_CONTAINER_multihashmap_put (
1002 : hs->cs_keys,
1003 : &hd->h_details.h_cs.hash,
1004 : hd,
1005 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1006 : }
1007 :
1008 :
1009 : /**
1010 : * Function called with information about available keys for signing. Usually
1011 : * only called once per key upon connect. Also called again in case a key is
1012 : * being revoked, in that case with an @a end_time of zero.
1013 : *
1014 : * @param cls closure with the `struct HelperState *`
1015 : * @param start_time when does the key become available for signing;
1016 : * zero if the key has been revoked or purged
1017 : * @param validity_duration how long does the key remain available for signing;
1018 : * zero if the key has been revoked or purged
1019 : * @param exchange_pub the public key itself, NULL if the key was revoked or purged
1020 : * @param sm_pub public key of the security module, NULL if the key was revoked or purged
1021 : * @param sm_sig signature from the security module, NULL if the key was revoked or purged
1022 : * The signature was already verified against @a sm_pub.
1023 : */
1024 : static void
1025 0 : helper_esign_cb (
1026 : void *cls,
1027 : struct GNUNET_TIME_Timestamp start_time,
1028 : struct GNUNET_TIME_Relative validity_duration,
1029 : const struct TALER_ExchangePublicKeyP *exchange_pub,
1030 : const struct TALER_SecurityModulePublicKeyP *sm_pub,
1031 : const struct TALER_SecurityModuleSignatureP *sm_sig)
1032 : {
1033 0 : struct HelperState *hs = cls;
1034 : struct HelperSignkey *hsk;
1035 : struct GNUNET_PeerIdentity pid;
1036 :
1037 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1038 : "EdDSA helper announces signing key %s with validity %s\n",
1039 : TALER_B2S (exchange_pub),
1040 : GNUNET_STRINGS_relative_time_to_string (validity_duration,
1041 : GNUNET_NO));
1042 0 : key_generation++;
1043 0 : TEH_resume_keys_requests (false);
1044 0 : pid.public_key = exchange_pub->eddsa_pub;
1045 0 : hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
1046 : &pid);
1047 0 : if (NULL != hsk)
1048 : {
1049 : /* should be just an update (revocation!), so update existing entry */
1050 0 : hsk->validity_duration = validity_duration;
1051 0 : return;
1052 : }
1053 0 : GNUNET_assert (NULL != sm_pub);
1054 0 : check_esign_sm_pub (sm_pub);
1055 0 : hsk = GNUNET_new (struct HelperSignkey);
1056 0 : hsk->start_time = start_time;
1057 0 : hsk->validity_duration = validity_duration;
1058 0 : hsk->exchange_pub = *exchange_pub;
1059 0 : hsk->sm_sig = *sm_sig;
1060 0 : GNUNET_assert (
1061 : GNUNET_OK ==
1062 : GNUNET_CONTAINER_multipeermap_put (
1063 : hs->esign_keys,
1064 : &pid,
1065 : hsk,
1066 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1067 : }
1068 :
1069 :
1070 : /**
1071 : * Setup helper state.
1072 : *
1073 : * @param[out] hs helper state to initialize
1074 : * @return #GNUNET_OK on success
1075 : */
1076 : static enum GNUNET_GenericReturnValue
1077 0 : setup_key_helpers (struct HelperState *hs)
1078 : {
1079 : hs->denom_keys
1080 0 : = GNUNET_CONTAINER_multihashmap_create (1024,
1081 : GNUNET_YES);
1082 : hs->rsa_keys
1083 0 : = GNUNET_CONTAINER_multihashmap_create (1024,
1084 : GNUNET_YES);
1085 : hs->cs_keys
1086 0 : = GNUNET_CONTAINER_multihashmap_create (1024,
1087 : GNUNET_YES);
1088 : hs->esign_keys
1089 0 : = GNUNET_CONTAINER_multipeermap_create (32,
1090 : GNUNET_NO /* MUST BE NO! */);
1091 0 : hs->rsadh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg,
1092 : &helper_rsa_cb,
1093 : hs);
1094 0 : if (NULL == hs->rsadh)
1095 : {
1096 0 : destroy_key_helpers (hs);
1097 0 : return GNUNET_SYSERR;
1098 : }
1099 0 : hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg,
1100 : &helper_cs_cb,
1101 : hs);
1102 0 : if (NULL == hs->csdh)
1103 : {
1104 0 : destroy_key_helpers (hs);
1105 0 : return GNUNET_SYSERR;
1106 : }
1107 0 : hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg,
1108 : &helper_esign_cb,
1109 : hs);
1110 0 : if (NULL == hs->esh)
1111 : {
1112 0 : destroy_key_helpers (hs);
1113 0 : return GNUNET_SYSERR;
1114 : }
1115 0 : return GNUNET_OK;
1116 : }
1117 :
1118 :
1119 : /**
1120 : * Synchronize helper state. Polls the key helper for updates.
1121 : *
1122 : * @param[in,out] hs helper state to synchronize
1123 : */
1124 : static void
1125 0 : sync_key_helpers (struct HelperState *hs)
1126 : {
1127 0 : TALER_CRYPTO_helper_rsa_poll (hs->rsadh);
1128 0 : TALER_CRYPTO_helper_cs_poll (hs->csdh);
1129 0 : TALER_CRYPTO_helper_esign_poll (hs->esh);
1130 0 : }
1131 :
1132 :
1133 : /**
1134 : * Free denomination key data.
1135 : *
1136 : * @param cls a `struct TEH_KeyStateHandle`, unused
1137 : * @param h_denom_pub hash of the denomination public key, unused
1138 : * @param value a `struct TEH_DenominationKey` to free
1139 : * @return #GNUNET_OK (continue to iterate)
1140 : */
1141 : static enum GNUNET_GenericReturnValue
1142 0 : clear_denomination_cb (void *cls,
1143 : const struct GNUNET_HashCode *h_denom_pub,
1144 : void *value)
1145 : {
1146 0 : struct TEH_DenominationKey *dk = value;
1147 : struct TEH_AuditorSignature *as;
1148 :
1149 : (void) cls;
1150 : (void) h_denom_pub;
1151 0 : TALER_denom_pub_free (&dk->denom_pub);
1152 0 : while (NULL != (as = dk->as_head))
1153 : {
1154 0 : GNUNET_CONTAINER_DLL_remove (dk->as_head,
1155 : dk->as_tail,
1156 : as);
1157 0 : GNUNET_free (as);
1158 : }
1159 0 : GNUNET_free (dk);
1160 0 : return GNUNET_OK;
1161 : }
1162 :
1163 :
1164 : /**
1165 : * Free denomination key data.
1166 : *
1167 : * @param cls a `struct TEH_KeyStateHandle`, unused
1168 : * @param pid the online signing key (type-disguised), unused
1169 : * @param value a `struct SigningKey` to free
1170 : * @return #GNUNET_OK (continue to iterate)
1171 : */
1172 : static enum GNUNET_GenericReturnValue
1173 0 : clear_signkey_cb (void *cls,
1174 : const struct GNUNET_PeerIdentity *pid,
1175 : void *value)
1176 : {
1177 0 : struct SigningKey *sk = value;
1178 :
1179 : (void) cls;
1180 : (void) pid;
1181 0 : GNUNET_free (sk);
1182 0 : return GNUNET_OK;
1183 : }
1184 :
1185 :
1186 : /**
1187 : * Free resources associated with @a cls, possibly excluding
1188 : * the helper data.
1189 : *
1190 : * @param[in] ksh key state to release
1191 : * @param free_helper true to also release the helper state
1192 : */
1193 : static void
1194 0 : destroy_key_state (struct TEH_KeyStateHandle *ksh,
1195 : bool free_helper)
1196 : {
1197 : struct TEH_GlobalFee *gf;
1198 :
1199 0 : clear_response_cache (ksh);
1200 0 : while (NULL != (gf = ksh->gf_head))
1201 : {
1202 0 : GNUNET_CONTAINER_DLL_remove (ksh->gf_head,
1203 : ksh->gf_tail,
1204 : gf);
1205 0 : GNUNET_free (gf);
1206 : }
1207 0 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
1208 : &clear_denomination_cb,
1209 : ksh);
1210 0 : GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map);
1211 0 : GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
1212 : &clear_signkey_cb,
1213 : ksh);
1214 0 : GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map);
1215 0 : json_decref (ksh->auditors);
1216 0 : ksh->auditors = NULL;
1217 0 : json_decref (ksh->global_fees);
1218 0 : ksh->global_fees = NULL;
1219 0 : if (free_helper)
1220 : {
1221 0 : destroy_key_helpers (ksh->helpers);
1222 0 : GNUNET_free (ksh->helpers);
1223 : }
1224 0 : if (NULL != ksh->management_keys_reply)
1225 : {
1226 0 : json_decref (ksh->management_keys_reply);
1227 0 : ksh->management_keys_reply = NULL;
1228 : }
1229 0 : GNUNET_free (ksh);
1230 0 : }
1231 :
1232 :
1233 : /**
1234 : * Function called whenever another exchange process has updated
1235 : * the keys data in the database.
1236 : *
1237 : * @param cls NULL
1238 : * @param extra unused
1239 : * @param extra_size number of bytes in @a extra unused
1240 : */
1241 : static void
1242 0 : keys_update_event_cb (void *cls,
1243 : const void *extra,
1244 : size_t extra_size)
1245 : {
1246 : (void) cls;
1247 : (void) extra;
1248 : (void) extra_size;
1249 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1250 : "Received /keys update event\n");
1251 0 : TEH_check_invariants ();
1252 0 : key_generation++;
1253 0 : TEH_resume_keys_requests (false);
1254 0 : TEH_check_invariants ();
1255 0 : }
1256 :
1257 :
1258 : enum GNUNET_GenericReturnValue
1259 0 : TEH_keys_init ()
1260 : {
1261 0 : struct GNUNET_DB_EventHeaderP es = {
1262 0 : .size = htons (sizeof (es)),
1263 0 : .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
1264 : };
1265 :
1266 0 : if (GNUNET_OK !=
1267 0 : GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
1268 : "exchange",
1269 : "SIGNKEY_LEGAL_DURATION",
1270 : &signkey_legal_duration))
1271 : {
1272 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1273 : "exchange",
1274 : "SIGNKEY_LEGAL_DURATION");
1275 0 : return GNUNET_SYSERR;
1276 : }
1277 0 : keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
1278 0 : GNUNET_TIME_UNIT_FOREVER_REL,
1279 : &es,
1280 : &keys_update_event_cb,
1281 : NULL);
1282 0 : if (NULL == keys_eh)
1283 : {
1284 0 : GNUNET_break (0);
1285 0 : return GNUNET_SYSERR;
1286 : }
1287 0 : return GNUNET_OK;
1288 : }
1289 :
1290 :
1291 : /**
1292 : * Fully clean up our state.
1293 : */
1294 : void
1295 0 : TEH_keys_finished ()
1296 : {
1297 0 : if (NULL != keys_tt)
1298 : {
1299 0 : GNUNET_SCHEDULER_cancel (keys_tt);
1300 0 : keys_tt = NULL;
1301 : }
1302 0 : if (NULL != key_state)
1303 0 : destroy_key_state (key_state,
1304 : true);
1305 0 : if (NULL != keys_eh)
1306 : {
1307 0 : TEH_plugin->event_listen_cancel (TEH_plugin->cls,
1308 : keys_eh);
1309 0 : keys_eh = NULL;
1310 : }
1311 0 : }
1312 :
1313 :
1314 : /**
1315 : * Function called with information about the exchange's denomination keys.
1316 : *
1317 : * @param cls closure with a `struct TEH_KeyStateHandle *`
1318 : * @param denom_pub public key of the denomination
1319 : * @param h_denom_pub hash of @a denom_pub
1320 : * @param meta meta data information about the denomination type (value, expirations, fees)
1321 : * @param master_sig master signature affirming the validity of this denomination
1322 : * @param recoup_possible true if the key was revoked and clients can currently recoup
1323 : * coins of this denomination
1324 : */
1325 : static void
1326 0 : denomination_info_cb (
1327 : void *cls,
1328 : const struct TALER_DenominationPublicKey *denom_pub,
1329 : const struct TALER_DenominationHashP *h_denom_pub,
1330 : const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
1331 : const struct TALER_MasterSignatureP *master_sig,
1332 : bool recoup_possible)
1333 : {
1334 0 : struct TEH_KeyStateHandle *ksh = cls;
1335 : struct TEH_DenominationKey *dk;
1336 :
1337 0 : GNUNET_assert (TALER_DENOMINATION_INVALID != denom_pub->cipher);
1338 0 : if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) ||
1339 0 : GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) ||
1340 0 : GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) ||
1341 0 : GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) )
1342 : {
1343 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1344 : "Database contains invalid denomination key %s\n",
1345 : GNUNET_h2s (&h_denom_pub->hash));
1346 0 : return;
1347 : }
1348 0 : dk = GNUNET_new (struct TEH_DenominationKey);
1349 0 : TALER_denom_pub_deep_copy (&dk->denom_pub,
1350 : denom_pub);
1351 0 : dk->h_denom_pub = *h_denom_pub;
1352 0 : dk->meta = *meta;
1353 0 : dk->master_sig = *master_sig;
1354 0 : dk->recoup_possible = recoup_possible;
1355 0 : dk->denom_pub.age_mask = meta->age_mask;
1356 :
1357 0 : GNUNET_assert (
1358 : GNUNET_OK ==
1359 : GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map,
1360 : &dk->h_denom_pub.hash,
1361 : dk,
1362 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1363 :
1364 : }
1365 :
1366 :
1367 : /**
1368 : * Function called with information about the exchange's online signing keys.
1369 : *
1370 : * @param cls closure with a `struct TEH_KeyStateHandle *`
1371 : * @param exchange_pub the public key
1372 : * @param meta meta data information about the denomination type (expirations)
1373 : * @param master_sig master signature affirming the validity of this denomination
1374 : */
1375 : static void
1376 0 : signkey_info_cb (
1377 : void *cls,
1378 : const struct TALER_ExchangePublicKeyP *exchange_pub,
1379 : const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
1380 : const struct TALER_MasterSignatureP *master_sig)
1381 : {
1382 0 : struct TEH_KeyStateHandle *ksh = cls;
1383 : struct SigningKey *sk;
1384 : struct GNUNET_PeerIdentity pid;
1385 :
1386 0 : sk = GNUNET_new (struct SigningKey);
1387 0 : sk->exchange_pub = *exchange_pub;
1388 0 : sk->meta = *meta;
1389 0 : sk->master_sig = *master_sig;
1390 0 : pid.public_key = exchange_pub->eddsa_pub;
1391 0 : GNUNET_assert (
1392 : GNUNET_OK ==
1393 : GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map,
1394 : &pid,
1395 : sk,
1396 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1397 0 : }
1398 :
1399 :
1400 : /**
1401 : * Closure for #get_auditor_sigs.
1402 : */
1403 : struct GetAuditorSigsContext
1404 : {
1405 : /**
1406 : * Where to store the matching signatures.
1407 : */
1408 : json_t *denom_keys;
1409 :
1410 : /**
1411 : * Public key of the auditor to match against.
1412 : */
1413 : const struct TALER_AuditorPublicKeyP *auditor_pub;
1414 : };
1415 :
1416 :
1417 : /**
1418 : * Extract the auditor signatures matching the auditor's public
1419 : * key from the @a value and generate the respective JSON.
1420 : *
1421 : * @param cls a `struct GetAuditorSigsContext`
1422 : * @param h_denom_pub hash of the denomination public key
1423 : * @param value a `struct TEH_DenominationKey`
1424 : * @return #GNUNET_OK (continue to iterate)
1425 : */
1426 : static enum GNUNET_GenericReturnValue
1427 0 : get_auditor_sigs (void *cls,
1428 : const struct GNUNET_HashCode *h_denom_pub,
1429 : void *value)
1430 : {
1431 0 : struct GetAuditorSigsContext *ctx = cls;
1432 0 : struct TEH_DenominationKey *dk = value;
1433 :
1434 0 : for (struct TEH_AuditorSignature *as = dk->as_head;
1435 : NULL != as;
1436 0 : as = as->next)
1437 : {
1438 0 : if (0 !=
1439 0 : GNUNET_memcmp (ctx->auditor_pub,
1440 : &as->apub))
1441 0 : continue;
1442 0 : GNUNET_break (0 ==
1443 : json_array_append_new (
1444 : ctx->denom_keys,
1445 : GNUNET_JSON_PACK (
1446 : GNUNET_JSON_pack_data_auto ("denom_pub_h",
1447 : h_denom_pub),
1448 : GNUNET_JSON_pack_data_auto ("auditor_sig",
1449 : &as->asig))));
1450 : }
1451 0 : return GNUNET_OK;
1452 : }
1453 :
1454 :
1455 : /**
1456 : * Function called with information about the exchange's auditors.
1457 : *
1458 : * @param cls closure with a `struct TEH_KeyStateHandle *`
1459 : * @param auditor_pub the public key of the auditor
1460 : * @param auditor_url URL of the REST API of the auditor
1461 : * @param auditor_name human readable official name of the auditor
1462 : */
1463 : static void
1464 0 : auditor_info_cb (
1465 : void *cls,
1466 : const struct TALER_AuditorPublicKeyP *auditor_pub,
1467 : const char *auditor_url,
1468 : const char *auditor_name)
1469 : {
1470 0 : struct TEH_KeyStateHandle *ksh = cls;
1471 : struct GetAuditorSigsContext ctx;
1472 :
1473 0 : ctx.denom_keys = json_array ();
1474 0 : GNUNET_assert (NULL != ctx.denom_keys);
1475 0 : ctx.auditor_pub = auditor_pub;
1476 0 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
1477 : &get_auditor_sigs,
1478 : &ctx);
1479 0 : GNUNET_break (0 ==
1480 : json_array_append_new (
1481 : ksh->auditors,
1482 : GNUNET_JSON_PACK (
1483 : GNUNET_JSON_pack_string ("auditor_name",
1484 : auditor_name),
1485 : GNUNET_JSON_pack_data_auto ("auditor_pub",
1486 : auditor_pub),
1487 : GNUNET_JSON_pack_string ("auditor_url",
1488 : auditor_url),
1489 : GNUNET_JSON_pack_array_steal ("denomination_keys",
1490 : ctx.denom_keys))));
1491 0 : }
1492 :
1493 :
1494 : /**
1495 : * Function called with information about the denominations
1496 : * audited by the exchange's auditors.
1497 : *
1498 : * @param cls closure with a `struct TEH_KeyStateHandle *`
1499 : * @param auditor_pub the public key of an auditor
1500 : * @param h_denom_pub hash of a denomination key audited by this auditor
1501 : * @param auditor_sig signature from the auditor affirming this
1502 : */
1503 : static void
1504 0 : auditor_denom_cb (
1505 : void *cls,
1506 : const struct TALER_AuditorPublicKeyP *auditor_pub,
1507 : const struct TALER_DenominationHashP *h_denom_pub,
1508 : const struct TALER_AuditorSignatureP *auditor_sig)
1509 : {
1510 0 : struct TEH_KeyStateHandle *ksh = cls;
1511 : struct TEH_DenominationKey *dk;
1512 : struct TEH_AuditorSignature *as;
1513 :
1514 0 : dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
1515 : &h_denom_pub->hash);
1516 0 : if (NULL == dk)
1517 : {
1518 : /* Odd, this should be impossible as per foreign key
1519 : constraint on 'auditor_denom_sigs'! Well, we can
1520 : safely continue anyway, so let's just log it. */
1521 0 : GNUNET_break (0);
1522 0 : return;
1523 : }
1524 0 : as = GNUNET_new (struct TEH_AuditorSignature);
1525 0 : as->asig = *auditor_sig;
1526 0 : as->apub = *auditor_pub;
1527 0 : GNUNET_CONTAINER_DLL_insert (dk->as_head,
1528 : dk->as_tail,
1529 : as);
1530 : }
1531 :
1532 :
1533 : /**
1534 : * Closure for #add_sign_key_cb.
1535 : */
1536 : struct SignKeyCtx
1537 : {
1538 : /**
1539 : * What is the current rotation frequency for signing keys. Updated.
1540 : */
1541 : struct GNUNET_TIME_Relative min_sk_frequency;
1542 :
1543 : /**
1544 : * JSON array of signing keys (being created).
1545 : */
1546 : json_t *signkeys;
1547 : };
1548 :
1549 :
1550 : /**
1551 : * Function called for all signing keys, used to build up the
1552 : * respective JSON response.
1553 : *
1554 : * @param cls a `struct SignKeyCtx *` with the array to append keys to
1555 : * @param pid the exchange public key (in type disguise)
1556 : * @param value a `struct SigningKey`
1557 : * @return #GNUNET_OK (continue to iterate)
1558 : */
1559 : static enum GNUNET_GenericReturnValue
1560 0 : add_sign_key_cb (void *cls,
1561 : const struct GNUNET_PeerIdentity *pid,
1562 : void *value)
1563 : {
1564 0 : struct SignKeyCtx *ctx = cls;
1565 0 : struct SigningKey *sk = value;
1566 :
1567 : (void) pid;
1568 0 : if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time))
1569 : {
1570 : ctx->min_sk_frequency =
1571 0 : GNUNET_TIME_relative_min (ctx->min_sk_frequency,
1572 : GNUNET_TIME_absolute_get_difference (
1573 : sk->meta.start.abs_time,
1574 : sk->meta.expire_sign.abs_time));
1575 : }
1576 0 : GNUNET_assert (
1577 : 0 ==
1578 : json_array_append_new (
1579 : ctx->signkeys,
1580 : GNUNET_JSON_PACK (
1581 : GNUNET_JSON_pack_timestamp ("stamp_start",
1582 : sk->meta.start),
1583 : GNUNET_JSON_pack_timestamp ("stamp_expire",
1584 : sk->meta.expire_sign),
1585 : GNUNET_JSON_pack_timestamp ("stamp_end",
1586 : sk->meta.expire_legal),
1587 : GNUNET_JSON_pack_data_auto ("master_sig",
1588 : &sk->master_sig),
1589 : GNUNET_JSON_pack_data_auto ("key",
1590 : &sk->exchange_pub))));
1591 0 : return GNUNET_OK;
1592 : }
1593 :
1594 :
1595 : /**
1596 : * Closure for #add_denom_key_cb.
1597 : */
1598 : struct DenomKeyCtx
1599 : {
1600 : /**
1601 : * Heap for sorting active denomination keys by start time.
1602 : */
1603 : struct GNUNET_CONTAINER_Heap *heap;
1604 :
1605 : /**
1606 : * JSON array of revoked denomination keys.
1607 : */
1608 : json_t *recoup;
1609 :
1610 : /**
1611 : * What is the minimum key rotation frequency of
1612 : * valid denomination keys?
1613 : */
1614 : struct GNUNET_TIME_Relative min_dk_frequency;
1615 : };
1616 :
1617 :
1618 : /**
1619 : * Function called for all denomination keys, used to build up the
1620 : * JSON list of *revoked* denomination keys and the
1621 : * heap of non-revoked denomination keys by timeout.
1622 : *
1623 : * @param cls a `struct DenomKeyCtx`
1624 : * @param h_denom_pub hash of the denomination key
1625 : * @param value a `struct TEH_DenominationKey`
1626 : * @return #GNUNET_OK (continue to iterate)
1627 : */
1628 : static enum GNUNET_GenericReturnValue
1629 0 : add_denom_key_cb (void *cls,
1630 : const struct GNUNET_HashCode *h_denom_pub,
1631 : void *value)
1632 : {
1633 0 : struct DenomKeyCtx *dkc = cls;
1634 0 : struct TEH_DenominationKey *dk = value;
1635 :
1636 0 : if (dk->recoup_possible)
1637 : {
1638 0 : GNUNET_assert (
1639 : 0 ==
1640 : json_array_append_new (
1641 : dkc->recoup,
1642 : GNUNET_JSON_PACK (
1643 : GNUNET_JSON_pack_data_auto ("h_denom_pub",
1644 : h_denom_pub))));
1645 : }
1646 : else
1647 : {
1648 0 : if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
1649 : {
1650 : dkc->min_dk_frequency =
1651 0 : GNUNET_TIME_relative_min (dkc->min_dk_frequency,
1652 : GNUNET_TIME_absolute_get_difference (
1653 : dk->meta.start.abs_time,
1654 : dk->meta.expire_withdraw.abs_time));
1655 : }
1656 0 : (void) GNUNET_CONTAINER_heap_insert (dkc->heap,
1657 : dk,
1658 : dk->meta.start.abs_time.abs_value_us);
1659 : }
1660 0 : return GNUNET_OK;
1661 : }
1662 :
1663 :
1664 : /**
1665 : * Add the headers we want to set for every /keys response.
1666 : *
1667 : * @param ksh the key state to use
1668 : * @param[in,out] response the response to modify
1669 : * @return #GNUNET_OK on success
1670 : */
1671 : static enum GNUNET_GenericReturnValue
1672 0 : setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
1673 : struct MHD_Response *response)
1674 : {
1675 : char dat[128];
1676 :
1677 0 : TALER_MHD_add_global_headers (response);
1678 0 : GNUNET_break (MHD_YES ==
1679 : MHD_add_response_header (response,
1680 : MHD_HTTP_HEADER_CONTENT_TYPE,
1681 : "application/json"));
1682 0 : TALER_MHD_get_date_string (ksh->reload_time.abs_time,
1683 : dat);
1684 0 : GNUNET_break (MHD_YES ==
1685 : MHD_add_response_header (response,
1686 : MHD_HTTP_HEADER_LAST_MODIFIED,
1687 : dat));
1688 0 : if (! GNUNET_TIME_relative_is_zero (ksh->rekey_frequency))
1689 : {
1690 : struct GNUNET_TIME_Relative r;
1691 : struct GNUNET_TIME_Absolute a;
1692 : struct GNUNET_TIME_Timestamp m;
1693 :
1694 0 : r = GNUNET_TIME_relative_min (TEH_max_keys_caching,
1695 : ksh->rekey_frequency);
1696 0 : a = GNUNET_TIME_relative_to_absolute (r);
1697 0 : m = GNUNET_TIME_absolute_to_timestamp (a);
1698 0 : TALER_MHD_get_date_string (m.abs_time,
1699 : dat);
1700 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1701 : "Setting /keys 'Expires' header to '%s'\n",
1702 : dat);
1703 0 : GNUNET_break (MHD_YES ==
1704 : MHD_add_response_header (response,
1705 : MHD_HTTP_HEADER_EXPIRES,
1706 : dat));
1707 : ksh->signature_expires
1708 0 : = GNUNET_TIME_timestamp_min (m,
1709 : ksh->signature_expires);
1710 : }
1711 : /* Set cache control headers: our response varies depending on these headers */
1712 0 : GNUNET_break (MHD_YES ==
1713 : MHD_add_response_header (response,
1714 : MHD_HTTP_HEADER_VARY,
1715 : MHD_HTTP_HEADER_ACCEPT_ENCODING));
1716 : /* Information is always public, revalidate after 1 hour */
1717 0 : GNUNET_break (MHD_YES ==
1718 : MHD_add_response_header (response,
1719 : MHD_HTTP_HEADER_CACHE_CONTROL,
1720 : "public,max-age=3600"));
1721 0 : return GNUNET_OK;
1722 : }
1723 :
1724 :
1725 : /**
1726 : * Function called with wallet balance thresholds.
1727 : *
1728 : * @param[in,out] cls a `json **` where to put the array of json amounts discovered
1729 : * @param threshold another threshold amount to add
1730 : */
1731 : static void
1732 0 : wallet_threshold_cb (void *cls,
1733 : const struct TALER_Amount *threshold)
1734 : {
1735 0 : json_t **ret = cls;
1736 :
1737 0 : if (NULL == *ret)
1738 0 : *ret = json_array ();
1739 0 : GNUNET_assert (0 ==
1740 : json_array_append_new (*ret,
1741 : TALER_JSON_from_amount (
1742 : threshold)));
1743 0 : }
1744 :
1745 :
1746 : /**
1747 : * Initialize @a krd using the given values for @a signkeys,
1748 : * @a recoup and @a denoms.
1749 : *
1750 : * @param[in,out] ksh key state handle we build @a krd for
1751 : * @param[in] denom_keys_hash hash over all the denomination keys in @a denoms
1752 : * @param last_cpd timestamp to use
1753 : * @param signkeys list of sign keys to return
1754 : * @param recoup list of revoked keys to return
1755 : * @param denoms list of denominations to return
1756 : * @param grouped_denominations list of grouped denominations to return
1757 : * @param[in] h_grouped XOR of all hashes in @a grouped_demoninations
1758 : * @return #GNUNET_OK on success
1759 : */
1760 : static enum GNUNET_GenericReturnValue
1761 0 : create_krd (struct TEH_KeyStateHandle *ksh,
1762 : const struct GNUNET_HashCode *denom_keys_hash,
1763 : struct GNUNET_TIME_Timestamp last_cpd,
1764 : json_t *signkeys,
1765 : json_t *recoup,
1766 : json_t *denoms,
1767 : json_t *grouped_denominations,
1768 : const struct GNUNET_HashCode *h_grouped)
1769 : {
1770 : struct KeysResponseData krd;
1771 : struct TALER_ExchangePublicKeyP exchange_pub;
1772 : struct TALER_ExchangeSignatureP exchange_sig;
1773 : struct TALER_ExchangePublicKeyP grouped_exchange_pub;
1774 : struct TALER_ExchangeSignatureP grouped_exchange_sig;
1775 : json_t *keys;
1776 :
1777 0 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time));
1778 0 : GNUNET_assert (NULL != signkeys);
1779 0 : GNUNET_assert (NULL != recoup);
1780 0 : GNUNET_assert (NULL != denoms);
1781 0 : GNUNET_assert (NULL != grouped_denominations);
1782 0 : GNUNET_assert (NULL != h_grouped);
1783 0 : GNUNET_assert (NULL != ksh->auditors);
1784 0 : GNUNET_assert (NULL != TEH_currency);
1785 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1786 : "Creating /keys at cherry pick date %s\n",
1787 : GNUNET_TIME_timestamp2s (last_cpd));
1788 :
1789 : /* Sign hash over denomination keys */
1790 : {
1791 : enum TALER_ErrorCode ec;
1792 :
1793 0 : if (TALER_EC_NONE !=
1794 : (ec =
1795 0 : TALER_exchange_online_key_set_sign (
1796 : &TEH_keys_exchange_sign2_,
1797 : ksh,
1798 : last_cpd,
1799 : denom_keys_hash,
1800 : &exchange_pub,
1801 : &exchange_sig)))
1802 : {
1803 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1804 : "Could not create key response data: cannot sign (%s)\n",
1805 : TALER_ErrorCode_get_hint (ec));
1806 0 : return GNUNET_SYSERR;
1807 : }
1808 : }
1809 :
1810 : /* Sign grouped hash */
1811 : {
1812 : enum TALER_ErrorCode ec;
1813 :
1814 0 : if (TALER_EC_NONE !=
1815 : (ec =
1816 0 : TALER_exchange_online_key_set_sign (
1817 : &TEH_keys_exchange_sign2_,
1818 : ksh,
1819 : last_cpd,
1820 : h_grouped,
1821 : &grouped_exchange_pub,
1822 : &grouped_exchange_sig)))
1823 : {
1824 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1825 : "Could not create key response data: cannot sign grouped hash (%s)\n",
1826 : TALER_ErrorCode_get_hint (ec));
1827 0 : return GNUNET_SYSERR;
1828 : }
1829 : }
1830 :
1831 : /* both public keys really must be the same */
1832 0 : GNUNET_assert (0 ==
1833 : memcmp (&grouped_exchange_pub,
1834 : &exchange_pub,
1835 : sizeof(exchange_pub)));
1836 :
1837 : {
1838 : const struct SigningKey *sk;
1839 :
1840 0 : sk = GNUNET_CONTAINER_multipeermap_get (
1841 0 : ksh->signkey_map,
1842 : (const struct GNUNET_PeerIdentity *) &exchange_pub);
1843 0 : ksh->signature_expires = GNUNET_TIME_timestamp_min (sk->meta.expire_sign,
1844 : ksh->signature_expires);
1845 : }
1846 :
1847 0 : keys = GNUNET_JSON_PACK (
1848 : GNUNET_JSON_pack_string ("version",
1849 : EXCHANGE_PROTOCOL_VERSION),
1850 : GNUNET_JSON_pack_string ("currency",
1851 : TEH_currency),
1852 : GNUNET_JSON_pack_data_auto ("master_public_key",
1853 : &TEH_master_public_key),
1854 : GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
1855 : TEH_reserve_closing_delay),
1856 : GNUNET_JSON_pack_array_incref ("signkeys",
1857 : signkeys),
1858 : GNUNET_JSON_pack_array_incref ("recoup",
1859 : recoup),
1860 : GNUNET_JSON_pack_array_incref ("denoms",
1861 : denoms),
1862 : GNUNET_JSON_pack_array_incref ("denominations",
1863 : grouped_denominations),
1864 : GNUNET_JSON_pack_array_incref ("auditors",
1865 : ksh->auditors),
1866 : GNUNET_JSON_pack_array_incref ("global_fees",
1867 : ksh->global_fees),
1868 : GNUNET_JSON_pack_timestamp ("list_issue_date",
1869 : last_cpd),
1870 : GNUNET_JSON_pack_data_auto ("eddsa_pub",
1871 : &exchange_pub),
1872 : GNUNET_JSON_pack_data_auto ("eddsa_sig",
1873 : &exchange_sig),
1874 : GNUNET_JSON_pack_data_auto ("denominations_sig",
1875 : &grouped_exchange_sig));
1876 0 : GNUNET_assert (NULL != keys);
1877 :
1878 : /* Set wallet limit if KYC is configured */
1879 : {
1880 0 : json_t *wblwk = NULL;
1881 :
1882 0 : TALER_KYCLOGIC_kyc_iterate_thresholds (
1883 : TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE,
1884 : &wallet_threshold_cb,
1885 : &wblwk);
1886 0 : if (NULL != wblwk)
1887 0 : GNUNET_assert (
1888 : 0 ==
1889 : json_object_set_new (
1890 : keys,
1891 : "wallet_balance_limit_without_kyc",
1892 : wblwk));
1893 : }
1894 :
1895 : /* Signal support for the configured, enabled extensions. */
1896 : {
1897 0 : json_t *extensions = json_object ();
1898 0 : bool has_extensions = false;
1899 :
1900 : /* Fill in the configurations of the enabled extensions */
1901 0 : for (const struct TALER_Extension *extension = TALER_extensions_get_head ();
1902 : NULL != extension;
1903 0 : extension = extension->next)
1904 : {
1905 : json_t *ext;
1906 : json_t *config_json;
1907 : int r;
1908 :
1909 : /* skip if not configured == disabled */
1910 0 : if (NULL == extension->config ||
1911 0 : NULL == extension->config_json)
1912 0 : continue;
1913 :
1914 : /* flag our findings so far */
1915 0 : has_extensions = true;
1916 :
1917 0 : GNUNET_assert (NULL != extension->config_json);
1918 :
1919 0 : config_json = json_copy (extension->config_json);
1920 0 : GNUNET_assert (NULL != config_json);
1921 :
1922 0 : ext = GNUNET_JSON_PACK (
1923 : GNUNET_JSON_pack_bool ("critical",
1924 : extension->critical),
1925 : GNUNET_JSON_pack_string ("version",
1926 : extension->version),
1927 : GNUNET_JSON_pack_object_steal ("config",
1928 : config_json)
1929 : );
1930 0 : GNUNET_assert (NULL != ext);
1931 :
1932 0 : r = json_object_set_new (
1933 : extensions,
1934 0 : extension->name,
1935 : ext);
1936 0 : GNUNET_assert (0 == r);
1937 : }
1938 :
1939 : /* Update the keys object with the extensions and its signature */
1940 0 : if (has_extensions)
1941 : {
1942 : json_t *sig;
1943 : int r;
1944 :
1945 0 : r = json_object_set (
1946 : keys,
1947 : "extensions",
1948 : extensions);
1949 0 : GNUNET_assert (0 == r);
1950 :
1951 0 : sig = GNUNET_JSON_PACK (
1952 : GNUNET_JSON_pack_data_auto ("extensions_sig",
1953 : &TEH_extensions_sig));
1954 :
1955 0 : r = json_object_update (keys, sig);
1956 0 : GNUNET_assert (0 == r);
1957 : }
1958 : else
1959 : {
1960 0 : json_decref (extensions);
1961 : }
1962 : }
1963 :
1964 :
1965 : {
1966 : char *keys_json;
1967 : void *keys_jsonz;
1968 : size_t keys_jsonz_size;
1969 : int comp;
1970 : char etag[sizeof (struct GNUNET_HashCode) * 2];
1971 :
1972 : /* Convert /keys response to UTF8-String */
1973 0 : keys_json = json_dumps (keys,
1974 : JSON_INDENT (2));
1975 0 : json_decref (keys);
1976 0 : GNUNET_assert (NULL != keys_json);
1977 :
1978 : /* Keep copy for later compression... */
1979 0 : keys_jsonz = GNUNET_strdup (keys_json);
1980 0 : keys_jsonz_size = strlen (keys_json);
1981 :
1982 : /* hash to compute etag */
1983 : {
1984 : struct GNUNET_HashCode ehash;
1985 : char *end;
1986 :
1987 0 : GNUNET_CRYPTO_hash (keys_jsonz,
1988 : keys_jsonz_size,
1989 : &ehash);
1990 0 : end = GNUNET_STRINGS_data_to_string (&ehash,
1991 : sizeof (ehash),
1992 : etag,
1993 : sizeof (etag));
1994 0 : *end = '\0';
1995 : }
1996 :
1997 : /* Create uncompressed response */
1998 : krd.response_uncompressed
1999 0 : = MHD_create_response_from_buffer (keys_jsonz_size,
2000 : keys_json,
2001 : MHD_RESPMEM_MUST_FREE);
2002 0 : GNUNET_assert (NULL != krd.response_uncompressed);
2003 0 : GNUNET_assert (GNUNET_OK ==
2004 : setup_general_response_headers (ksh,
2005 : krd.response_uncompressed));
2006 0 : GNUNET_break (MHD_YES ==
2007 : MHD_add_response_header (krd.response_uncompressed,
2008 : MHD_HTTP_HEADER_ETAG,
2009 : etag));
2010 : /* Also compute compressed version of /keys response */
2011 0 : comp = TALER_MHD_body_compress (&keys_jsonz,
2012 : &keys_jsonz_size);
2013 : krd.response_compressed
2014 0 : = MHD_create_response_from_buffer (keys_jsonz_size,
2015 : keys_jsonz,
2016 : MHD_RESPMEM_MUST_FREE);
2017 0 : GNUNET_assert (NULL != krd.response_compressed);
2018 : /* If the response is actually compressed, set the
2019 : respective header. */
2020 0 : GNUNET_assert ( (MHD_YES != comp) ||
2021 : (MHD_YES ==
2022 : MHD_add_response_header (krd.response_compressed,
2023 : MHD_HTTP_HEADER_CONTENT_ENCODING,
2024 : "deflate")) );
2025 0 : GNUNET_assert (GNUNET_OK ==
2026 : setup_general_response_headers (ksh,
2027 : krd.response_compressed));
2028 0 : GNUNET_break (MHD_YES ==
2029 : MHD_add_response_header (krd.response_compressed,
2030 : MHD_HTTP_HEADER_ETAG,
2031 : etag));
2032 0 : krd.etag = GNUNET_strdup (etag);
2033 : }
2034 0 : krd.cherry_pick_date = last_cpd;
2035 0 : GNUNET_array_append (ksh->krd_array,
2036 : ksh->krd_array_length,
2037 : krd);
2038 0 : return GNUNET_OK;
2039 : }
2040 :
2041 :
2042 : /**
2043 : * Update the "/keys" responses in @a ksh, computing the detailed replies.
2044 : *
2045 : * This function is to recompute all (including cherry-picked) responses we
2046 : * might want to return, based on the state already in @a ksh.
2047 : *
2048 : * @param[in,out] ksh state handle to update
2049 : * @return #GNUNET_OK on success
2050 : */
2051 : static enum GNUNET_GenericReturnValue
2052 0 : finish_keys_response (struct TEH_KeyStateHandle *ksh)
2053 : {
2054 : json_t *recoup;
2055 : struct SignKeyCtx sctx;
2056 0 : json_t *denoms = NULL;
2057 0 : json_t *grouped_denominations = NULL;
2058 : struct GNUNET_TIME_Timestamp last_cpd;
2059 : struct GNUNET_CONTAINER_Heap *heap;
2060 0 : struct GNUNET_HashContext *hash_context = NULL;
2061 0 : struct GNUNET_HashCode grouped_hash_xor = {0};
2062 :
2063 0 : sctx.signkeys = json_array ();
2064 0 : GNUNET_assert (NULL != sctx.signkeys);
2065 0 : sctx.min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL;
2066 0 : GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
2067 : &add_sign_key_cb,
2068 : &sctx);
2069 0 : recoup = json_array ();
2070 0 : GNUNET_assert (NULL != recoup);
2071 0 : heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
2072 : {
2073 0 : struct DenomKeyCtx dkc = {
2074 : .recoup = recoup,
2075 : .heap = heap,
2076 : .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
2077 : };
2078 :
2079 0 : GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
2080 : &add_denom_key_cb,
2081 : &dkc);
2082 : ksh->rekey_frequency
2083 0 : = GNUNET_TIME_relative_min (dkc.min_dk_frequency,
2084 : sctx.min_sk_frequency);
2085 : }
2086 :
2087 0 : denoms = json_array ();
2088 0 : GNUNET_assert (NULL != denoms);
2089 0 : hash_context = GNUNET_CRYPTO_hash_context_start ();
2090 :
2091 0 : grouped_denominations = json_array ();
2092 0 : GNUNET_assert (NULL != grouped_denominations);
2093 :
2094 0 : last_cpd = GNUNET_TIME_UNIT_ZERO_TS;
2095 :
2096 : // FIXME: This block contains the implementation of the DEPRECATED
2097 : // "denom_pubs" array along with the new grouped "denominations".
2098 : // "denom_pubs" Will be removed sooner or later.
2099 : {
2100 : struct TEH_DenominationKey *dk;
2101 : struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group;
2102 : /* groupData is the value we store for each group meta-data */
2103 : struct groupData
2104 : {
2105 : /**
2106 : * The json blob with the group meta-data and list of denominations
2107 : */
2108 : json_t *json;
2109 :
2110 : /**
2111 : * xor of all hashes of denominations in that group
2112 : */
2113 : struct GNUNET_HashCode hash_xor;
2114 : };
2115 :
2116 : denominations_by_group =
2117 0 : GNUNET_CONTAINER_multihashmap_create (1024,
2118 : GNUNET_NO /* NO, because keys are only on the stack */);
2119 :
2120 :
2121 : /* heap = min heap, sorted by start time */
2122 0 : while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
2123 : {
2124 0 : if (GNUNET_TIME_timestamp_cmp (last_cpd,
2125 : !=,
2126 0 : dk->meta.start) &&
2127 0 : (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time)) )
2128 : {
2129 : /*
2130 : * This is not the first entry in the heap (because last_cpd !=
2131 : * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different
2132 : * start time. Therefore, we create a new entry in ksh.
2133 : */
2134 : struct GNUNET_HashCode hc;
2135 :
2136 0 : GNUNET_CRYPTO_hash_context_finish (
2137 : GNUNET_CRYPTO_hash_context_copy (hash_context),
2138 : &hc);
2139 :
2140 0 : if (GNUNET_OK !=
2141 0 : create_krd (ksh,
2142 : &hc,
2143 : last_cpd,
2144 : sctx.signkeys,
2145 : recoup,
2146 : denoms,
2147 : grouped_denominations,
2148 : &grouped_hash_xor))
2149 : {
2150 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2151 : "Failed to generate key response data for %s\n",
2152 : GNUNET_TIME_timestamp2s (last_cpd));
2153 0 : GNUNET_CRYPTO_hash_context_abort (hash_context);
2154 : /* drain heap before destroying it */
2155 0 : while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
2156 : /* intentionally empty */;
2157 0 : GNUNET_CONTAINER_heap_destroy (heap);
2158 0 : json_decref (denoms);
2159 0 : json_decref (grouped_denominations);
2160 0 : json_decref (sctx.signkeys);
2161 0 : json_decref (recoup);
2162 0 : return GNUNET_SYSERR;
2163 : }
2164 : }
2165 :
2166 0 : last_cpd = dk->meta.start;
2167 :
2168 : {
2169 : json_t *denom;
2170 :
2171 : denom =
2172 0 : GNUNET_JSON_PACK (
2173 : GNUNET_JSON_pack_data_auto ("master_sig",
2174 : &dk->master_sig),
2175 : GNUNET_JSON_pack_timestamp ("stamp_start",
2176 : dk->meta.start),
2177 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
2178 : dk->meta.expire_withdraw),
2179 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
2180 : dk->meta.expire_deposit),
2181 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
2182 : dk->meta.expire_legal),
2183 : TALER_JSON_pack_denom_pub ("denom_pub",
2184 : &dk->denom_pub),
2185 : TALER_JSON_pack_amount ("value",
2186 : &dk->meta.value),
2187 : TALER_JSON_PACK_DENOM_FEES ("fee",
2188 : &dk->meta.fees));
2189 :
2190 0 : GNUNET_CRYPTO_hash_context_read (hash_context,
2191 0 : &dk->h_denom_pub,
2192 : sizeof (struct GNUNET_HashCode));
2193 :
2194 0 : GNUNET_assert (
2195 : 0 ==
2196 : json_array_append_new (
2197 : denoms,
2198 : denom));
2199 :
2200 : }
2201 :
2202 : /*
2203 : * Group the denominations by {cipher, value, fees, age_mask}.
2204 : *
2205 : * For each group we save the group meta-data and the list of
2206 : * denominations in this group as a json-blob in the multihashmap
2207 : * denominations_by_group.
2208 : */
2209 : {
2210 : static const char *denoms_key = "denoms";
2211 : struct groupData *group;
2212 : json_t *list;
2213 : json_t *entry;
2214 : struct GNUNET_HashCode key;
2215 0 : struct TALER_DenominationGroup meta = {
2216 0 : .cipher = dk->denom_pub.cipher,
2217 : .value = dk->meta.value,
2218 : .fees = dk->meta.fees,
2219 : .age_mask = dk->meta.age_mask,
2220 : };
2221 :
2222 0 : memset (&meta.hash, 0, sizeof(meta.hash));
2223 :
2224 : /* Search the group/JSON-blob for the key */
2225 0 : GNUNET_CRYPTO_hash (&meta, sizeof(meta), &key);
2226 :
2227 : group =
2228 0 : (struct groupData *) GNUNET_CONTAINER_multihashmap_get (
2229 : denominations_by_group,
2230 : &key);
2231 :
2232 0 : if (NULL == group)
2233 : {
2234 : /* There is no group for this meta-data yet, so we create a new group */
2235 0 : bool age_restricted = meta.age_mask.bits != 0;
2236 : char *cipher;
2237 :
2238 0 : group = GNUNET_new (struct groupData);
2239 0 : memset (group, 0, sizeof(*group));
2240 :
2241 0 : switch (meta.cipher)
2242 : {
2243 0 : case TALER_DENOMINATION_RSA:
2244 0 : cipher = age_restricted ? "RSA+age_restricted" : "RSA";
2245 0 : break;
2246 0 : case TALER_DENOMINATION_CS:
2247 0 : cipher = age_restricted ? "CS+age_restricted" : "CS";
2248 0 : break;
2249 0 : default:
2250 0 : GNUNET_assert (false);
2251 : }
2252 :
2253 0 : group->json = GNUNET_JSON_PACK (
2254 : GNUNET_JSON_pack_string ("cipher", cipher),
2255 : TALER_JSON_PACK_DENOM_FEES ("fee", &meta.fees),
2256 : TALER_JSON_pack_amount ("value", &meta.value));
2257 0 : GNUNET_assert (NULL != group->json);
2258 :
2259 0 : if (age_restricted)
2260 : {
2261 0 : int r = json_object_set (group->json,
2262 : "age_mask",
2263 0 : json_integer (meta.age_mask.bits));
2264 0 : GNUNET_assert (0 == r);
2265 : }
2266 :
2267 : /* Create a new array for the denominations in this group */
2268 0 : list = json_array ();
2269 0 : GNUNET_assert (NULL != list);
2270 0 : GNUNET_assert (0 ==
2271 : json_object_set (group->json, denoms_key, list));
2272 :
2273 0 : GNUNET_assert (
2274 : GNUNET_OK ==
2275 : GNUNET_CONTAINER_multihashmap_put (denominations_by_group,
2276 : &key,
2277 : group,
2278 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2279 : }
2280 :
2281 : /* Now that we have found/created the right group, add the
2282 : denomination to the list */
2283 : {
2284 : struct GNUNET_JSON_PackSpec key_spec;
2285 :
2286 0 : switch (meta.cipher)
2287 : {
2288 0 : case TALER_DENOMINATION_RSA:
2289 : key_spec =
2290 0 : GNUNET_JSON_pack_rsa_public_key ("rsa_pub",
2291 0 : dk->denom_pub.details.
2292 : rsa_public_key);
2293 0 : break;
2294 0 : case TALER_DENOMINATION_CS:
2295 : key_spec =
2296 0 : GNUNET_JSON_pack_data_varsize ("cs_pub",
2297 0 : &dk->denom_pub.details.
2298 : cs_public_key,
2299 : sizeof (dk->denom_pub.details.
2300 : cs_public_key));
2301 0 : break;
2302 0 : default:
2303 0 : GNUNET_assert (false);
2304 : }
2305 :
2306 0 : entry = GNUNET_JSON_PACK (
2307 : GNUNET_JSON_pack_data_auto ("master_sig",
2308 : &dk->master_sig),
2309 : GNUNET_JSON_pack_timestamp ("stamp_start",
2310 : dk->meta.start),
2311 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
2312 : dk->meta.expire_withdraw),
2313 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
2314 : dk->meta.expire_deposit),
2315 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
2316 : dk->meta.expire_legal),
2317 : key_spec
2318 : );
2319 0 : GNUNET_assert (NULL != entry);
2320 : }
2321 :
2322 : /* Build up the running xor of all hashes of the denominations in this
2323 : group */
2324 0 : GNUNET_CRYPTO_hash_xor (&dk->h_denom_pub.hash,
2325 0 : &group->hash_xor,
2326 : &group->hash_xor);
2327 :
2328 : /* Finally, add the denomination to the list of denominations in this
2329 : group */
2330 0 : list = json_object_get (group->json, denoms_key);
2331 0 : GNUNET_assert (NULL != list);
2332 0 : GNUNET_assert (true == json_is_array (list));
2333 0 : GNUNET_assert (0 ==
2334 : json_array_append_new (list, entry));
2335 : }
2336 : } /* loop over heap ends */
2337 :
2338 : /* Create the JSON-array of grouped denominations */
2339 0 : if (0 <
2340 0 : GNUNET_CONTAINER_multihashmap_size (denominations_by_group))
2341 : {
2342 : struct GNUNET_CONTAINER_MultiHashMapIterator *iter;
2343 0 : struct groupData *group = NULL;
2344 :
2345 : iter =
2346 0 : GNUNET_CONTAINER_multihashmap_iterator_create (denominations_by_group);
2347 :
2348 0 : while (GNUNET_OK ==
2349 0 : GNUNET_CONTAINER_multihashmap_iterator_next (iter,
2350 : NULL,
2351 : (const
2352 : void **) &group))
2353 : {
2354 : /* Add the XOR over all hashes of denominations in this group to the group */
2355 0 : GNUNET_assert (0 ==
2356 : json_object_set (
2357 : group->json,
2358 : "hash",
2359 : GNUNET_JSON_PACK (
2360 : GNUNET_JSON_pack_data_auto (NULL,
2361 : &group->hash_xor))));
2362 :
2363 : /* Add this group to the array */
2364 0 : GNUNET_assert (0 ==
2365 : json_array_append_new (
2366 : grouped_denominations,
2367 : group->json));
2368 :
2369 : /* Build the running XOR over all hash(_xor) */
2370 0 : GNUNET_CRYPTO_hash_xor (&group->hash_xor,
2371 : &grouped_hash_xor,
2372 : &grouped_hash_xor);
2373 :
2374 0 : GNUNET_free (group);
2375 : }
2376 :
2377 0 : GNUNET_CONTAINER_multihashmap_iterator_destroy (iter);
2378 0 : GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group);
2379 :
2380 : }
2381 : }
2382 :
2383 0 : GNUNET_CONTAINER_heap_destroy (heap);
2384 0 : if (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time))
2385 : {
2386 : struct GNUNET_HashCode hc;
2387 :
2388 0 : GNUNET_CRYPTO_hash_context_finish (hash_context,
2389 : &hc);
2390 0 : if (GNUNET_OK !=
2391 0 : create_krd (ksh,
2392 : &hc,
2393 : last_cpd,
2394 : sctx.signkeys,
2395 : recoup,
2396 : denoms,
2397 : grouped_denominations,
2398 : &grouped_hash_xor))
2399 : {
2400 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2401 : "Failed to generate key response data for %s\n",
2402 : GNUNET_TIME_timestamp2s (last_cpd));
2403 0 : json_decref (denoms);
2404 0 : json_decref (sctx.signkeys);
2405 0 : json_decref (recoup);
2406 0 : return GNUNET_SYSERR;
2407 : }
2408 0 : ksh->management_only = false;
2409 : }
2410 : else
2411 : {
2412 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2413 : "No denomination keys available. Refusing to generate /keys response.\n");
2414 0 : GNUNET_CRYPTO_hash_context_abort (hash_context);
2415 : }
2416 0 : json_decref (sctx.signkeys);
2417 0 : json_decref (recoup);
2418 0 : json_decref (denoms);
2419 0 : return GNUNET_OK;
2420 : }
2421 :
2422 :
2423 : /**
2424 : * Called with information about global fees.
2425 : *
2426 : * @param cls `struct TEH_KeyStateHandle *` we are building
2427 : * @param fees the global fees we charge
2428 : * @param purse_timeout when do purses time out
2429 : * @param kyc_timeout when do reserves without KYC time out
2430 : * @param history_expiration how long are account histories preserved
2431 : * @param purse_account_limit how many purses are free per account
2432 : * @param start_date from when are these fees valid (start date)
2433 : * @param end_date until when are these fees valid (end date, exclusive)
2434 : * @param master_sig master key signature affirming that this is the correct
2435 : * fee (of purpose #TALER_SIGNATURE_MASTER_GLOBAL_FEES)
2436 : */
2437 : static void
2438 0 : global_fee_info_cb (
2439 : void *cls,
2440 : const struct TALER_GlobalFeeSet *fees,
2441 : struct GNUNET_TIME_Relative purse_timeout,
2442 : struct GNUNET_TIME_Relative kyc_timeout,
2443 : struct GNUNET_TIME_Relative history_expiration,
2444 : uint32_t purse_account_limit,
2445 : struct GNUNET_TIME_Timestamp start_date,
2446 : struct GNUNET_TIME_Timestamp end_date,
2447 : const struct TALER_MasterSignatureP *master_sig)
2448 : {
2449 0 : struct TEH_KeyStateHandle *ksh = cls;
2450 : struct TEH_GlobalFee *gf;
2451 :
2452 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2453 : "Found global fees with %u purses\n",
2454 : purse_account_limit);
2455 0 : gf = GNUNET_new (struct TEH_GlobalFee);
2456 0 : gf->start_date = start_date;
2457 0 : gf->end_date = end_date;
2458 0 : gf->fees = *fees;
2459 0 : gf->purse_timeout = purse_timeout;
2460 0 : gf->kyc_timeout = kyc_timeout;
2461 0 : gf->history_expiration = history_expiration;
2462 0 : gf->purse_account_limit = purse_account_limit;
2463 0 : gf->master_sig = *master_sig;
2464 0 : GNUNET_CONTAINER_DLL_insert (ksh->gf_head,
2465 : ksh->gf_tail,
2466 : gf);
2467 0 : GNUNET_assert (
2468 : 0 ==
2469 : json_array_append_new (
2470 : ksh->global_fees,
2471 : GNUNET_JSON_PACK (
2472 : GNUNET_JSON_pack_timestamp ("start_date",
2473 : start_date),
2474 : GNUNET_JSON_pack_timestamp ("end_date",
2475 : end_date),
2476 : TALER_JSON_PACK_GLOBAL_FEES (fees),
2477 : GNUNET_JSON_pack_time_rel ("history_expiration",
2478 : history_expiration),
2479 : GNUNET_JSON_pack_time_rel ("account_kyc_timeout",
2480 : kyc_timeout),
2481 : GNUNET_JSON_pack_time_rel ("purse_timeout",
2482 : purse_timeout),
2483 : GNUNET_JSON_pack_uint64 ("purse_account_limit",
2484 : purse_account_limit),
2485 : GNUNET_JSON_pack_data_auto ("master_sig",
2486 : master_sig))));
2487 0 : }
2488 :
2489 :
2490 : /**
2491 : * Create a key state.
2492 : *
2493 : * @param[in] hs helper state to (re)use, NULL if not available
2494 : * @param management_only if we should NOT run 'finish_keys_response()'
2495 : * because we only need the state for the /management/keys API
2496 : * @return NULL on error (i.e. failed to access database)
2497 : */
2498 : static struct TEH_KeyStateHandle *
2499 0 : build_key_state (struct HelperState *hs,
2500 : bool management_only)
2501 : {
2502 : struct TEH_KeyStateHandle *ksh;
2503 : enum GNUNET_DB_QueryStatus qs;
2504 :
2505 0 : ksh = GNUNET_new (struct TEH_KeyStateHandle);
2506 0 : ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS;
2507 0 : ksh->reload_time = GNUNET_TIME_timestamp_get ();
2508 : /* We must use the key_generation from when we STARTED the process! */
2509 0 : ksh->key_generation = key_generation;
2510 0 : if (NULL == hs)
2511 : {
2512 0 : ksh->helpers = GNUNET_new (struct HelperState);
2513 0 : if (GNUNET_OK !=
2514 0 : setup_key_helpers (ksh->helpers))
2515 : {
2516 0 : GNUNET_free (ksh->helpers);
2517 0 : GNUNET_assert (NULL == ksh->management_keys_reply);
2518 0 : GNUNET_free (ksh);
2519 0 : return NULL;
2520 : }
2521 : }
2522 : else
2523 : {
2524 0 : ksh->helpers = hs;
2525 : }
2526 0 : ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
2527 : GNUNET_YES);
2528 0 : ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
2529 : GNUNET_NO /* MUST be NO! */);
2530 0 : ksh->auditors = json_array ();
2531 0 : GNUNET_assert (NULL != ksh->auditors);
2532 : /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
2533 0 : GNUNET_break (GNUNET_OK ==
2534 : TEH_plugin->preflight (TEH_plugin->cls));
2535 0 : if (NULL != ksh->global_fees)
2536 0 : json_decref (ksh->global_fees);
2537 0 : ksh->global_fees = json_array ();
2538 0 : qs = TEH_plugin->get_global_fees (TEH_plugin->cls,
2539 : &global_fee_info_cb,
2540 : ksh);
2541 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2542 : "Loading global fees from DB: %d\n",
2543 : qs);
2544 0 : if (qs < 0)
2545 : {
2546 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
2547 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
2548 0 : destroy_key_state (ksh,
2549 : true);
2550 0 : return NULL;
2551 : }
2552 0 : qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
2553 : &denomination_info_cb,
2554 : ksh);
2555 0 : if (qs < 0)
2556 : {
2557 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
2558 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
2559 0 : destroy_key_state (ksh,
2560 : true);
2561 0 : return NULL;
2562 : }
2563 : /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
2564 0 : qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
2565 : &signkey_info_cb,
2566 : ksh);
2567 0 : if (qs < 0)
2568 : {
2569 0 : GNUNET_break (0);
2570 0 : destroy_key_state (ksh,
2571 : true);
2572 0 : return NULL;
2573 : }
2574 0 : qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
2575 : &auditor_denom_cb,
2576 : ksh);
2577 0 : if (qs < 0)
2578 : {
2579 0 : GNUNET_break (0);
2580 0 : destroy_key_state (ksh,
2581 : true);
2582 0 : return NULL;
2583 : }
2584 0 : qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
2585 : &auditor_info_cb,
2586 : ksh);
2587 0 : if (qs < 0)
2588 : {
2589 0 : GNUNET_break (0);
2590 0 : destroy_key_state (ksh,
2591 : true);
2592 0 : return NULL;
2593 : }
2594 :
2595 0 : if (management_only)
2596 : {
2597 0 : ksh->management_only = true;
2598 0 : return ksh;
2599 : }
2600 :
2601 0 : if (GNUNET_OK !=
2602 0 : finish_keys_response (ksh))
2603 : {
2604 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2605 : "Could not finish /keys response (likely no signing keys available yet)\n");
2606 0 : destroy_key_state (ksh,
2607 : true);
2608 0 : return NULL;
2609 : }
2610 :
2611 0 : return ksh;
2612 : }
2613 :
2614 :
2615 : void
2616 0 : TEH_keys_update_states ()
2617 : {
2618 0 : struct GNUNET_DB_EventHeaderP es = {
2619 0 : .size = htons (sizeof (es)),
2620 0 : .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
2621 : };
2622 :
2623 0 : TEH_plugin->event_notify (TEH_plugin->cls,
2624 : &es,
2625 : NULL,
2626 : 0);
2627 0 : key_generation++;
2628 0 : TEH_resume_keys_requests (false);
2629 0 : }
2630 :
2631 :
2632 : struct TEH_KeyStateHandle *
2633 0 : TEH_keys_get_state2 (bool management_only)
2634 : {
2635 : struct TEH_KeyStateHandle *old_ksh;
2636 : struct TEH_KeyStateHandle *ksh;
2637 :
2638 0 : old_ksh = key_state;
2639 0 : if (NULL == old_ksh)
2640 : {
2641 0 : ksh = build_key_state (NULL,
2642 : management_only);
2643 0 : if (NULL == ksh)
2644 0 : return NULL;
2645 0 : key_state = ksh;
2646 0 : return ksh;
2647 : }
2648 0 : if ( (old_ksh->key_generation < key_generation) ||
2649 0 : (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) )
2650 : {
2651 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2652 : "Rebuilding /keys, generation upgrade from %llu to %llu\n",
2653 : (unsigned long long) old_ksh->key_generation,
2654 : (unsigned long long) key_generation);
2655 0 : ksh = build_key_state (old_ksh->helpers,
2656 : management_only);
2657 0 : key_state = ksh;
2658 0 : old_ksh->helpers = NULL;
2659 0 : destroy_key_state (old_ksh,
2660 : false);
2661 0 : return ksh;
2662 : }
2663 0 : sync_key_helpers (old_ksh->helpers);
2664 0 : return old_ksh;
2665 : }
2666 :
2667 :
2668 : struct TEH_KeyStateHandle *
2669 0 : TEH_keys_get_state (void)
2670 : {
2671 : struct TEH_KeyStateHandle *ksh;
2672 :
2673 0 : ksh = TEH_keys_get_state2 (false);
2674 0 : if (NULL == ksh)
2675 0 : return NULL;
2676 0 : if (ksh->management_only)
2677 : {
2678 0 : if (GNUNET_OK !=
2679 0 : finish_keys_response (ksh))
2680 0 : return NULL;
2681 : }
2682 0 : return ksh;
2683 : }
2684 :
2685 :
2686 : const struct TEH_GlobalFee *
2687 0 : TEH_keys_global_fee_by_time (
2688 : struct TEH_KeyStateHandle *ksh,
2689 : struct GNUNET_TIME_Timestamp ts)
2690 : {
2691 0 : for (const struct TEH_GlobalFee *gf = ksh->gf_head;
2692 : NULL != gf;
2693 0 : gf = gf->next)
2694 : {
2695 0 : if (GNUNET_TIME_timestamp_cmp (ts,
2696 : >=,
2697 0 : gf->start_date) &&
2698 0 : GNUNET_TIME_timestamp_cmp (ts,
2699 : <,
2700 : gf->end_date))
2701 0 : return gf;
2702 : }
2703 0 : return NULL;
2704 : }
2705 :
2706 :
2707 : struct TEH_DenominationKey *
2708 0 : TEH_keys_denomination_by_hash (
2709 : const struct TALER_DenominationHashP *h_denom_pub,
2710 : struct MHD_Connection *conn,
2711 : MHD_RESULT *mret)
2712 : {
2713 : struct TEH_KeyStateHandle *ksh;
2714 :
2715 0 : ksh = TEH_keys_get_state ();
2716 0 : if (NULL == ksh)
2717 : {
2718 0 : *mret = TALER_MHD_reply_with_error (conn,
2719 : MHD_HTTP_INTERNAL_SERVER_ERROR,
2720 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
2721 : NULL);
2722 0 : return NULL;
2723 : }
2724 0 : return TEH_keys_denomination_by_hash2 (ksh,
2725 : h_denom_pub,
2726 : conn,
2727 : mret);
2728 : }
2729 :
2730 :
2731 : struct TEH_DenominationKey *
2732 0 : TEH_keys_denomination_by_hash2 (
2733 : struct TEH_KeyStateHandle *ksh,
2734 : const struct TALER_DenominationHashP *h_denom_pub,
2735 : struct MHD_Connection *conn,
2736 : MHD_RESULT *mret)
2737 : {
2738 : struct TEH_DenominationKey *dk;
2739 :
2740 0 : dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
2741 : &h_denom_pub->hash);
2742 0 : if (NULL == dk)
2743 : {
2744 0 : if (NULL == conn)
2745 0 : return NULL;
2746 0 : *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
2747 : h_denom_pub);
2748 0 : return NULL;
2749 : }
2750 0 : return dk;
2751 : }
2752 :
2753 :
2754 : enum TALER_ErrorCode
2755 0 : TEH_keys_denomination_sign_withdraw (
2756 : const struct TALER_DenominationHashP *h_denom_pub,
2757 : const struct TALER_BlindedPlanchet *bp,
2758 : struct TALER_BlindedDenominationSignature *bs)
2759 : {
2760 : struct TEH_KeyStateHandle *ksh;
2761 : struct HelperDenomination *hd;
2762 :
2763 0 : ksh = TEH_keys_get_state ();
2764 0 : if (NULL == ksh)
2765 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
2766 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
2767 : &h_denom_pub->hash);
2768 0 : if (NULL == hd)
2769 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
2770 0 : if (bp->cipher != hd->denom_pub.cipher)
2771 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
2772 0 : switch (hd->denom_pub.cipher)
2773 : {
2774 0 : case TALER_DENOMINATION_RSA:
2775 0 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
2776 : {
2777 0 : struct TALER_CRYPTO_RsaSignRequest rsr = {
2778 0 : .h_rsa = &hd->h_details.h_rsa,
2779 0 : .msg = bp->details.rsa_blinded_planchet.blinded_msg,
2780 0 : .msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size
2781 : };
2782 :
2783 0 : return TALER_CRYPTO_helper_rsa_sign (
2784 0 : ksh->helpers->rsadh,
2785 : &rsr,
2786 : bs);
2787 : }
2788 0 : case TALER_DENOMINATION_CS:
2789 0 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
2790 0 : return TALER_CRYPTO_helper_cs_sign_withdraw (
2791 0 : ksh->helpers->csdh,
2792 0 : &hd->h_details.h_cs,
2793 : &bp->details.cs_blinded_planchet,
2794 : bs);
2795 0 : default:
2796 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
2797 : }
2798 : }
2799 :
2800 :
2801 : enum TALER_ErrorCode
2802 0 : TEH_keys_denomination_sign_melt (
2803 : const struct TALER_DenominationHashP *h_denom_pub,
2804 : const struct TALER_BlindedPlanchet *bp,
2805 : struct TALER_BlindedDenominationSignature *bs)
2806 : {
2807 : struct TEH_KeyStateHandle *ksh;
2808 : struct HelperDenomination *hd;
2809 :
2810 0 : ksh = TEH_keys_get_state ();
2811 0 : if (NULL == ksh)
2812 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
2813 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
2814 : &h_denom_pub->hash);
2815 0 : if (NULL == hd)
2816 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
2817 0 : if (bp->cipher != hd->denom_pub.cipher)
2818 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
2819 0 : switch (hd->denom_pub.cipher)
2820 : {
2821 0 : case TALER_DENOMINATION_RSA:
2822 0 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
2823 : {
2824 0 : struct TALER_CRYPTO_RsaSignRequest rsr = {
2825 0 : .h_rsa = &hd->h_details.h_rsa,
2826 0 : .msg = bp->details.rsa_blinded_planchet.blinded_msg,
2827 0 : .msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size
2828 : };
2829 :
2830 0 : return TALER_CRYPTO_helper_rsa_sign (
2831 0 : ksh->helpers->rsadh,
2832 : &rsr,
2833 : bs);
2834 : }
2835 0 : case TALER_DENOMINATION_CS:
2836 0 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
2837 0 : return TALER_CRYPTO_helper_cs_sign_melt (
2838 0 : ksh->helpers->csdh,
2839 0 : &hd->h_details.h_cs,
2840 : &bp->details.cs_blinded_planchet,
2841 : bs);
2842 0 : default:
2843 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
2844 : }
2845 : }
2846 :
2847 :
2848 : enum TALER_ErrorCode
2849 0 : TEH_keys_denomination_cs_r_pub_melt (
2850 : const struct TALER_DenominationHashP *h_denom_pub,
2851 : const struct TALER_CsNonce *nonce,
2852 : struct TALER_DenominationCSPublicRPairP *r_pub)
2853 : {
2854 : struct TEH_KeyStateHandle *ksh;
2855 : struct HelperDenomination *hd;
2856 :
2857 0 : ksh = TEH_keys_get_state ();
2858 0 : if (NULL == ksh)
2859 : {
2860 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
2861 : }
2862 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
2863 : &h_denom_pub->hash);
2864 0 : if (NULL == hd)
2865 : {
2866 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
2867 : }
2868 0 : if (TALER_DENOMINATION_CS != hd->denom_pub.cipher)
2869 : {
2870 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
2871 : }
2872 :
2873 0 : return TALER_CRYPTO_helper_cs_r_derive_melt (ksh->helpers->csdh,
2874 0 : &hd->h_details.h_cs,
2875 : nonce,
2876 : r_pub);
2877 : }
2878 :
2879 :
2880 : enum TALER_ErrorCode
2881 0 : TEH_keys_denomination_cs_r_pub_withdraw (
2882 : const struct TALER_DenominationHashP *h_denom_pub,
2883 : const struct TALER_CsNonce *nonce,
2884 : struct TALER_DenominationCSPublicRPairP *r_pub)
2885 : {
2886 : struct TEH_KeyStateHandle *ksh;
2887 : struct HelperDenomination *hd;
2888 :
2889 0 : ksh = TEH_keys_get_state ();
2890 0 : if (NULL == ksh)
2891 : {
2892 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
2893 : }
2894 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
2895 : &h_denom_pub->hash);
2896 0 : if (NULL == hd)
2897 : {
2898 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
2899 : }
2900 0 : if (TALER_DENOMINATION_CS != hd->denom_pub.cipher)
2901 : {
2902 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
2903 : }
2904 :
2905 0 : return TALER_CRYPTO_helper_cs_r_derive_withdraw (ksh->helpers->csdh,
2906 0 : &hd->h_details.h_cs,
2907 : nonce,
2908 : r_pub);
2909 : }
2910 :
2911 :
2912 : void
2913 0 : TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub)
2914 : {
2915 : struct TEH_KeyStateHandle *ksh;
2916 : struct HelperDenomination *hd;
2917 :
2918 0 : ksh = TEH_keys_get_state ();
2919 0 : if (NULL == ksh)
2920 : {
2921 0 : GNUNET_break (0);
2922 0 : return;
2923 : }
2924 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
2925 : &h_denom_pub->hash);
2926 0 : if (NULL == hd)
2927 : {
2928 0 : GNUNET_break (0);
2929 0 : return;
2930 : }
2931 0 : switch (hd->denom_pub.cipher)
2932 : {
2933 0 : case TALER_DENOMINATION_RSA:
2934 0 : TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh,
2935 0 : &hd->h_details.h_rsa);
2936 0 : TEH_keys_update_states ();
2937 0 : return;
2938 0 : case TALER_DENOMINATION_CS:
2939 0 : TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh,
2940 0 : &hd->h_details.h_cs);
2941 0 : TEH_keys_update_states ();
2942 0 : return;
2943 0 : default:
2944 0 : GNUNET_break (0);
2945 0 : return;
2946 : }
2947 : }
2948 :
2949 :
2950 : enum TALER_ErrorCode
2951 0 : TEH_keys_exchange_sign_ (
2952 : const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
2953 : struct TALER_ExchangePublicKeyP *pub,
2954 : struct TALER_ExchangeSignatureP *sig)
2955 : {
2956 : struct TEH_KeyStateHandle *ksh;
2957 :
2958 0 : ksh = TEH_keys_get_state ();
2959 0 : if (NULL == ksh)
2960 : {
2961 : /* This *can* happen if the exchange's crypto helper is not running
2962 : or had some bad error. */
2963 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2964 : "Cannot sign request, no valid signing keys available.\n");
2965 0 : return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
2966 : }
2967 0 : return TEH_keys_exchange_sign2_ (ksh,
2968 : purpose,
2969 : pub,
2970 : sig);
2971 : }
2972 :
2973 :
2974 : enum TALER_ErrorCode
2975 0 : TEH_keys_exchange_sign2_ (
2976 : void *cls,
2977 : const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
2978 : struct TALER_ExchangePublicKeyP *pub,
2979 : struct TALER_ExchangeSignatureP *sig)
2980 : {
2981 0 : struct TEH_KeyStateHandle *ksh = cls;
2982 : enum TALER_ErrorCode ec;
2983 :
2984 0 : TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_EDDSA]++;
2985 0 : ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh,
2986 : purpose,
2987 : pub,
2988 : sig);
2989 0 : if (TALER_EC_NONE != ec)
2990 0 : return ec;
2991 : {
2992 : /* Here we check here that 'pub' is set to an exchange public key that is
2993 : actually signed by the master key! Otherwise, we happily continue to
2994 : use key material even if the offline signatures have not been made
2995 : yet! */
2996 : struct GNUNET_PeerIdentity pid;
2997 : struct SigningKey *sk;
2998 :
2999 0 : pid.public_key = pub->eddsa_pub;
3000 0 : sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map,
3001 : &pid);
3002 0 : if (NULL == sk)
3003 : {
3004 : /* just to be safe, zero out the (valid) signature, as the key
3005 : should not or no longer be used */
3006 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3007 : "Cannot sign, offline key signatures are missing!\n");
3008 0 : memset (sig,
3009 : 0,
3010 : sizeof (*sig));
3011 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
3012 : }
3013 : }
3014 0 : return ec;
3015 : }
3016 :
3017 :
3018 : void
3019 0 : TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
3020 : {
3021 : struct TEH_KeyStateHandle *ksh;
3022 :
3023 0 : ksh = TEH_keys_get_state ();
3024 0 : if (NULL == ksh)
3025 : {
3026 0 : GNUNET_break (0);
3027 0 : return;
3028 : }
3029 0 : TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh,
3030 : exchange_pub);
3031 0 : TEH_keys_update_states ();
3032 : }
3033 :
3034 :
3035 : /**
3036 : * Comparator used for a binary search by cherry_pick_date for @a key in the
3037 : * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
3038 : *
3039 : * @param key pointer to a `struct GNUNET_TIME_Timestamp`
3040 : * @param value pointer to a `struct KeysResponseData` array entry
3041 : * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
3042 : */
3043 : static int
3044 0 : krd_search_comparator (const void *key,
3045 : const void *value)
3046 : {
3047 0 : const struct GNUNET_TIME_Timestamp *kd = key;
3048 0 : const struct KeysResponseData *krd = value;
3049 :
3050 0 : if (GNUNET_TIME_timestamp_cmp (*kd,
3051 : >,
3052 : krd->cherry_pick_date))
3053 0 : return -1;
3054 0 : if (GNUNET_TIME_timestamp_cmp (*kd,
3055 : <,
3056 : krd->cherry_pick_date))
3057 0 : return 1;
3058 0 : return 0;
3059 : }
3060 :
3061 :
3062 : MHD_RESULT
3063 0 : TEH_keys_get_handler (struct TEH_RequestContext *rc,
3064 : const char *const args[])
3065 : {
3066 : struct GNUNET_TIME_Timestamp last_issue_date;
3067 : const char *etag;
3068 :
3069 0 : etag = MHD_lookup_connection_value (rc->connection,
3070 : MHD_HEADER_KIND,
3071 : MHD_HTTP_HEADER_IF_NONE_MATCH);
3072 : (void) args;
3073 : {
3074 : const char *have_cherrypick;
3075 :
3076 0 : have_cherrypick = MHD_lookup_connection_value (rc->connection,
3077 : MHD_GET_ARGUMENT_KIND,
3078 : "last_issue_date");
3079 0 : if (NULL != have_cherrypick)
3080 : {
3081 : unsigned long long cherrypickn;
3082 :
3083 0 : if (1 !=
3084 0 : sscanf (have_cherrypick,
3085 : "%llu",
3086 : &cherrypickn))
3087 : {
3088 0 : GNUNET_break_op (0);
3089 0 : return TALER_MHD_reply_with_error (rc->connection,
3090 : MHD_HTTP_BAD_REQUEST,
3091 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
3092 : have_cherrypick);
3093 : }
3094 : /* The following multiplication may overflow; but this should not really
3095 : be a problem, as giving back 'older' data than what the client asks for
3096 : (given that the client asks for data in the distant future) is not
3097 : problematic */
3098 0 : last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn);
3099 : }
3100 : else
3101 : {
3102 0 : last_issue_date = GNUNET_TIME_UNIT_ZERO_TS;
3103 : }
3104 : }
3105 :
3106 : {
3107 : struct TEH_KeyStateHandle *ksh;
3108 : const struct KeysResponseData *krd;
3109 :
3110 0 : ksh = TEH_keys_get_state ();
3111 0 : if (NULL == ksh)
3112 : {
3113 0 : if ( ( (SKR_LIMIT == skr_size) &&
3114 0 : (rc->connection == skr_connection) ) ||
3115 : TEH_suicide)
3116 : {
3117 0 : return TALER_MHD_reply_with_error (
3118 : rc->connection,
3119 : MHD_HTTP_SERVICE_UNAVAILABLE,
3120 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
3121 : TEH_suicide
3122 0 : ? "server terminating"
3123 : : "too many connections suspended waiting on /keys");
3124 : }
3125 0 : return suspend_request (rc->connection);
3126 : }
3127 0 : krd = bsearch (&last_issue_date,
3128 0 : ksh->krd_array,
3129 0 : ksh->krd_array_length,
3130 : sizeof (struct KeysResponseData),
3131 : &krd_search_comparator);
3132 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3133 : "Filtering /keys by cherry pick date %s found entry %u/%u\n",
3134 : GNUNET_TIME_timestamp2s (last_issue_date),
3135 : (unsigned int) (krd - ksh->krd_array),
3136 : ksh->krd_array_length);
3137 0 : if ( (NULL == krd) &&
3138 0 : (ksh->krd_array_length > 0) )
3139 : {
3140 0 : if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time))
3141 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3142 : "Client provided invalid cherry picking timestamp %s, returning full response\n",
3143 : GNUNET_TIME_timestamp2s (last_issue_date));
3144 0 : krd = &ksh->krd_array[ksh->krd_array_length - 1];
3145 : }
3146 0 : if (NULL == krd)
3147 : {
3148 : /* Likely keys not ready *yet*.
3149 : Wait until they are. */
3150 0 : return suspend_request (rc->connection);
3151 : }
3152 0 : if ( (NULL != etag) &&
3153 0 : (0 == strcmp (etag,
3154 0 : krd->etag)) )
3155 : {
3156 : MHD_RESULT ret;
3157 : struct MHD_Response *resp;
3158 :
3159 0 : resp = MHD_create_response_from_buffer (0,
3160 : NULL,
3161 : MHD_RESPMEM_PERSISTENT);
3162 0 : TALER_MHD_add_global_headers (resp);
3163 0 : GNUNET_break (GNUNET_OK ==
3164 : setup_general_response_headers (ksh,
3165 : resp));
3166 0 : GNUNET_break (MHD_YES ==
3167 : MHD_add_response_header (resp,
3168 : MHD_HTTP_HEADER_ETAG,
3169 : krd->etag));
3170 0 : ret = MHD_queue_response (rc->connection,
3171 : MHD_HTTP_NOT_MODIFIED,
3172 : resp);
3173 0 : GNUNET_break (MHD_YES == ret);
3174 0 : MHD_destroy_response (resp);
3175 0 : return ret;
3176 : }
3177 0 : return MHD_queue_response (rc->connection,
3178 : MHD_HTTP_OK,
3179 : (MHD_YES ==
3180 0 : TALER_MHD_can_compress (rc->connection))
3181 : ? krd->response_compressed
3182 : : krd->response_uncompressed);
3183 : }
3184 : }
3185 :
3186 :
3187 : /**
3188 : * Load extension data, like fees, expiration times (!) and age restriction
3189 : * flags for the denomination type configured in section @a section_name.
3190 : * Before calling this function, the `start` and `validity_duration` times must
3191 : * already be initialized in @a meta.
3192 : *
3193 : * @param section_name section in the configuration to use
3194 : * @param[in,out] meta denomination type data to complete
3195 : * @return #GNUNET_OK on success
3196 : */
3197 : static enum GNUNET_GenericReturnValue
3198 0 : load_extension_data (const char *section_name,
3199 : struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
3200 : {
3201 : struct GNUNET_TIME_Relative deposit_duration;
3202 : struct GNUNET_TIME_Relative legal_duration;
3203 :
3204 0 : GNUNET_assert (! GNUNET_TIME_absolute_is_zero (meta->start.abs_time)); /* caller bug */
3205 0 : if (GNUNET_OK !=
3206 0 : GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
3207 : section_name,
3208 : "DURATION_SPEND",
3209 : &deposit_duration))
3210 : {
3211 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3212 : section_name,
3213 : "DURATION_SPEND");
3214 0 : return GNUNET_SYSERR;
3215 : }
3216 0 : if (GNUNET_OK !=
3217 0 : GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
3218 : section_name,
3219 : "DURATION_LEGAL",
3220 : &legal_duration))
3221 : {
3222 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3223 : section_name,
3224 : "DURATION_LEGAL");
3225 0 : return GNUNET_SYSERR;
3226 : }
3227 : meta->expire_deposit
3228 0 : = GNUNET_TIME_absolute_to_timestamp (
3229 : GNUNET_TIME_absolute_add (meta->expire_withdraw.abs_time,
3230 : deposit_duration));
3231 0 : meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
3232 : GNUNET_TIME_absolute_add (meta->expire_deposit.abs_time,
3233 : legal_duration));
3234 0 : if (GNUNET_OK !=
3235 0 : TALER_config_get_amount (TEH_cfg,
3236 : section_name,
3237 : "VALUE",
3238 : &meta->value))
3239 : {
3240 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3241 : "Need amount for option `%s' in section `%s'\n",
3242 : "VALUE",
3243 : section_name);
3244 0 : return GNUNET_SYSERR;
3245 : }
3246 0 : if (0 != strcasecmp (TEH_currency,
3247 0 : meta->value.currency))
3248 : {
3249 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3250 : "Need denomination value in section `%s' to use currency `%s'\n",
3251 : section_name,
3252 : TEH_currency);
3253 0 : return GNUNET_SYSERR;
3254 : }
3255 0 : if (GNUNET_OK !=
3256 0 : TALER_config_get_denom_fees (TEH_cfg,
3257 : TEH_currency,
3258 : section_name,
3259 : &meta->fees))
3260 0 : return GNUNET_SYSERR;
3261 0 : meta->age_mask = load_age_mask (section_name);
3262 0 : return GNUNET_OK;
3263 : }
3264 :
3265 :
3266 : enum GNUNET_GenericReturnValue
3267 0 : TEH_keys_load_fees (struct TEH_KeyStateHandle *ksh,
3268 : const struct TALER_DenominationHashP *h_denom_pub,
3269 : struct TALER_DenominationPublicKey *denom_pub,
3270 : struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
3271 : {
3272 : struct HelperDenomination *hd;
3273 : enum GNUNET_GenericReturnValue ok;
3274 :
3275 0 : hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
3276 : &h_denom_pub->hash);
3277 0 : if (NULL == hd)
3278 : {
3279 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3280 : "Denomination %s not known\n",
3281 : GNUNET_h2s (&h_denom_pub->hash));
3282 0 : return GNUNET_NO;
3283 : }
3284 0 : meta->start = hd->start_time;
3285 0 : meta->expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
3286 : GNUNET_TIME_absolute_add (meta->start.abs_time,
3287 : hd->validity_duration));
3288 0 : ok = load_extension_data (hd->section_name,
3289 : meta);
3290 0 : if (GNUNET_OK == ok)
3291 : {
3292 0 : GNUNET_assert (TALER_DENOMINATION_INVALID != hd->denom_pub.cipher);
3293 0 : TALER_denom_pub_deep_copy (denom_pub,
3294 0 : &hd->denom_pub);
3295 : }
3296 : else
3297 : {
3298 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3299 : "No fees for `%s', voiding key\n",
3300 : hd->section_name);
3301 0 : memset (denom_pub,
3302 : 0,
3303 : sizeof (*denom_pub));
3304 : }
3305 0 : return ok;
3306 : }
3307 :
3308 :
3309 : enum GNUNET_GenericReturnValue
3310 0 : TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
3311 : struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
3312 : {
3313 : struct TEH_KeyStateHandle *ksh;
3314 : struct HelperSignkey *hsk;
3315 : struct GNUNET_PeerIdentity pid;
3316 :
3317 0 : ksh = TEH_keys_get_state2 (true);
3318 0 : if (NULL == ksh)
3319 : {
3320 0 : GNUNET_break (0);
3321 0 : return GNUNET_SYSERR;
3322 : }
3323 :
3324 0 : pid.public_key = exchange_pub->eddsa_pub;
3325 0 : hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys,
3326 : &pid);
3327 0 : meta->start = hsk->start_time;
3328 :
3329 0 : meta->expire_sign = GNUNET_TIME_absolute_to_timestamp (
3330 : GNUNET_TIME_absolute_add (meta->start.abs_time,
3331 : hsk->validity_duration));
3332 0 : meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
3333 : GNUNET_TIME_absolute_add (meta->expire_sign.abs_time,
3334 : signkey_legal_duration));
3335 0 : return GNUNET_OK;
3336 : }
3337 :
3338 :
3339 : /**
3340 : * Closure for #add_future_denomkey_cb and #add_future_signkey_cb.
3341 : */
3342 : struct FutureBuilderContext
3343 : {
3344 : /**
3345 : * Our key state.
3346 : */
3347 : struct TEH_KeyStateHandle *ksh;
3348 :
3349 : /**
3350 : * Array of denomination keys.
3351 : */
3352 : json_t *denoms;
3353 :
3354 : /**
3355 : * Array of signing keys.
3356 : */
3357 : json_t *signkeys;
3358 :
3359 : };
3360 :
3361 :
3362 : /**
3363 : * Function called on all of our current and future denomination keys
3364 : * known to the helper process. Filters out those that are current
3365 : * and adds the remaining denomination keys (with their configuration
3366 : * data) to the JSON array.
3367 : *
3368 : * @param cls the `struct FutureBuilderContext *`
3369 : * @param h_denom_pub hash of the denomination public key
3370 : * @param value a `struct HelperDenomination`
3371 : * @return #GNUNET_OK (continue to iterate)
3372 : */
3373 : static enum GNUNET_GenericReturnValue
3374 0 : add_future_denomkey_cb (void *cls,
3375 : const struct GNUNET_HashCode *h_denom_pub,
3376 : void *value)
3377 : {
3378 0 : struct FutureBuilderContext *fbc = cls;
3379 0 : struct HelperDenomination *hd = value;
3380 : struct TEH_DenominationKey *dk;
3381 0 : struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
3382 :
3383 0 : dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
3384 : h_denom_pub);
3385 0 : if (NULL != dk)
3386 0 : return GNUNET_OK; /* skip: this key is already active! */
3387 0 : if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
3388 0 : return GNUNET_OK; /* this key already expired! */
3389 0 : meta.start = hd->start_time;
3390 0 : meta.expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
3391 : GNUNET_TIME_absolute_add (meta.start.abs_time,
3392 : hd->validity_duration));
3393 0 : if (GNUNET_OK !=
3394 0 : load_extension_data (hd->section_name,
3395 : &meta))
3396 : {
3397 : /* Woops, couldn't determine fee structure!? */
3398 0 : return GNUNET_OK;
3399 : }
3400 0 : GNUNET_assert (
3401 : 0 ==
3402 : json_array_append_new (
3403 : fbc->denoms,
3404 : GNUNET_JSON_PACK (
3405 : TALER_JSON_pack_amount ("value",
3406 : &meta.value),
3407 : GNUNET_JSON_pack_timestamp ("stamp_start",
3408 : meta.start),
3409 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
3410 : meta.expire_withdraw),
3411 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
3412 : meta.expire_deposit),
3413 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
3414 : meta.expire_legal),
3415 : TALER_JSON_pack_denom_pub ("denom_pub",
3416 : &hd->denom_pub),
3417 : TALER_JSON_PACK_DENOM_FEES ("fee",
3418 : &meta.fees),
3419 : GNUNET_JSON_pack_data_auto ("denom_secmod_sig",
3420 : &hd->sm_sig),
3421 : GNUNET_JSON_pack_string ("section_name",
3422 : hd->section_name))));
3423 0 : return GNUNET_OK;
3424 : }
3425 :
3426 :
3427 : /**
3428 : * Function called on all of our current and future exchange signing keys
3429 : * known to the helper process. Filters out those that are current
3430 : * and adds the remaining signing keys (with their configuration
3431 : * data) to the JSON array.
3432 : *
3433 : * @param cls the `struct FutureBuilderContext *`
3434 : * @param pid actually the exchange public key (type disguised)
3435 : * @param value a `struct HelperDenomination`
3436 : * @return #GNUNET_OK (continue to iterate)
3437 : */
3438 : static enum GNUNET_GenericReturnValue
3439 0 : add_future_signkey_cb (void *cls,
3440 : const struct GNUNET_PeerIdentity *pid,
3441 : void *value)
3442 : {
3443 0 : struct FutureBuilderContext *fbc = cls;
3444 0 : struct HelperSignkey *hsk = value;
3445 : struct SigningKey *sk;
3446 : struct GNUNET_TIME_Timestamp stamp_expire;
3447 : struct GNUNET_TIME_Timestamp legal_end;
3448 :
3449 0 : sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
3450 : pid);
3451 0 : if (NULL != sk)
3452 0 : return GNUNET_OK; /* skip: this key is already active */
3453 0 : if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
3454 0 : return GNUNET_OK; /* this key already expired! */
3455 0 : stamp_expire = GNUNET_TIME_absolute_to_timestamp (
3456 : GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
3457 : hsk->validity_duration));
3458 0 : legal_end = GNUNET_TIME_absolute_to_timestamp (
3459 : GNUNET_TIME_absolute_add (stamp_expire.abs_time,
3460 : signkey_legal_duration));
3461 0 : GNUNET_assert (0 ==
3462 : json_array_append_new (
3463 : fbc->signkeys,
3464 : GNUNET_JSON_PACK (
3465 : GNUNET_JSON_pack_data_auto ("key",
3466 : &hsk->exchange_pub),
3467 : GNUNET_JSON_pack_timestamp ("stamp_start",
3468 : hsk->start_time),
3469 : GNUNET_JSON_pack_timestamp ("stamp_expire",
3470 : stamp_expire),
3471 : GNUNET_JSON_pack_timestamp ("stamp_end",
3472 : legal_end),
3473 : GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
3474 : &hsk->sm_sig))));
3475 0 : return GNUNET_OK;
3476 : }
3477 :
3478 :
3479 : MHD_RESULT
3480 0 : TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
3481 : struct MHD_Connection *connection)
3482 : {
3483 : struct TEH_KeyStateHandle *ksh;
3484 : json_t *reply;
3485 :
3486 : (void) rh;
3487 0 : ksh = TEH_keys_get_state2 (true);
3488 0 : if (NULL == ksh)
3489 : {
3490 0 : return TALER_MHD_reply_with_error (connection,
3491 : MHD_HTTP_SERVICE_UNAVAILABLE,
3492 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
3493 : "no key state");
3494 : }
3495 0 : sync_key_helpers (ksh->helpers);
3496 0 : if (NULL == ksh->management_keys_reply)
3497 : {
3498 0 : struct FutureBuilderContext fbc = {
3499 : .ksh = ksh,
3500 0 : .denoms = json_array (),
3501 0 : .signkeys = json_array ()
3502 : };
3503 :
3504 0 : if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) &&
3505 0 : (GNUNET_is_zero (&denom_cs_sm_pub)) )
3506 : {
3507 0 : return TALER_MHD_reply_with_error (connection,
3508 : MHD_HTTP_BAD_GATEWAY,
3509 : TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
3510 : NULL);
3511 : }
3512 0 : if (GNUNET_is_zero (&esign_sm_pub))
3513 : {
3514 0 : return TALER_MHD_reply_with_error (connection,
3515 : MHD_HTTP_BAD_GATEWAY,
3516 : TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
3517 : NULL);
3518 : }
3519 : // then a secmod helper is not yet running and we should return an MHD_HTTP_BAD_GATEWAY!
3520 0 : GNUNET_assert (NULL != fbc.denoms);
3521 0 : GNUNET_assert (NULL != fbc.signkeys);
3522 0 : GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
3523 : &add_future_denomkey_cb,
3524 : &fbc);
3525 0 : GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
3526 : &add_future_signkey_cb,
3527 : &fbc);
3528 0 : reply = GNUNET_JSON_PACK (
3529 : GNUNET_JSON_pack_array_steal ("future_denoms",
3530 : fbc.denoms),
3531 : GNUNET_JSON_pack_array_steal ("future_signkeys",
3532 : fbc.signkeys),
3533 : GNUNET_JSON_pack_data_auto ("master_pub",
3534 : &TEH_master_public_key),
3535 : GNUNET_JSON_pack_data_auto ("denom_secmod_public_key",
3536 : &denom_rsa_sm_pub),
3537 : GNUNET_JSON_pack_data_auto ("denom_secmod_cs_public_key",
3538 : &denom_cs_sm_pub),
3539 : GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
3540 : &esign_sm_pub));
3541 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3542 : "Returning GET /management/keys response:\n");
3543 0 : if (NULL == reply)
3544 0 : return TALER_MHD_reply_with_error (connection,
3545 : MHD_HTTP_INTERNAL_SERVER_ERROR,
3546 : TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
3547 : NULL);
3548 0 : GNUNET_assert (NULL == ksh->management_keys_reply);
3549 0 : ksh->management_keys_reply = reply;
3550 : }
3551 : else
3552 : {
3553 0 : reply = ksh->management_keys_reply;
3554 : }
3555 0 : return TALER_MHD_reply_json (connection,
3556 : reply,
3557 : MHD_HTTP_OK);
3558 : }
3559 :
3560 :
3561 : /* end of taler-exchange-httpd_keys.c */
|