Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it
6 : under the terms of the GNU General Public License as published
7 : by the Free Software Foundation; either version 3, or (at your
8 : option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 :
20 : /**
21 : * @file lib/exchange_api_handle.c
22 : * @brief Implementation of the "handle" component of the exchange's HTTP API
23 : * @author Sree Harsha Totakura <sreeharsha@totakura.in>
24 : * @author Christian Grothoff
25 : */
26 : #include "platform.h"
27 : #include <microhttpd.h>
28 : #include <gnunet/gnunet_curl_lib.h>
29 : #include "taler_json_lib.h"
30 : #include "taler_exchange_service.h"
31 : #include "taler_auditor_service.h"
32 : #include "taler_signatures.h"
33 : #include "taler_extensions.h"
34 : #include "exchange_api_handle.h"
35 : #include "exchange_api_curl_defaults.h"
36 : #include "backoff.h"
37 : #include "taler_curl_lib.h"
38 :
39 : /**
40 : * Which version of the Taler protocol is implemented
41 : * by this library? Used to determine compatibility.
42 : */
43 : #define EXCHANGE_PROTOCOL_CURRENT 14
44 :
45 : /**
46 : * How many versions are we backwards compatible with?
47 : */
48 : #define EXCHANGE_PROTOCOL_AGE 0
49 :
50 : /**
51 : * Current version for (local) JSON serialization of persisted
52 : * /keys data.
53 : */
54 : #define EXCHANGE_SERIALIZATION_FORMAT_VERSION 0
55 :
56 : /**
57 : * How far off do we allow key liftimes to be?
58 : */
59 : #define LIFETIME_TOLERANCE GNUNET_TIME_UNIT_HOURS
60 :
61 : /**
62 : * If the "Expire" cache control header is missing, for
63 : * how long do we assume the reply to be valid at least?
64 : */
65 : #define DEFAULT_EXPIRATION GNUNET_TIME_UNIT_HOURS
66 :
67 : /**
68 : * Set to 1 for extra debug logging.
69 : */
70 : #define DEBUG 0
71 :
72 : /**
73 : * Log error related to CURL operations.
74 : *
75 : * @param type log level
76 : * @param function which function failed to run
77 : * @param code what was the curl error code
78 : */
79 : #define CURL_STRERROR(type, function, code) \
80 : GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
81 : function, __FILE__, __LINE__, curl_easy_strerror (code));
82 :
83 :
84 : /**
85 : * Data for the request to get the /keys of a exchange.
86 : */
87 : struct KeysRequest;
88 :
89 :
90 : /**
91 : * Entry in DLL of auditors used by an exchange.
92 : */
93 : struct TEAH_AuditorListEntry
94 : {
95 : /**
96 : * Next pointer of DLL.
97 : */
98 : struct TEAH_AuditorListEntry *next;
99 :
100 : /**
101 : * Prev pointer of DLL.
102 : */
103 : struct TEAH_AuditorListEntry *prev;
104 :
105 : /**
106 : * Base URL of the auditor.
107 : */
108 : char *auditor_url;
109 :
110 : /**
111 : * Handle to the auditor.
112 : */
113 : struct TALER_AUDITOR_Handle *ah;
114 :
115 : /**
116 : * Head of DLL of interactions with this auditor.
117 : */
118 : struct TEAH_AuditorInteractionEntry *ai_head;
119 :
120 : /**
121 : * Tail of DLL of interactions with this auditor.
122 : */
123 : struct TEAH_AuditorInteractionEntry *ai_tail;
124 :
125 : /**
126 : * Public key of the auditor.
127 : */
128 : struct TALER_AuditorPublicKeyP auditor_pub;
129 :
130 : /**
131 : * Flag indicating that the auditor is available and that protocol
132 : * version compatibility is given.
133 : */
134 : bool is_up;
135 :
136 : };
137 :
138 :
139 : /* ***************** Internal /keys fetching ************* */
140 :
141 : /**
142 : * Data for the request to get the /keys of a exchange.
143 : */
144 : struct KeysRequest
145 : {
146 : /**
147 : * The connection to exchange this request handle will use
148 : */
149 : struct TALER_EXCHANGE_Handle *exchange;
150 :
151 : /**
152 : * The url for this handle
153 : */
154 : char *url;
155 :
156 : /**
157 : * Entry for this request with the `struct GNUNET_CURL_Context`.
158 : */
159 : struct GNUNET_CURL_Job *job;
160 :
161 : /**
162 : * Expiration time according to "Expire:" header.
163 : * 0 if not provided by the server.
164 : */
165 : struct GNUNET_TIME_Timestamp expire;
166 :
167 : };
168 :
169 :
170 : void
171 0 : TEAH_acc_confirmation_cb (void *cls,
172 : const struct TALER_AUDITOR_HttpResponse *hr)
173 : {
174 0 : struct TEAH_AuditorInteractionEntry *aie = cls;
175 0 : struct TEAH_AuditorListEntry *ale = aie->ale;
176 :
177 0 : if (MHD_HTTP_OK != hr->http_status)
178 : {
179 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
180 : "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n",
181 : ale->auditor_url,
182 : hr->http_status,
183 : hr->ec);
184 : }
185 0 : GNUNET_CONTAINER_DLL_remove (ale->ai_head,
186 : ale->ai_tail,
187 : aie);
188 0 : GNUNET_free (aie);
189 0 : }
190 :
191 :
192 : void
193 0 : TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h,
194 : TEAH_AuditorCallback ac,
195 : void *ac_cls)
196 : {
197 0 : if (NULL == h->auditors_head)
198 : {
199 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
200 : "No auditor available for exchange `%s'. Not submitting deposit confirmations.\n",
201 : h->url);
202 0 : return;
203 : }
204 0 : for (struct TEAH_AuditorListEntry *ale = h->auditors_head;
205 : NULL != ale;
206 0 : ale = ale->next)
207 : {
208 : struct TEAH_AuditorInteractionEntry *aie;
209 :
210 0 : if (! ale->is_up)
211 0 : continue;
212 0 : aie = ac (ac_cls,
213 : ale->ah,
214 0 : &ale->auditor_pub);
215 0 : if (NULL != aie)
216 : {
217 0 : aie->ale = ale;
218 0 : GNUNET_CONTAINER_DLL_insert (ale->ai_head,
219 : ale->ai_tail,
220 : aie);
221 : }
222 : }
223 : }
224 :
225 :
226 : /**
227 : * Release memory occupied by a keys request. Note that this does not
228 : * cancel the request itself.
229 : *
230 : * @param kr request to free
231 : */
232 : static void
233 0 : free_keys_request (struct KeysRequest *kr)
234 : {
235 0 : GNUNET_free (kr->url);
236 0 : GNUNET_free (kr);
237 0 : }
238 :
239 :
240 : #define EXITIF(cond) \
241 : do { \
242 : if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
243 : } while (0)
244 :
245 :
246 : /**
247 : * Parse a exchange's signing key encoded in JSON.
248 : *
249 : * @param[out] sign_key where to return the result
250 : * @param check_sigs should we check signatures?
251 : * @param[in] sign_key_obj json to parse
252 : * @param master_key master key to use to verify signature
253 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
254 : * invalid or the json malformed.
255 : */
256 : static enum GNUNET_GenericReturnValue
257 0 : parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
258 : bool check_sigs,
259 : json_t *sign_key_obj,
260 : const struct TALER_MasterPublicKeyP *master_key)
261 : {
262 : struct TALER_MasterSignatureP sign_key_issue_sig;
263 : struct GNUNET_JSON_Specification spec[] = {
264 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
265 : &sign_key_issue_sig),
266 0 : GNUNET_JSON_spec_fixed_auto ("key",
267 : &sign_key->key),
268 0 : GNUNET_JSON_spec_timestamp ("stamp_start",
269 : &sign_key->valid_from),
270 0 : GNUNET_JSON_spec_timestamp ("stamp_expire",
271 : &sign_key->valid_until),
272 0 : GNUNET_JSON_spec_timestamp ("stamp_end",
273 : &sign_key->valid_legal),
274 0 : GNUNET_JSON_spec_end ()
275 : };
276 :
277 0 : if (GNUNET_OK !=
278 0 : GNUNET_JSON_parse (sign_key_obj,
279 : spec,
280 : NULL, NULL))
281 : {
282 0 : GNUNET_break_op (0);
283 0 : return GNUNET_SYSERR;
284 : }
285 :
286 0 : if (! check_sigs)
287 0 : return GNUNET_OK;
288 0 : if (GNUNET_OK !=
289 0 : TALER_exchange_offline_signkey_validity_verify (
290 0 : &sign_key->key,
291 : sign_key->valid_from,
292 : sign_key->valid_until,
293 : sign_key->valid_legal,
294 : master_key,
295 : &sign_key_issue_sig))
296 : {
297 0 : GNUNET_break_op (0);
298 0 : return GNUNET_SYSERR;
299 : }
300 0 : sign_key->master_sig = sign_key_issue_sig;
301 0 : return GNUNET_OK;
302 : }
303 :
304 :
305 : /**
306 : * Parse a exchange's denomination key encoded in JSON partially.
307 : *
308 : * Only the values for master_sig, timestamps and the cipher-specific public
309 : * key are parsed. All other fields (fees, age_mask, value) MUST have been set
310 : * prior to calling this function, otherwise the signature verification
311 : * performed within this function will fail.
312 : *
313 : * @param[out] denom_key where to return the result
314 : * @param cipher cipher type to parse
315 : * @param check_sigs should we check signatures?
316 : * @param[in] denom_key_obj json to parse
317 : * @param master_key master key to use to verify signature
318 : * @param hash_xor where to accumulate data for signature verification via XOR
319 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
320 : * invalid or the json malformed.
321 : */
322 : static enum GNUNET_GenericReturnValue
323 0 : parse_json_denomkey_partially (
324 : struct TALER_EXCHANGE_DenomPublicKey *denom_key,
325 : enum TALER_DenominationCipher cipher,
326 : bool check_sigs,
327 : json_t *denom_key_obj,
328 : struct TALER_MasterPublicKeyP *master_key,
329 : struct GNUNET_HashCode *hash_xor)
330 : {
331 : struct GNUNET_JSON_Specification spec[] = {
332 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
333 : &denom_key->master_sig),
334 0 : GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
335 : &denom_key->expire_deposit),
336 0 : GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
337 : &denom_key->withdraw_valid_until),
338 0 : GNUNET_JSON_spec_timestamp ("stamp_start",
339 : &denom_key->valid_from),
340 0 : GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
341 : &denom_key->expire_legal),
342 0 : TALER_JSON_spec_denom_pub_cipher (NULL,
343 : cipher,
344 : &denom_key->key),
345 0 : GNUNET_JSON_spec_end ()
346 : };
347 :
348 0 : if (GNUNET_OK !=
349 0 : GNUNET_JSON_parse (denom_key_obj,
350 : spec,
351 : NULL, NULL))
352 : {
353 0 : GNUNET_break_op (0);
354 0 : return GNUNET_SYSERR;
355 : }
356 0 : TALER_denom_pub_hash (&denom_key->key,
357 : &denom_key->h_key);
358 0 : if (NULL != hash_xor)
359 0 : GNUNET_CRYPTO_hash_xor (&denom_key->h_key.hash,
360 : hash_xor,
361 : hash_xor);
362 :
363 0 : if (! check_sigs)
364 0 : return GNUNET_OK;
365 0 : EXITIF (GNUNET_SYSERR ==
366 : TALER_exchange_offline_denom_validity_verify (
367 : &denom_key->h_key,
368 : denom_key->valid_from,
369 : denom_key->withdraw_valid_until,
370 : denom_key->expire_deposit,
371 : denom_key->expire_legal,
372 : &denom_key->value,
373 : &denom_key->fees,
374 : master_key,
375 : &denom_key->master_sig));
376 0 : return GNUNET_OK;
377 0 : EXITIF_exit:
378 : /* invalidate denom_key, just to be sure */
379 0 : memset (denom_key,
380 : 0,
381 : sizeof (*denom_key));
382 0 : GNUNET_JSON_parse_free (spec);
383 0 : return GNUNET_SYSERR;
384 : }
385 :
386 :
387 : /**
388 : * Parse a exchange's auditor information encoded in JSON.
389 : *
390 : * @param[out] auditor where to return the result
391 : * @param check_sigs should we check signatures
392 : * @param[in] auditor_obj json to parse
393 : * @param key_data information about denomination keys
394 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
395 : * invalid or the json malformed.
396 : */
397 : static enum GNUNET_GenericReturnValue
398 0 : parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
399 : bool check_sigs,
400 : json_t *auditor_obj,
401 : const struct TALER_EXCHANGE_Keys *key_data)
402 : {
403 : json_t *keys;
404 : json_t *key;
405 : unsigned int len;
406 : unsigned int off;
407 : unsigned int i;
408 : const char *auditor_url;
409 : struct GNUNET_JSON_Specification spec[] = {
410 0 : GNUNET_JSON_spec_fixed_auto ("auditor_pub",
411 : &auditor->auditor_pub),
412 0 : GNUNET_JSON_spec_string ("auditor_url",
413 : &auditor_url),
414 0 : GNUNET_JSON_spec_json ("denomination_keys",
415 : &keys),
416 0 : GNUNET_JSON_spec_end ()
417 : };
418 :
419 0 : if (GNUNET_OK !=
420 0 : GNUNET_JSON_parse (auditor_obj,
421 : spec,
422 : NULL, NULL))
423 : {
424 0 : GNUNET_break_op (0);
425 : #if DEBUG
426 : json_dumpf (auditor_obj,
427 : stderr,
428 : JSON_INDENT (2));
429 : #endif
430 0 : return GNUNET_SYSERR;
431 : }
432 0 : auditor->auditor_url = GNUNET_strdup (auditor_url);
433 0 : len = json_array_size (keys);
434 0 : auditor->denom_keys = GNUNET_new_array (len,
435 : struct
436 : TALER_EXCHANGE_AuditorDenominationInfo);
437 0 : off = 0;
438 0 : json_array_foreach (keys, i, key) {
439 : struct TALER_AuditorSignatureP auditor_sig;
440 : struct TALER_DenominationHashP denom_h;
441 : const struct TALER_EXCHANGE_DenomPublicKey *dk;
442 : unsigned int dk_off;
443 : struct GNUNET_JSON_Specification kspec[] = {
444 0 : GNUNET_JSON_spec_fixed_auto ("auditor_sig",
445 : &auditor_sig),
446 0 : GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
447 : &denom_h),
448 0 : GNUNET_JSON_spec_end ()
449 : };
450 :
451 0 : if (GNUNET_OK !=
452 0 : GNUNET_JSON_parse (key,
453 : kspec,
454 : NULL, NULL))
455 : {
456 0 : GNUNET_break_op (0);
457 0 : continue;
458 : }
459 0 : dk = NULL;
460 0 : dk_off = UINT_MAX;
461 0 : for (unsigned int j = 0; j<key_data->num_denom_keys; j++)
462 : {
463 0 : if (0 == GNUNET_memcmp (&denom_h,
464 : &key_data->denom_keys[j].h_key))
465 : {
466 0 : dk = &key_data->denom_keys[j];
467 0 : dk_off = j;
468 0 : break;
469 : }
470 : }
471 0 : if (NULL == dk)
472 : {
473 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
474 : "Auditor signed denomination %s, which we do not know. Ignoring signature.\n",
475 : GNUNET_h2s (&denom_h.hash));
476 0 : continue;
477 : }
478 0 : if (check_sigs)
479 : {
480 0 : if (GNUNET_OK !=
481 0 : TALER_auditor_denom_validity_verify (
482 : auditor_url,
483 : &dk->h_key,
484 : &key_data->master_pub,
485 : dk->valid_from,
486 : dk->withdraw_valid_until,
487 : dk->expire_deposit,
488 : dk->expire_legal,
489 : &dk->value,
490 : &dk->fees,
491 0 : &auditor->auditor_pub,
492 : &auditor_sig))
493 : {
494 0 : GNUNET_break_op (0);
495 0 : GNUNET_JSON_parse_free (spec);
496 0 : return GNUNET_SYSERR;
497 : }
498 : }
499 0 : auditor->denom_keys[off].denom_key_offset = dk_off;
500 0 : auditor->denom_keys[off].auditor_sig = auditor_sig;
501 0 : off++;
502 : }
503 0 : auditor->num_denom_keys = off;
504 0 : GNUNET_JSON_parse_free (spec);
505 0 : return GNUNET_OK;
506 : }
507 :
508 :
509 : /**
510 : * Parse a exchange's global fee information encoded in JSON.
511 : *
512 : * @param[out] gf where to return the result
513 : * @param check_sigs should we check signatures
514 : * @param[in] fee_obj json to parse
515 : * @param key_data already parsed information about the exchange
516 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
517 : * invalid or the json malformed.
518 : */
519 : static enum GNUNET_GenericReturnValue
520 0 : parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf,
521 : bool check_sigs,
522 : json_t *fee_obj,
523 : const struct TALER_EXCHANGE_Keys *key_data)
524 : {
525 : struct GNUNET_JSON_Specification spec[] = {
526 0 : GNUNET_JSON_spec_timestamp ("start_date",
527 : &gf->start_date),
528 0 : GNUNET_JSON_spec_timestamp ("end_date",
529 : &gf->end_date),
530 0 : GNUNET_JSON_spec_relative_time ("purse_timeout",
531 : &gf->purse_timeout),
532 0 : GNUNET_JSON_spec_relative_time ("account_kyc_timeout",
533 : &gf->kyc_timeout),
534 0 : GNUNET_JSON_spec_relative_time ("history_expiration",
535 : &gf->history_expiration),
536 0 : GNUNET_JSON_spec_uint32 ("purse_account_limit",
537 : &gf->purse_account_limit),
538 0 : TALER_JSON_SPEC_GLOBAL_FEES (key_data->currency,
539 : &gf->fees),
540 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
541 : &gf->master_sig),
542 0 : GNUNET_JSON_spec_end ()
543 : };
544 :
545 0 : if (GNUNET_OK !=
546 0 : GNUNET_JSON_parse (fee_obj,
547 : spec,
548 : NULL, NULL))
549 : {
550 0 : GNUNET_break_op (0);
551 : #if DEBUG
552 : json_dumpf (fee_obj,
553 : stderr,
554 : JSON_INDENT (2));
555 : #endif
556 0 : return GNUNET_SYSERR;
557 : }
558 0 : if (check_sigs)
559 : {
560 0 : if (GNUNET_OK !=
561 0 : TALER_exchange_offline_global_fee_verify (
562 : gf->start_date,
563 : gf->end_date,
564 0 : &gf->fees,
565 : gf->purse_timeout,
566 : gf->kyc_timeout,
567 : gf->history_expiration,
568 : gf->purse_account_limit,
569 : &key_data->master_pub,
570 0 : &gf->master_sig))
571 : {
572 0 : GNUNET_break_op (0);
573 0 : GNUNET_JSON_parse_free (spec);
574 0 : return GNUNET_SYSERR;
575 : }
576 : }
577 0 : GNUNET_JSON_parse_free (spec);
578 0 : return GNUNET_OK;
579 : }
580 :
581 :
582 : /**
583 : * Function called with information about the auditor. Marks an
584 : * auditor as 'up'.
585 : *
586 : * @param cls closure, a `struct TEAH_AuditorListEntry *`
587 : * @param hr http response from the auditor
588 : * @param vi basic information about the auditor
589 : * @param compat protocol compatibility information
590 : */
591 : static void
592 0 : auditor_version_cb (
593 : void *cls,
594 : const struct TALER_AUDITOR_HttpResponse *hr,
595 : const struct TALER_AUDITOR_VersionInformation *vi,
596 : enum TALER_AUDITOR_VersionCompatibility compat)
597 : {
598 0 : struct TEAH_AuditorListEntry *ale = cls;
599 :
600 : (void) hr;
601 0 : if (NULL == vi)
602 : {
603 : /* In this case, we don't mark the auditor as 'up' */
604 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
605 : "Auditor `%s' gave unexpected version response.\n",
606 : ale->auditor_url);
607 0 : return;
608 : }
609 :
610 0 : if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat))
611 : {
612 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
613 : "Auditor `%s' runs incompatible protocol version!\n",
614 : ale->auditor_url);
615 0 : if (0 != (TALER_AUDITOR_VC_OLDER & compat))
616 : {
617 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
618 : "Auditor `%s' runs outdated protocol version!\n",
619 : ale->auditor_url);
620 : }
621 0 : if (0 != (TALER_AUDITOR_VC_NEWER & compat))
622 : {
623 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
624 : "Auditor `%s' runs more recent incompatible version. We should upgrade!\n",
625 : ale->auditor_url);
626 : }
627 0 : return;
628 : }
629 0 : ale->is_up = true;
630 : }
631 :
632 :
633 : /**
634 : * Recalculate our auditor list, we got /keys and it may have
635 : * changed.
636 : *
637 : * @param exchange exchange for which to update the list.
638 : */
639 : static void
640 0 : update_auditors (struct TALER_EXCHANGE_Handle *exchange)
641 : {
642 0 : struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
643 :
644 0 : TALER_LOG_DEBUG ("Updating auditors\n");
645 0 : for (unsigned int i = 0; i<kd->num_auditors; i++)
646 : {
647 : /* Compare auditor data from /keys with auditor data
648 : * from owned exchange structures. */
649 0 : struct TALER_EXCHANGE_AuditorInformation *auditor = &kd->auditors[i];
650 0 : struct TEAH_AuditorListEntry *ale = NULL;
651 :
652 0 : for (struct TEAH_AuditorListEntry *a = exchange->auditors_head;
653 : NULL != a;
654 0 : a = a->next)
655 : {
656 0 : if (0 == GNUNET_memcmp (&auditor->auditor_pub,
657 : &a->auditor_pub))
658 : {
659 0 : ale = a;
660 0 : break;
661 : }
662 : }
663 0 : if (NULL != ale)
664 0 : continue; /* found, no need to add */
665 :
666 : /* new auditor, add */
667 0 : TALER_LOG_DEBUG ("Found new auditor %s!\n",
668 : auditor->auditor_url);
669 0 : ale = GNUNET_new (struct TEAH_AuditorListEntry);
670 0 : ale->auditor_pub = auditor->auditor_pub;
671 0 : ale->auditor_url = GNUNET_strdup (auditor->auditor_url);
672 0 : GNUNET_CONTAINER_DLL_insert (exchange->auditors_head,
673 : exchange->auditors_tail,
674 : ale);
675 0 : ale->ah = TALER_AUDITOR_connect (exchange->ctx,
676 0 : ale->auditor_url,
677 : &auditor_version_cb,
678 : ale);
679 : }
680 0 : }
681 :
682 :
683 : /**
684 : * Compare two denomination keys. Ignores revocation data.
685 : *
686 : * @param denom1 first denomination key
687 : * @param denom2 second denomination key
688 : * @return 0 if the two keys are equal (not necessarily
689 : * the same object), 1 otherwise.
690 : */
691 : static unsigned int
692 0 : denoms_cmp (const struct TALER_EXCHANGE_DenomPublicKey *denom1,
693 : const struct TALER_EXCHANGE_DenomPublicKey *denom2)
694 : {
695 : struct TALER_EXCHANGE_DenomPublicKey tmp1;
696 : struct TALER_EXCHANGE_DenomPublicKey tmp2;
697 :
698 0 : if (0 !=
699 0 : TALER_denom_pub_cmp (&denom1->key,
700 : &denom2->key))
701 0 : return 1;
702 0 : tmp1 = *denom1;
703 0 : tmp2 = *denom2;
704 0 : tmp1.revoked = false;
705 0 : tmp2.revoked = false;
706 0 : memset (&tmp1.key,
707 : 0,
708 : sizeof (tmp1.key));
709 0 : memset (&tmp2.key,
710 : 0,
711 : sizeof (tmp2.key));
712 0 : return GNUNET_memcmp (&tmp1,
713 : &tmp2);
714 : }
715 :
716 :
717 : /**
718 : * Decode the JSON in @a resp_obj from the /keys response
719 : * and store the data in the @a key_data.
720 : *
721 : * @param[in] resp_obj JSON object to parse
722 : * @param check_sig true if we should check the signature
723 : * @param[out] key_data where to store the results we decoded
724 : * @param[out] vc where to store version compatibility data
725 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
726 : * (malformed JSON)
727 : */
728 : static enum GNUNET_GenericReturnValue
729 0 : decode_keys_json (const json_t *resp_obj,
730 : bool check_sig,
731 : struct TALER_EXCHANGE_Keys *key_data,
732 : enum TALER_EXCHANGE_VersionCompatibility *vc)
733 : {
734 : struct TALER_ExchangeSignatureP denominations_sig;
735 0 : struct GNUNET_HashCode hash_xor = {0};
736 : struct TALER_ExchangePublicKeyP pub;
737 : const char *currency;
738 0 : json_t *wblwk = NULL;
739 : struct GNUNET_JSON_Specification mspec[] = {
740 0 : GNUNET_JSON_spec_fixed_auto ("denominations_sig",
741 : &denominations_sig),
742 0 : GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
743 : &pub),
744 0 : GNUNET_JSON_spec_fixed_auto ("master_public_key",
745 : &key_data->master_pub),
746 0 : GNUNET_JSON_spec_timestamp ("list_issue_date",
747 : &key_data->list_issue_date),
748 0 : GNUNET_JSON_spec_relative_time ("reserve_closing_delay",
749 : &key_data->reserve_closing_delay),
750 0 : GNUNET_JSON_spec_string ("currency",
751 : ¤cy),
752 0 : GNUNET_JSON_spec_mark_optional (
753 : GNUNET_JSON_spec_json ("wallet_balance_limit_without_kyc",
754 : &wblwk),
755 : NULL),
756 0 : GNUNET_JSON_spec_end ()
757 : };
758 :
759 0 : if (JSON_OBJECT != json_typeof (resp_obj))
760 : {
761 0 : GNUNET_break_op (0);
762 0 : return GNUNET_SYSERR;
763 : }
764 : #if DEBUG
765 : json_dumpf (resp_obj,
766 : stderr,
767 : JSON_INDENT (2));
768 : #endif
769 : /* check the version first */
770 : {
771 : const char *ver;
772 : unsigned int age;
773 : unsigned int revision;
774 : unsigned int current;
775 : char dummy;
776 : struct GNUNET_JSON_Specification spec[] = {
777 0 : GNUNET_JSON_spec_string ("version",
778 : &ver),
779 0 : GNUNET_JSON_spec_end ()
780 : };
781 :
782 0 : if (GNUNET_OK !=
783 0 : GNUNET_JSON_parse (resp_obj,
784 : spec,
785 : NULL, NULL))
786 : {
787 0 : GNUNET_break_op (0);
788 0 : return GNUNET_SYSERR;
789 : }
790 0 : if (3 != sscanf (ver,
791 : "%u:%u:%u%c",
792 : ¤t,
793 : &revision,
794 : &age,
795 : &dummy))
796 : {
797 0 : GNUNET_break_op (0);
798 0 : return GNUNET_SYSERR;
799 : }
800 0 : *vc = TALER_EXCHANGE_VC_MATCH;
801 0 : if (EXCHANGE_PROTOCOL_CURRENT < current)
802 : {
803 0 : *vc |= TALER_EXCHANGE_VC_NEWER;
804 0 : if (EXCHANGE_PROTOCOL_CURRENT < current - age)
805 0 : *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
806 : }
807 0 : if (EXCHANGE_PROTOCOL_CURRENT > current)
808 : {
809 0 : *vc |= TALER_EXCHANGE_VC_OLDER;
810 0 : if (EXCHANGE_PROTOCOL_CURRENT - EXCHANGE_PROTOCOL_AGE > current)
811 0 : *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
812 : }
813 0 : key_data->version = GNUNET_strdup (ver);
814 : }
815 :
816 0 : EXITIF (GNUNET_OK !=
817 : GNUNET_JSON_parse (resp_obj,
818 : (check_sig) ? mspec : &mspec[2],
819 : NULL, NULL));
820 0 : key_data->currency = GNUNET_strdup (currency);
821 :
822 : /* parse the global fees */
823 : {
824 : json_t *global_fees;
825 : json_t *global_fee;
826 : unsigned int index;
827 :
828 0 : EXITIF (NULL == (global_fees =
829 : json_object_get (resp_obj,
830 : "global_fees")));
831 0 : EXITIF (! json_is_array (global_fees));
832 0 : if (0 != (key_data->num_global_fees =
833 0 : json_array_size (global_fees)))
834 : {
835 : key_data->global_fees
836 0 : = GNUNET_new_array (key_data->num_global_fees,
837 : struct TALER_EXCHANGE_GlobalFee);
838 0 : json_array_foreach (global_fees, index, global_fee) {
839 0 : EXITIF (GNUNET_SYSERR ==
840 : parse_global_fee (&key_data->global_fees[index],
841 : check_sig,
842 : global_fee,
843 : key_data));
844 : }
845 : }
846 : }
847 :
848 : /* parse the signing keys */
849 : {
850 : json_t *sign_keys_array;
851 : json_t *sign_key_obj;
852 : unsigned int index;
853 :
854 0 : EXITIF (NULL == (sign_keys_array =
855 : json_object_get (resp_obj,
856 : "signkeys")));
857 0 : EXITIF (! json_is_array (sign_keys_array));
858 0 : if (0 != (key_data->num_sign_keys =
859 0 : json_array_size (sign_keys_array)))
860 : {
861 : key_data->sign_keys
862 0 : = GNUNET_new_array (key_data->num_sign_keys,
863 : struct TALER_EXCHANGE_SigningPublicKey);
864 0 : json_array_foreach (sign_keys_array, index, sign_key_obj) {
865 0 : EXITIF (GNUNET_SYSERR ==
866 : parse_json_signkey (&key_data->sign_keys[index],
867 : check_sig,
868 : sign_key_obj,
869 : &key_data->master_pub));
870 : }
871 : }
872 : }
873 :
874 : /* Parse balance limits */
875 0 : if (NULL != wblwk)
876 : {
877 0 : key_data->wblwk_length = json_array_size (wblwk);
878 : key_data->wallet_balance_limit_without_kyc
879 0 : = GNUNET_new_array (key_data->wblwk_length,
880 : struct TALER_Amount);
881 0 : for (unsigned int i = 0; i<key_data->wblwk_length; i++)
882 : {
883 0 : struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
884 0 : const json_t *aj = json_array_get (wblwk,
885 : i);
886 : struct GNUNET_JSON_Specification spec[] = {
887 0 : TALER_JSON_spec_amount (NULL,
888 : currency,
889 : a),
890 0 : GNUNET_JSON_spec_end ()
891 : };
892 :
893 0 : EXITIF (GNUNET_OK !=
894 : GNUNET_JSON_parse (aj,
895 : spec,
896 : NULL, NULL));
897 : }
898 : }
899 :
900 : /* Parse the supported extension(s): age-restriction. */
901 : /* TODO: maybe lift all this into a FP in TALER_Extension ? */
902 : {
903 0 : struct TALER_MasterSignatureP extensions_sig = {0};
904 0 : json_t *extensions = NULL;
905 : struct GNUNET_JSON_Specification ext_spec[] = {
906 0 : GNUNET_JSON_spec_mark_optional (
907 : GNUNET_JSON_spec_json ("extensions",
908 : &extensions),
909 : NULL),
910 0 : GNUNET_JSON_spec_mark_optional (
911 : GNUNET_JSON_spec_fixed_auto (
912 : "extensions_sig",
913 : &extensions_sig),
914 : NULL),
915 0 : GNUNET_JSON_spec_end ()
916 : };
917 :
918 : /* 1. Search for extensions in the response to /keys */
919 0 : EXITIF (GNUNET_OK !=
920 : GNUNET_JSON_parse (resp_obj,
921 : ext_spec,
922 : NULL, NULL));
923 :
924 0 : if (NULL != extensions)
925 : {
926 : /* 2. We have an extensions object. Verify its signature. */
927 0 : EXITIF (GNUNET_OK !=
928 : TALER_extensions_verify_json_config_signature (
929 : extensions,
930 : &extensions_sig,
931 : &key_data->master_pub));
932 :
933 : /* 3. Parse and set the the configuration of the extensions accordingly */
934 0 : EXITIF (GNUNET_OK !=
935 : TALER_extensions_load_json_config (extensions));
936 : }
937 :
938 : /* 4. assuming we might have now a new value for age_mask, set it in key_data */
939 0 : key_data->age_mask = TALER_extensions_age_restriction_ageMask ();
940 : }
941 :
942 : /**
943 : * Parse the denomination keys, merging with the
944 : * possibly EXISTING array as required (/keys cherry picking).
945 : *
946 : * The denominations are grouped by common values of
947 : * {cipher, value, fee, age_mask}.
948 : **/
949 : {
950 : json_t *denominations_by_group;
951 : json_t *group_obj;
952 : unsigned int group_idx;
953 :
954 : denominations_by_group =
955 0 : json_object_get (
956 : resp_obj,
957 : "denominations");
958 :
959 0 : EXITIF (JSON_ARRAY !=
960 : json_typeof (denominations_by_group));
961 :
962 0 : json_array_foreach (denominations_by_group, group_idx, group_obj) {
963 : /* Running XOR of each SHA512 hash of the denominations' public key in
964 : this group. Used to compare against group.hash after all keys have
965 : been parsed. */
966 0 : struct GNUNET_HashCode group_hash_xor = {0};
967 :
968 : /* First, parse { cipher, fees, value, age_mask, hash } of the current
969 : group. */
970 0 : struct TALER_DenominationGroup group = {0};
971 : struct GNUNET_JSON_Specification group_spec[] = {
972 0 : TALER_JSON_spec_denomination_group (NULL,
973 : currency, &group),
974 0 : GNUNET_JSON_spec_end ()
975 : };
976 0 : EXITIF (GNUNET_SYSERR ==
977 : GNUNET_JSON_parse (group_obj,
978 : group_spec,
979 : NULL,
980 : NULL));
981 :
982 : /* Now, parse the individual denominations */
983 : {
984 : json_t *denom_keys_array;
985 : json_t *denom_key_obj;
986 : unsigned int index;
987 0 : denom_keys_array = json_object_get (group_obj, "denoms");
988 0 : EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
989 :
990 0 : json_array_foreach (denom_keys_array, index, denom_key_obj) {
991 0 : struct TALER_EXCHANGE_DenomPublicKey dk = {0};
992 0 : bool found = false;
993 :
994 0 : memset (&dk, 0, sizeof (dk));
995 :
996 : /* Set the common fields from the group for this particular
997 : denomination. Required to make the validity check inside
998 : parse_json_denomkey_partially pass */
999 0 : dk.key.cipher = group.cipher;
1000 0 : dk.value = group.value;
1001 0 : dk.fees = group.fees;
1002 0 : dk.key.age_mask = group.age_mask;
1003 :
1004 0 : EXITIF (GNUNET_SYSERR ==
1005 : parse_json_denomkey_partially (&dk,
1006 : group.cipher,
1007 : check_sig,
1008 : denom_key_obj,
1009 : &key_data->master_pub,
1010 : check_sig ? &hash_xor : NULL));
1011 :
1012 : /* Build the running xor of the SHA512-hash of the public keys */
1013 : {
1014 0 : struct TALER_DenominationHashP hc = {0};
1015 0 : TALER_denom_pub_hash (&dk.key, &hc);
1016 0 : GNUNET_CRYPTO_hash_xor (&hc.hash,
1017 : &group_hash_xor,
1018 : &group_hash_xor);
1019 : }
1020 :
1021 0 : for (unsigned int j = 0;
1022 0 : j<key_data->num_denom_keys;
1023 0 : j++)
1024 : {
1025 0 : if (0 == denoms_cmp (&dk,
1026 0 : &key_data->denom_keys[j]))
1027 : {
1028 0 : found = true;
1029 0 : break;
1030 : }
1031 : }
1032 :
1033 0 : if (found)
1034 : {
1035 : /* 0:0:0 did not support /keys cherry picking */
1036 0 : TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
1037 0 : TALER_denom_pub_free (&dk.key);
1038 0 : continue;
1039 : }
1040 :
1041 0 : if (key_data->denom_keys_size == key_data->num_denom_keys)
1042 0 : GNUNET_array_grow (key_data->denom_keys,
1043 : key_data->denom_keys_size,
1044 : key_data->denom_keys_size * 2 + 2);
1045 0 : key_data->denom_keys[key_data->num_denom_keys++] = dk;
1046 :
1047 : /* Update "last_denom_issue_date" */
1048 0 : TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
1049 : GNUNET_TIME_timestamp2s (dk.valid_from));
1050 : key_data->last_denom_issue_date
1051 0 : = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
1052 : dk.valid_from);
1053 : }; // json_array_foreach over denominations
1054 :
1055 : // The calculated group_hash_xor must be the same as group.hash from
1056 : // the json.
1057 0 : EXITIF (0 !=
1058 : GNUNET_CRYPTO_hash_cmp (&group_hash_xor, &group.hash));
1059 :
1060 : } // block for parsing individual denominations
1061 : }; // json_array_foreach over groups of denominations
1062 : }
1063 :
1064 : /* parse the auditor information */
1065 : {
1066 : json_t *auditors_array;
1067 : json_t *auditor_info;
1068 : unsigned int index;
1069 :
1070 0 : EXITIF (NULL == (auditors_array =
1071 : json_object_get (resp_obj,
1072 : "auditors")));
1073 0 : EXITIF (JSON_ARRAY != json_typeof (auditors_array));
1074 :
1075 : /* Merge with the existing auditor information we have (/keys cherry picking) */
1076 0 : json_array_foreach (auditors_array, index, auditor_info) {
1077 : struct TALER_EXCHANGE_AuditorInformation ai;
1078 0 : bool found = false;
1079 :
1080 0 : memset (&ai,
1081 : 0,
1082 : sizeof (ai));
1083 0 : EXITIF (GNUNET_SYSERR ==
1084 : parse_json_auditor (&ai,
1085 : check_sig,
1086 : auditor_info,
1087 : key_data));
1088 0 : for (unsigned int j = 0; j<key_data->num_auditors; j++)
1089 : {
1090 0 : struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
1091 :
1092 0 : if (0 == GNUNET_memcmp (&ai.auditor_pub,
1093 : &aix->auditor_pub))
1094 : {
1095 0 : found = true;
1096 : /* Merge denomination key signatures of downloaded /keys into existing
1097 : auditor information 'aix'. */
1098 0 : TALER_LOG_DEBUG (
1099 : "Merging %u new audited keys with %u known audited keys\n",
1100 : aix->num_denom_keys,
1101 : ai.num_denom_keys);
1102 0 : for (unsigned int i = 0; i<ai.num_denom_keys; i++)
1103 : {
1104 0 : bool kfound = false;
1105 :
1106 0 : for (unsigned int k = 0; k<aix->num_denom_keys; k++)
1107 : {
1108 0 : if (aix->denom_keys[k].denom_key_offset ==
1109 0 : ai.denom_keys[i].denom_key_offset)
1110 : {
1111 0 : kfound = true;
1112 0 : break;
1113 : }
1114 : }
1115 0 : if (! kfound)
1116 0 : GNUNET_array_append (aix->denom_keys,
1117 : aix->num_denom_keys,
1118 : ai.denom_keys[i]);
1119 : }
1120 0 : break;
1121 : }
1122 : }
1123 0 : if (found)
1124 : {
1125 0 : GNUNET_array_grow (ai.denom_keys,
1126 : ai.num_denom_keys,
1127 : 0);
1128 0 : GNUNET_free (ai.auditor_url);
1129 0 : continue; /* we are done */
1130 : }
1131 0 : if (key_data->auditors_size == key_data->num_auditors)
1132 0 : GNUNET_array_grow (key_data->auditors,
1133 : key_data->auditors_size,
1134 : key_data->auditors_size * 2 + 2);
1135 0 : GNUNET_assert (NULL != ai.auditor_url);
1136 0 : key_data->auditors[key_data->num_auditors++] = ai;
1137 : };
1138 : }
1139 :
1140 : /* parse the revocation/recoup information */
1141 : {
1142 : json_t *recoup_array;
1143 : json_t *recoup_info;
1144 : unsigned int index;
1145 :
1146 0 : if (NULL != (recoup_array =
1147 0 : json_object_get (resp_obj,
1148 : "recoup")))
1149 : {
1150 0 : EXITIF (JSON_ARRAY != json_typeof (recoup_array));
1151 :
1152 0 : json_array_foreach (recoup_array, index, recoup_info) {
1153 : struct TALER_DenominationHashP h_denom_pub;
1154 : struct GNUNET_JSON_Specification spec[] = {
1155 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1156 : &h_denom_pub),
1157 0 : GNUNET_JSON_spec_end ()
1158 : };
1159 :
1160 0 : EXITIF (GNUNET_OK !=
1161 : GNUNET_JSON_parse (recoup_info,
1162 : spec,
1163 : NULL, NULL));
1164 0 : for (unsigned int j = 0;
1165 0 : j<key_data->num_denom_keys;
1166 0 : j++)
1167 : {
1168 0 : if (0 == GNUNET_memcmp (&h_denom_pub,
1169 : &key_data->denom_keys[j].h_key))
1170 : {
1171 0 : key_data->denom_keys[j].revoked = GNUNET_YES;
1172 0 : break;
1173 : }
1174 : }
1175 : };
1176 : }
1177 : }
1178 :
1179 0 : if (check_sig)
1180 : {
1181 0 : EXITIF (GNUNET_OK !=
1182 : TALER_EXCHANGE_test_signing_key (key_data,
1183 : &pub));
1184 :
1185 0 : EXITIF (GNUNET_OK !=
1186 : TALER_exchange_online_key_set_verify (
1187 : key_data->list_issue_date,
1188 : &hash_xor,
1189 : &pub,
1190 : &denominations_sig));
1191 : }
1192 :
1193 0 : return GNUNET_OK;
1194 :
1195 0 : EXITIF_exit:
1196 0 : *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
1197 0 : return GNUNET_SYSERR;
1198 : }
1199 :
1200 :
1201 : /**
1202 : * Free key data object.
1203 : *
1204 : * @param key_data data to free (pointer itself excluded)
1205 : */
1206 : static void
1207 0 : free_key_data (struct TALER_EXCHANGE_Keys *key_data)
1208 : {
1209 0 : GNUNET_array_grow (key_data->sign_keys,
1210 : key_data->num_sign_keys,
1211 : 0);
1212 0 : for (unsigned int i = 0; i<key_data->num_denom_keys; i++)
1213 0 : TALER_denom_pub_free (&key_data->denom_keys[i].key);
1214 :
1215 0 : GNUNET_array_grow (key_data->denom_keys,
1216 : key_data->denom_keys_size,
1217 : 0);
1218 0 : for (unsigned int i = 0; i<key_data->num_auditors; i++)
1219 : {
1220 0 : GNUNET_array_grow (key_data->auditors[i].denom_keys,
1221 : key_data->auditors[i].num_denom_keys,
1222 : 0);
1223 0 : GNUNET_free (key_data->auditors[i].auditor_url);
1224 : }
1225 0 : GNUNET_array_grow (key_data->auditors,
1226 : key_data->auditors_size,
1227 : 0);
1228 0 : GNUNET_free (key_data->wallet_balance_limit_without_kyc);
1229 0 : GNUNET_free (key_data->version);
1230 0 : GNUNET_free (key_data->currency);
1231 0 : GNUNET_free (key_data->global_fees);
1232 0 : }
1233 :
1234 :
1235 : /**
1236 : * Initiate download of /keys from the exchange.
1237 : *
1238 : * @param cls exchange where to download /keys from
1239 : */
1240 : static void
1241 : request_keys (void *cls);
1242 :
1243 :
1244 : void
1245 0 : TALER_EXCHANGE_set_last_denom (struct TALER_EXCHANGE_Handle *exchange,
1246 : struct GNUNET_TIME_Timestamp last_denom_new)
1247 : {
1248 0 : TALER_LOG_DEBUG (
1249 : "Application explicitly set last denomination validity to %s\n",
1250 : GNUNET_TIME_timestamp2s (last_denom_new));
1251 0 : exchange->key_data.last_denom_issue_date = last_denom_new;
1252 0 : }
1253 :
1254 :
1255 : struct GNUNET_TIME_Timestamp
1256 0 : TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
1257 : enum TALER_EXCHANGE_CheckKeysFlags flags)
1258 : {
1259 0 : bool force_download = 0 != (flags & TALER_EXCHANGE_CKF_FORCE_DOWNLOAD);
1260 0 : bool pull_all_keys = 0 != (flags & TALER_EXCHANGE_CKF_PULL_ALL_KEYS);
1261 :
1262 0 : if (NULL != exchange->kr)
1263 0 : return GNUNET_TIME_UNIT_ZERO_TS;
1264 :
1265 0 : if (pull_all_keys)
1266 : {
1267 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1268 : "Forcing re-download of all exchange keys\n");
1269 0 : GNUNET_break (GNUNET_YES == force_download);
1270 0 : exchange->state = MHS_INIT;
1271 : }
1272 0 : if ( (! force_download) &&
1273 0 : (GNUNET_TIME_absolute_is_future (
1274 : exchange->key_data_expiration.abs_time)) )
1275 0 : return exchange->key_data_expiration;
1276 0 : if (NULL == exchange->retry_task)
1277 0 : exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys,
1278 : exchange);
1279 0 : return GNUNET_TIME_UNIT_ZERO_TS;
1280 : }
1281 :
1282 :
1283 : /**
1284 : * Callback used when downloading the reply to a /keys request
1285 : * is complete.
1286 : *
1287 : * @param cls the `struct KeysRequest`
1288 : * @param response_code HTTP response code, 0 on error
1289 : * @param resp_obj parsed JSON result, NULL on error
1290 : */
1291 : static void
1292 0 : keys_completed_cb (void *cls,
1293 : long response_code,
1294 : const void *resp_obj)
1295 : {
1296 0 : struct KeysRequest *kr = cls;
1297 0 : struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
1298 : struct TALER_EXCHANGE_Keys kd;
1299 : struct TALER_EXCHANGE_Keys kd_old;
1300 : enum TALER_EXCHANGE_VersionCompatibility vc;
1301 0 : const json_t *j = resp_obj;
1302 0 : struct TALER_EXCHANGE_HttpResponse hr = {
1303 : .reply = j,
1304 0 : .http_status = (unsigned int) response_code
1305 : };
1306 :
1307 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1308 : "Received keys from URL `%s' with status %ld and expiration %s.\n",
1309 : kr->url,
1310 : response_code,
1311 : GNUNET_TIME_timestamp2s (kr->expire));
1312 0 : if (GNUNET_TIME_absolute_is_past (kr->expire.abs_time))
1313 : {
1314 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1315 : "Exchange failed to give expiration time, assuming in %s\n",
1316 : GNUNET_TIME_relative2s (DEFAULT_EXPIRATION,
1317 : true));
1318 : kr->expire
1319 0 : = GNUNET_TIME_absolute_to_timestamp (
1320 : GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
1321 : }
1322 0 : kd_old = exchange->key_data;
1323 0 : memset (&kd,
1324 : 0,
1325 : sizeof (struct TALER_EXCHANGE_Keys));
1326 0 : vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
1327 0 : switch (response_code)
1328 : {
1329 0 : case 0:
1330 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1331 : "Failed to receive /keys response from exchange %s\n",
1332 : exchange->url);
1333 0 : free_keys_request (kr);
1334 0 : exchange->keys_error_count++;
1335 0 : exchange->kr = NULL;
1336 0 : GNUNET_assert (NULL == exchange->retry_task);
1337 0 : exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay);
1338 0 : exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
1339 : &request_keys,
1340 : exchange);
1341 0 : return;
1342 0 : case MHD_HTTP_OK:
1343 0 : exchange->keys_error_count = 0;
1344 0 : if (NULL == j)
1345 : {
1346 0 : response_code = 0;
1347 0 : break;
1348 : }
1349 : /* We keep the denomination keys and auditor signatures from the
1350 : previous iteration (/keys cherry picking) */
1351 0 : kd.num_denom_keys = kd_old.num_denom_keys;
1352 0 : kd.last_denom_issue_date = kd_old.last_denom_issue_date;
1353 0 : GNUNET_array_grow (kd.denom_keys,
1354 : kd.denom_keys_size,
1355 : kd.num_denom_keys);
1356 :
1357 : /* First make a shallow copy, we then need another pass for the RSA key... */
1358 0 : memcpy (kd.denom_keys,
1359 0 : kd_old.denom_keys,
1360 0 : kd_old.num_denom_keys * sizeof (struct
1361 : TALER_EXCHANGE_DenomPublicKey));
1362 :
1363 0 : for (unsigned int i = 0; i<kd_old.num_denom_keys; i++)
1364 0 : TALER_denom_pub_deep_copy (&kd.denom_keys[i].key,
1365 0 : &kd_old.denom_keys[i].key);
1366 :
1367 0 : kd.num_auditors = kd_old.num_auditors;
1368 0 : kd.auditors = GNUNET_new_array (kd.num_auditors,
1369 : struct TALER_EXCHANGE_AuditorInformation);
1370 : /* Now the necessary deep copy... */
1371 0 : for (unsigned int i = 0; i<kd_old.num_auditors; i++)
1372 : {
1373 0 : const struct TALER_EXCHANGE_AuditorInformation *aold =
1374 0 : &kd_old.auditors[i];
1375 0 : struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
1376 :
1377 0 : anew->auditor_pub = aold->auditor_pub;
1378 0 : GNUNET_assert (NULL != aold->auditor_url);
1379 0 : anew->auditor_url = GNUNET_strdup (aold->auditor_url);
1380 0 : GNUNET_array_grow (anew->denom_keys,
1381 : anew->num_denom_keys,
1382 : aold->num_denom_keys);
1383 0 : memcpy (anew->denom_keys,
1384 0 : aold->denom_keys,
1385 0 : aold->num_denom_keys
1386 : * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo));
1387 : }
1388 :
1389 : /* Old auditors got just copied into new ones. */
1390 0 : if (GNUNET_OK !=
1391 0 : decode_keys_json (j,
1392 : true,
1393 : &kd,
1394 : &vc))
1395 : {
1396 0 : TALER_LOG_ERROR ("Could not decode /keys response\n");
1397 0 : hr.http_status = 0;
1398 0 : hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
1399 0 : for (unsigned int i = 0; i<kd.num_auditors; i++)
1400 : {
1401 0 : struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
1402 :
1403 0 : GNUNET_array_grow (anew->denom_keys,
1404 : anew->num_denom_keys,
1405 : 0);
1406 0 : GNUNET_free (anew->auditor_url);
1407 : }
1408 0 : GNUNET_free (kd.auditors);
1409 0 : kd.auditors = NULL;
1410 0 : kd.num_auditors = 0;
1411 0 : for (unsigned int i = 0; i<kd_old.num_denom_keys; i++)
1412 0 : TALER_denom_pub_free (&kd.denom_keys[i].key);
1413 0 : GNUNET_array_grow (kd.denom_keys,
1414 : kd.denom_keys_size,
1415 : 0);
1416 0 : kd.num_denom_keys = 0;
1417 0 : break;
1418 : }
1419 0 : json_decref (exchange->key_data_raw);
1420 0 : exchange->key_data_raw = json_deep_copy (j);
1421 0 : exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
1422 0 : break;
1423 0 : case MHD_HTTP_BAD_REQUEST:
1424 : case MHD_HTTP_UNAUTHORIZED:
1425 : case MHD_HTTP_FORBIDDEN:
1426 : case MHD_HTTP_NOT_FOUND:
1427 0 : if (NULL == j)
1428 : {
1429 0 : hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
1430 0 : hr.hint = TALER_ErrorCode_get_hint (hr.ec);
1431 : }
1432 : else
1433 : {
1434 0 : hr.ec = TALER_JSON_get_error_code (j);
1435 0 : hr.hint = TALER_JSON_get_error_hint (j);
1436 : }
1437 0 : break;
1438 0 : default:
1439 0 : if (MHD_HTTP_GATEWAY_TIMEOUT == response_code)
1440 0 : exchange->keys_error_count++;
1441 0 : if (NULL == j)
1442 : {
1443 0 : hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
1444 0 : hr.hint = TALER_ErrorCode_get_hint (hr.ec);
1445 : }
1446 : else
1447 : {
1448 0 : hr.ec = TALER_JSON_get_error_code (j);
1449 0 : hr.hint = TALER_JSON_get_error_hint (j);
1450 : }
1451 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1452 : "Unexpected response code %u/%d\n",
1453 : (unsigned int) response_code,
1454 : (int) hr.ec);
1455 0 : break;
1456 : }
1457 0 : exchange->key_data = kd;
1458 0 : if (GNUNET_TIME_absolute_is_past (
1459 : exchange->key_data.last_denom_issue_date.abs_time))
1460 0 : TALER_LOG_WARNING ("Last DK issue date from exchange is in the past: %s\n",
1461 : GNUNET_TIME_timestamp2s (
1462 : exchange->key_data.last_denom_issue_date));
1463 : else
1464 0 : TALER_LOG_DEBUG ("Last DK issue date updated to: %s\n",
1465 : GNUNET_TIME_timestamp2s (
1466 : exchange->key_data.last_denom_issue_date));
1467 :
1468 :
1469 0 : if (MHD_HTTP_OK != response_code)
1470 : {
1471 0 : exchange->kr = NULL;
1472 0 : free_keys_request (kr);
1473 0 : exchange->state = MHS_FAILED;
1474 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1475 : "Exchange keys download failed\n");
1476 0 : if (NULL != exchange->key_data_raw)
1477 : {
1478 0 : json_decref (exchange->key_data_raw);
1479 0 : exchange->key_data_raw = NULL;
1480 : }
1481 0 : free_key_data (&kd_old);
1482 : /* notify application that we failed */
1483 0 : exchange->cert_cb (exchange->cert_cb_cls,
1484 : &hr,
1485 : NULL,
1486 : vc);
1487 0 : return;
1488 : }
1489 :
1490 0 : exchange->kr = NULL;
1491 0 : exchange->key_data_expiration = kr->expire;
1492 0 : free_keys_request (kr);
1493 0 : exchange->state = MHS_CERT;
1494 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1495 : "Successfully downloaded exchange's keys\n");
1496 0 : update_auditors (exchange);
1497 : /* notify application about the key information */
1498 0 : exchange->cert_cb (exchange->cert_cb_cls,
1499 : &hr,
1500 0 : &exchange->key_data,
1501 : vc);
1502 0 : free_key_data (&kd_old);
1503 : }
1504 :
1505 :
1506 : /* ********************* library internal API ********* */
1507 :
1508 :
1509 : struct GNUNET_CURL_Context *
1510 0 : TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
1511 : {
1512 0 : return h->ctx;
1513 : }
1514 :
1515 :
1516 : enum GNUNET_GenericReturnValue
1517 0 : TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
1518 : {
1519 0 : return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
1520 : }
1521 :
1522 :
1523 : char *
1524 0 : TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
1525 : const char *path)
1526 : {
1527 0 : GNUNET_assert ('/' == path[0]);
1528 0 : return TALER_url_join (h->url,
1529 : path + 1,
1530 : NULL);
1531 : }
1532 :
1533 :
1534 : /**
1535 : * Define a max length for the HTTP "Expire:" header
1536 : */
1537 : #define MAX_DATE_LINE_LEN 32
1538 :
1539 :
1540 : /**
1541 : * Parse HTTP timestamp.
1542 : *
1543 : * @param dateline header to parse header
1544 : * @param at where to write the result
1545 : * @return #GNUNET_OK on success
1546 : */
1547 : static enum GNUNET_GenericReturnValue
1548 0 : parse_date_string (const char *dateline,
1549 : struct GNUNET_TIME_Timestamp *at)
1550 : {
1551 : static const char *MONTHS[] =
1552 : { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1553 : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
1554 : int year;
1555 : int mon;
1556 : int day;
1557 : int hour;
1558 : int min;
1559 : int sec;
1560 : char month[4];
1561 : struct tm tm;
1562 : time_t t;
1563 :
1564 : /* We recognize the three formats in RFC2616, section 3.3.1. Month
1565 : names are always in English. The formats are:
1566 : Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
1567 : Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
1568 : Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
1569 : Note that the first is preferred.
1570 : */
1571 :
1572 0 : if (strlen (dateline) > MAX_DATE_LINE_LEN)
1573 : {
1574 0 : GNUNET_break_op (0);
1575 0 : return GNUNET_SYSERR;
1576 : }
1577 0 : while (*dateline == ' ')
1578 0 : ++dateline;
1579 0 : while (*dateline && *dateline != ' ')
1580 0 : ++dateline;
1581 0 : while (*dateline == ' ')
1582 0 : ++dateline;
1583 : /* We just skipped over the day of the week. Now we have:*/
1584 0 : if ( (sscanf (dateline,
1585 : "%d %3s %d %d:%d:%d",
1586 0 : &day, month, &year, &hour, &min, &sec) != 6) &&
1587 0 : (sscanf (dateline,
1588 : "%d-%3s-%d %d:%d:%d",
1589 0 : &day, month, &year, &hour, &min, &sec) != 6) &&
1590 0 : (sscanf (dateline,
1591 : "%3s %d %d:%d:%d %d",
1592 : month, &day, &hour, &min, &sec, &year) != 6) )
1593 : {
1594 0 : GNUNET_break (0);
1595 0 : return GNUNET_SYSERR;
1596 : }
1597 : /* Two digit dates are defined to be relative to 1900; all other dates
1598 : * are supposed to be represented as four digits. */
1599 0 : if (year < 100)
1600 0 : year += 1900;
1601 :
1602 0 : for (mon = 0; ; mon++)
1603 : {
1604 0 : if (! MONTHS[mon])
1605 : {
1606 0 : GNUNET_break_op (0);
1607 0 : return GNUNET_SYSERR;
1608 : }
1609 0 : if (0 == strcasecmp (month,
1610 : MONTHS[mon]))
1611 0 : break;
1612 : }
1613 :
1614 0 : memset (&tm, 0, sizeof(tm));
1615 0 : tm.tm_year = year - 1900;
1616 0 : tm.tm_mon = mon;
1617 0 : tm.tm_mday = day;
1618 0 : tm.tm_hour = hour;
1619 0 : tm.tm_min = min;
1620 0 : tm.tm_sec = sec;
1621 :
1622 0 : t = mktime (&tm);
1623 0 : if (((time_t) -1) == t)
1624 : {
1625 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1626 : "mktime");
1627 0 : return GNUNET_SYSERR;
1628 : }
1629 0 : if (t < 0)
1630 0 : t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
1631 0 : *at = GNUNET_TIME_timestamp_from_s (t);
1632 0 : return GNUNET_OK;
1633 : }
1634 :
1635 :
1636 : /**
1637 : * Function called for each header in the HTTP /keys response.
1638 : * Finds the "Expire:" header and parses it, storing the result
1639 : * in the "expire" field of the keys request.
1640 : *
1641 : * @param buffer header data received
1642 : * @param size size of an item in @a buffer
1643 : * @param nitems number of items in @a buffer
1644 : * @param userdata the `struct KeysRequest`
1645 : * @return `size * nitems` on success (everything else aborts)
1646 : */
1647 : static size_t
1648 0 : header_cb (char *buffer,
1649 : size_t size,
1650 : size_t nitems,
1651 : void *userdata)
1652 : {
1653 0 : struct KeysRequest *kr = userdata;
1654 0 : size_t total = size * nitems;
1655 : char *val;
1656 :
1657 0 : if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
1658 0 : return total;
1659 0 : if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
1660 : buffer,
1661 : strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
1662 0 : return total;
1663 0 : val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
1664 : total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
1665 0 : if (GNUNET_OK !=
1666 0 : parse_date_string (val,
1667 : &kr->expire))
1668 : {
1669 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1670 : "Failed to parse %s-header `%s'\n",
1671 : MHD_HTTP_HEADER_EXPIRES,
1672 : val);
1673 0 : kr->expire = GNUNET_TIME_UNIT_ZERO_TS;
1674 : }
1675 0 : GNUNET_free (val);
1676 0 : return total;
1677 : }
1678 :
1679 :
1680 : /* ********************* public API ******************* */
1681 :
1682 :
1683 : /**
1684 : * Deserialize the key data and use it to bootstrap @a exchange to
1685 : * more efficiently recover the state. Errors in @a data must be
1686 : * tolerated (i.e. by re-downloading instead).
1687 : *
1688 : * @param exchange which exchange's key and wire data should be deserialized
1689 : * @param data the data to deserialize
1690 : */
1691 : static void
1692 0 : deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
1693 : const json_t *data)
1694 : {
1695 : enum TALER_EXCHANGE_VersionCompatibility vc;
1696 : json_t *keys;
1697 : const char *url;
1698 : uint32_t version;
1699 : struct GNUNET_TIME_Timestamp expire;
1700 : struct GNUNET_JSON_Specification spec[] = {
1701 0 : GNUNET_JSON_spec_uint32 ("version",
1702 : &version),
1703 0 : GNUNET_JSON_spec_json ("keys",
1704 : &keys),
1705 0 : GNUNET_JSON_spec_string ("exchange_url",
1706 : &url),
1707 0 : GNUNET_JSON_spec_timestamp ("expire",
1708 : &expire),
1709 0 : GNUNET_JSON_spec_end ()
1710 : };
1711 : struct TALER_EXCHANGE_Keys key_data;
1712 0 : struct TALER_EXCHANGE_HttpResponse hr = {
1713 : .ec = TALER_EC_NONE,
1714 : .http_status = MHD_HTTP_OK,
1715 : .reply = data
1716 : };
1717 :
1718 0 : if (NULL == data)
1719 0 : return;
1720 0 : if (GNUNET_OK !=
1721 0 : GNUNET_JSON_parse (data,
1722 : spec,
1723 : NULL, NULL))
1724 : {
1725 0 : GNUNET_break_op (0);
1726 0 : return;
1727 : }
1728 0 : if (0 != version)
1729 : {
1730 0 : GNUNET_JSON_parse_free (spec);
1731 0 : return; /* unsupported version */
1732 : }
1733 0 : if (0 != strcmp (url,
1734 0 : exchange->url))
1735 : {
1736 0 : GNUNET_break (0);
1737 0 : GNUNET_JSON_parse_free (spec);
1738 0 : return;
1739 : }
1740 0 : memset (&key_data,
1741 : 0,
1742 : sizeof (struct TALER_EXCHANGE_Keys));
1743 0 : if (GNUNET_OK !=
1744 0 : decode_keys_json (keys,
1745 : false,
1746 : &key_data,
1747 : &vc))
1748 : {
1749 0 : GNUNET_break (0);
1750 0 : GNUNET_JSON_parse_free (spec);
1751 0 : return;
1752 : }
1753 : /* decode successful, initialize with the result */
1754 0 : GNUNET_assert (NULL == exchange->key_data_raw);
1755 0 : exchange->key_data_raw = json_deep_copy (keys);
1756 0 : exchange->key_data = key_data;
1757 0 : exchange->key_data_expiration = expire;
1758 0 : exchange->state = MHS_CERT;
1759 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1760 : "Successfully loaded exchange's keys via deserialization\n");
1761 0 : update_auditors (exchange);
1762 : /* notify application about the key information */
1763 0 : exchange->cert_cb (exchange->cert_cb_cls,
1764 : &hr,
1765 0 : &exchange->key_data,
1766 : vc);
1767 0 : GNUNET_JSON_parse_free (spec);
1768 : }
1769 :
1770 :
1771 : json_t *
1772 0 : TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
1773 : {
1774 0 : const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
1775 : struct GNUNET_TIME_Timestamp now;
1776 : json_t *keys;
1777 : json_t *signkeys;
1778 : json_t *denoms;
1779 : json_t *auditors;
1780 :
1781 0 : now = GNUNET_TIME_timestamp_get ();
1782 0 : signkeys = json_array ();
1783 0 : if (NULL == signkeys)
1784 : {
1785 0 : GNUNET_break (0);
1786 0 : return NULL;
1787 : }
1788 0 : for (unsigned int i = 0; i<kd->num_sign_keys; i++)
1789 : {
1790 0 : const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
1791 : json_t *signkey;
1792 :
1793 0 : if (GNUNET_TIME_timestamp_cmp (now,
1794 : >,
1795 : sk->valid_until))
1796 0 : continue; /* skip keys that have expired */
1797 0 : signkey = GNUNET_JSON_PACK (
1798 : GNUNET_JSON_pack_data_auto ("key",
1799 : &sk->key),
1800 : GNUNET_JSON_pack_data_auto ("master_sig",
1801 : &sk->master_sig),
1802 : GNUNET_JSON_pack_timestamp ("stamp_start",
1803 : sk->valid_from),
1804 : GNUNET_JSON_pack_timestamp ("stamp_expire",
1805 : sk->valid_until),
1806 : GNUNET_JSON_pack_timestamp ("stamp_end",
1807 : sk->valid_legal));
1808 0 : if (NULL == signkey)
1809 : {
1810 0 : GNUNET_break (0);
1811 0 : continue;
1812 : }
1813 0 : if (0 != json_array_append_new (signkeys,
1814 : signkey))
1815 : {
1816 0 : GNUNET_break (0);
1817 0 : json_decref (signkey);
1818 0 : json_decref (signkeys);
1819 0 : return NULL;
1820 : }
1821 : }
1822 0 : denoms = json_array ();
1823 0 : if (NULL == denoms)
1824 : {
1825 0 : GNUNET_break (0);
1826 0 : json_decref (signkeys);
1827 0 : return NULL;
1828 : }
1829 0 : for (unsigned int i = 0; i<kd->num_denom_keys; i++)
1830 : {
1831 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
1832 : json_t *denom;
1833 :
1834 0 : if (GNUNET_TIME_timestamp_cmp (now,
1835 : >,
1836 : dk->expire_deposit))
1837 0 : continue; /* skip keys that have expired */
1838 0 : denom = GNUNET_JSON_PACK (
1839 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
1840 : dk->expire_deposit),
1841 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
1842 : dk->withdraw_valid_until),
1843 : GNUNET_JSON_pack_timestamp ("stamp_start",
1844 : dk->valid_from),
1845 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
1846 : dk->expire_legal),
1847 : TALER_JSON_pack_amount ("value",
1848 : &dk->value),
1849 : TALER_JSON_PACK_DENOM_FEES ("fee",
1850 : &dk->fees),
1851 : GNUNET_JSON_pack_data_auto ("master_sig",
1852 : &dk->master_sig),
1853 : TALER_JSON_pack_denom_pub ("denom_pub",
1854 : &dk->key));
1855 0 : GNUNET_assert (0 ==
1856 : json_array_append_new (denoms,
1857 : denom));
1858 : }
1859 0 : auditors = json_array ();
1860 0 : GNUNET_assert (NULL != auditors);
1861 0 : for (unsigned int i = 0; i<kd->num_auditors; i++)
1862 : {
1863 0 : const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
1864 : json_t *a;
1865 : json_t *adenoms;
1866 :
1867 0 : adenoms = json_array ();
1868 0 : if (NULL == adenoms)
1869 : {
1870 0 : GNUNET_break (0);
1871 0 : json_decref (denoms);
1872 0 : json_decref (signkeys);
1873 0 : json_decref (auditors);
1874 0 : return NULL;
1875 : }
1876 0 : for (unsigned int j = 0; j<ai->num_denom_keys; j++)
1877 : {
1878 0 : const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
1879 0 : &ai->denom_keys[j];
1880 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk =
1881 0 : &kd->denom_keys[adi->denom_key_offset];
1882 : json_t *k;
1883 :
1884 0 : if (GNUNET_TIME_timestamp_cmp (now,
1885 : >,
1886 : dk->expire_deposit))
1887 0 : continue; /* skip auditor signatures for denomination keys that have expired */
1888 0 : GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
1889 0 : k = GNUNET_JSON_PACK (
1890 : GNUNET_JSON_pack_data_auto ("denom_pub_h",
1891 : &dk->h_key),
1892 : GNUNET_JSON_pack_data_auto ("auditor_sig",
1893 : &adi->auditor_sig));
1894 0 : GNUNET_assert (0 ==
1895 : json_array_append_new (adenoms,
1896 : k));
1897 : }
1898 :
1899 0 : a = GNUNET_JSON_PACK (
1900 : GNUNET_JSON_pack_data_auto ("auditor_pub",
1901 : &ai->auditor_pub),
1902 : GNUNET_JSON_pack_string ("auditor_url",
1903 : ai->auditor_url),
1904 : GNUNET_JSON_pack_array_steal ("denomination_keys",
1905 : adenoms));
1906 0 : GNUNET_assert (0 ==
1907 : json_array_append_new (auditors,
1908 : a));
1909 : }
1910 0 : keys = GNUNET_JSON_PACK (
1911 : GNUNET_JSON_pack_string ("version",
1912 : kd->version),
1913 : GNUNET_JSON_pack_string ("currency",
1914 : kd->currency),
1915 : GNUNET_JSON_pack_data_auto ("master_public_key",
1916 : &kd->master_pub),
1917 : GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
1918 : kd->reserve_closing_delay),
1919 : GNUNET_JSON_pack_timestamp ("list_issue_date",
1920 : kd->list_issue_date),
1921 : GNUNET_JSON_pack_array_steal ("signkeys",
1922 : signkeys),
1923 : GNUNET_JSON_pack_array_steal ("denoms",
1924 : denoms),
1925 : GNUNET_JSON_pack_array_steal ("auditors",
1926 : auditors));
1927 0 : return GNUNET_JSON_PACK (
1928 : GNUNET_JSON_pack_uint64 ("version",
1929 : EXCHANGE_SERIALIZATION_FORMAT_VERSION),
1930 : GNUNET_JSON_pack_timestamp ("expire",
1931 : exchange->key_data_expiration),
1932 : GNUNET_JSON_pack_string ("exchange_url",
1933 : exchange->url),
1934 : GNUNET_JSON_pack_object_steal ("keys",
1935 : keys));
1936 : }
1937 :
1938 :
1939 : struct TALER_EXCHANGE_Handle *
1940 0 : TALER_EXCHANGE_connect (
1941 : struct GNUNET_CURL_Context *ctx,
1942 : const char *url,
1943 : TALER_EXCHANGE_CertificationCallback cert_cb,
1944 : void *cert_cb_cls,
1945 : ...)
1946 : {
1947 : struct TALER_EXCHANGE_Handle *exchange;
1948 : va_list ap;
1949 : enum TALER_EXCHANGE_Option opt;
1950 :
1951 0 : TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
1952 : url);
1953 : /* Disable 100 continue processing */
1954 0 : GNUNET_break (GNUNET_OK ==
1955 : GNUNET_CURL_append_header (ctx,
1956 : MHD_HTTP_HEADER_EXPECT ":"));
1957 0 : exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
1958 0 : exchange->ctx = ctx;
1959 0 : exchange->url = GNUNET_strdup (url);
1960 0 : exchange->cert_cb = cert_cb;
1961 0 : exchange->cert_cb_cls = cert_cb_cls;
1962 0 : exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys,
1963 : exchange);
1964 0 : va_start (ap, cert_cb_cls);
1965 0 : while (TALER_EXCHANGE_OPTION_END !=
1966 0 : (opt = va_arg (ap, int)))
1967 : {
1968 0 : switch (opt)
1969 : {
1970 0 : case TALER_EXCHANGE_OPTION_END:
1971 0 : GNUNET_assert (0);
1972 : break;
1973 0 : case TALER_EXCHANGE_OPTION_DATA:
1974 : {
1975 0 : const json_t *data = va_arg (ap, const json_t *);
1976 :
1977 0 : deserialize_data (exchange,
1978 : data);
1979 0 : break;
1980 : }
1981 0 : default:
1982 0 : GNUNET_assert (0);
1983 : break;
1984 : }
1985 : }
1986 0 : va_end (ap);
1987 0 : return exchange;
1988 : }
1989 :
1990 :
1991 : /**
1992 : * Compute the network timeout for the next request to /keys.
1993 : *
1994 : * @param exchange the exchange handle
1995 : * @returns the timeout in seconds (for use by CURL)
1996 : */
1997 : static long
1998 0 : get_keys_timeout_seconds (struct TALER_EXCHANGE_Handle *exchange)
1999 : {
2000 : unsigned int kec;
2001 :
2002 : /* if retry counter >= 8, do not bother to go further, we
2003 : stop the exponential back-off at 128 anyway. */
2004 0 : kec = GNUNET_MIN (7,
2005 : exchange->keys_error_count);
2006 0 : return GNUNET_MIN (120,
2007 : 5 + (1L << kec));
2008 : }
2009 :
2010 :
2011 : /**
2012 : * Initiate download of /keys from the exchange.
2013 : *
2014 : * @param cls exchange where to download /keys from
2015 : */
2016 : static void
2017 0 : request_keys (void *cls)
2018 : {
2019 0 : struct TALER_EXCHANGE_Handle *exchange = cls;
2020 : struct KeysRequest *kr;
2021 : CURL *eh;
2022 0 : char url[200] = "/keys?";
2023 :
2024 0 : exchange->retry_task = NULL;
2025 0 : GNUNET_assert (NULL == exchange->kr);
2026 0 : kr = GNUNET_new (struct KeysRequest);
2027 0 : kr->exchange = exchange;
2028 :
2029 0 : if (GNUNET_YES == TEAH_handle_is_ready (exchange))
2030 : {
2031 0 : TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
2032 : GNUNET_TIME_timestamp2s (
2033 : exchange->key_data.last_denom_issue_date));
2034 0 : sprintf (&url[strlen (url)],
2035 : "last_issue_date=%llu&",
2036 : (unsigned long long)
2037 0 : exchange->key_data.last_denom_issue_date.abs_time.abs_value_us
2038 : / 1000000LLU);
2039 : }
2040 :
2041 : /* Clean the last '&'/'?' sign that we optimistically put. */
2042 0 : url[strlen (url) - 1] = '\0';
2043 0 : kr->url = TEAH_path_to_url (exchange,
2044 : url);
2045 0 : if (NULL == kr->url)
2046 : {
2047 0 : struct TALER_EXCHANGE_HttpResponse hr = {
2048 : .ec = TALER_EC_GENERIC_CONFIGURATION_INVALID
2049 : };
2050 :
2051 0 : GNUNET_free (kr);
2052 0 : exchange->keys_error_count++;
2053 0 : exchange->state = MHS_FAILED;
2054 0 : exchange->cert_cb (exchange->cert_cb_cls,
2055 : &hr,
2056 : NULL,
2057 : TALER_EXCHANGE_VC_PROTOCOL_ERROR);
2058 0 : return;
2059 : }
2060 :
2061 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2062 : "Requesting keys with URL `%s'.\n",
2063 : kr->url);
2064 0 : eh = TALER_EXCHANGE_curl_easy_get_ (kr->url);
2065 0 : if (NULL == eh)
2066 : {
2067 0 : GNUNET_free (kr->url);
2068 0 : GNUNET_free (kr);
2069 0 : exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay);
2070 0 : exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
2071 : &request_keys,
2072 : exchange);
2073 0 : return;
2074 : }
2075 0 : GNUNET_break (CURLE_OK ==
2076 : curl_easy_setopt (eh,
2077 : CURLOPT_VERBOSE,
2078 : 0));
2079 0 : GNUNET_break (CURLE_OK ==
2080 : curl_easy_setopt (eh,
2081 : CURLOPT_TIMEOUT,
2082 : get_keys_timeout_seconds (exchange)));
2083 0 : GNUNET_assert (CURLE_OK ==
2084 : curl_easy_setopt (eh,
2085 : CURLOPT_HEADERFUNCTION,
2086 : &header_cb));
2087 0 : GNUNET_assert (CURLE_OK ==
2088 : curl_easy_setopt (eh,
2089 : CURLOPT_HEADERDATA,
2090 : kr));
2091 0 : kr->job = GNUNET_CURL_job_add_with_ct_json (exchange->ctx,
2092 : eh,
2093 : &keys_completed_cb,
2094 : kr);
2095 0 : exchange->kr = kr;
2096 : }
2097 :
2098 :
2099 : void
2100 0 : TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
2101 : {
2102 : struct TEAH_AuditorListEntry *ale;
2103 :
2104 0 : while (NULL != (ale = exchange->auditors_head))
2105 : {
2106 : struct TEAH_AuditorInteractionEntry *aie;
2107 :
2108 0 : while (NULL != (aie = ale->ai_head))
2109 : {
2110 0 : GNUNET_assert (aie->ale == ale);
2111 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2112 : "Not sending deposit confirmation to auditor `%s' due to exchange disconnect\n",
2113 : ale->auditor_url);
2114 0 : TALER_AUDITOR_deposit_confirmation_cancel (aie->dch);
2115 0 : GNUNET_CONTAINER_DLL_remove (ale->ai_head,
2116 : ale->ai_tail,
2117 : aie);
2118 0 : GNUNET_free (aie);
2119 : }
2120 0 : GNUNET_CONTAINER_DLL_remove (exchange->auditors_head,
2121 : exchange->auditors_tail,
2122 : ale);
2123 0 : TALER_LOG_DEBUG ("Disconnecting the auditor `%s'\n",
2124 : ale->auditor_url);
2125 0 : TALER_AUDITOR_disconnect (ale->ah);
2126 0 : GNUNET_free (ale->auditor_url);
2127 0 : GNUNET_free (ale);
2128 : }
2129 0 : if (NULL != exchange->kr)
2130 : {
2131 0 : GNUNET_CURL_job_cancel (exchange->kr->job);
2132 0 : free_keys_request (exchange->kr);
2133 0 : exchange->kr = NULL;
2134 : }
2135 0 : free_key_data (&exchange->key_data);
2136 0 : if (NULL != exchange->key_data_raw)
2137 : {
2138 0 : json_decref (exchange->key_data_raw);
2139 0 : exchange->key_data_raw = NULL;
2140 : }
2141 0 : if (NULL != exchange->retry_task)
2142 : {
2143 0 : GNUNET_SCHEDULER_cancel (exchange->retry_task);
2144 0 : exchange->retry_task = NULL;
2145 : }
2146 0 : GNUNET_free (exchange->url);
2147 0 : GNUNET_free (exchange);
2148 0 : }
2149 :
2150 :
2151 : enum GNUNET_GenericReturnValue
2152 0 : TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
2153 : const struct TALER_ExchangePublicKeyP *pub)
2154 : {
2155 : struct GNUNET_TIME_Absolute now;
2156 :
2157 : /* we will check using a tolerance of 1h for the time */
2158 0 : now = GNUNET_TIME_absolute_get ();
2159 0 : for (unsigned int i = 0; i<keys->num_sign_keys; i++)
2160 0 : if ( (GNUNET_TIME_absolute_cmp (
2161 : keys->sign_keys[i].valid_from.abs_time,
2162 : <=,
2163 : GNUNET_TIME_absolute_add (now,
2164 0 : LIFETIME_TOLERANCE))) &&
2165 0 : (GNUNET_TIME_absolute_cmp (
2166 : keys->sign_keys[i].valid_until.abs_time,
2167 : >,
2168 : GNUNET_TIME_absolute_subtract (now,
2169 0 : LIFETIME_TOLERANCE))) &&
2170 0 : (0 == GNUNET_memcmp (pub,
2171 : &keys->sign_keys[i].key)) )
2172 0 : return GNUNET_OK;
2173 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2174 : "Signing key not valid at time %s\n",
2175 : GNUNET_TIME_absolute2s (now));
2176 0 : return GNUNET_SYSERR;
2177 : }
2178 :
2179 :
2180 : const char *
2181 0 : TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange)
2182 : {
2183 0 : return exchange->url;
2184 : }
2185 :
2186 :
2187 : const struct TALER_EXCHANGE_DenomPublicKey *
2188 0 : TALER_EXCHANGE_get_denomination_key (
2189 : const struct TALER_EXCHANGE_Keys *keys,
2190 : const struct TALER_DenominationPublicKey *pk)
2191 : {
2192 0 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
2193 0 : if (0 ==
2194 0 : TALER_denom_pub_cmp (pk,
2195 0 : &keys->denom_keys[i].key))
2196 0 : return &keys->denom_keys[i];
2197 0 : return NULL;
2198 : }
2199 :
2200 :
2201 : const struct TALER_EXCHANGE_GlobalFee *
2202 0 : TALER_EXCHANGE_get_global_fee (
2203 : const struct TALER_EXCHANGE_Keys *keys,
2204 : struct GNUNET_TIME_Timestamp ts)
2205 : {
2206 0 : for (unsigned int i = 0; i<keys->num_global_fees; i++)
2207 : {
2208 0 : const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
2209 :
2210 0 : if (GNUNET_TIME_timestamp_cmp (ts,
2211 : >=,
2212 0 : gf->start_date) &&
2213 0 : GNUNET_TIME_timestamp_cmp (ts,
2214 : <,
2215 : gf->end_date))
2216 0 : return gf;
2217 : }
2218 0 : return NULL;
2219 : }
2220 :
2221 :
2222 : struct TALER_EXCHANGE_DenomPublicKey *
2223 0 : TALER_EXCHANGE_copy_denomination_key (
2224 : const struct TALER_EXCHANGE_DenomPublicKey *key)
2225 : {
2226 : struct TALER_EXCHANGE_DenomPublicKey *copy;
2227 :
2228 0 : copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
2229 0 : *copy = *key;
2230 0 : TALER_denom_pub_deep_copy (©->key,
2231 : &key->key);
2232 0 : return copy;
2233 : }
2234 :
2235 :
2236 : void
2237 0 : TALER_EXCHANGE_destroy_denomination_key (
2238 : struct TALER_EXCHANGE_DenomPublicKey *key)
2239 : {
2240 0 : TALER_denom_pub_free (&key->key);
2241 0 : GNUNET_free (key);
2242 0 : }
2243 :
2244 :
2245 : const struct TALER_EXCHANGE_DenomPublicKey *
2246 0 : TALER_EXCHANGE_get_denomination_key_by_hash (
2247 : const struct TALER_EXCHANGE_Keys *keys,
2248 : const struct TALER_DenominationHashP *hc)
2249 : {
2250 0 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
2251 0 : if (0 == GNUNET_memcmp (hc,
2252 : &keys->denom_keys[i].h_key))
2253 0 : return &keys->denom_keys[i];
2254 0 : return NULL;
2255 : }
2256 :
2257 :
2258 : const struct TALER_EXCHANGE_Keys *
2259 0 : TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange)
2260 : {
2261 0 : (void) TALER_EXCHANGE_check_keys_current (exchange,
2262 : TALER_EXCHANGE_CKF_NONE);
2263 0 : return &exchange->key_data;
2264 : }
2265 :
2266 :
2267 : json_t *
2268 0 : TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange)
2269 : {
2270 0 : (void) TALER_EXCHANGE_check_keys_current (exchange,
2271 : TALER_EXCHANGE_CKF_NONE);
2272 0 : return json_deep_copy (exchange->key_data_raw);
2273 : }
2274 :
2275 :
2276 : /* end of exchange_api_handle.c */
|